hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/elf.zig2
-rw-r--r--boot/regs.zig6
-rw-r--r--boot/sched.zig33
3 files changed, 8 insertions, 33 deletions
diff --git a/boot/elf.zig b/boot/elf.zig
index 906e380..51dc107 100644
--- a/boot/elf.zig
+++ b/boot/elf.zig
@@ -1,6 +1,4 @@
-// the embedded ring 3 programs, boot copies each to frames at startup
pub const Program = struct { name: []const u8, bytes: []const u8 };
-
pub const programs = [_]Program{
.{ .name = "hexview", .bytes = @embedFile("user_hexview") },
.{ .name = "calc", .bytes = @embedFile("user_calc") },
diff --git a/boot/regs.zig b/boot/regs.zig
index aedae99..7b2bb88 100644
--- a/boot/regs.zig
+++ b/boot/regs.zig
@@ -24,10 +24,8 @@ pub const Frame = extern struct {
ss: u64,
};
-// push/pop the 15 gprs in frames exact order (rax pushed first -> highest field,
-// r15 last -> at rsp = &frame). shared by every save/restore stub so they cant
-// drift from the frame layout above. `mov %rsp, %rdi` after push_gprs hands the
-// handler a *frame
+// push/pop the 15 gprs in frames exact order
+// (rax pushed first -> highest field, r15 last -> at rsp = &frame)
pub const PUSH_GPRS =
\\push %rax
\\push %rbx
diff --git a/boot/sched.zig b/boot/sched.zig
index 60a8fa0..0857abe 100644
--- a/boot/sched.zig
+++ b/boot/sched.zig
@@ -26,18 +26,15 @@ var tasks: [MAX_TASKS]Task = @splat(.{});
var kstacks: [MAX_TASKS][KSTACK_SIZE]u8 align(16) = undefined;
var current: usize = 0;
var spawn_count: u64 = 0;
-// the one task currently blocked in read(), if any
var blocked_reader: ?usize = null;
-// the "foreground" task that owns keyboard input (set when a task first reads,
-// cleared when it exits). keystrokes route to it, into stdin_buf when it isnt
-// currently blocked, so nothing is lost between its reads. else the shell
+
var foreground: ?usize = null;
var stdin_buf: [64]u8 = undefined;
var stdin_head: usize = 0;
var stdin_tail: usize = 0;
fn stdinPush(byte: u8) void {
- if (stdin_tail -% stdin_head >= stdin_buf.len) return; // full, drop
+ if (stdin_tail -% stdin_head >= stdin_buf.len) return;
stdin_buf[stdin_tail % stdin_buf.len] = byte;
stdin_tail +%= 1;
}
@@ -54,9 +51,6 @@ pub fn init(kernel_cr3: u64) void {
current = 0;
}
-// queue a ring 3 process. it starts running the next time the scheduler picks
-// it (the tick copies its initial frame onto the stack and iretqs in). rdi is
-// seeded with a small per spawn id so demo programs can tell instances apart
pub fn spawn(cr3: u64, entry: u64, ustack: u64) void {
var i: usize = 1;
while (i < MAX_TASKS) : (i += 1) {
@@ -79,7 +73,6 @@ pub fn spawn(cr3: u64, entry: u64, ustack: u64) void {
}
}
-// number of live user processes (ready or blocked), excluding the kernel task
pub fn procCount() u64 {
var count: u64 = 0;
var i: usize = 1;
@@ -91,8 +84,7 @@ pub fn procCount() u64 {
var proc_exited_flag: bool = false;
-// mark the running process dead. it then sti+hlts, the next tick reclaims the
-// slot and switches away, never returning here
+// mark the running process dead. it then sti+hlts
pub fn exitCurrent() void {
if (current != 0) {
tasks[current].state = .dead;
@@ -105,23 +97,17 @@ pub fn exitCurrent() void {
}
}
-// did a process exit since last checked? (consumed once.)
pub fn takeProcExited() bool {
const e = proc_exited_flag;
proc_exited_flag = false;
return e;
}
-// called at the top of read(): the caller becomes the foreground reader. returns
-// a buffered byte if one is waiting (so read() neednt block), else null
pub fn readReady() ?u8 {
foreground = current;
return stdinPop();
}
-// block the running task in read(). `resume_frame` is a context that iretqs
-// straight back to just after the processs int 0x80, so when input arrives we
-// set its rax and mark it ready, and the scheduler resumes it there
pub fn blockCurrentOnRead(resume_frame: Frame) void {
if (current == 0) return; // the kernel task never blocks like this
tasks[current].frame = resume_frame;
@@ -129,9 +115,6 @@ pub fn blockCurrentOnRead(resume_frame: Frame) void {
blocked_reader = current;
}
-// route one input byte. if a task is blocked in read(), wake it with the byte
-// else if a foreground reader exists, buffer it for its next read(). returns
-// false only when nothing wants it (so the caller feeds the shell instead)
pub fn deliverInput(byte: u8) bool {
if (blocked_reader) |task| {
tasks[task].frame.rax = byte; // read()s return value
@@ -146,20 +129,17 @@ pub fn deliverInput(byte: u8) bool {
return false;
}
-// the preemption point, called from the pit irq with the interrupted frame
pub fn tick(frame: *Frame) void {
- // dont preempt task 0 mid vm call, the shared fiber cant be re-entered
if (bridge.vmBusy()) return;
if (tasks[current].state == .dead) {
tasks[current].state = .free; // reclaim, dont bother saving its context
} else if (tasks[current].state == .blocked) {
- // keep the resume frame saved by blockcurrentonread, dont clobber it
+ // keep the resume frame saved by blockcurrentonread, dont clobber it you bitch
} else {
tasks[current].frame = frame.*; // freeze the current task
}
- // round robin to the next ready task
var next = current;
var i = current;
var n: usize = 0;
@@ -170,10 +150,9 @@ pub fn tick(frame: *Frame) void {
break;
}
}
- // if the current task cant continue (dead/blocked) and nothing else is
- // ready, fall back to the kernel task (0), which is always ready
+
if (tasks[current].state != .ready and next == current) next = 0;
- if (next == current) return; // nothing else to run, keep going
+ if (next == current) return;
current = next;
frame.* = tasks[current].frame;