diff --git a/build.zig b/build.zig index 1c5934b..070487a 100644 --- a/build.zig +++ b/build.zig @@ -29,9 +29,9 @@ pub fn build(b: *Builder) void { 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 arch_boot = concat(b.allocator, "kernel/arch/", target) catch unreachable; + arch_boot.append("/boot") catch unreachable; + src_files.append(arch_boot.toSlice()) catch unreachable; var objects_steps = buildObjects(b, builtin_target, build_path, src_path); var link_step = buildLink(b, builtin_target, build_path); diff --git a/src/kernel/arch.zig b/src/kernel/arch.zig index 2949827..316f47b 100644 --- a/src/kernel/arch.zig +++ b/src/kernel/arch.zig @@ -1,32 +1,6 @@ -// Zig version: 0.4.0 +const builtin = @import("builtin"); -/// -/// Initialise the architecture -/// -pub extern fn init() void; - -/// -/// Inline assembly to write to a given port with a byte of data. -/// -/// Arguments: -/// IN port: u16 - The port to write to. -/// IN data: u8 - The byte of data that will be sent. -/// -pub extern fn outb(port: u16, data: u8) void; - -/// -/// Inline assembly that reads data from a given port and returns its value. -/// -/// Arguments: -/// IN port: u16 - The port to read data from. -/// -/// Return: -/// The data that the port returns. -/// -pub extern fn inb(port: u16) u8; - -/// -/// A simple way of waiting for I/O event to happen by doing an I/O event to flush the I/O -/// event being waited. -/// -pub extern fn ioWait() void; +pub const internals = switch (builtin.arch) { + builtin.Arch.i386 => @import("arch/x86/arch.zig"), + else => unreachable, +}; diff --git a/src/kernel/arch/x86/arch.zig b/src/kernel/arch/x86/arch.zig index bf9981b..4adbc85 100644 --- a/src/kernel/arch/x86/arch.zig +++ b/src/kernel/arch/x86/arch.zig @@ -2,119 +2,10 @@ const is_test = @import("builtin").is_test; -const ALIGN = 1 << 0; -const MEMINFO = 1 << 1; -const MAGIC = 0x1BADB002; -const FLAGS = ALIGN | MEMINFO; - -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; - -extern fn kmain() void; - -const MultiBoot = packed struct { - magic: i32, - flags: i32, - checksum: i32, -}; - -export var multiboot align(4) linksection(".rodata.boot") = MultiBoot { - .magic = MAGIC, - .flags = FLAGS, - .checksum = -(MAGIC + FLAGS), -}; - -// 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 unnecessary 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 succeeding pages with zeroes. May be unnecessary 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 - ); - // Push the bootloader magic number and multiboot header address with virtual offset - asm volatile ( - \\.extern KERNEL_ADDR_OFFSET - \\push %%eax - \\add $KERNEL_ADDR_OFFSET, %%ebx - \\push %%ebx - ); - kmain(); - while (true) {} -} - /// /// Initialise the architecture /// -export fn init() void {} +pub fn init() void {} /// /// Inline assembly to write to a given port with a byte of data. @@ -123,10 +14,12 @@ export fn init() void {} /// IN port: u16 - The port to write to. /// IN data: u8 - The byte of data that will be sent. /// -export fn outb(port: u16, data: u8) void { +pub fn outb(port: u16, data: u8) void { asm volatile ("outb %[data], %[port]" : - : [port] "{dx}" (port), [data] "{al}" (data)); + : [port] "{dx}" (port), + [data] "{al}" (data) + ); } /// @@ -138,16 +31,17 @@ export fn outb(port: u16, data: u8) void { /// Return: /// The data that the port returns. /// -export fn inb(port: u16) u8 { +pub fn inb(port: u16) u8 { return asm volatile ("inb %[port], %[result]" : [result] "={al}" (-> u8) - : [port] "N{dx}" (port)); + : [port] "N{dx}" (port) + ); } /// /// A simple way of waiting for I/O event to happen by doing an I/O event to flush the I/O /// event being waited. /// -export fn ioWait() void { +pub fn ioWait() void { outb(0x80, 0); } diff --git a/src/kernel/arch/x86/boot.zig b/src/kernel/arch/x86/boot.zig new file mode 100644 index 0000000..37cf1f1 --- /dev/null +++ b/src/kernel/arch/x86/boot.zig @@ -0,0 +1,108 @@ +const ALIGN = 1 << 0; +const MEMINFO = 1 << 1; +const MAGIC = 0x1BADB002; +const FLAGS = ALIGN | MEMINFO; + +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; + +extern fn kmain() void; + +const MultiBoot = packed struct { + magic: i32, + flags: i32, + checksum: i32, +}; + +export var multiboot align(4) linksection(".rodata.boot") = MultiBoot{ + .magic = MAGIC, + .flags = FLAGS, + .checksum = -(MAGIC + FLAGS), +}; + +// 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 unnecessary 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 succeeding pages with zeroes. May be unnecessary 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 + ); + // Push the bootloader magic number and multiboot header address with virtual offset + asm volatile ( + \\.extern KERNEL_ADDR_OFFSET + \\push %%eax + \\add $KERNEL_ADDR_OFFSET, %%ebx + \\push %%ebx + ); + kmain(); + while (true) {} +} diff --git a/src/kernel/kmain.zig b/src/kernel/kmain.zig index a75270e..ffd88ab 100644 --- a/src/kernel/kmain.zig +++ b/src/kernel/kmain.zig @@ -1,7 +1,7 @@ // Zig version: 0.4.0 const builtin = @import("builtin"); -const arch = if (builtin.is_test) @import("../../test/kernel/arch_mock.zig") else @import("arch.zig"); +const arch = if (builtin.is_test) @import("../../test/kernel/arch_mock.zig") else @import("arch.zig").internals; const multiboot = @import("multiboot.zig"); const tty = @import("tty.zig"); const vga = @import("vga.zig"); diff --git a/src/kernel/vga.zig b/src/kernel/vga.zig index e778655..05ba4b1 100644 --- a/src/kernel/vga.zig +++ b/src/kernel/vga.zig @@ -1,8 +1,7 @@ // Zig version: 0.4.0 const builtin = @import("builtin"); -const arch = if (builtin.is_test) @import("../../test/kernel/arch_mock.zig") - else @import("arch.zig"); +const arch = @import("arch.zig").internals; const expectEqual = @import("std").testing.expectEqual; const warn = @import("std").debug.warn; @@ -207,7 +206,7 @@ pub fn disableCursor() void { /// IN shape: CURSOR_SHAPE - The enum CURSOR_SHAPE that selects which shape to use. /// pub fn setCursorShape(shape: CursorShape) void { - switch(shape) { + switch (shape) { CursorShape.UNDERLINE => { arch.outb(PORT_ADDRESS, REG_CURSOR_START); arch.outb(PORT_DATA, CURSOR_SCANLINE_MIDDLE); @@ -280,7 +279,7 @@ test "entry" { } fn testOutOfBounds(x: u16, y: u16) bool { - if(x < HEIGHT and y < WIDTH) { + if (x < HEIGHT and y < WIDTH) { return true; } return false; @@ -410,4 +409,4 @@ test "init all" { init(); expectEqual(CURSOR_SCANLINE_MIDDLE, cursor_scanline_start); expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end); -} \ No newline at end of file +}