Merge pull request #17 from SamTebbs33/feature/architecture-separation

This patch separates the architecture-specific and core code from each other, with the arch code moved to its own directory under src/kernel/arch. The architecture and core code are built to objects, then linked togetherm, and an interface is added in src/kernel/arch.zig which each architecture must implement. Closes #16
This commit is contained in:
Sam Tebbs 2019-05-17 19:18:47 +01:00 committed by GitHub
commit bc54f0ef09
4 changed files with 120 additions and 105 deletions

View file

@ -8,7 +8,7 @@ const ArrayList = std.ArrayList;
const warn = std.debug.warn; const warn = std.debug.warn;
const mem = std.mem; 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 { fn concat(allocator: *std.mem.Allocator, str: []const u8, str2: []const u8) !std.Buffer {
var b = try std.Buffer.init(allocator, str); 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 { 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; 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 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"; 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; 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 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);
const iso_step = buildISO(b, build_path, iso_path.toSlice()); 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 { fn buildTest(b: *Builder, src_path: []const u8) void {
const step = b.step("test", "Run all tests"); const step = b.step("test", "Run all tests");
const src_path2 = concat(b.allocator, src_path, "/") catch unreachable; 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; var file_src = concat(b.allocator, src_path2.toSlice(), file) catch unreachable;
file_src.append(".zig") catch unreachable; file_src.append(".zig") catch unreachable;
const tst = b.addTest(file_src.toSlice()); 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.setOutputDir(elf_path.toSlice());
exec.setLinkerScriptPath("link.ld"); exec.setLinkerScriptPath("link.ld");
exec.setTarget(target, builtin.Os.freestanding, builtin.Abi.gnu); 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; var file_obj = concat(b.allocator, build_path, "/") catch unreachable;
file_obj.append(file) catch unreachable; file_obj.append(file) catch unreachable;
file_obj.append(".o") 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) { fn buildObjects(b: *Builder, target: builtin.Arch, build_path: []const u8, src_path: []const u8) ArrayList(*Step) {
var objects = ArrayList(*Step).init(b.allocator); var objects = ArrayList(*Step).init(b.allocator);
const src_path2 = concat(b.allocator, src_path, "/") catch unreachable; 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; var file_src = concat(b.allocator, src_path2.toSlice(), file) catch unreachable;
file_src.append(".zig") catch unreachable; file_src.append(".zig") catch unreachable;
const obj = b.addObject(file, file_src.toSlice()); const obj = b.addObject(file, file_src.toSlice());

2
src/kernel/arch.zig Normal file
View file

@ -0,0 +1,2 @@
/// Initialise the architecture
pub extern fn init() void;

View file

@ -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 {}

View file

@ -5,106 +5,7 @@
// Date: 2019-03-30 // Date: 2019-03-30
// //
const builtin = @import("builtin"); const builtin = @import("builtin");
const arch = @import("arch.zig");
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) {}
}
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
@setCold(true); @setCold(true);
@ -113,7 +14,8 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn
while (true) {} while (true) {}
} }
fn kmain() void { pub export fn kmain() void {
arch.init();
terminal.initialize(); terminal.initialize();
terminal.write("Hello, kernel World!"); terminal.write("Hello, kernel World!");
} }