Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ jobs:
run: zig*/zig build rt-test -Ddisable-display -Dtest-mode=Initialisation ${{ matrix.build_mode }}
- name: Run runtime test - Panic
run: zig*/zig build rt-test -Ddisable-display -Dtest-mode=Panic ${{ matrix.build_mode }}
- name: Run runtime test - Scheduler
run: zig*/zig build rt-test -Ddisable-display -Dtest-mode=Scheduler ${{ matrix.build_mode }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
# Intellij
.idea/

# VSCode
.vscode/

# Zig
zig-cache

Expand Down
2 changes: 0 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ const builtin = @import("builtin");
const rt = @import("test/runtime_test.zig");
const RuntimeStep = rt.RuntimeStep;
const Builder = std.build.Builder;
const LibExeObjStep = std.build.LibExeObjStep;
const Step = std.build.Step;
const Target = std.Target;
const CrossTarget = std.zig.CrossTarget;
const fs = std.fs;
Expand Down
4 changes: 3 additions & 1 deletion src/kernel/arch.zig
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const std = @import("std");
const builtin = @import("builtin");
const is_test = builtin.is_test;
const build_options = @import("build_options");
const mock_path = build_options.mock_path;

pub const internals = if (is_test) @import(build_options.mock_path ++ "arch_mock.zig") else switch (builtin.arch) {
pub const internals = if (is_test) @import(mock_path ++ "arch_mock.zig") else switch (builtin.arch) {
.i386 => @import("arch/x86/arch.zig"),
else => unreachable,
};
Expand Down
124 changes: 86 additions & 38 deletions src/kernel/arch/x86/arch.zig
Original file line number Diff line number Diff line change
@@ -1,47 +1,54 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const builtin = @import("builtin");
const cmos = @import("cmos.zig");
const gdt = @import("gdt.zig");
const idt = @import("idt.zig");
const pic = @import("pic.zig");
const irq = @import("irq.zig");
const isr = @import("isr.zig");
const paging = @import("paging.zig");
const pic = @import("pic.zig");
const pit = @import("pit.zig");
const rtc = @import("rtc.zig");
const serial = @import("serial.zig");
const paging = @import("paging.zig");
const syscalls = @import("syscalls.zig");
const tty = @import("tty.zig");
const vga = @import("vga.zig");
const mem = @import("../../mem.zig");
const multiboot = @import("multiboot.zig");
const pmm = @import("pmm.zig");
const vmm = @import("../../vmm.zig");
const log = @import("../../log.zig");
const tty = @import("tty.zig");
const vga = @import("vga.zig");
const Serial = @import("../../serial.zig").Serial;
const panic = @import("../../panic.zig").panic;
const TTY = @import("../../tty.zig").TTY;
const MemProfile = mem.MemProfile;

/// The virtual end of the kernel code
/// The virtual end of the kernel code.
extern var KERNEL_VADDR_END: *u32;

/// The virtual start of the kernel code
/// The virtual start of the kernel code.
extern var KERNEL_VADDR_START: *u32;

/// The physical end of the kernel code
/// The physical end of the kernel code.
extern var KERNEL_PHYSADDR_END: *u32;

/// The physical start of the kernel code
/// The physical start of the kernel code.
extern var KERNEL_PHYSADDR_START: *u32;

/// The boot-time offset that the virtual addresses are from the physical addresses
/// The boot-time offset that the virtual addresses are from the physical addresses.
extern var KERNEL_ADDR_OFFSET: *u32;

/// The virtual address of the top limit of the stack.
extern var KERNEL_STACK_START: *u32;

/// The virtual address of the base of the stack.
extern var KERNEL_STACK_END: *u32;

/// The interrupt context that is given to a interrupt handler. It contains most of the registers
/// and the interrupt number and error code (if there is one).
pub const InterruptContext = struct {
pub const CpuState = packed struct {
// Extra segments
ss: u32,
gs: u32,
fs: u32,
es: u32,
Expand All @@ -68,7 +75,7 @@ pub const InterruptContext = struct {
cs: u32,
eflags: u32,
user_esp: u32,
ss: u32,
user_ss: u32,
};

/// x86's boot payload is the multiboot info passed by grub
Expand All @@ -89,6 +96,9 @@ pub const VMM_MAPPER: vmm.Mapper(VmmPayload) = vmm.Mapper(VmmPayload){ .mapFn =
/// The size of each allocatable block of memory, normally set to the page size.
pub const MEMORY_BLOCK_SIZE: usize = paging.PAGE_SIZE_4KB;

/// The default stack size of a task. Currently this is set to a page size.
pub const STACK_SIZE: u32 = MEMORY_BLOCK_SIZE / @sizeOf(u32);

///
/// Assembly to write to a given port with a byte of data.
///
Expand Down Expand Up @@ -239,10 +249,9 @@ pub fn halt() void {
/// Wait the kernel but still can handle interrupts.
///
pub fn spinWait() noreturn {
enableInterrupts();
while (true) {
enableInterrupts();
halt();
disableInterrupts();
}
}

Expand Down Expand Up @@ -312,13 +321,21 @@ pub fn initTTY(boot_payload: BootPayload) TTY {
/// Return: mem.MemProfile
/// The constructed memory profile
///
/// Error: std.mem.Allocator.Error
/// std.mem.Allocator.Error.OutOfMemory - There wasn't enough memory in the allocated created to populate the memory profile, consider increasing mem.FIXED_ALLOC_SIZE
/// Error: Allocator.Error
/// Allocator.Error.OutOfMemory - There wasn't enough memory in the allocated created to populate the memory profile, consider increasing mem.FIXED_ALLOC_SIZE
///
pub fn initMem(mb_info: BootPayload) std.mem.Allocator.Error!MemProfile {
pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
log.logInfo("Init mem\n", .{});
defer log.logInfo("Done mem\n", .{});

log.logDebug("KERNEL_ADDR_OFFSET: 0x{X}\n", .{@ptrToInt(&KERNEL_ADDR_OFFSET)});
log.logDebug("KERNEL_STACK_START: 0x{X}\n", .{@ptrToInt(&KERNEL_STACK_START)});
log.logDebug("KERNEL_STACK_END: 0x{X}\n", .{@ptrToInt(&KERNEL_STACK_END)});
log.logDebug("KERNEL_VADDR_START: 0x{X}\n", .{@ptrToInt(&KERNEL_VADDR_START)});
log.logDebug("KERNEL_VADDR_END: 0x{X}\n", .{@ptrToInt(&KERNEL_VADDR_END)});
log.logDebug("KERNEL_PHYSADDR_START: 0x{X}\n", .{@ptrToInt(&KERNEL_PHYSADDR_START)});
log.logDebug("KERNEL_PHYSADDR_END: 0x{X}\n", .{@ptrToInt(&KERNEL_PHYSADDR_END)});

const mods_count = mb_info.mods_count;
mem.ADDR_OFFSET = @ptrToInt(&KERNEL_ADDR_OFFSET);
const mmap_addr = mb_info.mmap_addr;
Expand All @@ -338,6 +355,7 @@ pub fn initMem(mb_info: BootPayload) std.mem.Allocator.Error!MemProfile {
try reserved_physical_mem.append(.{ .start = @intCast(usize, entry.addr), .end = end });
}
}

// Map the multiboot info struct itself
const mb_region = mem.Range{
.start = @ptrToInt(mb_info),
Expand Down Expand Up @@ -384,53 +402,83 @@ pub fn initMem(mb_info: BootPayload) std.mem.Allocator.Error!MemProfile {
};
}

///
/// Initialise a 32bit kernel stack used for creating a task.
/// Currently only support fn () noreturn functions for the entry point.
///
/// Arguments:
/// IN entry_point: usize - The pointer to the entry point of the function. Functions only
/// supported is fn () noreturn
/// IN allocator: *Allocator - The allocator use for allocating a stack.
///
/// Return: struct { stack: []u32, pointer: usize }
/// The stack and stack pointer with the stack initialised as a 32bit kernel stack.
///
/// Error: Allocator.Error
/// OutOfMemory - Unable to allocate space for the stack.
///
pub fn initTaskStack(entry_point: usize, allocator: *Allocator) Allocator.Error!struct { stack: []u32, pointer: usize } {
// TODO Will need to add the exit point
// Set up everything as a kernel task
var stack = try allocator.alloc(u32, STACK_SIZE);
stack[STACK_SIZE - 18] = gdt.KERNEL_DATA_OFFSET; // ss
stack[STACK_SIZE - 17] = gdt.KERNEL_DATA_OFFSET; // gs
stack[STACK_SIZE - 16] = gdt.KERNEL_DATA_OFFSET; // fs
stack[STACK_SIZE - 15] = gdt.KERNEL_DATA_OFFSET; // es
stack[STACK_SIZE - 14] = gdt.KERNEL_DATA_OFFSET; // ds

stack[STACK_SIZE - 13] = 0; // edi
stack[STACK_SIZE - 12] = 0; // esi
// End of the stack
stack[STACK_SIZE - 11] = @ptrToInt(&stack[STACK_SIZE - 1]); // ebp
stack[STACK_SIZE - 10] = 0; // esp (temp) this won't be popped by popa bc intel is dump XD

stack[STACK_SIZE - 9] = 0; // ebx
stack[STACK_SIZE - 8] = 0; // edx
stack[STACK_SIZE - 7] = 0; // ecx
stack[STACK_SIZE - 6] = 0; // eax

stack[STACK_SIZE - 5] = 0; // int_num
stack[STACK_SIZE - 4] = 0; // error_code

stack[STACK_SIZE - 3] = entry_point; // eip
stack[STACK_SIZE - 2] = gdt.KERNEL_CODE_OFFSET; // cs
stack[STACK_SIZE - 1] = 0x202; // eflags

const ret = .{ .stack = stack, .pointer = @ptrToInt(&stack[STACK_SIZE - 18]) };
return ret;
}

///
/// Initialise the architecture
///
/// Arguments:
/// IN boot_payload: BootPayload - The multiboot information from the GRUB bootloader.
/// IN mem_profile: *const MemProfile - The memory profile of the computer. Used to set up
/// paging.
/// IN allocator: *Allocator - The allocator use to handle memory.
/// IN comptime options: type - The build options that is passed to the kernel to be
/// used for run time testing.
///
pub fn init(mb_info: *multiboot.multiboot_info_t, mem_profile: *const MemProfile, allocator: *Allocator) void {
disableInterrupts();

pub fn init(boot_payload: BootPayload, mem_profile: *const MemProfile, allocator: *Allocator) void {
gdt.init();
idt.init();

pic.init();
isr.init();
irq.init();

paging.init(mb_info, mem_profile, allocator);
paging.init(boot_payload, mem_profile, allocator);

pit.init();
rtc.init();

syscalls.init();

enableInterrupts();

// Initialise the VGA and TTY here since their tests belong the architecture and so should be a part of the
// arch init test messages
vga.init();
tty.init();
}

test "" {
_ = @import("gdt.zig");
_ = @import("idt.zig");
_ = @import("pic.zig");
_ = @import("isr.zig");
_ = @import("irq.zig");
_ = @import("pit.zig");
_ = @import("cmos.zig");
_ = @import("rtc.zig");
_ = @import("syscalls.zig");
_ = @import("paging.zig");
_ = @import("serial.zig");
_ = @import("tty.zig");
_ = @import("vga.zig");
std.meta.refAllDecls(@This());
}
6 changes: 3 additions & 3 deletions src/kernel/arch/x86/boot.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const constants = @import("constants");
const multiboot_info = @import("multiboot.zig").multiboot_info_t;
const arch = @import("arch.zig");

/// The multiboot header
const MultiBoot = packed struct {
Expand Down Expand Up @@ -66,7 +66,7 @@ export var boot_page_directory: [1024]u32 align(4096) linksection(".rodata.boot"
export var kernel_stack: [16 * 1024]u8 align(16) linksection(".bss.stack") = undefined;
extern var KERNEL_ADDR_OFFSET: *u32;

extern fn kmain(mb_info: *multiboot_info) void;
extern fn kmain(mb_info: arch.BootPayload) void;

export fn _start() align(16) linksection(".text.boot") callconv(.Naked) noreturn {
// Set the page directory to the boot directory
Expand Down Expand Up @@ -109,6 +109,6 @@ export fn start_higher_half() callconv(.Naked) noreturn {
\\mov %%ebx, %[res]
: [res] "=r" (-> usize)
) + @ptrToInt(&KERNEL_ADDR_OFFSET);
kmain(@intToPtr(*multiboot_info, mb_info_addr));
kmain(@intToPtr(arch.BootPayload, mb_info_addr));
while (true) {}
}
Loading