core: Add basic threading code
This commit is contained in:
parent
fa04363a51
commit
ed324fcf9e
39
core/src/arch/cpu.zig
Normal file
39
core/src/arch/cpu.zig
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const target = @import("builtin").target;
|
||||||
|
const thread = @import("../thread.zig");
|
||||||
|
const pmm = @import("../pmm.zig");
|
||||||
|
const vmm = @import("vmm.zig").arch;
|
||||||
|
|
||||||
|
pub const arch = switch (target.cpu.arch) {
|
||||||
|
.x86_64 => @import("x86_64/cpu.zig"),
|
||||||
|
else => {
|
||||||
|
@compileError("unsupported architecture");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: single-core hack, we need a proper way to figure which core this is when SMP support is added.
|
||||||
|
var this_core: *arch.Core = undefined;
|
||||||
|
|
||||||
|
pub fn setupCore(allocator: *pmm.FrameAllocator) !void {
|
||||||
|
const frame = try pmm.allocFrame(allocator);
|
||||||
|
|
||||||
|
const core: *arch.Core = @ptrFromInt(frame.virtualAddress(vmm.PHYSICAL_MAPPING_BASE));
|
||||||
|
core.id = 0; // FIXME: Actually check core id
|
||||||
|
core.thread_list = .{};
|
||||||
|
|
||||||
|
const idle_thread = &core.idle_thread.data;
|
||||||
|
|
||||||
|
idle_thread.id = 0;
|
||||||
|
idle_thread.directory = null;
|
||||||
|
idle_thread.regs = std.mem.zeroes(@TypeOf(idle_thread.regs));
|
||||||
|
thread.arch.initKernelRegisters(&idle_thread.regs);
|
||||||
|
thread.arch.setAddress(&idle_thread.regs, @intFromPtr(&thread.arch.idleLoop));
|
||||||
|
|
||||||
|
core.thread_list.append(&core.idle_thread);
|
||||||
|
|
||||||
|
this_core = core;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn thisCore() *arch.Core {
|
||||||
|
return this_core;
|
||||||
|
}
|
9
core/src/arch/thread.zig
Normal file
9
core/src/arch/thread.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const target = @import("builtin").target;
|
||||||
|
|
||||||
|
pub const arch = switch (target.cpu.arch) {
|
||||||
|
.x86_64 => @import("x86_64/thread.zig"),
|
||||||
|
else => {
|
||||||
|
@compileError("unsupported architecture");
|
||||||
|
},
|
||||||
|
};
|
3
core/src/arch/x86_64/cpu.zig
Normal file
3
core/src/arch/x86_64/cpu.zig
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const thread = @import("../../thread.zig");
|
||||||
|
|
||||||
|
pub const Core = struct { id: u32, thread_list: thread.ThreadList, current_thread: *thread.ThreadControlBlock, idle_thread: thread.ThreadList.Node };
|
74
core/src/arch/x86_64/thread.zig
Normal file
74
core/src/arch/x86_64/thread.zig
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const interrupts = @import("interrupts.zig");
|
||||||
|
|
||||||
|
pub inline fn enterTask(regs: *interrupts.InterruptStackFrame, comptime base: u64, directory: *anyopaque) noreturn {
|
||||||
|
asm volatile (
|
||||||
|
\\ addq %[base], %rsp
|
||||||
|
\\ push %[ss]
|
||||||
|
\\ push %[rsp]
|
||||||
|
\\ push %[rflags]
|
||||||
|
\\ push %[cs]
|
||||||
|
\\ push %[rip]
|
||||||
|
\\ mov %[directory], %cr3
|
||||||
|
\\ mov $0, %rax
|
||||||
|
\\ mov $0, %rbx
|
||||||
|
\\ mov $0, %rcx
|
||||||
|
\\ mov $0, %rdx
|
||||||
|
\\ mov $0, %rsi
|
||||||
|
\\ mov $0, %rbp
|
||||||
|
\\ mov $0, %r8
|
||||||
|
\\ mov $0, %r9
|
||||||
|
\\ mov $0, %r10
|
||||||
|
\\ mov $0, %r11
|
||||||
|
\\ mov $0, %r12
|
||||||
|
\\ mov $0, %r13
|
||||||
|
\\ mov $0, %r14
|
||||||
|
\\ mov $0, %r15
|
||||||
|
\\ iretq
|
||||||
|
:
|
||||||
|
: [ss] "r" (regs.ss),
|
||||||
|
[rsp] "r" (regs.rsp),
|
||||||
|
[rflags] "r" (regs.rflags),
|
||||||
|
[cs] "r" (regs.cs),
|
||||||
|
[rip] "r" (regs.rip),
|
||||||
|
[arg] "{rdi}" (regs.rdi),
|
||||||
|
[base] "r" (base),
|
||||||
|
[directory] "r" (directory),
|
||||||
|
);
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn idleLoop() callconv(.Naked) noreturn {
|
||||||
|
asm volatile (
|
||||||
|
\\.loop:
|
||||||
|
\\ sti
|
||||||
|
\\ hlt
|
||||||
|
\\ jmp .loop
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setAddress(regs: *interrupts.InterruptStackFrame, address: u64) void {
|
||||||
|
regs.rip = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setArgument(regs: *interrupts.InterruptStackFrame, argument: u64) void {
|
||||||
|
regs.rdi = argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setStack(regs: *interrupts.InterruptStackFrame, stack: u64) void {
|
||||||
|
regs.rsp = stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initKernelRegisters(regs: *interrupts.InterruptStackFrame) void {
|
||||||
|
regs.* = std.mem.zeroes(interrupts.InterruptStackFrame);
|
||||||
|
regs.cs = 0x08;
|
||||||
|
regs.ss = 0x10;
|
||||||
|
regs.rflags = 1 << 9; // IF (Interrupt enable flag)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initUserRegisters(regs: *interrupts.InterruptStackFrame) void {
|
||||||
|
regs.* = std.mem.zeroes(interrupts.InterruptStackFrame);
|
||||||
|
regs.cs = 0x18 | 3;
|
||||||
|
regs.ss = 0x20 | 3;
|
||||||
|
regs.rflags = 1 << 9; // IF (Interrupt enable flag)
|
||||||
|
}
|
89
core/src/thread.zig
Normal file
89
core/src/thread.zig
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const vmm = @import("arch/vmm.zig").arch;
|
||||||
|
const interrupts = @import("arch/interrupts.zig").arch;
|
||||||
|
pub const arch = @import("arch/thread.zig").arch;
|
||||||
|
const pmm = @import("pmm.zig");
|
||||||
|
const cpu = @import("arch/cpu.zig");
|
||||||
|
|
||||||
|
pub const ThreadState = enum {
|
||||||
|
Running,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ThreadControlBlock = struct {
|
||||||
|
id: u64,
|
||||||
|
directory: ?*vmm.PageDirectory,
|
||||||
|
regs: interrupts.InterruptStackFrame,
|
||||||
|
|
||||||
|
ticks: u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ThreadList = std.DoublyLinkedList(ThreadControlBlock);
|
||||||
|
|
||||||
|
var g_threads: ThreadList = .{};
|
||||||
|
|
||||||
|
const ALLOCATED_TICKS_PER_TASK = 20;
|
||||||
|
|
||||||
|
pub fn enterTask(task: *ThreadControlBlock) noreturn {
|
||||||
|
cpu.thisCore().current_thread = task;
|
||||||
|
|
||||||
|
task.ticks = ALLOCATED_TICKS_PER_TASK;
|
||||||
|
|
||||||
|
var directory = vmm.readPageDirectory();
|
||||||
|
|
||||||
|
if (task.directory) |dir| {
|
||||||
|
directory = vmm.getPhysicalPageDirectory(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
arch.enterTask(&task.regs, vmm.PHYSICAL_MAPPING_BASE, @ptrCast(directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switchTask(regs: *interrupts.InterruptStackFrame, new_task: *ThreadControlBlock) void {
|
||||||
|
const core = cpu.thisCore();
|
||||||
|
|
||||||
|
core.current_thread.regs = regs.*;
|
||||||
|
regs.* = new_task.regs;
|
||||||
|
|
||||||
|
if (new_task.directory) |directory| {
|
||||||
|
if (vmm.readPageDirectory() != directory) vmm.setPageDirectory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_task.ticks = ALLOCATED_TICKS_PER_TASK;
|
||||||
|
|
||||||
|
core.current_thread = new_task;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scheduleNewTask(regs: *interrupts.InterruptStackFrame) void {
|
||||||
|
const core = cpu.thisCore();
|
||||||
|
|
||||||
|
const new_task = core.thread_list.popFirst() orelse return;
|
||||||
|
core.thread_list.append(new_task);
|
||||||
|
|
||||||
|
switchTask(regs, &new_task.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn preempt(regs: *interrupts.InterruptStackFrame) void {
|
||||||
|
const core = cpu.thisCore();
|
||||||
|
|
||||||
|
core.current_thread.ticks -= 1;
|
||||||
|
if (core.current_thread.ticks == 0) {
|
||||||
|
scheduleNewTask(regs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var next_id: std.atomic.Value(u64) = std.atomic.Value(u64).init(1);
|
||||||
|
|
||||||
|
pub fn addThreadToScheduler(core: *cpu.arch.Core, thread: *ThreadControlBlock) void {
|
||||||
|
core.thread_list.append(@fieldParentPtr("data", thread));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createThreadControlBlock(allocator: *pmm.FrameAllocator) !*ThreadControlBlock {
|
||||||
|
const frame = try pmm.allocFrame(allocator);
|
||||||
|
|
||||||
|
const node: *ThreadList.Node = @ptrFromInt(frame.virtualAddress(vmm.PHYSICAL_MAPPING_BASE));
|
||||||
|
const thread = &node.data;
|
||||||
|
thread.id = next_id.fetchAdd(1, .seq_cst);
|
||||||
|
thread.directory = null;
|
||||||
|
thread.regs = std.mem.zeroes(@TypeOf(thread.regs));
|
||||||
|
|
||||||
|
return thread;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user