Compare commits
7 Commits
09fb2b6554
...
d7557d84f7
Author | SHA1 | Date | |
---|---|---|---|
d7557d84f7 | |||
46a0c8c800 | |||
5eabb6bdf0 | |||
c86481f2e7 | |||
6a2323c16b | |||
77cee5aeb0 | |||
2fd618173f |
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 => {},
|
||||
}
|
||||
|
28
core/src/arch/x86_64/pit.zig
Normal file
28
core/src/arch/x86_64/pit.zig
Normal 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);
|
||||
}
|
@ -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
24
core/src/lib/spinlock.zig
Normal 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;
|
||||
}
|
||||
};
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
26
core/src/sys/mem.zig
Normal 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
7
core/src/sys/sched.zig
Normal 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);
|
||||
}
|
@ -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) {
|
||||
|
@ -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
41
system/init/kernel.zig
Normal 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);
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user