towards 0.10
This commit is contained in:
parent
08d447115d
commit
77fd0ce4cf
9 changed files with 132 additions and 156 deletions
|
|
@ -58,32 +58,32 @@ pub fn initialize() void {
|
||||||
x86.isr.install_exceptions();
|
x86.isr.install_exceptions();
|
||||||
x86.isr.install_irqs();
|
x86.isr.install_irqs();
|
||||||
x86.isr.install_syscalls();
|
x86.isr.install_syscalls();
|
||||||
x86.interrupt.registerIRQ(0, kernel.time.increment);
|
// x86.interrupt.registerIRQ(0, kernel.time.increment);
|
||||||
x86.interrupt.registerIRQ(1, kernel.ps2.keyboard_handler);
|
// x86.interrupt.registerIRQ(1, kernel.ps2.keyboard_handler);
|
||||||
x86.interrupt.register(1, debug_trap);
|
// x86.interrupt.register(1, debug_trap);
|
||||||
x86.interrupt.register(13, general_protection_fault);
|
// x86.interrupt.register(13, general_protection_fault);
|
||||||
x86.interrupt.register(14, page_fault);
|
// x86.interrupt.register(14, page_fault);
|
||||||
|
|
||||||
// load IDT
|
// load IDT
|
||||||
x86.instr.lidt(@ptrToInt(&idtr));
|
x86.instr.lidt(@ptrToInt(&idtr));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn general_protection_fault() void {
|
fn general_protection_fault() void {
|
||||||
kernel.println("general protection fault", .{});
|
kernel.vga.println("general protection fault", .{});
|
||||||
x86.instr.hang();
|
x86.instr.hang();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_trap() void {
|
fn debug_trap() void {
|
||||||
kernel.println("debug fault/trap", .{});
|
kernel.vga.println("debug fault/trap", .{});
|
||||||
kernel.println("dr7: 0b{b}", .{x86.instr.dr7()});
|
kernel.vga.println("dr7: 0b{b}", .{x86.instr.dr7()});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn page_fault() void {
|
fn page_fault() void {
|
||||||
const vaddr = x86.instr.cr2();
|
const vaddr = x86.instr.cr2();
|
||||||
kernel.println("cr2: 0x{x}", .{vaddr});
|
kernel.vga.println("cr2: 0x{x}", .{vaddr});
|
||||||
kernel.println("phy: 0x{x}", .{kernel.paging.translate(vaddr)});
|
kernel.vga.println("phy: 0x{x}", .{x86.paging.translate(vaddr)});
|
||||||
kernel.println("pde: 0x{x} ({})", .{ kernel.paging.pde(vaddr), vaddr >> 22 });
|
kernel.vga.println("pde: 0x{x} ({})", .{ x86.paging.pde(vaddr), vaddr >> 22 });
|
||||||
kernel.println("pte: 0x{x} ({})", .{ kernel.paging.pte(vaddr), vaddr >> 12 });
|
kernel.vga.println("pte: 0x{x} ({})", .{ x86.paging.pte(vaddr), vaddr >> 12 });
|
||||||
// paging.format();
|
// paging.format();
|
||||||
x86.instr.hang();
|
x86.instr.hang();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ const IRQ_15 = IRQ_0 + 15;
|
||||||
const SYSCALL = 128;
|
const SYSCALL = 128;
|
||||||
|
|
||||||
// Registered interrupt handlers. (see x86.isr.s)
|
// Registered interrupt handlers. (see x86.isr.s)
|
||||||
var handlers = [_]fn () void{unhandled} ** 48;
|
const handlers = [_]fn () void{unhandled} ** 48;
|
||||||
// Registered IRQ subscribers. (see x86.isr.s)
|
// Registered IRQ subscribers. (see x86.isr.s)
|
||||||
// var irq_subscribers = []MailboxId{MailboxId.Kernel} ** 16;
|
// var irq_subscribers = []MailboxId{MailboxId.Kernel} ** 16;
|
||||||
|
|
||||||
|
|
@ -130,11 +130,11 @@ inline fn endOfInterrupt(irq: u8) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register(n: u8, handler: fn () void) void {
|
pub fn register(n: u8, comptime handler: fn () void) void {
|
||||||
handlers[n] = handler;
|
handlers[n] = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn registerIRQ(irq: u8, handler: fn () void) void {
|
pub fn registerIRQ(irq: u8, comptime handler: fn () void) void {
|
||||||
register(IRQ_0 + irq, handler);
|
register(IRQ_0 + irq, handler);
|
||||||
maskIRQ(irq, false); // Unmask the IRQ.
|
maskIRQ(irq, false); // Unmask the IRQ.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
pub usingnamespace @import("../common.zig");
|
// pub usingnamespace @import("../common.zig");
|
||||||
|
|
||||||
pub const kernel = @import("../index.zig");
|
// pub const kernel = @import("../index.zig");
|
||||||
|
|
||||||
pub const x86 = @import("../arch/x86/index.zig");
|
pub const x86 = @import("../arch/x86/index.zig");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
|
pub const dq = @import("delta_queue.zig");
|
||||||
// pub usingnamespace @import("common.zig");
|
// pub usingnamespace @import("common.zig");
|
||||||
// pub usingnamespace @import("delta_queue.zig");
|
|
||||||
// pub usingnamespace @import("ring_buffer.zig");
|
// pub usingnamespace @import("ring_buffer.zig");
|
||||||
|
|
||||||
pub const vga = @import("vga.zig");
|
pub const vga = @import("vga.zig");
|
||||||
|
|
||||||
//drivers
|
//drivers
|
||||||
// pub const driver = @import("driver/index.zig");
|
pub const driver = @import("driver/index.zig");
|
||||||
|
|
||||||
//arch
|
//arch
|
||||||
pub const x86 = @import("arch/x86/index.zig");
|
pub const x86 = @import("arch/x86/index.zig");
|
||||||
|
|
@ -15,11 +15,11 @@ pub const constants = @import("constants.zig");
|
||||||
pub const layout = @import("layout.zig");
|
pub const layout = @import("layout.zig");
|
||||||
pub const multiboot = @import("multiboot.zig");
|
pub const multiboot = @import("multiboot.zig");
|
||||||
pub const vmem = @import("vmem.zig");
|
pub const vmem = @import("vmem.zig");
|
||||||
// pub const task = @import("task.zig");
|
pub const task = @import("task.zig");
|
||||||
pub const time = @import("time.zig");
|
pub const time = @import("time.zig");
|
||||||
|
|
||||||
//extra
|
//extra
|
||||||
// pub const console = @import("console.zig");
|
// pub const console = @import("console.zig");
|
||||||
// pub const bio = @import("bio.zig");
|
// pub const bio = @import("bio.zig");
|
||||||
// pub const pci = @import("pci/pci.zig");
|
pub const pci = @import("pci/pci.zig");
|
||||||
// pub const ps2 = @import("ps2.zig");
|
pub const ps2 = @import("ps2.zig");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
pub usingnamespace @import("../index.zig");
|
pub const std = @import("std");
|
||||||
pub const virtio = @import("virtio.zig");
|
|
||||||
pub const ide = @import("ide.zig");
|
pub const kernel = @import("index.zig");
|
||||||
|
pub const x86 = @import("x86.zig");
|
||||||
|
pub const driver = @import("driver/index.zig");
|
||||||
|
|
||||||
const PCI_CONFIG_ADDRESS = 0xCF8;
|
const PCI_CONFIG_ADDRESS = 0xCF8;
|
||||||
const PCI_CONFIG_DATA = 0xCFC;
|
const PCI_CONFIG_DATA = 0xCFC;
|
||||||
|
|
@ -41,10 +43,10 @@ pub const PciDevice = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format(self: PciDevice) void {
|
pub fn format(self: PciDevice) void {
|
||||||
print("{}:{}.{}", .{ self.bus, self.slot, self.function });
|
kernel.vga.print("{}:{}.{}", .{ self.bus, self.slot, self.function });
|
||||||
print(" {x},{x:2}", .{ self.class(), self.subclass() });
|
kernel.vga.print(" {x},{x:2}", .{ self.class(), self.subclass() });
|
||||||
print(" 0x{x} 0x{x}", .{ self.vendor, self.device() });
|
kernel.vga.print(" 0x{x} 0x{x}", .{ self.vendor, self.device() });
|
||||||
println(" {}", .{if (self.driver()) |d| d.name else " (none)"});
|
kernel.vga.println(" {}", .{if (self.driver()) |d| d.name else " (none)"});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn driver(self: PciDevice) ?Driver {
|
pub fn driver(self: PciDevice) ?Driver {
|
||||||
|
|
@ -94,7 +96,7 @@ pub const PciDevice = struct {
|
||||||
return self.config_read(u8, 0x3c);
|
return self.config_read(u8, 0x3c);
|
||||||
}
|
}
|
||||||
pub fn bar(self: PciDevice, comptime n: usize) u32 {
|
pub fn bar(self: PciDevice, comptime n: usize) u32 {
|
||||||
assert(n <= 5);
|
std.debug.assert(n <= 5);
|
||||||
return self.config_read(u32, 0x10 + 4 * n);
|
return self.config_read(u32, 0x10 + 4 * n);
|
||||||
}
|
}
|
||||||
// only for header_type == 0
|
// only for header_type == 0
|
||||||
|
|
@ -102,7 +104,7 @@ pub const PciDevice = struct {
|
||||||
return self.config_read(u8, 0x2e);
|
return self.config_read(u8, 0x2e);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn config_write(self: PciDevice, value: var, comptime offset: u8) void {
|
pub inline fn config_write(self: PciDevice, value: anytype, comptime offset: u8) void {
|
||||||
// ask for access before writing config
|
// ask for access before writing config
|
||||||
x86.outl(PCI_CONFIG_ADDRESS, self.address(offset));
|
x86.outl(PCI_CONFIG_ADDRESS, self.address(offset));
|
||||||
switch (@TypeOf(value)) {
|
switch (@TypeOf(value)) {
|
||||||
|
|
@ -172,7 +174,7 @@ pub fn scan() void {
|
||||||
|
|
||||||
pub fn lspci() void {
|
pub fn lspci() void {
|
||||||
var slot: u5 = 0;
|
var slot: u5 = 0;
|
||||||
println("b:s.f c, s vendor device driver", .{});
|
kernel.vga.println("b:s.f c, s vendor device driver", .{});
|
||||||
while (slot < 31) : (slot += 1) {
|
while (slot < 31) : (slot += 1) {
|
||||||
if (PciDevice.init(0, slot, 0)) |dev| {
|
if (PciDevice.init(0, slot, 0)) |dev| {
|
||||||
var function: u3 = 0;
|
var function: u3 = 0;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
usingnamespace @import("index.zig");
|
usingnamespace @import("index.zig");
|
||||||
// const x86 = @import("x86");
|
const x86 = @import("x86");
|
||||||
|
|
||||||
const PS2_DATA = 0x60;
|
const PS2_DATA = 0x60;
|
||||||
const PS2_STATUS = 0x64;
|
const PS2_STATUS = 0x64;
|
||||||
|
|
@ -67,8 +67,8 @@ const KEYMAP_US = [_][]const u8{
|
||||||
|
|
||||||
fn ps2_scancode() u8 {
|
fn ps2_scancode() u8 {
|
||||||
var scancode: u8 = 0;
|
var scancode: u8 = 0;
|
||||||
while (true) if (x86.inb(PS2_DATA) != scancode) {
|
while (true) if (x86.io.inb(PS2_DATA) != scancode) {
|
||||||
scancode = x86.inb(PS2_DATA);
|
scancode = x86.io.inb(PS2_DATA);
|
||||||
if (scancode > 0) return scancode;
|
if (scancode > 0) return scancode;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
140
src/task.zig
140
src/task.zig
|
|
@ -1,25 +1,27 @@
|
||||||
pub usingnamespace @import("index.zig");
|
const kernel = @import("kernel");
|
||||||
|
const std = @import("std");
|
||||||
|
const x86 = @import("x86");
|
||||||
|
|
||||||
var boot_task = Task{ .tid = 0, .esp = 0x47, .state = .Running, .born = true };
|
var boot_task = Task{ .tid = 0, .esp = 0x47, .state = .Running, .born = true };
|
||||||
var tid_counter: u16 = 1;
|
var tid_counter: u16 = 1;
|
||||||
|
|
||||||
pub const TaskNode = std.TailQueue(*Task).Node;
|
pub const TaskNode = std.TailQueue(*Task).Node;
|
||||||
pub const SleepNode = DeltaQueue(*TaskNode).Node;
|
pub const SleepNode = kernel.dq.DeltaQueue(*TaskNode).Node;
|
||||||
|
|
||||||
pub var current_task: *TaskNode = &TaskNode.init(&boot_task);
|
pub var current_task: *TaskNode = &TaskNode.init(&boot_task);
|
||||||
pub var cleaner_task: *TaskNode = undefined;
|
pub var cleaner_task: *TaskNode = undefined;
|
||||||
pub var ready_tasks = std.TailQueue(*Task).init();
|
pub var ready_tasks = std.TailQueue(*Task).init();
|
||||||
pub var blocked_tasks = std.TailQueue(*Task).init();
|
pub var blocked_tasks = std.TailQueue(*Task).init();
|
||||||
pub var terminated_tasks = std.TailQueue(*Task).init();
|
pub var terminated_tasks = std.TailQueue(*Task).init();
|
||||||
pub var sleeping_tasks = DeltaQueue(*TaskNode).init();
|
pub var sleeping_tasks = kernel.dq.DeltaQueue(*TaskNode).init();
|
||||||
|
|
||||||
const STACK_SIZE = x86.PAGE_SIZE; // Size of thread stacks.
|
const STACK_SIZE = x86.PAGE_SIZE; // Size of thread stacks.
|
||||||
|
|
||||||
var timer_last_count: u64 = 0;
|
var timer_last_count: u64 = 0;
|
||||||
pub fn update_time_used() void {
|
pub fn update_time_used() void {
|
||||||
const current_count = time.offset_us;
|
const current_count = kernel.time.offset_us;
|
||||||
const elapsed = current_count - timer_last_count;
|
const elapsed = current_count - timer_last_count;
|
||||||
// if (current_task.data.tid == 1) println("{} adding {} time", current_task.data.tid, elapsed);
|
// if (current_task.data.tid == 1) kernel.vga.println("{} adding {} time", current_task.data.tid, elapsed);
|
||||||
timer_last_count = current_count;
|
timer_last_count = current_count;
|
||||||
current_task.data.time_used += elapsed;
|
current_task.data.time_used += elapsed;
|
||||||
}
|
}
|
||||||
|
|
@ -45,22 +47,22 @@ pub const Task = struct {
|
||||||
|
|
||||||
pub fn create(entrypoint: usize) !*Task {
|
pub fn create(entrypoint: usize) !*Task {
|
||||||
// Allocate and initialize the thread structure.
|
// Allocate and initialize the thread structure.
|
||||||
var t = try vmem.allocator.create(Task);
|
var t = try kernel.vmem.allocator.create(Task);
|
||||||
errdefer vmem.allocator.destroy(t);
|
errdefer kernel.vmem.allocator.destroy(t);
|
||||||
|
|
||||||
t.time_used = 0;
|
t.time_used = 0;
|
||||||
t.state = .ReadyToRun;
|
t.state = .ReadyToRun;
|
||||||
t.tid = tid_counter;
|
t.tid = tid_counter;
|
||||||
tid_counter +%= 1;
|
tid_counter +%= 1;
|
||||||
assert(tid_counter != 0); //overflow
|
std.debug.assert(tid_counter != 0); //overflow
|
||||||
|
|
||||||
// allocate a new stack
|
// allocate a new stack
|
||||||
t.stack = try vmem.allocator.create([STACK_SIZE]u8);
|
t.stack = try kernel.vmem.allocator.create([STACK_SIZE]u8);
|
||||||
t.esp = @ptrToInt(t.stack) + STACK_SIZE;
|
t.esp = @ptrToInt(t.stack) + STACK_SIZE;
|
||||||
// if the tasks rets from its main function, it will go to terminate
|
// if the tasks rets from its main function, it will go to terminate
|
||||||
// NOTE: if terminate is called this way it has an incorrect ebp!
|
// NOTE: if terminate is called this way it has an incorrect ebp!
|
||||||
t.esp -= 4;
|
t.esp -= 4;
|
||||||
@intToPtr(*usize, t.esp).* = @ptrToInt(task.terminate);
|
@intToPtr(*usize, t.esp).* = @ptrToInt(terminate);
|
||||||
// this will be what ret goes to
|
// this will be what ret goes to
|
||||||
t.esp -= 4;
|
t.esp -= 4;
|
||||||
@intToPtr(*usize, t.esp).* = entrypoint;
|
@intToPtr(*usize, t.esp).* = entrypoint;
|
||||||
|
|
@ -72,8 +74,8 @@ pub const Task = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(self: *Task) void {
|
pub fn destroy(self: *Task) void {
|
||||||
vmem.allocator.destroy(self.stack);
|
kernel.vmem.allocator.destroy(self.stack);
|
||||||
vmem.allocator.destroy(self);
|
kernel.vmem.allocator.destroy(self);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -81,11 +83,11 @@ pub const Task = struct {
|
||||||
extern fn switch_tasks(new_esp: usize, old_esp_addr: usize) void;
|
extern fn switch_tasks(new_esp: usize, old_esp_addr: usize) void;
|
||||||
|
|
||||||
pub fn new(entrypoint: usize) !*TaskNode {
|
pub fn new(entrypoint: usize) !*TaskNode {
|
||||||
task.lock_scheduler();
|
kernel.task.lock_scheduler();
|
||||||
defer task.unlock_scheduler();
|
defer kernel.task.unlock_scheduler();
|
||||||
|
|
||||||
const node = try vmem.allocator.create(TaskNode);
|
const node = try kernel.vmem.allocator.create(TaskNode);
|
||||||
errdefer vmem.allocator.destroy(node);
|
errdefer kernel.vmem.allocator.destroy(node);
|
||||||
|
|
||||||
node.data = try Task.create(entrypoint);
|
node.data = try Task.create(entrypoint);
|
||||||
ready_tasks.prepend(node);
|
ready_tasks.prepend(node);
|
||||||
|
|
@ -93,16 +95,16 @@ pub fn new(entrypoint: usize) !*TaskNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wakeup_tick(tick: usize) bool {
|
pub fn wakeup_tick(tick: usize) bool {
|
||||||
task.lock_scheduler();
|
kernel.task.lock_scheduler();
|
||||||
defer task.unlock_scheduler();
|
defer kernel.task.unlock_scheduler();
|
||||||
|
|
||||||
task.sleeping_tasks.decrement(tick);
|
kernel.task.sleeping_tasks.decrement(tick);
|
||||||
var popped = false;
|
var popped = false;
|
||||||
while (task.sleeping_tasks.popZero()) |sleepnode| {
|
while (kernel.task.sleeping_tasks.popZero()) |sleepnode| {
|
||||||
const tasknode = sleepnode.data;
|
const tasknode = sleepnode.data;
|
||||||
tasknode.data.state = .ReadyToRun;
|
tasknode.data.state = .ReadyToRun;
|
||||||
vmem.allocator.destroy(sleepnode);
|
kernel.vmem.allocator.destroy(sleepnode);
|
||||||
task.ready_tasks.prepend(tasknode);
|
ready_tasks.prepend(tasknode);
|
||||||
popped = true;
|
popped = true;
|
||||||
}
|
}
|
||||||
return popped;
|
return popped;
|
||||||
|
|
@ -110,10 +112,10 @@ pub fn wakeup_tick(tick: usize) bool {
|
||||||
|
|
||||||
// TODO: make a sleep without malloc
|
// TODO: make a sleep without malloc
|
||||||
pub fn usleep(usec: u64) !void {
|
pub fn usleep(usec: u64) !void {
|
||||||
assert(current_task.data.state == .Running);
|
std.debug.assert(current_task.data.state == .Running);
|
||||||
update_time_used();
|
update_time_used();
|
||||||
|
|
||||||
const node = try vmem.allocator.create(SleepNode);
|
const node = try kernel.vmem.allocator.create(SleepNode);
|
||||||
|
|
||||||
lock_scheduler();
|
lock_scheduler();
|
||||||
defer unlock_scheduler();
|
defer unlock_scheduler();
|
||||||
|
|
@ -126,9 +128,9 @@ pub fn usleep(usec: u64) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn block(state: TaskState) void {
|
pub fn block(state: TaskState) void {
|
||||||
assert(current_task.data.state == .Running);
|
std.debug.assert(current_task.data.state == .Running);
|
||||||
assert(state != .Running);
|
std.debug.assert(state != .Running);
|
||||||
assert(state != .ReadyToRun);
|
std.debug.assert(state != .ReadyToRun);
|
||||||
update_time_used();
|
update_time_used();
|
||||||
|
|
||||||
// println("blocking {} as {}", current_task.data.tid, state);
|
// println("blocking {} as {}", current_task.data.tid, state);
|
||||||
|
|
@ -161,7 +163,7 @@ pub fn unblock(node: *TaskNode) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn terminate() noreturn {
|
pub fn terminate() noreturn {
|
||||||
assert(current_task.data.state == .Running);
|
std.debug.assert(current_task.data.state == .Running);
|
||||||
|
|
||||||
lock_scheduler();
|
lock_scheduler();
|
||||||
current_task.data.state = .Terminated;
|
current_task.data.state = .Terminated;
|
||||||
|
|
@ -179,7 +181,7 @@ pub fn cleaner_loop() noreturn {
|
||||||
if (terminated_tasks.popFirst()) |n| {
|
if (terminated_tasks.popFirst()) |n| {
|
||||||
notify("DESTROYING {}", .{n.data.tid});
|
notify("DESTROYING {}", .{n.data.tid});
|
||||||
n.data.destroy();
|
n.data.destroy();
|
||||||
vmem.allocator.destroy(n);
|
kernel.vmem.allocator.destroy(n);
|
||||||
} else {
|
} else {
|
||||||
notify("NOTHING TO CLEAN", .{});
|
notify("NOTHING TO CLEAN", .{});
|
||||||
block(.Paused);
|
block(.Paused);
|
||||||
|
|
@ -191,15 +193,15 @@ pub var IRQ_disable_counter: usize = 0;
|
||||||
pub var postpone_task_switches_counter: isize = 0; // this counter can go negative when we are scheduling after a postpone
|
pub var postpone_task_switches_counter: isize = 0; // this counter can go negative when we are scheduling after a postpone
|
||||||
pub var postpone_task_switches_flag: bool = false;
|
pub var postpone_task_switches_flag: bool = false;
|
||||||
fn lock_scheduler() void {
|
fn lock_scheduler() void {
|
||||||
if (constants.SMP == false) {
|
if (kernel.constants.SMP == false) {
|
||||||
x86.cli();
|
x86.instr.cli();
|
||||||
IRQ_disable_counter += 1;
|
IRQ_disable_counter += 1;
|
||||||
postpone_task_switches_counter += 1;
|
postpone_task_switches_counter += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn unlock_scheduler() void {
|
fn unlock_scheduler() void {
|
||||||
if (constants.SMP == false) {
|
if (kernel.constants.SMP == false) {
|
||||||
assert(IRQ_disable_counter > 0);
|
std.debug.assert(IRQ_disable_counter > 0);
|
||||||
postpone_task_switches_counter -= 1;
|
postpone_task_switches_counter -= 1;
|
||||||
if (postpone_task_switches_flag == true and postpone_task_switches_counter == 0) {
|
if (postpone_task_switches_flag == true and postpone_task_switches_counter == 0) {
|
||||||
postpone_task_switches_flag = false;
|
postpone_task_switches_flag = false;
|
||||||
|
|
@ -208,7 +210,7 @@ fn unlock_scheduler() void {
|
||||||
}
|
}
|
||||||
IRQ_disable_counter -= 1;
|
IRQ_disable_counter -= 1;
|
||||||
// must be the last instruction because we do interrupts inside interrupts
|
// must be the last instruction because we do interrupts inside interrupts
|
||||||
if (IRQ_disable_counter == 0) x86.sti();
|
if (IRQ_disable_counter == 0) x86.instr.sti();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,7 +220,7 @@ pub fn preempt() void {
|
||||||
update_time_used();
|
update_time_used();
|
||||||
if (ready_tasks.first == null) {
|
if (ready_tasks.first == null) {
|
||||||
notify("NO PREEMPT SINGLE TASK", .{});
|
notify("NO PREEMPT SINGLE TASK", .{});
|
||||||
time.task_slice_remaining = 0;
|
kernel.time.task_slice_remaining = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,8 +236,8 @@ pub fn preempt() void {
|
||||||
// - scheduler is locked
|
// - scheduler is locked
|
||||||
// - the tasks being switched to will unlock_scheduler()
|
// - the tasks being switched to will unlock_scheduler()
|
||||||
pub fn switch_to(chosen: *TaskNode) void {
|
pub fn switch_to(chosen: *TaskNode) void {
|
||||||
assert(chosen.data.state == .ReadyToRun);
|
std.debug.assert(chosen.data.state == .ReadyToRun);
|
||||||
assert(current_task.data.state != .Running);
|
std.debug.assert(current_task.data.state != .Running);
|
||||||
|
|
||||||
// save old stack
|
// save old stack
|
||||||
const old_task_esp_addr = ¤t_task.data.esp;
|
const old_task_esp_addr = ¤t_task.data.esp;
|
||||||
|
|
@ -243,8 +245,8 @@ pub fn switch_to(chosen: *TaskNode) void {
|
||||||
// switch states
|
// switch states
|
||||||
chosen.data.state = .Running;
|
chosen.data.state = .Running;
|
||||||
current_task = chosen;
|
current_task = chosen;
|
||||||
if (ready_tasks.first == null) time.task_slice_remaining = 0;
|
if (ready_tasks.first == null) kernel.time.task_slice_remaining = 0;
|
||||||
if (ready_tasks.first != null) time.task_slice_remaining = time.TASK_SLICE;
|
if (ready_tasks.first != null) kernel.time.task_slice_remaining = kernel.time.TASK_SLICE;
|
||||||
|
|
||||||
// we don't have any startup code for tasks, so i do it here
|
// we don't have any startup code for tasks, so i do it here
|
||||||
if (current_task.data.born == false) {
|
if (current_task.data.born == false) {
|
||||||
|
|
@ -267,8 +269,8 @@ pub var CPU_idle_start_time: u64 = 0;
|
||||||
// unlock_scheduler should be called after
|
// unlock_scheduler should be called after
|
||||||
// current_task is blocked or running (preemption)
|
// current_task is blocked or running (preemption)
|
||||||
pub fn schedule() void {
|
pub fn schedule() void {
|
||||||
assert(IRQ_disable_counter > 0);
|
std.debug.assert(IRQ_disable_counter > 0);
|
||||||
assert(current_task.data.state != .ReadyToRun);
|
std.debug.assert(current_task.data.state != .ReadyToRun);
|
||||||
|
|
||||||
// postponed
|
// postponed
|
||||||
if (postpone_task_switches_counter != 0 and current_task.data.state == .Running) {
|
if (postpone_task_switches_counter != 0 and current_task.data.state == .Running) {
|
||||||
|
|
@ -291,7 +293,7 @@ pub fn schedule() void {
|
||||||
// single task
|
// single task
|
||||||
if (current_task.data.state == .Running) {
|
if (current_task.data.state == .Running) {
|
||||||
notify("SINGLE TASK", .{});
|
notify("SINGLE TASK", .{});
|
||||||
time.task_slice_remaining = 0;
|
kernel.time.task_slice_remaining = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// no tasks
|
// no tasks
|
||||||
|
|
@ -299,21 +301,21 @@ pub fn schedule() void {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn idle_mode() void {
|
fn idle_mode() void {
|
||||||
assert(ready_tasks.first == null);
|
std.debug.assert(ready_tasks.first == null);
|
||||||
assert(current_task.data.state != .Running);
|
std.debug.assert(current_task.data.state != .Running);
|
||||||
assert(current_task.data.state != .ReadyToRun);
|
std.debug.assert(current_task.data.state != .ReadyToRun);
|
||||||
|
|
||||||
notify("IDLE", .{});
|
notify("IDLE", .{});
|
||||||
|
|
||||||
// borrow the current task
|
// borrow the current task
|
||||||
const borrow = current_task;
|
const borrow = current_task;
|
||||||
|
|
||||||
CPU_idle_start_time = time.offset_us; //for power management
|
CPU_idle_start_time = kernel.time.offset_us; //for power management
|
||||||
|
|
||||||
while (true) { // idle loop
|
while (true) { // idle loop
|
||||||
if (ready_tasks.popFirst()) |t| { // found a new task
|
if (ready_tasks.popFirst()) |t| { // found a new task
|
||||||
CPU_idle_time += time.offset_us - CPU_idle_start_time; // count time as idle
|
CPU_idle_time += kernel.time.offset_us - CPU_idle_start_time; // count time as idle
|
||||||
timer_last_count = time.offset_us; // don't count time as used
|
timer_last_count = kernel.time.offset_us; // don't count time as used
|
||||||
// println("went into idle mode for {}usecs", time.offset_us - CPU_idle_start_time);
|
// println("went into idle mode for {}usecs", time.offset_us - CPU_idle_start_time);
|
||||||
|
|
||||||
if (t == borrow) {
|
if (t == borrow) {
|
||||||
|
|
@ -322,43 +324,43 @@ fn idle_mode() void {
|
||||||
}
|
}
|
||||||
return switch_to(t);
|
return switch_to(t);
|
||||||
} else { // no tasks ready, let the timer fire
|
} else { // no tasks ready, let the timer fire
|
||||||
x86.sti(); // enable interrupts to allow the timer to fire
|
x86.instr.sti(); // enable interrupts to allow the timer to fire
|
||||||
x86.hlt(); // halt and wait for the timer to fire
|
x86.instr.hlt(); // halt and wait for the timer to fire
|
||||||
x86.cli(); // disable interrupts again to see if there is something to do
|
x86.instr.cli(); // disable interrupts again to see if there is something to do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notify(comptime message: []const u8, args: var) void {
|
pub fn notify(comptime message: []const u8, args: anytype) void {
|
||||||
const bg = vga.background;
|
const bg = kernel.vga.background;
|
||||||
const fg = vga.foreground;
|
const fg = kernel.vga.foreground;
|
||||||
const cursor = vga.cursor;
|
const cursor = kernel.vga.cursor;
|
||||||
vga.background = fg;
|
kernel.vga.background = fg;
|
||||||
vga.foreground = bg;
|
kernel.vga.foreground = bg;
|
||||||
vga.cursor = 80 - message.len;
|
kernel.vga.cursor = 80 - message.len;
|
||||||
vga.cursor_enabled = false;
|
kernel.vga.cursor_enabled = false;
|
||||||
|
|
||||||
print(message, args);
|
kernel.vga.print(message, args);
|
||||||
|
|
||||||
vga.cursor_enabled = true;
|
kernel.vga.cursor_enabled = true;
|
||||||
vga.cursor = cursor;
|
kernel.vga.cursor = cursor;
|
||||||
vga.background = bg;
|
kernel.vga.background = bg;
|
||||||
vga.foreground = fg;
|
kernel.vga.foreground = fg;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_short() void {
|
pub fn format_short() void {
|
||||||
print("{}R {}B {}S", .{ ready_tasks.len, blocked_tasks.len, sleeping_tasks.len });
|
kernel.vga.print("{}R {}B {}S", .{ ready_tasks.len, blocked_tasks.len, sleeping_tasks.len });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format() void {
|
pub fn format() void {
|
||||||
update_time_used();
|
update_time_used();
|
||||||
|
|
||||||
println("{}", .{current_task.data});
|
kernel.vga.println("{}", .{current_task.data});
|
||||||
|
|
||||||
var it = ready_tasks.first;
|
var it = ready_tasks.first;
|
||||||
while (it) |node| : (it = node.next) println("{}", .{node.data});
|
while (it) |node| : (it = node.next) kernel.vga.println("{}", .{node.data});
|
||||||
it = blocked_tasks.first;
|
it = blocked_tasks.first;
|
||||||
while (it) |node| : (it = node.next) println("{}", .{node.data});
|
while (it) |node| : (it = node.next) kernel.vga.println("{}", .{node.data});
|
||||||
var sit = sleeping_tasks.first;
|
var sit = sleeping_tasks.first;
|
||||||
while (sit) |node| : (sit = node.next) println("{} {}", .{ node.data.data, node.counter });
|
while (sit) |node| : (sit = node.next) kernel.vga.println("{} {}", .{ node.data.data, node.counter });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ pub fn topbar() void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn printCallback(string: []const u8) Errors!void {
|
fn printCallback(string: []const u8) anyerror!void {
|
||||||
vga.writeString(string);
|
vga.writeString(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
74
src/vmem.zig
74
src/vmem.zig
|
|
@ -18,67 +18,39 @@ pub fn available() usize {
|
||||||
return stack_index * x86.PAGE_SIZE;
|
return stack_index * x86.PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dealloc(addr: usize) void {
|
fn free(addr: usize) void {
|
||||||
x86.paging.unmap(addr);
|
x86.paging.unmap(addr);
|
||||||
stack[stack_index] = addr;
|
stack[stack_index] = addr;
|
||||||
stack_index += 1;
|
stack_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Error = error{OutOfMemory};
|
// const Error = error{OutOfMemory};
|
||||||
|
|
||||||
fn realloc(
|
fn alloc(
|
||||||
self: *std.mem.Allocator,
|
ctx: *anyopaque,
|
||||||
old_mem: []u8,
|
len: usize,
|
||||||
old_alignment: u29,
|
ptr_align: u8,
|
||||||
new_byte_count: usize,
|
ret_addr: usize,
|
||||||
new_alignment: u29,
|
) ?[*]u8 {
|
||||||
) ![]u8 {
|
// new allocation
|
||||||
if (old_mem.len == 0) {
|
std.debug.assert(len < x86.PAGE_SIZE); // this allocator only support 1:1 mapping
|
||||||
// new allocation
|
if (available() == 0) return error.OutOfMemory;
|
||||||
std.debug.assert(new_byte_count < x86.PAGE_SIZE); // this allocator only support 1:1 mapping
|
stack_index -= 1;
|
||||||
if (available() == 0) return error.OutOfMemory;
|
var vaddr: usize = stack[stack_index];
|
||||||
stack_index -= 1;
|
try x86.paging.mmap(vaddr, null);
|
||||||
var vaddr: usize = stack[stack_index];
|
return @intToPtr([*]u8, vaddr)[0..len];
|
||||||
try x86.paging.mmap(vaddr, null);
|
|
||||||
return @intToPtr([*]u8, vaddr)[0..new_byte_count];
|
|
||||||
}
|
|
||||||
// free
|
|
||||||
if (new_byte_count == 0) {
|
|
||||||
dealloc(@ptrToInt(&old_mem[0]));
|
|
||||||
return &[_]u8{};
|
|
||||||
}
|
|
||||||
kernel.vga.println("vmem: unsupported allocator operation", .{});
|
|
||||||
x86.hang();
|
|
||||||
// return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shrink(
|
|
||||||
self: *std.mem.Allocator,
|
|
||||||
old_mem: []u8,
|
|
||||||
old_alignment: u29,
|
|
||||||
new_byte_count: usize,
|
|
||||||
new_alignment: u29,
|
|
||||||
) []u8 {
|
|
||||||
// free
|
|
||||||
if (new_byte_count == 0) {
|
|
||||||
dealloc(@ptrToInt(&old_mem[0]));
|
|
||||||
return &[_]u8{};
|
|
||||||
}
|
|
||||||
|
|
||||||
kernel.vga.println("vmem doesn't support shrinking, {}, {}, {}, {}", .{
|
|
||||||
old_mem,
|
|
||||||
old_alignment,
|
|
||||||
new_byte_count,
|
|
||||||
new_alignment,
|
|
||||||
});
|
|
||||||
x86.hang();
|
|
||||||
// return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
allocator = std.mem.Allocator{
|
allocator = std.mem.Allocator{
|
||||||
.reallocFn = realloc,
|
.ptr = undefined,
|
||||||
.shrinkFn = shrink,
|
.vtable = std.mem.Allocator.VTable{
|
||||||
|
.alloc = alloc,
|
||||||
|
.resize = undefined,
|
||||||
|
.free = free,
|
||||||
|
}
|
||||||
|
// .reallocFn = realloc,
|
||||||
|
// .shrinkFn = shrink,
|
||||||
};
|
};
|
||||||
var addr: usize = kernel.layout.HEAP;
|
var addr: usize = kernel.layout.HEAP;
|
||||||
while (addr < kernel.layout.HEAP_END) : (addr += x86.PAGE_SIZE) {
|
while (addr < kernel.layout.HEAP_END) : (addr += x86.PAGE_SIZE) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue