Refactor compilation of architecture-specific code
This commit is contained in:
parent
b3f7785fd8
commit
08dbf09e00
6 changed files with 130 additions and 155 deletions
|
@ -29,9 +29,9 @@ pub fn build(b: *Builder) void {
|
||||||
src_files.append("kernel/kmain") catch unreachable;
|
src_files.append("kernel/kmain") catch unreachable;
|
||||||
|
|
||||||
// Add the architecture init file to the source files
|
// Add the architecture init file to the source files
|
||||||
var arch_init = concat(b.allocator, "kernel/arch/", target) catch unreachable;
|
var arch_boot = concat(b.allocator, "kernel/arch/", target) catch unreachable;
|
||||||
arch_init.append("/arch") catch unreachable;
|
arch_boot.append("/boot") catch unreachable;
|
||||||
src_files.append(arch_init.toSlice()) catch unreachable;
|
src_files.append(arch_boot.toSlice()) catch unreachable;
|
||||||
|
|
||||||
var objects_steps = buildObjects(b, builtin_target, build_path, src_path);
|
var objects_steps = buildObjects(b, builtin_target, build_path, src_path);
|
||||||
var link_step = buildLink(b, builtin_target, build_path);
|
var link_step = buildLink(b, builtin_target, build_path);
|
||||||
|
|
|
@ -1,32 +1,6 @@
|
||||||
// Zig version: 0.4.0
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
///
|
pub const internals = switch (builtin.arch) {
|
||||||
/// Initialise the architecture
|
builtin.Arch.i386 => @import("arch/x86/arch.zig"),
|
||||||
///
|
else => unreachable,
|
||||||
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;
|
|
||||||
|
|
|
@ -2,119 +2,10 @@
|
||||||
|
|
||||||
const is_test = @import("builtin").is_test;
|
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
|
/// Initialise the architecture
|
||||||
///
|
///
|
||||||
export fn init() void {}
|
pub fn init() void {}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Inline assembly to write to a given port with a byte of data.
|
/// 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 port: u16 - The port to write to.
|
||||||
/// IN data: u8 - The byte of data that will be sent.
|
/// 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]"
|
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:
|
/// Return:
|
||||||
/// The data that the port returns.
|
/// The data that the port returns.
|
||||||
///
|
///
|
||||||
export fn inb(port: u16) u8 {
|
pub fn inb(port: u16) u8 {
|
||||||
return asm volatile ("inb %[port], %[result]"
|
return asm volatile ("inb %[port], %[result]"
|
||||||
: [result] "={al}" (-> u8)
|
: [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
|
/// 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.
|
/// event being waited.
|
||||||
///
|
///
|
||||||
export fn ioWait() void {
|
pub fn ioWait() void {
|
||||||
outb(0x80, 0);
|
outb(0x80, 0);
|
||||||
}
|
}
|
||||||
|
|
108
src/kernel/arch/x86/boot.zig
Normal file
108
src/kernel/arch/x86/boot.zig
Normal file
|
@ -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) {}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
// Zig version: 0.4.0
|
// Zig version: 0.4.0
|
||||||
|
|
||||||
const builtin = @import("builtin");
|
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 multiboot = @import("multiboot.zig");
|
||||||
const tty = @import("tty.zig");
|
const tty = @import("tty.zig");
|
||||||
const vga = @import("vga.zig");
|
const vga = @import("vga.zig");
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
// Zig version: 0.4.0
|
// Zig version: 0.4.0
|
||||||
|
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const arch = if (builtin.is_test) @import("../../test/kernel/arch_mock.zig")
|
const arch = @import("arch.zig").internals;
|
||||||
else @import("arch.zig");
|
|
||||||
|
|
||||||
const expectEqual = @import("std").testing.expectEqual;
|
const expectEqual = @import("std").testing.expectEqual;
|
||||||
const warn = @import("std").debug.warn;
|
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.
|
/// IN shape: CURSOR_SHAPE - The enum CURSOR_SHAPE that selects which shape to use.
|
||||||
///
|
///
|
||||||
pub fn setCursorShape(shape: CursorShape) void {
|
pub fn setCursorShape(shape: CursorShape) void {
|
||||||
switch(shape) {
|
switch (shape) {
|
||||||
CursorShape.UNDERLINE => {
|
CursorShape.UNDERLINE => {
|
||||||
arch.outb(PORT_ADDRESS, REG_CURSOR_START);
|
arch.outb(PORT_ADDRESS, REG_CURSOR_START);
|
||||||
arch.outb(PORT_DATA, CURSOR_SCANLINE_MIDDLE);
|
arch.outb(PORT_DATA, CURSOR_SCANLINE_MIDDLE);
|
||||||
|
@ -280,7 +279,7 @@ test "entry" {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testOutOfBounds(x: u16, y: u16) bool {
|
fn testOutOfBounds(x: u16, y: u16) bool {
|
||||||
if(x < HEIGHT and y < WIDTH) {
|
if (x < HEIGHT and y < WIDTH) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -410,4 +409,4 @@ test "init all" {
|
||||||
init();
|
init();
|
||||||
expectEqual(CURSOR_SCANLINE_MIDDLE, cursor_scanline_start);
|
expectEqual(CURSOR_SCANLINE_MIDDLE, cursor_scanline_start);
|
||||||
expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
|
expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue