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"); } };