birth/src/user/arch/x86_64.zig
David Gonzalez Martin beda088388 wip
2023-08-09 20:35:16 -06:00

115 lines
3.9 KiB
Zig

const lib = @import("lib");
const log = lib.log;
const assert = lib.assert;
const birth = @import("birth");
const user = @import("user");
const FPU = birth.arch.FPU;
const Registers = birth.arch.Registers;
const RegisterArena = birth.arch.RegisterArena;
const VirtualAddress = lib.VirtualAddress;
const PhysicalMemoryRegion = user.PhysicalMemoryRegion;
const PhysicalMap = user.PhysicalMap;
const SlotAllocator = user.SlotAllocator;
const Thread = user.Thread;
const VirtualAddressSpace = user.VirtualAddressSpace;
pub const Scheduler = extern struct {
common: birth.arch.UserScheduler,
generic: user.Scheduler,
pub fn initDisabled(scheduler: *Scheduler) void {
_ = scheduler;
// TODO:
// *set entry points?
// *set tls registers?
}
pub noinline fn restore(scheduler: *Scheduler, register_arena: *const RegisterArena) noreturn {
assert(scheduler.common.generic.disabled);
assert(scheduler.common.generic.has_work);
assert(register_arena.registers.rip > lib.arch.valid_page_sizes[0]);
assert(register_arena.registers.rflags.IF and register_arena.registers.rflags.reserved0);
register_arena.contextSwitch();
}
};
// CRT0
pub fn _start() callconv(.Naked) noreturn {
asm volatile (
\\push %rbp
\\jmp *%[startFunction]
:
: [startFunction] "r" (user.start),
);
}
pub inline fn setInitialState(register_arena: *RegisterArena, entry: VirtualAddress, stack_virtual_address: VirtualAddress, arguments: birth.syscall.Arguments) void {
assert(stack_virtual_address.value() > lib.arch.valid_page_sizes[0]);
assert(lib.isAligned(stack_virtual_address.value(), lib.arch.stack_alignment));
var stack_address = stack_virtual_address;
// x86_64 ABI
stack_address.subOffset(@sizeOf(usize));
register_arena.registers.rip = entry.value();
register_arena.registers.rsp = stack_address.value();
register_arena.registers.rflags = .{ .IF = true };
register_arena.registers.rdi = arguments[0];
register_arena.registers.rsi = arguments[1];
register_arena.registers.rdx = arguments[2];
register_arena.registers.rcx = arguments[3];
register_arena.registers.r8 = arguments[4];
register_arena.registers.r9 = arguments[5];
register_arena.fpu = lib.zeroes(FPU);
// register_arena.fpu.fcw = 0x037f;
register_arena.fpu.fcw = 0x1f80;
}
pub inline fn maybeCurrentScheduler() ?*user.Scheduler {
return asm volatile (
\\mov %fs:0, %[user_scheduler]
: [user_scheduler] "=r" (-> ?*user.Scheduler),
:
: "memory"
);
}
pub inline fn currentScheduler() *user.Scheduler {
const result = maybeCurrentScheduler().?;
return result;
}
/// This is an interface to user.PhysicalMap, providing the architecture-specific functionality
pub const PhysicalMapInterface = struct {
pub fn determineAddress(physical_map: *PhysicalMap, physical_memory_region: PhysicalMemoryRegion, alignment: usize) !VirtualAddress {
_ = physical_memory_region;
_ = alignment;
assert(physical_map.virtual_address_space.regions != null);
log.debug("PMap: 0x{x}", .{@intFromPtr(physical_map.virtual_address_space.regions)});
log.debug("PMap: {?}", .{physical_map.virtual_address_space.regions});
@panic("TODO: PhysicalMapInterface.determineAddress");
}
pub fn initializeCurrent(physical_map: *PhysicalMap) !void {
_ = physical_map;
log.warn("TODO: PhysicalMapInterface.initializeCurrent", .{});
}
pub fn init(virtual_address_space: *VirtualAddressSpace, page_level: u3, slot_allocator: *SlotAllocator) !PhysicalMap {
var result = PhysicalMap{
.virtual_address_space = virtual_address_space,
.slot_allocator = slot_allocator,
};
_ = page_level;
try result.initPageTableManagement();
@panic("TODO: PhysicalMap.init");
}
};