Compare commits

...

7 Commits

13 changed files with 189 additions and 13 deletions

View File

@ -3,6 +3,7 @@ const target = @import("builtin").target;
const thread = @import("../thread.zig");
const pmm = @import("../pmm.zig");
const vmm = @import("vmm.zig").arch;
const platform = @import("platform.zig").arch;
pub const arch = switch (target.cpu.arch) {
.x86_64 => @import("x86_64/cpu.zig"),
@ -26,11 +27,15 @@ pub fn setupCore(allocator: *pmm.FrameAllocator) !void {
idle_thread.id = 0;
idle_thread.directory = null;
idle_thread.regs = std.mem.zeroes(@TypeOf(idle_thread.regs));
idle_thread.state = .Running;
thread.arch.initKernelRegisters(&idle_thread.regs);
thread.arch.setAddress(&idle_thread.regs, @intFromPtr(&thread.arch.idleLoop));
core.thread_list.append(&core.idle_thread);
const stack = try pmm.allocFrame(allocator);
thread.arch.setStack(&idle_thread.regs, stack.virtualAddress(vmm.PHYSICAL_MAPPING_BASE) + (platform.PAGE_SIZE - 16));
this_core = core;
}

View File

@ -139,7 +139,16 @@ fn pageFault(frame: *InterruptStackFrame) void {
}
export fn interruptEntry(frame: *InterruptStackFrame) callconv(.C) void {
debug.print("Caught interrupt {d}\n", .{frame.isr});
if (frame.isr >= 32 and frame.isr < 48) {
// IRQ
const irq_handler = irq_handlers[frame.error_or_irq];
if (irq_handler) |handler| {
handler(@intCast(frame.error_or_irq), frame);
}
pic.picEOI(@intCast(frame.error_or_irq));
return;
}
switch (frame.isr) {
@intFromEnum(Exceptions.PageFault) => {
pageFault(frame);
@ -149,7 +158,7 @@ export fn interruptEntry(frame: *InterruptStackFrame) callconv(.C) void {
},
SYSCALL_INTERRUPT => {
var args = sys.Arguments{ .arg0 = frame.rdi, .arg1 = frame.rsi, .arg2 = frame.rdx, .arg3 = frame.r10, .arg4 = frame.r8, .arg5 = frame.r9 };
sys.invokeSyscall(frame.rax, frame, &args, @ptrFromInt(@as(usize, @intFromPtr(&frame.rax))));
sys.invokeSyscall(frame.rax, frame, &args, @ptrCast(&frame.rax));
},
else => {},
}

View File

@ -0,0 +1,28 @@
const io = @import("ioports.zig");
const interrupts = @import("interrupts.zig");
const pic = @import("pic.zig");
const thread = @import("../../thread.zig");
// Every timer tick is equivalent to 1 millisecond.
const TIMER_RESOLUTION = 1;
const PIT_CHANNEL_0 = 0x40;
const base_frequency: u64 = 1193182;
pub fn initializePIT() void {
const divisor: u16 = @intCast(base_frequency / (TIMER_RESOLUTION * 1000));
if (divisor < 100) {
@compileError("Timer resolution is too low");
}
io.outb(PIT_CHANNEL_0, @as(u8, @intCast(divisor & 0xFF)));
io.outb(0x80, 0); // short delay
io.outb(PIT_CHANNEL_0, @as(u8, @intCast((divisor & 0xFF00) >> 8)));
_ = interrupts.registerIRQ(0, &pitTimerHandler);
}
pub fn pitTimerHandler(_: u32, regs: *interrupts.InterruptStackFrame) void {
thread.preempt(regs);
}

View File

@ -1,6 +1,7 @@
const gdt = @import("gdt.zig");
const idt = @import("idt.zig");
const pic = @import("pic.zig");
const pit = @import("pit.zig");
const interrupts = @import("interrupts.zig");
pub const PAGE_SIZE = 4096;
@ -26,5 +27,5 @@ pub fn platformInit() void {
pub fn platformEndInit() void {
pic.remapPIC();
interrupts.syncInterrupts();
interrupts.enableInterrupts();
pit.initializePIT();
}

24
core/src/lib/spinlock.zig Normal file
View File

@ -0,0 +1,24 @@
const std = @import("std");
const debug = @import("../arch/debug.zig");
pub const SpinLock = struct {
lock_value: std.atomic.Value(u32) = std.atomic.Value(u32).init(0),
pub fn lock(self: *SpinLock) void {
while (self.lock_value.cmpxchgWeak(0, 1, .seq_cst, .seq_cst) != null) {}
}
pub fn unlock(self: *SpinLock) void {
if (self.lock_value.cmpxchgStrong(1, 0, .seq_cst, .seq_cst) != null) {
debug.print("Error: SpinLock.unlock() called on an unlocked lock!\n", .{});
}
}
pub fn tryLock(self: *SpinLock) bool {
return self.lock_value.cmpxchgStrong(0, 1, .seq_cst, .seq_cst) == null;
}
pub fn isLocked(self: *SpinLock) bool {
return self.lock_value.load() != 0;
}
};

View File

@ -99,8 +99,14 @@ export fn _start(magic: u32, info: MultibootInfo) callconv(.C) noreturn {
};
thread.arch.setStack(&init.regs, stack);
pmm.setGlobalAllocator(&allocator) catch |err| {
debug.print("Error while setting up global frame allocator: {}\n", .{err});
while (true) {}
};
platform.platformEndInit();
init.state = .Running;
thread.enterTask(init);
}

View File

@ -1,8 +1,10 @@
const std = @import("std");
const easyboot = @cImport(@cInclude("easyboot.h"));
const platform = @import("arch/platform.zig").arch;
const vmm = @import("arch/vmm.zig").arch;
const mmap = @import("mmap.zig");
const bmap = @import("lib/bitmap.zig");
const locking = @import("lib/spinlock.zig");
const FrameAllocatorError = error{
InvalidMemoryMap,
@ -104,3 +106,28 @@ pub fn initializeFrameAllocator(tag: *easyboot.multiboot_tag_mmap_t) !FrameAlloc
return allocator;
}
var lock: locking.SpinLock = .{};
var global_allocator: *FrameAllocator = undefined;
pub fn setGlobalAllocator(allocator: *FrameAllocator) !void {
const frame = try allocFrame(allocator);
const virt = frame.virtualAddress(vmm.PHYSICAL_MAPPING_BASE);
global_allocator = @ptrFromInt(virt);
global_allocator.* = allocator.*;
}
pub fn lockGlobalAllocator() *FrameAllocator {
lock.lock();
return global_allocator;
}
pub fn tryLockGlobalAllocator() ?*FrameAllocator {
if (!lock.tryLock()) return null;
return global_allocator;
}
pub fn unlockGlobalAllocator() void {
lock.unlock();
}

26
core/src/sys/mem.zig Normal file
View File

@ -0,0 +1,26 @@
const interrupts = @import("../arch/interrupts.zig").arch;
const sys = @import("syscall.zig");
const pmm = @import("../pmm.zig");
pub fn allocFrame(_: *interrupts.InterruptStackFrame, _: *sys.Arguments, retval: *isize) anyerror!void {
const allocator = pmm.lockGlobalAllocator();
defer pmm.unlockGlobalAllocator();
const frame = try pmm.allocFrame(allocator);
retval.* = @bitCast(frame.address);
}
pub fn freeFrame(_: *interrupts.InterruptStackFrame, args: *sys.Arguments, _: *isize) anyerror!void {
const allocator = pmm.lockGlobalAllocator();
defer pmm.unlockGlobalAllocator();
try pmm.freeFrame(allocator, args.arg0);
}
pub fn lockFrame(_: *interrupts.InterruptStackFrame, args: *sys.Arguments, _: *isize) anyerror!void {
const allocator = pmm.lockGlobalAllocator();
defer pmm.unlockGlobalAllocator();
try pmm.lockFrame(allocator, args.arg0);
}

7
core/src/sys/sched.zig Normal file
View File

@ -0,0 +1,7 @@
const interrupts = @import("../arch/interrupts.zig").arch;
const sys = @import("syscall.zig");
const thread = @import("../thread.zig");
pub fn yield(regs: *interrupts.InterruptStackFrame, _: *sys.Arguments, _: *isize) anyerror!void {
thread.scheduleNewTask(regs);
}

View File

@ -1,6 +1,8 @@
const std = @import("std");
const interrupts = @import("../arch/interrupts.zig").arch;
const print = @import("print.zig").print;
const mem = @import("mem.zig");
const sched = @import("sched.zig");
pub const Arguments = struct {
arg0: usize,
@ -13,7 +15,7 @@ pub const Arguments = struct {
const SystemCall = *const fn (frame: *interrupts.InterruptStackFrame, args: *Arguments, retval: *isize) anyerror!void;
const syscalls = [_]SystemCall{print};
const syscalls = [_]SystemCall{ print, mem.allocFrame, mem.lockFrame, mem.freeFrame, sched.yield };
pub fn invokeSyscall(number: usize, frame: *interrupts.InterruptStackFrame, args: *Arguments, retval: *isize) void {
if (number >= syscalls.len) {

View File

@ -6,13 +6,16 @@ const pmm = @import("pmm.zig");
const cpu = @import("arch/cpu.zig");
pub const ThreadState = enum {
Inactive,
Running,
Blocked,
};
pub const ThreadControlBlock = struct {
id: u64,
directory: ?*vmm.PageDirectory,
regs: interrupts.InterruptStackFrame,
state: ThreadState,
ticks: u64,
};
@ -82,6 +85,7 @@ pub fn createThreadControlBlock(allocator: *pmm.FrameAllocator) !*ThreadControlB
thread.id = next_id.fetchAdd(1, .seq_cst);
thread.directory = null;
thread.regs = std.mem.zeroes(@TypeOf(thread.regs));
thread.state = .Inactive;
return thread;
}

41
system/init/kernel.zig Normal file
View File

@ -0,0 +1,41 @@
const SystemCall = enum(u64) {
Print,
AllocFrame,
LockFrame,
FreeFrame,
Yield,
};
const SystemError = error{
OutOfMemory,
};
fn syscall(num: SystemCall, arg: u64) i64 {
return asm volatile ("int $66"
: [result] "=r" (-> i64),
: [num] "{rax}" (@intFromEnum(num)),
[arg] "{rdi}" (arg),
);
}
pub fn print(arg: u64) void {
_ = syscall(.Print, arg);
}
pub fn allocFrame() !usize {
const retval = syscall(.AllocFrame, 0);
if (retval < 0) return error.OutOfMemory;
return @bitCast(retval);
}
pub fn lockFrame(address: u64) void {
_ = syscall(.LockFrame, address);
}
pub fn freeFrame(address: u64) void {
_ = syscall(.FreeFrame, address);
}
pub fn yield() void {
_ = syscall(.Yield, 0);
}

View File

@ -1,13 +1,9 @@
fn syscall(num: u64, arg: u64) void {
asm volatile ("int $66"
:
: [num] "{rax}" (num),
[arg] "{rdi}" (arg),
);
}
const kernel = @import("kernel.zig");
export fn _start(base: u64) callconv(.C) noreturn {
syscall(0, base);
kernel.print(base);
while (true) {}
while (true) {
kernel.yield();
}
}