diff --git a/core/src/arch/cpu.zig b/core/src/arch/cpu.zig index 6f4b048..694d49a 100644 --- a/core/src/arch/cpu.zig +++ b/core/src/arch/cpu.zig @@ -25,7 +25,7 @@ pub fn setupCore(allocator: *pmm.FrameAllocator) !void { const idle_thread = &core.idle_thread.data; idle_thread.id = 0; - idle_thread.directory = null; + idle_thread.mapper = null; idle_thread.regs = std.mem.zeroes(@TypeOf(idle_thread.regs)); idle_thread.state = .Running; thread.arch.initKernelRegisters(&idle_thread.regs); diff --git a/core/src/arch/x86_64/thread.zig b/core/src/arch/x86_64/thread.zig index 7049400..60fbd4f 100644 --- a/core/src/arch/x86_64/thread.zig +++ b/core/src/arch/x86_64/thread.zig @@ -1,7 +1,7 @@ const std = @import("std"); const interrupts = @import("interrupts.zig"); -pub inline fn enterTask(regs: *interrupts.InterruptStackFrame, comptime base: u64, directory: *anyopaque) noreturn { +pub inline fn enterTask(regs: *interrupts.InterruptStackFrame, comptime base: u64, directory: u64) noreturn { asm volatile ( \\ addq %[base], %rsp \\ push %[ss] diff --git a/core/src/arch/x86_64/vmm.zig b/core/src/arch/x86_64/vmm.zig index fddd282..3d9fb6a 100644 --- a/core/src/arch/x86_64/vmm.zig +++ b/core/src/arch/x86_64/vmm.zig @@ -40,6 +40,15 @@ pub const PageDirectory = struct { entries: [512]PageTableEntry, }; +pub const MemoryMapper = struct { + phys: pmm.PhysFrame, + directory: *PageDirectory, + + pub fn create(frame: pmm.PhysFrame, base: usize) MemoryMapper { + return .{ .phys = frame, .directory = @ptrFromInt(frame.virtualAddress(base)) }; + } +}; + pub const Flags = enum(u32) { None = 0, ReadWrite = 1, @@ -97,9 +106,9 @@ fn getTable(pte: *PageTableEntry, base: usize) *allowzero PageDirectory { return @ptrFromInt(frame.virtualAddress(base)); } -pub fn map(allocator: *pmm.FrameAllocator, directory: *PageDirectory, base: usize, virt_address: u64, phys: pmm.PhysFrame, flags: u32, use_huge_pages: bool) !void { +pub fn map(allocator: *pmm.FrameAllocator, mapper: MemoryMapper, base: usize, virt_address: u64, phys: pmm.PhysFrame, flags: u32, use_huge_pages: bool) !void { const indexes = calculatePageTableIndexes(virt_address); - const l4 = &directory.entries[indexes.level4]; + const l4 = &mapper.directory.entries[indexes.level4]; try setUpParentPageTableEntry(allocator, l4, flags, base); const l3 = &getTable(l4, base).entries[indexes.level3]; @@ -122,9 +131,9 @@ pub fn map(allocator: *pmm.FrameAllocator, directory: *PageDirectory, base: usiz updatePageTableEntry(l1, phys, flags); } -pub fn getEntry(directory: *PageDirectory, base: usize, virt_address: u64) ?*PageTableEntry { +pub fn getEntry(mapper: MemoryMapper, base: usize, virt_address: u64) ?*PageTableEntry { const indexes = calculatePageTableIndexes(virt_address); - const l4 = &directory.entries[indexes.level4]; + const l4 = &mapper.directory.entries[indexes.level4]; if (l4.present == 0) return null; const l3 = &getTable(l4, base).entries[indexes.level3]; @@ -141,7 +150,7 @@ pub fn getEntry(directory: *PageDirectory, base: usize, virt_address: u64) ?*Pag return l1; } -pub fn copyToUser(directory: *PageDirectory, base: usize, user: usize, kernel: [*]const u8, size: usize) !void { +pub fn copyToUser(mapper: MemoryMapper, base: usize, user: usize, kernel: [*]const u8, size: usize) !void { const remainder: usize = @rem(user, platform.PAGE_SIZE); const user_page = user - remainder; @@ -150,7 +159,7 @@ pub fn copyToUser(directory: *PageDirectory, base: usize, user: usize, kernel: [ var count = size; if (user_address != user_page) { - const pte = getEntry(directory, base, user_page) orelse return error.MemoryNotInUse; + const pte = getEntry(mapper, base, user_page) orelse return error.MemoryNotInUse; const frame = pmm.PhysFrame{ .address = pte.get_address() }; const amount: usize = @min((platform.PAGE_SIZE - remainder), count); const virt = frame.virtualAddress(base) + remainder; @@ -163,7 +172,7 @@ pub fn copyToUser(directory: *PageDirectory, base: usize, user: usize, kernel: [ } while (count > 0) { - const pte = getEntry(directory, base, user_address) orelse return error.MemoryNotInUse; + const pte = getEntry(mapper, base, user_address) orelse return error.MemoryNotInUse; const frame = pmm.PhysFrame{ .address = pte.get_address() }; const amount: usize = @min(platform.PAGE_SIZE, count); const virt = frame.virtualAddress(base); @@ -178,7 +187,7 @@ pub fn copyToUser(directory: *PageDirectory, base: usize, user: usize, kernel: [ return; } -pub fn memsetUser(directory: *PageDirectory, base: usize, user: usize, elem: u8, size: usize) !void { +pub fn memsetUser(mapper: MemoryMapper, base: usize, user: usize, elem: u8, size: usize) !void { const remainder: usize = @rem(user, platform.PAGE_SIZE); const user_page = user - remainder; @@ -186,7 +195,7 @@ pub fn memsetUser(directory: *PageDirectory, base: usize, user: usize, elem: u8, var count = size; if (user_address != user_page) { - const pte = getEntry(directory, base, user_page) orelse return error.MemoryNotInUse; + const pte = getEntry(mapper, base, user_page) orelse return error.MemoryNotInUse; const frame = pmm.PhysFrame{ .address = pte.get_address() }; const amount: usize = @min((platform.PAGE_SIZE - remainder), count); const virt = frame.virtualAddress(base) + remainder; @@ -198,7 +207,7 @@ pub fn memsetUser(directory: *PageDirectory, base: usize, user: usize, elem: u8, } while (count > 0) { - const pte = getEntry(directory, base, user_address) orelse return error.MemoryNotInUse; + const pte = getEntry(mapper, base, user_address) orelse return error.MemoryNotInUse; const frame = pmm.PhysFrame{ .address = pte.get_address() }; const amount: usize = @min(platform.PAGE_SIZE, count); const virt = frame.virtualAddress(base); @@ -212,25 +221,25 @@ pub fn memsetUser(directory: *PageDirectory, base: usize, user: usize, elem: u8, return; } -pub fn allocAndMap(allocator: *pmm.FrameAllocator, directory: *PageDirectory, base: u64, pages: usize, flags: u32) !void { +pub fn allocAndMap(allocator: *pmm.FrameAllocator, mapper: MemoryMapper, base: u64, pages: usize, flags: u32) !void { var virt = base; var i: usize = 0; while (i < pages) { const frame = try pmm.allocFrame(allocator); - try map(allocator, directory, PHYSICAL_MAPPING_BASE, virt, frame, flags, false); + try map(allocator, mapper, PHYSICAL_MAPPING_BASE, virt, frame, flags, false); virt += platform.PAGE_SIZE; i += 1; } } -fn mapPhysicalMemory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, directory: *PageDirectory, base: usize, flags: u32) !void { +fn mapPhysicalMemory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, mapper: MemoryMapper, base: usize, flags: u32) !void { const address_space_size = mmap.getAddressSpaceSize(tag) orelse return error.InvalidMemoryMap; const address_space_pages = address_space_size / HUGE_PAGE_SIZE; var index: usize = 0; while (index < address_space_pages) : (index += 1) { - try map(allocator, directory, 0, base + index * HUGE_PAGE_SIZE, pmm.PhysFrame{ .address = index * HUGE_PAGE_SIZE }, flags, true); + try map(allocator, mapper, 0, base + index * HUGE_PAGE_SIZE, pmm.PhysFrame{ .address = index * HUGE_PAGE_SIZE }, flags, true); } } @@ -251,16 +260,18 @@ fn lockPageDirectoryFrames(allocator: *pmm.FrameAllocator, directory: *PageDirec } } -fn lockPageDirectory(allocator: *pmm.FrameAllocator, directory: *PageDirectory) !void { - try pmm.lockFrame(allocator, @intFromPtr(directory)); - try lockPageDirectoryFrames(allocator, directory, 4); +fn lockPageDirectory(allocator: *pmm.FrameAllocator, mapper: MemoryMapper) !void { + try pmm.lockFrame(allocator, mapper.phys.address); + try lockPageDirectoryFrames(allocator, mapper.directory, 4); } -fn setUpKernelPageDirectory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t) !*PageDirectory { +fn setUpKernelPageDirectory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t) !pmm.PhysFrame { const directory = readPageDirectory(); - try lockPageDirectory(allocator, directory); - try mapPhysicalMemory(allocator, tag, directory, PHYSICAL_MAPPING_BASE, @intFromEnum(Flags.ReadWrite) | @intFromEnum(Flags.NoExecute) | @intFromEnum(Flags.Global)); + const mapper = MemoryMapper.create(directory, 0); + + try lockPageDirectory(allocator, mapper); + try mapPhysicalMemory(allocator, tag, mapper, PHYSICAL_MAPPING_BASE, @intFromEnum(Flags.ReadWrite) | @intFromEnum(Flags.NoExecute) | @intFromEnum(Flags.Global)); return directory; } @@ -276,37 +287,35 @@ fn setUpInitialUserPageDirectory(allocator: *pmm.FrameAllocator, tag: *easyboot. const user_physical_address_base = (USER_ADDRESS_RANGE_END + 1) - physical_address_space_size; - try mapPhysicalMemory(allocator, tag, user_directory, user_physical_address_base, @intFromEnum(Flags.ReadWrite) | @intFromEnum(Flags.NoExecute) | @intFromEnum(Flags.User)); + const mapper = MemoryMapper.create(.{ .address = @intFromPtr(user_directory) }, 0); + + try mapPhysicalMemory(allocator, tag, mapper, user_physical_address_base, @intFromEnum(Flags.ReadWrite) | @intFromEnum(Flags.NoExecute) | @intFromEnum(Flags.User)); return user_physical_address_base; } pub fn createInitialMappings(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, user_directory: *PageDirectory) !usize { - const directory = try setUpKernelPageDirectory(allocator, tag); - const base = try setUpInitialUserPageDirectory(allocator, tag, directory, user_directory); + const frame = try setUpKernelPageDirectory(allocator, tag); + const mapper = MemoryMapper.create(frame, 0); + const base = try setUpInitialUserPageDirectory(allocator, tag, mapper.directory, user_directory); - setPageDirectory(directory); + setPageDirectory(mapper.phys); allocator.bitmap.location = @ptrFromInt(@as(usize, PHYSICAL_MAPPING_BASE) + @intFromPtr(allocator.bitmap.location)); return base; } -pub fn readPageDirectory() *PageDirectory { - var directory: *PageDirectory = undefined; +pub fn readPageDirectory() pmm.PhysFrame { + var address: u64 = undefined; asm volatile ("mov %%cr3, %[dir]" - : [dir] "=r" (directory), + : [dir] "=r" (address), ); - return directory; + return .{ .address = address }; } - -pub fn getPhysicalPageDirectory(directory: *PageDirectory) *PageDirectory { - return @ptrFromInt(@intFromPtr(directory) - @as(usize, PHYSICAL_MAPPING_BASE)); -} - -pub fn setPageDirectory(directory: *PageDirectory) void { +pub fn setPageDirectory(directory: pmm.PhysFrame) void { asm volatile ("mov %[dir], %%cr3" : - : [dir] "{rdi}" (directory), + : [dir] "{rdi}" (directory.address), ); } diff --git a/core/src/elf.zig b/core/src/elf.zig index be6bea7..a1725ed 100644 --- a/core/src/elf.zig +++ b/core/src/elf.zig @@ -58,7 +58,7 @@ fn canWriteSegment(flags: u32) bool { return (flags & 2) > 0; } -pub fn loadElf(allocator: *pmm.FrameAllocator, directory: *vmm.PageDirectory, base_address: pmm.PhysFrame) !usize { +pub fn loadElf(allocator: *pmm.FrameAllocator, mapper: vmm.MemoryMapper, base_address: pmm.PhysFrame) !usize { const address = base_address.virtualAddress(vmm.PHYSICAL_MAPPING_BASE); debug.print("Address: {}\n", .{address}); @@ -117,15 +117,15 @@ pub fn loadElf(allocator: *pmm.FrameAllocator, directory: *vmm.PageDirectory, ba if (canExecuteSegment(program_header.p_flags)) flags &= ~@as(u32, @intFromEnum(vmm.Flags.NoExecute)); // Allocate physical memory for the segment - try vmm.allocAndMap(allocator, directory, base_vaddr, try std.math.divCeil(usize, program_header.p_memsz + vaddr_diff, platform.PAGE_SIZE), flags); + try vmm.allocAndMap(allocator, mapper, base_vaddr, try std.math.divCeil(usize, program_header.p_memsz + vaddr_diff, platform.PAGE_SIZE), flags); - try vmm.memsetUser(directory, vmm.PHYSICAL_MAPPING_BASE, base_vaddr, 0, vaddr_diff); + try vmm.memsetUser(mapper, vmm.PHYSICAL_MAPPING_BASE, base_vaddr, 0, vaddr_diff); - try vmm.copyToUser(directory, vmm.PHYSICAL_MAPPING_BASE, program_header.p_vaddr, @ptrFromInt(address + program_header.p_offset), program_header.p_filesz); + try vmm.copyToUser(mapper, vmm.PHYSICAL_MAPPING_BASE, program_header.p_vaddr, @ptrFromInt(address + program_header.p_offset), program_header.p_filesz); const bss_size = program_header.p_memsz - program_header.p_filesz; - try vmm.memsetUser(directory, vmm.PHYSICAL_MAPPING_BASE, program_header.p_vaddr + program_header.p_filesz, 0, bss_size); + try vmm.memsetUser(mapper, vmm.PHYSICAL_MAPPING_BASE, program_header.p_vaddr + program_header.p_filesz, 0, bss_size); } else { debug.print("ELF: Encountered non-loadable program header, skipping\n", .{}); } @@ -142,11 +142,11 @@ pub fn loadElf(allocator: *pmm.FrameAllocator, directory: *vmm.PageDirectory, ba return elf_header.e_entry; } -pub fn allocateStack(allocator: *pmm.FrameAllocator, directory: *vmm.PageDirectory, stack_top: usize, stack_size: usize) !usize { +pub fn allocateStack(allocator: *pmm.FrameAllocator, mapper: vmm.MemoryMapper, stack_top: usize, stack_size: usize) !usize { const pages = try std.math.divCeil(usize, stack_size, platform.PAGE_SIZE); const stack_bottom = stack_top - (pages * platform.PAGE_SIZE); - try vmm.allocAndMap(allocator, directory, stack_bottom, pages, @intFromEnum(vmm.Flags.ReadWrite) | @intFromEnum(vmm.Flags.User) | @intFromEnum(vmm.Flags.NoExecute)); + try vmm.allocAndMap(allocator, mapper, stack_bottom, pages, @intFromEnum(vmm.Flags.ReadWrite) | @intFromEnum(vmm.Flags.User) | @intFromEnum(vmm.Flags.NoExecute)); return stack_top - 16; } diff --git a/core/src/main.zig b/core/src/main.zig index df44027..a33b1fa 100644 --- a/core/src/main.zig +++ b/core/src/main.zig @@ -14,7 +14,7 @@ const MultibootInfo = [*c]u8; const Context = struct { allocator: *pmm.FrameAllocator, - directory: *vmm.PageDirectory, + mapper: vmm.MemoryMapper, regs: *interrupts.InterruptStackFrame, }; @@ -55,8 +55,8 @@ export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn { }; // At this point the physical address space is already mapped into kernel virtual memory. - const init_directory: *vmm.PageDirectory = @ptrFromInt(frame.virtualAddress(vmm.PHYSICAL_MAPPING_BASE)); - init_directory.* = dir; + const mapper = vmm.MemoryMapper.create(frame, vmm.PHYSICAL_MAPPING_BASE); + mapper.directory.* = dir; cpu.setupCore(&allocator) catch |err| { debug.print("Error while setting up core-specific scheduler structures: {}\n", .{err}); @@ -68,13 +68,13 @@ export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn { while (true) {} }; - init.directory = init_directory; + init.mapper = mapper; thread.arch.initUserRegisters(&init.regs); thread.arch.setArgument(&init.regs, base); thread.addThreadToScheduler(cpu.thisCore(), init); - const ctx = Context{ .allocator = &allocator, .directory = init_directory, .regs = &init.regs }; + const ctx = Context{ .allocator = &allocator, .mapper = mapper, .regs = &init.regs }; multiboot.findMultibootTags(easyboot.multiboot_tag_module_t, @ptrCast(info), struct { fn handler(mod: *easyboot.multiboot_tag_module_t, c: *const anyopaque) void { @@ -83,7 +83,7 @@ export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn { if (std.mem.eql(u8, mod.string()[0..name.len], name[0..name.len])) { const phys_frame = pmm.PhysFrame{ .address = mod.mod_start }; debug.print("Loading init from module at address {x}, virtual {x}\n", .{ mod.mod_start, phys_frame.virtualAddress(vmm.PHYSICAL_MAPPING_BASE) }); - const entry = elf.loadElf(context.allocator, context.directory, pmm.PhysFrame{ .address = mod.mod_start }) catch |err| { + const entry = elf.loadElf(context.allocator, context.mapper, pmm.PhysFrame{ .address = mod.mod_start }) catch |err| { debug.print("Error while loading ELF file for init: {}\n", .{err}); while (true) {} }; @@ -93,7 +93,7 @@ export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn { }.handler, &ctx); const default_stack_size = 0x80000; // 512 KiB. - const stack = elf.allocateStack(&allocator, init_directory, base - platform.PAGE_SIZE, default_stack_size) catch |err| { + const stack = elf.allocateStack(&allocator, mapper, base - platform.PAGE_SIZE, default_stack_size) catch |err| { debug.print("Error while creating stack for init: {}\n", .{err}); while (true) {} }; diff --git a/core/src/thread.zig b/core/src/thread.zig index 1f0374c..49d7bfe 100644 --- a/core/src/thread.zig +++ b/core/src/thread.zig @@ -13,7 +13,7 @@ pub const ThreadState = enum { pub const ThreadControlBlock = struct { id: u64, - directory: ?*vmm.PageDirectory, + mapper: ?vmm.MemoryMapper, regs: interrupts.InterruptStackFrame, state: ThreadState, @@ -31,11 +31,11 @@ pub fn enterTask(task: *ThreadControlBlock) noreturn { var directory = vmm.readPageDirectory(); - if (task.directory) |dir| { - directory = vmm.getPhysicalPageDirectory(dir); + if (task.mapper) |mapper| { + directory = mapper.phys; } - arch.enterTask(&task.regs, vmm.PHYSICAL_MAPPING_BASE, @ptrCast(directory)); + arch.enterTask(&task.regs, vmm.PHYSICAL_MAPPING_BASE, directory.address); } pub fn switchTask(regs: *interrupts.InterruptStackFrame, new_task: *ThreadControlBlock) void { @@ -44,8 +44,8 @@ pub fn switchTask(regs: *interrupts.InterruptStackFrame, new_task: *ThreadContro core.current_thread.regs = regs.*; regs.* = new_task.regs; - if (new_task.directory) |directory| { - if (vmm.readPageDirectory() != directory) vmm.setPageDirectory(vmm.getPhysicalPageDirectory(directory)); + if (new_task.mapper) |mapper| { + if (vmm.readPageDirectory().address != mapper.phys.address) vmm.setPageDirectory(mapper.phys); } new_task.ticks = ALLOCATED_TICKS_PER_TASK; @@ -83,7 +83,7 @@ pub fn createThreadControlBlock(allocator: *pmm.FrameAllocator) !*ThreadControlB const node: *ThreadList.Node = @ptrFromInt(frame.virtualAddress(vmm.PHYSICAL_MAPPING_BASE)); const thread = &node.data; thread.id = next_id.fetchAdd(1, .seq_cst); - thread.directory = null; + thread.mapper = null; thread.regs = std.mem.zeroes(@TypeOf(thread.regs)); thread.state = .Inactive;