diff --git a/build.zig b/build.zig index 32589c3..a4f867d 100644 --- a/build.zig +++ b/build.zig @@ -8,7 +8,7 @@ const ArrayList = std.ArrayList; const warn = std.debug.warn; const mem = std.mem; -const src_files = [][]const u8{"kernel/kmain"}; +var src_files: ArrayList([]const u8) = undefined; fn concat(allocator: *std.mem.Allocator, str: []const u8, str2: []const u8) !std.Buffer { var b = try std.Buffer.init(allocator, str); @@ -17,6 +17,7 @@ fn concat(allocator: *std.mem.Allocator, str: []const u8, str2: []const u8) !std } pub fn build(b: *Builder) void { + src_files = ArrayList([]const u8).init(b.allocator); const debug = b.option(bool, "debug", "build with debug symbols / make qemu wait for a debug connection") orelse false; var build_path = b.option([]const u8, "build-path", "path to build to") orelse "bin"; var src_path = b.option([]const u8, "source-path", "path to source") orelse "src"; @@ -25,6 +26,13 @@ pub fn build(b: *Builder) void { const iso_path = concat(b.allocator, build_path, "/pluto.iso") catch unreachable; + src_files.append("kernel/kmain") catch unreachable; + + // Add the architecture init file to the source files + var arch_init = concat(b.allocator, "kernel/arch/", target) catch unreachable; + arch_init.append("/arch") catch unreachable; + src_files.append(arch_init.toSlice()) catch unreachable; + var objects_steps = buildObjects(b, builtin_target, build_path, src_path); var link_step = buildLink(b, builtin_target, build_path); const iso_step = buildISO(b, build_path, iso_path.toSlice()); @@ -41,7 +49,7 @@ pub fn build(b: *Builder) void { fn buildTest(b: *Builder, src_path: []const u8) void { const step = b.step("test", "Run all tests"); const src_path2 = concat(b.allocator, src_path, "/") catch unreachable; - for (src_files) |file| { + for (src_files.toSlice()) |file| { var file_src = concat(b.allocator, src_path2.toSlice(), file) catch unreachable; file_src.append(".zig") catch unreachable; const tst = b.addTest(file_src.toSlice()); @@ -100,7 +108,7 @@ fn buildLink(b: *Builder, target: builtin.Arch, build_path: []const u8) *Step { exec.setOutputDir(elf_path.toSlice()); exec.setLinkerScriptPath("link.ld"); exec.setTarget(target, builtin.Os.freestanding, builtin.Abi.gnu); - for (src_files) |file| { + for (src_files.toSlice()) |file| { var file_obj = concat(b.allocator, build_path, "/") catch unreachable; file_obj.append(file) catch unreachable; file_obj.append(".o") catch unreachable; @@ -112,7 +120,7 @@ fn buildLink(b: *Builder, target: builtin.Arch, build_path: []const u8) *Step { fn buildObjects(b: *Builder, target: builtin.Arch, build_path: []const u8, src_path: []const u8) ArrayList(*Step) { var objects = ArrayList(*Step).init(b.allocator); const src_path2 = concat(b.allocator, src_path, "/") catch unreachable; - for (src_files) |file| { + for (src_files.toSlice()) |file| { var file_src = concat(b.allocator, src_path2.toSlice(), file) catch unreachable; file_src.append(".zig") catch unreachable; const obj = b.addObject(file, file_src.toSlice()); diff --git a/src/kernel/arch.zig b/src/kernel/arch.zig new file mode 100644 index 0000000..6f9f2cd --- /dev/null +++ b/src/kernel/arch.zig @@ -0,0 +1,2 @@ +/// Initialise the architecture +pub extern fn init() void; diff --git a/src/kernel/arch/x86/arch.zig b/src/kernel/arch/x86/arch.zig new file mode 100644 index 0000000..3ec59f3 --- /dev/null +++ b/src/kernel/arch/x86/arch.zig @@ -0,0 +1,103 @@ +extern fn kmain() void; + +const MultiBoot = packed struct { + magic: i32, + flags: i32, + checksum: i32, +}; + +const ALIGN = 1 << 0; +const MEMINFO = 1 << 1; +const MAGIC = 0x1BADB002; +const FLAGS = ALIGN | MEMINFO; + +export var multiboot align(4) linksection(".rodata.boot") = MultiBoot{ + .magic = MAGIC, + .flags = FLAGS, + .checksum = -(MAGIC + FLAGS), +}; + +const KERNEL_ADDR_OFFSET = 0xC0000000; +const KERNEL_PAGE_NUMBER = KERNEL_ADDR_OFFSET >> 22; +// The number of pages occupied by the kernel, will need to be increased as we add a heap etc. +const KERNEL_NUM_PAGES = 1; + +// The initial page directory used for booting into the higher half. Should be overwritten later +export var boot_page_directory: [1024]u32 align(4096) linksection(".rodata.boot") = init: { + // Increase max number of branches done by comptime evaluator + @setEvalBranchQuota(1024); + // Temp value + var dir: [1024]u32 = undefined; + + // Page for 0 -> 4 MiB. Gets unmapped later + dir[0] = 0x00000083; + + var i = 0; + var idx = 1; + + // Fill preceding pages with zeroes. May be unecessary but incurs no runtime cost + while (i < KERNEL_PAGE_NUMBER - 1) : ({ + i += 1; + idx += 1; + }) { + dir[idx] = 0; + } + + // Map the kernel's higher half pages increasing by 4 MiB every time + i = 0; + while (i < KERNEL_NUM_PAGES) : ({ + i += 1; + idx += 1; + }) { + dir[idx] = 0x00000083 | (i << 22); + } + // Fill suceeding pages with zeroes. May be unecessary but incurs no runtime cost + i = 0; + while (i < 1024 - KERNEL_PAGE_NUMBER - KERNEL_NUM_PAGES) : ({ + i += 1; + idx += 1; + }) { + dir[idx] = 0; + } + break :init dir; +}; + +export var kernel_stack: [16 * 1024]u8 align(16) linksection(".bss.stack") = undefined; + +export nakedcc fn _start() align(16) linksection(".text.boot") noreturn { + // Seth the page directory to the boot directory + asm volatile ( + \\.extern boot_page_directory + \\mov $boot_page_directory, %%ecx + \\mov %%ecx, %%cr3 + ); + // Enable 4 MiB pages + asm volatile ( + \\mov %%cr4, %%ecx + \\or $0x00000010, %%ecx + \\mov %%ecx, %%cr4 + ); + // Enable paging + asm volatile ( + \\mov %%cr0, %%ecx + \\or $0x80000000, %%ecx + \\mov %%ecx, %%cr0 + ); + asm volatile ("jmp start_higher_half"); + while (true) {} +} + +export nakedcc fn start_higher_half() noreturn { + // Invalidate the page for the first 4MiB as it's no longer needed + asm volatile ("invlpg (0)"); + // Setup the stack + asm volatile ( + \\.extern KERNEL_STACK_END + \\mov $KERNEL_STACK_END, %%esp + \\mov %%esp, %%ebp + ); + kmain(); + while (true) {} +} + +export fn init() void {} diff --git a/src/kernel/kmain.zig b/src/kernel/kmain.zig index 261e608..a6fc489 100644 --- a/src/kernel/kmain.zig +++ b/src/kernel/kmain.zig @@ -5,106 +5,7 @@ // Date: 2019-03-30 // const builtin = @import("builtin"); - -const MultiBoot = packed struct { - magic: i32, - flags: i32, - checksum: i32, -}; - -const ALIGN = 1 << 0; -const MEMINFO = 1 << 1; -const MAGIC = 0x1BADB002; -const FLAGS = ALIGN | MEMINFO; - -export var multiboot align(4) linksection(".rodata.boot") = MultiBoot{ - .magic = MAGIC, - .flags = FLAGS, - .checksum = -(MAGIC + FLAGS), -}; - -const KERNEL_ADDR_OFFSET = 0xC0000000; -const KERNEL_PAGE_NUMBER = KERNEL_ADDR_OFFSET >> 22; -// The number of pages occupied by the kernel, will need to be increased as we add a heap etc. -const KERNEL_NUM_PAGES = 1; - -// The initial page directory used for booting into the higher half. Should be overwritten later -export var boot_page_directory: [1024]u32 align(4096) linksection(".rodata.boot") = init: { - // Increase max number of branches done by comptime evaluator - @setEvalBranchQuota(1024); - // Temp value - var dir: [1024]u32 = undefined; - - // Page for 0 -> 4 MiB. Gets unmapped later - dir[0] = 0x00000083; - - var i = 0; - var idx = 1; - - // Fill preceding pages with zeroes. May be unecessary but incurs no runtime cost - while (i < KERNEL_PAGE_NUMBER - 1) : ({ - i += 1; - idx += 1; - }) { - dir[idx] = 0; - } - - // Map the kernel's higher half pages increasing by 4 MiB every time - i = 0; - while (i < KERNEL_NUM_PAGES) : ({ - i += 1; - idx += 1; - }) { - dir[idx] = 0x00000083 | (i << 22); - } - // Fill suceeding pages with zeroes. May be unecessary but incurs no runtime cost - i = 0; - while (i < 1024 - KERNEL_PAGE_NUMBER - KERNEL_NUM_PAGES) : ({ - i += 1; - idx += 1; - }) { - dir[idx] = 0; - } - break :init dir; -}; - -export var kernel_stack: [16 * 1024]u8 align(16) linksection(".bss.stack") = undefined; - -export nakedcc fn _start() align(16) linksection(".text.boot") noreturn { - // Seth the page directory to the boot directory - asm volatile ( - \\.extern boot_page_directory - \\mov $boot_page_directory, %%ecx - \\mov %%ecx, %%cr3 - ); - // Enable 4 MiB pages - asm volatile ( - \\mov %%cr4, %%ecx - \\or $0x00000010, %%ecx - \\mov %%ecx, %%cr4 - ); - // Enable paging - asm volatile ( - \\mov %%cr0, %%ecx - \\or $0x80000000, %%ecx - \\mov %%ecx, %%cr0 - ); - asm volatile ("jmp start_higher_half"); - while (true) {} -} - -export nakedcc fn start_higher_half() noreturn { - // Invalidate the page for the first 4MiB as it's no longer needed - asm volatile ("invlpg (0)"); - // Setup the stack - asm volatile ( - \\.extern KERNEL_STACK_END - \\mov $KERNEL_STACK_END, %%esp - \\mov %%esp, %%ebp - ); - kmain(); - while (true) {} -} +const arch = @import("arch.zig"); pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { @setCold(true); @@ -113,7 +14,8 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn while (true) {} } -fn kmain() void { +pub export fn kmain() void { + arch.init(); terminal.initialize(); terminal.write("Hello, kernel World!"); }