From c5876768c5734e8d42b64d8b7da7d35f3ee5ab85 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Mon, 24 Feb 2025 19:16:35 +0100 Subject: [PATCH] core: Reserve kernel physical pages + provide our own stack This solves a very weird bug that occurred when we allocated a page that was already used for the stack. --- core/src/arch/x86_64/platform.zig | 16 ++++++++ core/src/arch/x86_64/vmm.zig | 14 ++++--- core/src/main.zig | 50 +++-------------------- core/src/pmm.zig | 67 +++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 50 deletions(-) diff --git a/core/src/arch/x86_64/platform.zig b/core/src/arch/x86_64/platform.zig index 905358c..fe8b2ee 100644 --- a/core/src/arch/x86_64/platform.zig +++ b/core/src/arch/x86_64/platform.zig @@ -1,3 +1,4 @@ +const std = @import("std"); const gdt = @import("gdt.zig"); const idt = @import("idt.zig"); const pic = @import("pic.zig"); @@ -18,6 +19,21 @@ fn enableNX() void { ); } +var stack: [PAGE_SIZE * 8]u8 = std.mem.zeroes([PAGE_SIZE * 8]u8); +const top: usize = (PAGE_SIZE * 8) - 16; + +pub inline fn _start() noreturn { + asm volatile ( + \\ mov %[stack], %rsp + \\ addq %[top], %rsp + \\ call main + : + : [stack] "i" (&stack), + [top] "i" (top), + ); + unreachable; +} + // Initialize platform-specific components. pub fn platformInit() void { gdt.setupGDT(); diff --git a/core/src/arch/x86_64/vmm.zig b/core/src/arch/x86_64/vmm.zig index 93fb7f1..09e5e17 100644 --- a/core/src/arch/x86_64/vmm.zig +++ b/core/src/arch/x86_64/vmm.zig @@ -3,6 +3,7 @@ const easyboot = @cImport(@cInclude("easyboot.h")); const mmap = @import("../../mmap.zig"); const pmm = @import("../../pmm.zig"); const platform = @import("platform.zig"); +const debug = @import("../debug.zig"); const USER_ADDRESS_RANGE_END = 0x0000_7fff_ffff_ffff; pub const PHYSICAL_MAPPING_BASE = 0xffff_8000_0000_0000; @@ -151,6 +152,11 @@ pub fn getEntry(space: AddressSpace, base: usize, virt_address: u64) ?*PageTable return pt_entry; } +pub fn getAddress(space: AddressSpace, base: usize, virt_address: u64) ?usize { + const entry = getEntry(space, base, virt_address) orelse return null; + return entry.getAddress(); +} + pub fn copyToUser(space: AddressSpace, base: usize, user: usize, kernel: [*]const u8, size: usize) !void { const remainder: usize = @rem(user, platform.PAGE_SIZE); const user_page = user - remainder; @@ -277,22 +283,20 @@ fn setUpKernelPageDirectory(allocator: *pmm.FrameAllocator, tag: *easyboot.multi return table; } -pub fn setUpInitialUserPageDirectory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, user_table: *PageTable) !usize { +pub fn setUpInitialUserPageDirectory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, space: AddressSpace) !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); + space.table.* = std.mem.zeroes(PageTable); const directory_upper_half: *[256]PageTableEntry = kernel_table.entries[256..]; - const user_directory_upper_half: *[256]PageTableEntry = user_table.entries[256..]; + const user_directory_upper_half: *[256]PageTableEntry = space.table.entries[256..]; @memcpy(user_directory_upper_half, directory_upper_half); const user_physical_address_base = (USER_ADDRESS_RANGE_END + 1) - physical_address_space_size; - const space = AddressSpace.create(.{ .address = @intFromPtr(user_table) }, 0); - 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; diff --git a/core/src/main.zig b/core/src/main.zig index 0dbe38f..f33b101 100644 --- a/core/src/main.zig +++ b/core/src/main.zig @@ -13,51 +13,11 @@ const elf = @import("elf.zig"); const MultibootInfo = [*c]u8; -fn adjustAddressToPageBoundary(address: *usize, size: *usize) void { - const diff = address.* % platform.PAGE_SIZE; - - address.* -= diff; - size.* += diff; +export fn _start(_: u32, _: MultibootInfo) callconv(.C) noreturn { + platform._start(); } -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 { +export fn main(magic: u32, info: MultibootInfo) callconv(.C) noreturn { interrupts.disableInterrupts(); if (magic != easyboot.MULTIBOOT2_BOOTLOADER_MAGIC) { @@ -80,7 +40,7 @@ export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn { while (true) {} }; - reserveMultibootMemory(&allocator, info) catch |err| { + pmm.reserveMultibootMemory(&allocator, info) catch |err| { debug.print("Error while reserving multiboot memory: {}\n", .{err}); while (true) {} }; @@ -108,7 +68,7 @@ export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn { 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 base = try vmm.setUpInitialUserPageDirectory(context.allocator, context.mmap, space); const module = try thread.createThreadControlBlock(context.allocator); diff --git a/core/src/pmm.zig b/core/src/pmm.zig index e133272..9b7f1c6 100644 --- a/core/src/pmm.zig +++ b/core/src/pmm.zig @@ -5,6 +5,8 @@ const vmm = @import("arch/vmm.zig"); const mmap = @import("mmap.zig"); const bmap = @import("lib/bitmap.zig"); const locking = @import("lib/spinlock.zig"); +const debug = @import("arch/debug.zig"); +const multiboot = @import("multiboot.zig"); const FrameAllocatorError = error{ InvalidMemoryMap, @@ -104,9 +106,74 @@ pub fn initializeFrameAllocator(tag: *easyboot.multiboot_tag_mmap_t) !FrameAlloc // Avoid causing trouble. try lockFrame(&allocator, 0); + try reserveKernelMemory(&allocator); + return allocator; } +fn adjustAddressToPageBoundary(address: *usize, size: *usize) void { + const diff = address.* % platform.PAGE_SIZE; + + address.* -= diff; + size.* += diff; +} + +extern const kernel_start: [*]u8; +extern const kernel_end: [*]u8; + +fn reserveKernelMemory(allocator: *FrameAllocator) !void { + debug.print("Kernel begins at {*} and ends at {*}\n", .{ &kernel_start, &kernel_end }); + + const start: usize = @intFromPtr(&kernel_start); + const end: usize = @intFromPtr(&kernel_end); + const pages = try std.math.divCeil(usize, end - start, platform.PAGE_SIZE); + + const page_table = vmm.readPageTable(); + const space = vmm.AddressSpace.create(page_table, 0); + + var i: usize = 0; + while (i < pages) : (i += 1) { + try lockFrame(allocator, vmm.getAddress(space, 0, start + (i * platform.PAGE_SIZE)).?); + } +} + +pub fn reserveMultibootMemory(allocator: *FrameAllocator, info: [*c]u8) !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 lockFrames(allocator, address, try std.math.divCeil(usize, size, platform.PAGE_SIZE)); + + const Context = struct { + allocator: *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 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); +} + var lock: locking.SpinLock = .{}; var global_allocator: *FrameAllocator = undefined;