From 55ddc468d508dee7f1137166940203e634360eb7 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sat, 22 Feb 2025 23:00:53 +0100 Subject: [PATCH] core: Reserve multiboot tags and module memory + load all modules as independent threads instead of just init Only init is started though, other modules are left in a dormant state so init can do whatever it wants and adjust them according to its needs before running them. --- core/src/arch/x86_64/vmm.zig | 18 ++--- core/src/main.zig | 141 +++++++++++++++++++++++------------ 2 files changed, 102 insertions(+), 57 deletions(-) diff --git a/core/src/arch/x86_64/vmm.zig b/core/src/arch/x86_64/vmm.zig index 9c5ad41..93fb7f1 100644 --- a/core/src/arch/x86_64/vmm.zig +++ b/core/src/arch/x86_64/vmm.zig @@ -234,13 +234,13 @@ pub fn allocAndMap(allocator: *pmm.FrameAllocator, space: AddressSpace, base: u6 } } -fn mapPhysicalMemory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, space: AddressSpace, base: usize, flags: u32) !void { +fn mapPhysicalMemory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, space: AddressSpace, base: usize, start_addr: 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, space, 0, base + index * HUGE_PAGE_SIZE, pmm.PhysFrame{ .address = index * HUGE_PAGE_SIZE }, flags, true); + try map(allocator, space, base, start_addr + index * HUGE_PAGE_SIZE, pmm.PhysFrame{ .address = index * HUGE_PAGE_SIZE }, flags, true); } } @@ -272,12 +272,15 @@ fn setUpKernelPageDirectory(allocator: *pmm.FrameAllocator, tag: *easyboot.multi const space = AddressSpace.create(table, 0); try lockPageTable(allocator, space); - try mapPhysicalMemory(allocator, tag, space, PHYSICAL_MAPPING_BASE, @intFromEnum(Flags.ReadWrite) | @intFromEnum(Flags.NoExecute) | @intFromEnum(Flags.Global)); + try mapPhysicalMemory(allocator, tag, space, 0, PHYSICAL_MAPPING_BASE, @intFromEnum(Flags.ReadWrite) | @intFromEnum(Flags.NoExecute) | @intFromEnum(Flags.Global)); return table; } -fn setUpInitialUserPageDirectory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, kernel_table: *PageTable, user_table: *PageTable) !usize { +pub fn setUpInitialUserPageDirectory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, user_table: *PageTable) !usize { + const kernel_space = AddressSpace.create(readPageTable(), PHYSICAL_MAPPING_BASE); + const kernel_table = kernel_space.table; + const physical_address_space_size = mmap.getAddressSpaceSize(tag) orelse return error.InvalidMemoryMap; user_table.* = std.mem.zeroes(PageTable); @@ -290,21 +293,18 @@ fn setUpInitialUserPageDirectory(allocator: *pmm.FrameAllocator, tag: *easyboot. const space = AddressSpace.create(.{ .address = @intFromPtr(user_table) }, 0); - try mapPhysicalMemory(allocator, tag, space, user_physical_address_base, @intFromEnum(Flags.ReadWrite) | @intFromEnum(Flags.NoExecute) | @intFromEnum(Flags.User)); + try mapPhysicalMemory(allocator, tag, space, PHYSICAL_MAPPING_BASE, 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_table: *PageTable) !usize { +pub fn createInitialMapping(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t) !void { const frame = try setUpKernelPageDirectory(allocator, tag); const space = AddressSpace.create(frame, 0); - const base = try setUpInitialUserPageDirectory(allocator, tag, space.table, user_table); setPageTable(space.phys); allocator.bitmap.location = @ptrFromInt(@as(usize, PHYSICAL_MAPPING_BASE) + @intFromPtr(allocator.bitmap.location)); - - return base; } pub fn readPageTable() pmm.PhysFrame { diff --git a/core/src/main.zig b/core/src/main.zig index b0e104a..0dbe38f 100644 --- a/core/src/main.zig +++ b/core/src/main.zig @@ -13,11 +13,49 @@ const elf = @import("elf.zig"); const MultibootInfo = [*c]u8; -const Context = struct { - allocator: *pmm.FrameAllocator, - space: vmm.AddressSpace, - regs: *platform.Registers, -}; +fn adjustAddressToPageBoundary(address: *usize, size: *usize) void { + const diff = address.* % platform.PAGE_SIZE; + + address.* -= diff; + size.* += diff; +} + +fn reserveMultibootMemory(allocator: *pmm.FrameAllocator, info: MultibootInfo) !void { + const info_tag: *easyboot.multiboot_info_t = @alignCast(@ptrCast(info)); + + var address: usize = @intFromPtr(info); + var size: usize = info_tag.total_size; + adjustAddressToPageBoundary(&address, &size); + + debug.print("Locking multiboot memory at {x}, {d} bytes\n", .{ address, size }); + + try pmm.lockFrames(allocator, address, try std.math.divCeil(usize, size, platform.PAGE_SIZE)); + + const Context = struct { + allocator: *pmm.FrameAllocator, + }; + + var ctx = Context{ .allocator = allocator }; + + multiboot.findMultibootTags(easyboot.multiboot_tag_module_t, @ptrCast(info), struct { + fn reserveMemory(mod: *easyboot.multiboot_tag_module_t, context: *const Context) !void { + var mod_address: usize = mod.mod_start; + var mod_size: usize = mod.mod_end - mod.mod_start; + adjustAddressToPageBoundary(&mod_address, &mod_size); + + debug.print("Locking memory for module {s} at address {x}, {d} bytes\n", .{ mod.string(), mod_address, mod_size }); + + try pmm.lockFrames(context.allocator, mod_address, try std.math.divCeil(usize, mod_size, platform.PAGE_SIZE)); + } + + fn handler(mod: *easyboot.multiboot_tag_module_t, context: *const anyopaque) void { + reserveMemory(mod, @alignCast(@ptrCast(context))) catch |err| { + debug.print("Error while reserving multiboot memory {s}: {}\n", .{ mod.string(), err }); + while (true) {} + }; + } + }.handler, &ctx); +} export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn { interrupts.disableInterrupts(); @@ -42,64 +80,66 @@ export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn { while (true) {} }; - var table: vmm.PageTable = std.mem.zeroes(vmm.PageTable); - const base: usize = vmm.createInitialMappings(&allocator, tag, &table) catch |err| { + reserveMultibootMemory(&allocator, info) catch |err| { + debug.print("Error while reserving multiboot memory: {}\n", .{err}); + while (true) {} + }; + + vmm.createInitialMapping(&allocator, tag) catch |err| { debug.print("Error while creating initial mappings: {}\n", .{err}); while (true) {} }; - debug.print("Physical memory base mapping for init: {x}\n", .{base}); - - const frame = pmm.allocFrame(&allocator) catch |err| { - debug.print("Error while creating frame for user page directory: {}\n", .{err}); - while (true) {} - }; - - // At this point the physical address space is already mapped into kernel virtual memory. - const space = vmm.AddressSpace.create(frame, vmm.PHYSICAL_MAPPING_BASE); - space.table.* = table; - cpu.setupCore(&allocator) catch |err| { debug.print("Error while setting up core-specific scheduler structures: {}\n", .{err}); while (true) {} }; - const init = thread.createThreadControlBlock(&allocator) catch |err| { - debug.print("Error while creating thread control block for init: {}\n", .{err}); - while (true) {} + const Context = struct { + allocator: *pmm.FrameAllocator, + mmap: *easyboot.multiboot_tag_mmap_t, + init: ?*thread.ThreadControlBlock, }; - init.address_space = space; - init.user_priority = 255; - init.tokens = @intFromEnum(system.kernel.Token.Root); - thread.arch.initUserRegisters(&init.regs); - thread.arch.setArguments(&init.regs, base, space.phys.address); - - const ctx = Context{ .allocator = &allocator, .space = space, .regs = &init.regs }; + var ctx = Context{ .allocator = &allocator, .mmap = tag, .init = null }; multiboot.findMultibootTags(easyboot.multiboot_tag_module_t, @ptrCast(info), struct { - fn handler(mod: *easyboot.multiboot_tag_module_t, c: *const anyopaque) void { - const context: *const Context = @alignCast(@ptrCast(c)); - const name = "init"; - 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.space, pmm.PhysFrame{ .address = mod.mod_start }) catch |err| { - debug.print("Error while loading ELF file for init: {}\n", .{err}); - while (true) {} - }; - thread.arch.setAddress(context.regs, entry); - } + fn loadModule(mod: *easyboot.multiboot_tag_module_t, context: *Context) !void { + const frame = try pmm.allocFrame(context.allocator); + const space = vmm.AddressSpace.create(frame, vmm.PHYSICAL_MAPPING_BASE); + + const base = try vmm.setUpInitialUserPageDirectory(context.allocator, context.mmap, space.table); + + const module = try thread.createThreadControlBlock(context.allocator); + + module.address_space = space; + module.user_priority = 255; + module.tokens = @intFromEnum(system.kernel.Token.Root); + thread.arch.initUserRegisters(&module.regs); + thread.arch.setArguments(&module.regs, base, space.phys.address); + + const mod_start = pmm.PhysFrame{ .address = mod.mod_start }; + + debug.print("Loading module {s} at address {x}, virtual {x}\n", .{ mod.string(), mod.mod_start, mod_start.virtualAddress(vmm.PHYSICAL_MAPPING_BASE) }); + const entry = try elf.loadElf(context.allocator, space, mod_start); + thread.arch.setAddress(&module.regs, entry); + + const default_stack_size = 0x40000; // 256 KiB. + const stack = try elf.allocateStack(context.allocator, space, base - platform.PAGE_SIZE, default_stack_size); + thread.arch.setStack(&module.regs, stack); + + const init_name = "init"; + if (std.mem.eql(u8, init_name[0..init_name.len], mod.string()[0..init_name.len])) context.init = module; + } + + fn handler(mod: *easyboot.multiboot_tag_module_t, context: *anyopaque) void { + loadModule(mod, @alignCast(@ptrCast(context))) catch |err| { + debug.print("Error while loading module file {s}: {}\n", .{ mod.string(), err }); + while (true) {} + }; } }.handler, &ctx); - const default_stack_size = 0x80000; // 512 KiB. - const stack = elf.allocateStack(&allocator, space, base - platform.PAGE_SIZE, default_stack_size) catch |err| { - debug.print("Error while creating stack for init: {}\n", .{err}); - while (true) {} - }; - thread.arch.setStack(&init.regs, stack); - pmm.setGlobalAllocator(&allocator) catch |err| { debug.print("Error while setting up global frame allocator: {}\n", .{err}); while (true) {} @@ -107,7 +147,12 @@ export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn { platform.platformEndInit(); - thread.enterThread(init); + if (ctx.init) |init| { + thread.enterThread(init); + } else { + debug.print("Error: no init module loaded!\n", .{}); + while (true) {} + } } pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {