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 thread = @import("../thread.zig");
|
||||||
const pmm = @import("../pmm.zig");
|
const pmm = @import("../pmm.zig");
|
||||||
const vmm = @import("vmm.zig").arch;
|
const vmm = @import("vmm.zig").arch;
|
||||||
|
const platform = @import("platform.zig").arch;
|
||||||
|
|
||||||
pub const arch = switch (target.cpu.arch) {
|
pub const arch = switch (target.cpu.arch) {
|
||||||
.x86_64 => @import("x86_64/cpu.zig"),
|
.x86_64 => @import("x86_64/cpu.zig"),
|
||||||
@ -26,11 +27,15 @@ pub fn setupCore(allocator: *pmm.FrameAllocator) !void {
|
|||||||
idle_thread.id = 0;
|
idle_thread.id = 0;
|
||||||
idle_thread.directory = null;
|
idle_thread.directory = null;
|
||||||
idle_thread.regs = std.mem.zeroes(@TypeOf(idle_thread.regs));
|
idle_thread.regs = std.mem.zeroes(@TypeOf(idle_thread.regs));
|
||||||
|
idle_thread.state = .Running;
|
||||||
thread.arch.initKernelRegisters(&idle_thread.regs);
|
thread.arch.initKernelRegisters(&idle_thread.regs);
|
||||||
thread.arch.setAddress(&idle_thread.regs, @intFromPtr(&thread.arch.idleLoop));
|
thread.arch.setAddress(&idle_thread.regs, @intFromPtr(&thread.arch.idleLoop));
|
||||||
|
|
||||||
core.thread_list.append(&core.idle_thread);
|
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;
|
this_core = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,16 @@ fn pageFault(frame: *InterruptStackFrame) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export fn interruptEntry(frame: *InterruptStackFrame) callconv(.C) 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) {
|
switch (frame.isr) {
|
||||||
@intFromEnum(Exceptions.PageFault) => {
|
@intFromEnum(Exceptions.PageFault) => {
|
||||||
pageFault(frame);
|
pageFault(frame);
|
||||||
@ -149,7 +158,7 @@ export fn interruptEntry(frame: *InterruptStackFrame) callconv(.C) void {
|
|||||||
},
|
},
|
||||||
SYSCALL_INTERRUPT => {
|
SYSCALL_INTERRUPT => {
|
||||||
var args = sys.Arguments{ .arg0 = frame.rdi, .arg1 = frame.rsi, .arg2 = frame.rdx, .arg3 = frame.r10, .arg4 = frame.r8, .arg5 = frame.r9 };
|
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 => {},
|
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 gdt = @import("gdt.zig");
|
||||||
const idt = @import("idt.zig");
|
const idt = @import("idt.zig");
|
||||||
const pic = @import("pic.zig");
|
const pic = @import("pic.zig");
|
||||||
|
const pit = @import("pit.zig");
|
||||||
const interrupts = @import("interrupts.zig");
|
const interrupts = @import("interrupts.zig");
|
||||||
|
|
||||||
pub const PAGE_SIZE = 4096;
|
pub const PAGE_SIZE = 4096;
|
||||||
@ -26,5 +27,5 @@ pub fn platformInit() void {
|
|||||||
pub fn platformEndInit() void {
|
pub fn platformEndInit() void {
|
||||||
pic.remapPIC();
|
pic.remapPIC();
|
||||||
interrupts.syncInterrupts();
|
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);
|
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();
|
platform.platformEndInit();
|
||||||
|
|
||||||
|
init.state = .Running;
|
||||||
thread.enterTask(init);
|
thread.enterTask(init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const easyboot = @cImport(@cInclude("easyboot.h"));
|
const easyboot = @cImport(@cInclude("easyboot.h"));
|
||||||
const platform = @import("arch/platform.zig").arch;
|
const platform = @import("arch/platform.zig").arch;
|
||||||
|
const vmm = @import("arch/vmm.zig").arch;
|
||||||
const mmap = @import("mmap.zig");
|
const mmap = @import("mmap.zig");
|
||||||
const bmap = @import("lib/bitmap.zig");
|
const bmap = @import("lib/bitmap.zig");
|
||||||
|
const locking = @import("lib/spinlock.zig");
|
||||||
|
|
||||||
const FrameAllocatorError = error{
|
const FrameAllocatorError = error{
|
||||||
InvalidMemoryMap,
|
InvalidMemoryMap,
|
||||||
@ -104,3 +106,28 @@ pub fn initializeFrameAllocator(tag: *easyboot.multiboot_tag_mmap_t) !FrameAlloc
|
|||||||
|
|
||||||
return allocator;
|
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 std = @import("std");
|
||||||
const interrupts = @import("../arch/interrupts.zig").arch;
|
const interrupts = @import("../arch/interrupts.zig").arch;
|
||||||
const print = @import("print.zig").print;
|
const print = @import("print.zig").print;
|
||||||
|
const mem = @import("mem.zig");
|
||||||
|
const sched = @import("sched.zig");
|
||||||
|
|
||||||
pub const Arguments = struct {
|
pub const Arguments = struct {
|
||||||
arg0: usize,
|
arg0: usize,
|
||||||
@ -13,7 +15,7 @@ pub const Arguments = struct {
|
|||||||
|
|
||||||
const SystemCall = *const fn (frame: *interrupts.InterruptStackFrame, args: *Arguments, retval: *isize) anyerror!void;
|
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 {
|
pub fn invokeSyscall(number: usize, frame: *interrupts.InterruptStackFrame, args: *Arguments, retval: *isize) void {
|
||||||
if (number >= syscalls.len) {
|
if (number >= syscalls.len) {
|
||||||
|
@ -6,13 +6,16 @@ const pmm = @import("pmm.zig");
|
|||||||
const cpu = @import("arch/cpu.zig");
|
const cpu = @import("arch/cpu.zig");
|
||||||
|
|
||||||
pub const ThreadState = enum {
|
pub const ThreadState = enum {
|
||||||
|
Inactive,
|
||||||
Running,
|
Running,
|
||||||
|
Blocked,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ThreadControlBlock = struct {
|
pub const ThreadControlBlock = struct {
|
||||||
id: u64,
|
id: u64,
|
||||||
directory: ?*vmm.PageDirectory,
|
directory: ?*vmm.PageDirectory,
|
||||||
regs: interrupts.InterruptStackFrame,
|
regs: interrupts.InterruptStackFrame,
|
||||||
|
state: ThreadState,
|
||||||
|
|
||||||
ticks: u64,
|
ticks: u64,
|
||||||
};
|
};
|
||||||
@ -82,6 +85,7 @@ pub fn createThreadControlBlock(allocator: *pmm.FrameAllocator) !*ThreadControlB
|
|||||||
thread.id = next_id.fetchAdd(1, .seq_cst);
|
thread.id = next_id.fetchAdd(1, .seq_cst);
|
||||||
thread.directory = null;
|
thread.directory = null;
|
||||||
thread.regs = std.mem.zeroes(@TypeOf(thread.regs));
|
thread.regs = std.mem.zeroes(@TypeOf(thread.regs));
|
||||||
|
thread.state = .Inactive;
|
||||||
|
|
||||||
return thread;
|
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 {
|
const kernel = @import("kernel.zig");
|
||||||
asm volatile ("int $66"
|
|
||||||
:
|
|
||||||
: [num] "{rax}" (num),
|
|
||||||
[arg] "{rdi}" (arg),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn _start(base: u64) callconv(.C) noreturn {
|
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