2019-05-23 17:50:37 +01:00
|
|
|
const std = @import("std");
|
2019-04-17 17:40:26 +01:00
|
|
|
const builtin = @import("builtin");
|
2019-10-05 20:46:31 +01:00
|
|
|
const is_test = builtin.is_test;
|
2019-09-16 22:19:21 +01:00
|
|
|
const build_options = @import("build_options");
|
2019-10-05 20:46:31 +01:00
|
|
|
const mock_path = build_options.mock_path;
|
2019-09-08 20:48:23 +01:00
|
|
|
const arch = @import("arch.zig").internals;
|
2019-05-22 20:12:46 +01:00
|
|
|
const tty = @import("tty.zig");
|
|
|
|
const vga = @import("vga.zig");
|
2020-07-23 20:47:56 +01:00
|
|
|
const log_root = @import("log.zig");
|
2019-09-09 23:38:06 +01:00
|
|
|
const pmm = @import("pmm.zig");
|
2020-06-04 14:39:37 +01:00
|
|
|
const serial = @import("serial.zig");
|
2020-01-09 16:16:51 +00:00
|
|
|
const vmm = if (is_test) @import(mock_path ++ "vmm_mock.zig") else @import("vmm.zig");
|
2019-10-05 20:46:31 +01:00
|
|
|
const mem = if (is_test) @import(mock_path ++ "mem_mock.zig") else @import("mem.zig");
|
2019-11-02 02:18:02 +00:00
|
|
|
const panic_root = if (is_test) @import(mock_path ++ "panic_mock.zig") else @import("panic.zig");
|
2020-07-18 22:46:24 +01:00
|
|
|
const task = if (is_test) @import(mock_path ++ "task_mock.zig") else @import("task.zig");
|
2020-01-09 13:27:49 +00:00
|
|
|
const heap = @import("heap.zig");
|
2020-07-18 22:46:24 +01:00
|
|
|
const scheduler = @import("scheduler.zig");
|
2020-08-06 18:13:53 +01:00
|
|
|
const vfs = @import("filesystem/vfs.zig");
|
|
|
|
const initrd = @import("filesystem/initrd.zig");
|
2020-07-14 21:52:54 +01:00
|
|
|
const keyboard = @import("keyboard.zig");
|
2019-04-17 17:40:26 +01:00
|
|
|
|
2019-09-03 14:13:26 -04:00
|
|
|
comptime {
|
2020-01-09 13:08:00 +00:00
|
|
|
if (!is_test) {
|
|
|
|
switch (builtin.arch) {
|
|
|
|
.i386 => _ = @import("arch/x86/boot.zig"),
|
|
|
|
else => {},
|
|
|
|
}
|
2019-09-03 14:13:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-09 16:16:51 +00:00
|
|
|
/// The virtual memory manager associated with the kernel address space
|
|
|
|
var kernel_vmm: vmm.VirtualMemoryManager(arch.VmmPayload) = undefined;
|
|
|
|
|
2019-09-08 20:48:23 +01:00
|
|
|
// This is for unit testing as we need to export KERNEL_ADDR_OFFSET as it is no longer available
|
|
|
|
// from the linker script
|
2020-07-18 22:46:24 +01:00
|
|
|
// These will need to be kept up to date with the debug logs in the mem init.
|
2019-09-08 20:48:23 +01:00
|
|
|
export var KERNEL_ADDR_OFFSET: u32 = if (builtin.is_test) 0xC0000000 else undefined;
|
2020-07-18 22:46:24 +01:00
|
|
|
export var KERNEL_STACK_START: u32 = if (builtin.is_test) 0xC014A000 else undefined;
|
|
|
|
export var KERNEL_STACK_END: u32 = if (builtin.is_test) 0xC014E000 else undefined;
|
|
|
|
export var KERNEL_VADDR_START: u32 = if (builtin.is_test) 0xC0100000 else undefined;
|
|
|
|
export var KERNEL_VADDR_END: u32 = if (builtin.is_test) 0xC014E000 else undefined;
|
|
|
|
export var KERNEL_PHYSADDR_START: u32 = if (builtin.is_test) 0x100000 else undefined;
|
|
|
|
export var KERNEL_PHYSADDR_END: u32 = if (builtin.is_test) 0x14E000 else undefined;
|
2019-09-08 20:48:23 +01:00
|
|
|
|
2019-05-31 07:41:28 +01:00
|
|
|
// Just call the panic function, as this need to be in the root source file
|
2019-04-17 17:40:26 +01:00
|
|
|
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
|
|
|
|
@setCold(true);
|
2020-01-01 19:12:36 +00:00
|
|
|
panic_root.panic(error_return_trace, "{}", .{msg});
|
2019-04-17 17:40:26 +01:00
|
|
|
}
|
|
|
|
|
2020-07-23 20:47:56 +01:00
|
|
|
pub const log_level: std.log.Level = .debug;
|
|
|
|
// Define root.log to override the std implementation
|
|
|
|
pub fn log(
|
|
|
|
comptime level: std.log.Level,
|
|
|
|
comptime scope: @TypeOf(.EnumLiteral),
|
|
|
|
comptime format: []const u8,
|
|
|
|
args: anytype,
|
|
|
|
) void {
|
|
|
|
log_root.log(level, "(" ++ @tagName(scope) ++ "): " ++ format, args);
|
|
|
|
}
|
|
|
|
|
2020-05-14 17:34:50 +01:00
|
|
|
export fn kmain(boot_payload: arch.BootPayload) void {
|
2020-06-09 13:47:06 +01:00
|
|
|
const serial_stream = serial.init(boot_payload);
|
2020-04-12 22:26:34 +01:00
|
|
|
|
2020-07-23 20:47:56 +01:00
|
|
|
log_root.init(serial_stream);
|
2020-04-12 22:26:34 +01:00
|
|
|
|
2020-07-24 23:51:27 +01:00
|
|
|
const mem_profile = arch.initMem(boot_payload) catch |e| {
|
|
|
|
panic_root.panic(@errorReturnTrace(), "Failed to initialise memory profile: {}", .{e});
|
|
|
|
};
|
2020-05-14 17:34:50 +01:00
|
|
|
var fixed_allocator = mem_profile.fixed_allocator;
|
2019-06-22 10:00:57 +01:00
|
|
|
|
2020-05-14 17:34:50 +01:00
|
|
|
panic_root.init(&mem_profile, &fixed_allocator.allocator) catch |e| {
|
2020-07-25 11:18:19 +01:00
|
|
|
panic_root.panic(@errorReturnTrace(), "Failed to initialise panic: {}\n", .{e});
|
2020-05-14 17:34:50 +01:00
|
|
|
};
|
2020-01-09 16:16:51 +00:00
|
|
|
|
2020-05-14 17:34:50 +01:00
|
|
|
pmm.init(&mem_profile, &fixed_allocator.allocator);
|
2020-07-24 23:51:27 +01:00
|
|
|
kernel_vmm = vmm.init(&mem_profile, &fixed_allocator.allocator) catch |e| {
|
|
|
|
panic_root.panic(@errorReturnTrace(), "Failed to initialise kernel VMM: {}", .{e});
|
|
|
|
};
|
2020-01-09 16:16:51 +00:00
|
|
|
|
2020-07-23 20:47:56 +01:00
|
|
|
std.log.info(.kmain, "Init arch " ++ @tagName(builtin.arch) ++ "\n", .{});
|
2020-07-24 23:51:27 +01:00
|
|
|
arch.init(&mem_profile);
|
2020-07-23 20:47:56 +01:00
|
|
|
std.log.info(.kmain, "Arch init done\n", .{});
|
2020-01-09 16:16:51 +00:00
|
|
|
|
2020-05-14 17:34:50 +01:00
|
|
|
// Give the kernel heap 10% of the available memory. This can be fine-tuned as time goes on.
|
|
|
|
var heap_size = mem_profile.mem_kb / 10 * 1024;
|
|
|
|
// The heap size must be a power of two so find the power of two smaller than or equal to the heap_size
|
|
|
|
if (!std.math.isPowerOfTwo(heap_size)) {
|
|
|
|
heap_size = std.math.floorPowerOfTwo(usize, heap_size);
|
|
|
|
}
|
2020-07-11 21:12:13 +01:00
|
|
|
var kernel_heap = heap.init(arch.VmmPayload, &kernel_vmm, vmm.Attributes{ .kernel = true, .writable = true, .cachable = true }, heap_size) catch |e| {
|
2020-05-14 17:34:50 +01:00
|
|
|
panic_root.panic(@errorReturnTrace(), "Failed to initialise kernel heap: {}\n", .{e});
|
|
|
|
};
|
2020-07-18 22:46:24 +01:00
|
|
|
|
2020-06-12 12:05:50 +01:00
|
|
|
tty.init(&kernel_heap.allocator, boot_payload);
|
2020-07-14 21:52:54 +01:00
|
|
|
var arch_kb = keyboard.init(&fixed_allocator.allocator) catch |e| {
|
|
|
|
panic_root.panic(@errorReturnTrace(), "Failed to inititalise keyboard: {}\n", .{e});
|
|
|
|
};
|
|
|
|
if (arch_kb) |kb| {
|
|
|
|
keyboard.addKeyboard(kb) catch |e| panic_root.panic(@errorReturnTrace(), "Failed to add architecture keyboard: {}\n", .{e});
|
|
|
|
}
|
2020-06-12 12:05:50 +01:00
|
|
|
|
2020-07-18 22:46:24 +01:00
|
|
|
scheduler.init(&kernel_heap.allocator) catch |e| {
|
2020-07-25 11:18:19 +01:00
|
|
|
panic_root.panic(@errorReturnTrace(), "Failed to initialise scheduler: {}\n", .{e});
|
2020-07-18 22:46:24 +01:00
|
|
|
};
|
|
|
|
|
2020-07-25 11:18:19 +01:00
|
|
|
// Get the ramdisk module
|
|
|
|
const rd_module = for (mem_profile.modules) |module| {
|
|
|
|
if (std.mem.eql(u8, module.name, "initrd.ramdisk")) {
|
|
|
|
break module;
|
|
|
|
}
|
|
|
|
} else null;
|
|
|
|
|
|
|
|
if (rd_module) |module| {
|
|
|
|
// Load the ram disk
|
2020-08-06 18:13:53 +01:00
|
|
|
const rd_len: usize = module.region.end - module.region.start;
|
|
|
|
const ramdisk_bytes = @intToPtr([*]u8, module.region.start)[0..rd_len];
|
|
|
|
var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes);
|
|
|
|
var ramdisk_filesystem = initrd.InitrdFS.init(&initrd_stream, &kernel_heap.allocator) catch |e| {
|
2020-07-25 11:18:19 +01:00
|
|
|
panic_root.panic(@errorReturnTrace(), "Failed to initialise ramdisk: {}\n", .{e});
|
|
|
|
};
|
2020-08-06 18:13:53 +01:00
|
|
|
defer ramdisk_filesystem.deinit();
|
|
|
|
|
|
|
|
// Can now free the module as new memory is allocated for the ramdisk filesystem
|
|
|
|
kernel_vmm.free(module.region.start) catch |e| {
|
|
|
|
panic_root.panic(@errorReturnTrace(), "Failed to free ramdisk: {}\n", .{e});
|
|
|
|
};
|
2020-07-25 11:18:19 +01:00
|
|
|
|
|
|
|
// Need to init the vfs after the ramdisk as we need the root node from the ramdisk filesystem
|
|
|
|
vfs.setRoot(ramdisk_filesystem.root_node);
|
|
|
|
|
|
|
|
// Load all files here
|
|
|
|
}
|
|
|
|
|
2020-07-18 22:46:24 +01:00
|
|
|
// Initialisation is finished, now does other stuff
|
2020-07-23 20:47:56 +01:00
|
|
|
std.log.info(.kmain, "Init\n", .{});
|
2020-04-12 22:26:34 +01:00
|
|
|
|
2020-07-18 22:46:24 +01:00
|
|
|
// Main initialisation finished so can enable interrupts
|
|
|
|
arch.enableInterrupts();
|
|
|
|
|
2020-07-23 20:47:56 +01:00
|
|
|
std.log.info(.kmain, "Creating init2\n", .{});
|
2020-07-18 22:46:24 +01:00
|
|
|
|
|
|
|
// Create a init2 task
|
|
|
|
var idle_task = task.Task.create(initStage2, &kernel_heap.allocator) catch |e| {
|
2020-07-25 11:18:19 +01:00
|
|
|
panic_root.panic(@errorReturnTrace(), "Failed to create init stage 2 task: {}\n", .{e});
|
2020-07-18 22:46:24 +01:00
|
|
|
};
|
|
|
|
scheduler.scheduleTask(idle_task, &kernel_heap.allocator) catch |e| {
|
2020-07-25 11:18:19 +01:00
|
|
|
panic_root.panic(@errorReturnTrace(), "Failed to schedule init stage 2 task: {}\n", .{e});
|
2020-07-18 22:46:24 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// Can't return for now, later this can return maybe
|
|
|
|
// TODO: Maybe make this the idle task
|
|
|
|
arch.spinWait();
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Stage 2 initialisation. This will initialise main kernel features after the architecture
|
|
|
|
/// initialisation.
|
|
|
|
///
|
|
|
|
fn initStage2() noreturn {
|
2020-06-12 12:05:50 +01:00
|
|
|
tty.clear();
|
|
|
|
const logo =
|
|
|
|
\\ _____ _ _ _ _______ ____
|
|
|
|
\\ | __ \ | | | | | | |__ __| / __ \
|
|
|
|
\\ | |__) | | | | | | | | | | | | |
|
|
|
|
\\ | ___/ | | | | | | | | | | | |
|
|
|
|
\\ | | | |____ | |__| | | | | |__| |
|
|
|
|
\\ |_| |______| \____/ |_| \____/
|
|
|
|
;
|
|
|
|
tty.print("{}\n\n", .{logo});
|
|
|
|
|
2020-05-14 17:34:50 +01:00
|
|
|
tty.print("Hello Pluto from kernel :)\n", .{});
|
2020-01-09 13:27:49 +00:00
|
|
|
|
2020-06-23 12:43:52 +01:00
|
|
|
switch (build_options.test_mode) {
|
|
|
|
.Initialisation => {
|
2020-07-23 20:47:56 +01:00
|
|
|
std.log.info(.kmain, "SUCCESS\n", .{});
|
2020-06-23 12:43:52 +01:00
|
|
|
},
|
|
|
|
else => {},
|
|
|
|
}
|
|
|
|
|
2020-07-14 21:52:54 +01:00
|
|
|
const kb = keyboard.getKeyboard(0) orelse unreachable;
|
|
|
|
var shift = false;
|
|
|
|
while (true) {
|
|
|
|
if (kb.readKey()) |key| {
|
|
|
|
if (key.released) {
|
|
|
|
if (key.position == keyboard.KeyPosition.LEFT_SHIFT) {
|
|
|
|
shift = false;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
var char: ?u8 = switch (key.position) {
|
|
|
|
keyboard.KeyPosition.LEFT_SHIFT, keyboard.KeyPosition.RIGHT_SHIFT => blk: {
|
|
|
|
shift = true;
|
|
|
|
break :blk null;
|
|
|
|
},
|
|
|
|
keyboard.KeyPosition.Q => if (shift) @as(u8, 'Q') else @as(u8, 'q'),
|
|
|
|
keyboard.KeyPosition.W => if (shift) @as(u8, 'W') else @as(u8, 'w'),
|
|
|
|
else => null,
|
|
|
|
};
|
|
|
|
if (char) |ch| {
|
|
|
|
tty.print("{c}", .{ch});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-18 22:46:24 +01:00
|
|
|
// Can't return for now, later this can return maybe
|
2020-06-23 12:43:52 +01:00
|
|
|
arch.spinWait();
|
2019-04-17 17:40:26 +01:00
|
|
|
}
|