Simplify task switches

No longer using the rsp from the entry to the kernel, but instead
switching rsp at task-switching time in assembly.

This currently breaks fork()
This commit is contained in:
Justin C. Miller
2019-03-31 22:49:24 -07:00
parent 5cdbedd4d1
commit ca2362f858
21 changed files with 311 additions and 178 deletions

View File

@@ -2,6 +2,8 @@
#include <stdint.h>
struct process;
struct cpu_state
{
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
@@ -10,10 +12,13 @@ struct cpu_state
uint64_t rip, cs, rflags, user_rsp, ss;
};
/// Per-cpu state data. If you change this, remember to update the assembly
/// version in 'tasking.inc'
struct cpu_data
{
uintptr_t rsp0;
uintptr_t rsp3;
process *tcb;
};
extern cpu_data bsp_cpu_data;

View File

@@ -12,6 +12,9 @@ print_regs(const cpu_state &regs)
{
console *cons = console::get();
uint64_t cr2 = 0;
__asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2));
print_regL("rax", regs.rax);
print_regM("rbx", regs.rbx);
print_regR("rcx", regs.rcx);
@@ -36,7 +39,9 @@ print_regs(const cpu_state &regs)
print_regL("rip", regs.rip);
print_regM("cr3", page_manager::get()->get_pml4());
cons->puts("\n\n");
print_regR("cr2", cr2);
cons->puts("\n");
}
struct frame

View File

@@ -9,6 +9,7 @@ extern "C" {
uintptr_t get_rip();
uintptr_t get_frame(int frame);
uintptr_t get_gsbase();
void _halt();
}
extern size_t __counter_syscall_enter;

View File

@@ -18,9 +18,9 @@ static const uint16_t PIC2 = 0xa0;
extern "C" {
void _halt();
uintptr_t isr_handler(uintptr_t, cpu_state*);
uintptr_t irq_handler(uintptr_t, cpu_state*);
uintptr_t syscall_handler(uintptr_t, cpu_state);
void isr_handler(cpu_state*);
void irq_handler(cpu_state*);
void syscall_handler(cpu_state*);
#define ISR(i, name) extern void name ();
#define EISR(i, name) extern void name ();
@@ -104,8 +104,8 @@ interrupts_init()
log::info(logs::boot, "Interrupts enabled.");
}
uintptr_t
isr_handler(uintptr_t return_rsp, cpu_state *regs)
void
isr_handler(cpu_state *regs)
{
console *cons = console::get();
@@ -193,21 +193,14 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs)
if (regs->errorcode & 0x08) cons->puts(" reserved");
if (regs->errorcode & 0x10) cons->puts(" ip");
cons->puts("\n");
uint64_t cr2 = 0;
__asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2));
print_regL("cr2", cr2);
print_regM("rsp", regs->user_rsp);
print_regR("rip", regs->rip);
//print_stacktrace(2);
print_regs(*regs);
print_stacktrace(2);
}
_halt();
break;
case isr::isrTimer: {
scheduler &s = scheduler::get();
return_rsp = s.tick(return_rsp);
}
case isr::isrTimer:
scheduler::get().tick();
break;
case isr::isrLINT0:
@@ -226,14 +219,13 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs)
_halt();
break;
case isr::isrSyscall: {
return_rsp = syscall_dispatch(return_rsp, *regs);
}
case isr::isrSyscall:
syscall_dispatch(regs);
break;
case isr::isrSpurious:
// No EOI for the spurious interrupt
return return_rsp;
return;
case isr::isrIgnore0:
case isr::isrIgnore1:
@@ -274,12 +266,10 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs)
_halt();
}
*reinterpret_cast<uint32_t *>(0xffffff80fee000b0) = 0;
return return_rsp;
}
uintptr_t
irq_handler(uintptr_t return_rsp, cpu_state *regs)
void
irq_handler(cpu_state *regs)
{
console *cons = console::get();
uint8_t irq = get_irq(regs->interrupt);
@@ -293,11 +283,10 @@ irq_handler(uintptr_t return_rsp, cpu_state *regs)
}
*reinterpret_cast<uint32_t *>(0xffffff80fee000b0) = 0;
return return_rsp;
}
uintptr_t
syscall_handler(uintptr_t return_rsp, cpu_state regs)
void
syscall_handler(cpu_state *regs)
{
return syscall_dispatch(return_rsp, regs);
syscall_dispatch(regs);
}

View File

@@ -9,7 +9,6 @@ isr_handler_prelude:
mov rdi, rsp
mov rsi, rsp
call isr_handler
mov rsp, rax
jmp isr_handler_return
extern irq_handler
@@ -21,7 +20,6 @@ irq_handler_prelude:
mov rdi, rsp
mov rsi, rsp
call irq_handler
mov rsp, rax
; fall through to isr_handler_return
global isr_handler_return

View File

@@ -7,12 +7,11 @@ ramdisk_process_loader:
; create_process already pushed a cpu_state onto the stack for us, this
; acts both as the cpu_state parameter to load_process, and the saved
; state for the following iretq
;
; Additional parameters:
; rdi - the address of the program image
; rsi - the size of the program image
; rdx - the address of this process' process structure
; rcx - the stack pointer, which points at the cpu_state
pop rdi ; the address of the program image
pop rsi ; the size of the program image
pop rdx ; the address of this process' process structure
pop rcx ; the cpu_state
call load_process
swapgs

View File

@@ -2,6 +2,7 @@
#include "kutil/memory.h"
#include "console.h"
#include "log.h"
#include "scheduler.h"
namespace logs {
@@ -21,7 +22,7 @@ output_log(log::area_t area, log::level severity, const char *message)
{
auto *cons = console::get();
cons->set_color(level_colors[static_cast<int>(severity)]);
cons->printf("%9s %8s: %s\n",
cons->printf("%7s %5s: %s\n",
g_logger.area_name(area),
g_logger.level_name(severity),
message);
@@ -35,21 +36,23 @@ logger_task()
auto *ent = reinterpret_cast<log::logger::entry *>(buffer);
auto *cons = console::get();
g_logger.set_immediate(nullptr);
//g_logger.set_immediate(nullptr);
log::info(logs::task, "Starting kernel logger task");
scheduler &s = scheduler::get();
while (true) {
__asm__ ("cli");
if(g_logger.get_entry(buffer, sizeof(buffer))) {
buffer[ent->bytes] = 0;
cons->set_color(level_colors[static_cast<int>(ent->severity)]);
cons->printf("%9s %8s: %s\n",
cons->printf("%7s %5s: %s\n",
g_logger.area_name(ent->area),
g_logger.level_name(ent->severity),
ent->message);
cons->set_color();
} else {
s.schedule();
}
__asm__ ("sti");
}
}

View File

@@ -1,8 +1,8 @@
LOG(apic, info);
LOG(device, debug);
LOG(paging, info);
LOG(driver, debug);
LOG(device, info);
LOG(paging, debug);
LOG(driver, info);
LOG(memory, debug);
LOG(fs, debug);
LOG(fs, info);
LOG(task, debug);
LOG(boot, debug);

View File

@@ -150,7 +150,7 @@ page_manager::delete_process_map(page_table *pml4)
void
page_manager::map_offset_pointer(void **pointer, size_t length)
{
log::info(logs::paging, "Mapping offset pointer region at %016lx size 0x%lx", *pointer, length);
log::debug(logs::paging, "Mapping offset pointer region at %016lx size 0x%lx", *pointer, length);
*pointer = kutil::offset_pointer(*pointer, page_offset);
}
@@ -185,6 +185,7 @@ page_manager::get_table_page()
free_page_header *page = m_page_cache;
m_page_cache = page->next;
return reinterpret_cast<page_table *>(page);
}
@@ -294,8 +295,10 @@ page_manager::check_needs_page(page_table *table, unsigned index, bool user)
void
page_manager::page_in(page_table *pml4, uintptr_t phys_addr, uintptr_t virt_addr, size_t count, bool user, bool large)
{
/*
log::debug(logs::paging, "page_in for table %016lx p:%016lx v:%016lx c:%4d u:%d l:%d",
pml4, phys_addr, virt_addr, count, user, large);
*/
page_table_indices idx{virt_addr};
page_table *tables[4] = {pml4, nullptr, nullptr, nullptr};

View File

@@ -1,4 +1,5 @@
#include "cpu.h"
#include "debug.h"
#include "log.h"
#include "process.h"
#include "scheduler.h"
@@ -12,7 +13,7 @@ process::exit(uint32_t code)
}
pid_t
process::fork(uintptr_t in_rsp)
process::fork(cpu_state *regs)
{
auto &sched = scheduler::get();
auto *child = sched.create_process();
@@ -25,40 +26,49 @@ process::fork(uintptr_t in_rsp)
sched.m_runlists[child->priority].push_back(child);
child->rsp = in_rsp;
child->pml4 = page_manager::get()->copy_table(pml4);
kassert(child->pml4, "process::fork() got null pml4");
child->setup_kernel_stack(kernel_stack_size, kernel_stack);
child->rsp = child->kernel_stack + (in_rsp - kernel_stack);
log::debug(logs::task, "Copied process %d to %d, new PML4 %016lx.",
pid, child->pid, child->pml4);
log::debug(logs::task, " copied stack %016lx to %016lx, rsp %016lx to %016lx.",
kernel_stack, child->kernel_stack, in_rsp, child->rsp);
log::debug(logs::task, " copied stack %016lx to %016lx, rsp %016lx.",
kernel_stack, child->kernel_stack, child->rsp);
// Add in the faked fork return value
cpu_state *regs = reinterpret_cast<cpu_state *>(child->rsp);
regs->rax = 0;
child->setup_kernel_stack();
task_fork(child); // Both parent and child will return from this
if (bsp_cpu_data.tcb->pid == child->pid) {
return 0;
}
return child->pid;
}
void *
process::setup_kernel_stack(size_t size, uintptr_t orig)
process::setup_kernel_stack()
{
void *stack0 = kutil::malloc(size);
constexpr unsigned null_frame_entries = 2;
constexpr size_t null_frame_size = null_frame_entries * sizeof(uint64_t);
if (orig)
kutil::memcpy(stack0, reinterpret_cast<void*>(orig), size);
else
kutil::memset(stack0, 0, size);
void *stack_bottom = kutil::malloc(initial_stack_size);
kutil::memset(stack_bottom, 0, initial_stack_size);
kernel_stack_size = size;
kernel_stack = reinterpret_cast<uintptr_t>(stack0);
log::debug(logs::memory, "Created kernel stack at %016lx size 0x%lx",
stack_bottom, initial_stack_size);
return stack0;
void *stack_top =
kutil::offset_pointer(stack_bottom,
initial_stack_size - null_frame_size);
uint64_t *null_frame = reinterpret_cast<uint64_t*>(stack_top);
for (unsigned i = 0; i < null_frame_entries; ++i)
null_frame[i] = 0;
kernel_stack_size = initial_stack_size;
kernel_stack = reinterpret_cast<uintptr_t>(stack_bottom);
rsp0 = reinterpret_cast<uintptr_t>(stack_top);
return stack_top;
}
bool

View File

@@ -8,6 +8,7 @@
#include "page_manager.h"
typedef int32_t pid_t;
struct cpu_state;
enum class process_flags : uint32_t
@@ -32,9 +33,19 @@ enum class process_wait : uint8_t
receive
};
/// A process
/// A process.
///
struct process
{
static const size_t initial_stack_size = 0x1000;
// Fields used by assembly routines go first. If you change any of these,
// be sure to change the assembly definitions in 'tasking.inc'
uintptr_t rsp;
uintptr_t rsp0;
page_table *pml4;
// End of assembly fields
pid_t pid;
pid_t ppid;
@@ -51,9 +62,6 @@ struct process
uint32_t reserved1;
uintptr_t rsp;
page_table *pml4;
uintptr_t kernel_stack;
size_t kernel_stack_size;
@@ -62,10 +70,10 @@ struct process
void exit(unsigned code);
/// Copy this process.
/// \arg in_rsp The RSP of the calling process
/// \arg regs The saved state from the fork syscall
/// \returns Returns the child's pid to the parent, and
/// 0 to the child.
pid_t fork(uint64_t in_rsp);
pid_t fork(cpu_state *regs);
/// Unready this process until it gets a signal
/// \arg sigmask A bitfield of signals to wake on
@@ -122,13 +130,10 @@ struct process
private:
friend class scheduler;
/// Set up a new kernel stack for this process, optionally copying the
/// given stack. Sets the kernel stack on the process object, but also
/// returns it.
/// \arg size Size of the stack to allocate
/// \arg orig Address of a stack to copy, or 0 for no copying.
/// \returns The address of the new stack as a pointer
void * setup_kernel_stack(size_t size, uintptr_t orig);
/// Set up a new empty kernel stack for this process. Sets rsp0 on this
/// process object, but also returns it.
/// \returns The new rsp0 as a pointer
void * setup_kernel_stack();
};
using process_list = kutil::linked_list<process>;

View File

@@ -18,7 +18,6 @@ using memory::initial_stack;
scheduler scheduler::s_instance(nullptr);
const int stack_size = 0x1000;
const uint64_t rflags_noint = 0x002;
const uint64_t rflags_int = 0x202;
@@ -32,6 +31,7 @@ scheduler::scheduler(lapic *apic) :
m_next_pid(1)
{
auto *idle = m_process_allocator.pop();
idle->setup_kernel_stack();
uint8_t last_pri = num_priorities - 1;
@@ -49,6 +49,9 @@ scheduler::scheduler(lapic *apic) :
m_runlists[last_pri].push_back(idle);
m_current = idle;
bsp_cpu_data.rsp0 = idle->rsp0;
bsp_cpu_data.tcb = idle;
}
void
@@ -120,6 +123,24 @@ scheduler::create_process(pid_t pid)
return proc;
}
static uintptr_t
add_fake_stack_return(uintptr_t rsp, uintptr_t rbp, uintptr_t rip)
{
// Initialize a new empty stack with a fake return segment
// for returning out of task_switch
rsp -= sizeof(uintptr_t) * 7;
uintptr_t *stack = reinterpret_cast<uintptr_t*>(rsp);
stack[0] = rbp; // rbp
stack[1] = 0xbbbbbbbb; // rbx
stack[2] = 0x12121212; // r12
stack[3] = 0x13131313; // r13
stack[4] = 0x14141414; // r14
stack[5] = 0x15151515; // r15
stack[6] = rip; // return rip
return rsp;
}
void
scheduler::load_process(const char *name, const void *data, size_t size)
{
@@ -132,15 +153,10 @@ scheduler::load_process(const char *name, const void *data, size_t size)
uint16_t ss = (4 << 3) | 3; // User SS is GDT entry 4, ring 3
// Set up the page tables - this also allocates an initial user stack
page_table *pml4 = page_manager::get()->create_process_map();
// Create a one-page kernel stack space
void *stack0 = proc->setup_kernel_stack(stack_size, 0);
// Stack grows down, point to the end, resere space for initial null frame
static const size_t null_frame = sizeof(uint64_t);
void *sp0 = kutil::offset_pointer(stack0, stack_size - null_frame);
proc->pml4 = page_manager::get()->create_process_map();
// Create an initial kernel stack space
void *sp0 = proc->setup_kernel_stack();
cpu_state *state = reinterpret_cast<cpu_state *>(sp0) - 1;
// Highest state in the stack is the process' kernel stack for the loader
@@ -151,24 +167,18 @@ scheduler::load_process(const char *name, const void *data, size_t size)
state->rip = 0; // to be filled by the loader
state->user_rsp = initial_stack;
// Next state in the stack is the loader's kernel stack. The scheduler will
// iret to this which will kick off the loading:
cpu_state *loader_state = reinterpret_cast<cpu_state *>(sp0) - 2;
// Pass args to ramdisk_process_loader on the stack
uintptr_t *stack = reinterpret_cast<uintptr_t *>(state) - 4;
stack[0] = reinterpret_cast<uintptr_t>(data);
stack[1] = reinterpret_cast<uintptr_t>(size);
stack[2] = reinterpret_cast<uintptr_t>(proc);
stack[3] = reinterpret_cast<uintptr_t>(state);
loader_state->ss = kss;
loader_state->cs = kcs;
loader_state->rflags = rflags_noint;
loader_state->rip = reinterpret_cast<uint64_t>(ramdisk_process_loader);
loader_state->user_rsp = reinterpret_cast<uint64_t>(state);
proc->rsp = add_fake_stack_return(
reinterpret_cast<uintptr_t>(stack),
proc->rsp0,
reinterpret_cast<uintptr_t>(ramdisk_process_loader));
// Set up the registers to have the arguments to the load_process call
loader_state->rdi = reinterpret_cast<uint64_t>(data); // arg 1
loader_state->rsi = size; // arg 2
loader_state->rdx = reinterpret_cast<uint64_t>(proc); // arg 3
loader_state->rcx = loader_state->user_rsp; // arg 4
proc->rsp = reinterpret_cast<uintptr_t>(loader_state);
proc->pml4 = pml4;
proc->quanta = process_quanta;
proc->flags =
process_flags::running |
@@ -177,10 +187,9 @@ scheduler::load_process(const char *name, const void *data, size_t size)
m_runlists[default_priority].push_back(proc);
log::debug(logs::task, "Creating process %s: pid %d pri %d", name, proc->pid, proc->priority);
log::debug(logs::task, " RSP0 %016lx", state);
log::debug(logs::task, " PML4 %016lx", pml4);
log::debug(logs::task, " PML4 %016lx", proc->pml4);
}
void
@@ -191,24 +200,12 @@ scheduler::create_kernel_task(pid_t pid, void (*task)())
uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0
uint16_t kss = (2 << 3) | 0; // Kernel SS is GDT entry 2, ring 0
// Create a one-page kernel stack space
void *stack0 = proc->setup_kernel_stack(stack_size, 0);
// Create an initial kernel stack space
proc->setup_kernel_stack();
proc->rsp = add_fake_stack_return(
proc->rsp0, proc->rsp0,
reinterpret_cast<uintptr_t>(task));
// Stack grows down, point to the end, resere space for initial null frame
static const size_t null_frame = sizeof(uint64_t);
void *sp0 = kutil::offset_pointer(stack0, stack_size - null_frame);
cpu_state *state = reinterpret_cast<cpu_state *>(sp0) - 1;
// Highest state in the stack is the process' kernel stack for the loader
// to iret to:
state->ss = kss;
state->cs = kcs;
state->rflags = rflags_int;
state->rip = reinterpret_cast<uint64_t>(task);
state->user_rsp = reinterpret_cast<uint64_t>(state);
proc->rsp = reinterpret_cast<uintptr_t>(state);
proc->pml4 = page_manager::get()->get_kernel_pml4();
proc->quanta = process_quanta;
proc->flags =
@@ -218,7 +215,8 @@ scheduler::create_kernel_task(pid_t pid, void (*task)())
m_runlists[default_priority].push_back(proc);
log::debug(logs::task, "Creating kernel task: pid %d pri %d", proc->pid, proc->priority);
log::debug(logs::task, " RSP0 %016lx", state);
log::debug(logs::task, " RSP0 %016lx", proc->rsp0);
log::debug(logs::task, " RSP %016lx", proc->rsp);
}
void
@@ -278,17 +276,15 @@ void scheduler::prune(uint64_t now)
}
}
uintptr_t
scheduler::schedule(uintptr_t rsp0)
void
scheduler::schedule()
{
// TODO: lol a real clock
static uint64_t now = 0;
pid_t lastpid = m_current->pid;
m_current->rsp = rsp0;
m_runlists[m_current->priority].remove(m_current);
if (m_current->flags && process_flags::ready) {
m_runlists[m_current->priority].push_back(m_current);
} else {
@@ -304,34 +300,25 @@ scheduler::schedule(uintptr_t rsp0)
}
m_current = m_runlists[pri].pop_front();
rsp0 = m_current->rsp;
// Set rsp0 to after the end of the about-to-be-popped cpu state
tss_set_stack(0, rsp0 + sizeof(cpu_state));
bsp_cpu_data.rsp0 = rsp0;
// Swap page tables
page_table *pml4 = m_current->pml4;
page_manager::set_pml4(pml4);
if (lastpid != m_current->pid) {
bool loading = m_current->flags && process_flags::loading;
log::debug(logs::task, "Scheduler switched to process %d, priority %d%s.",
m_current->pid, m_current->priority, loading ? " (loading)" : "");
}
return rsp0;
bool loading = m_current->flags && process_flags::loading;
log::debug(logs::task, "Scheduler switching to process %d, priority %d%s.",
m_current->pid, m_current->priority, loading ? " (loading)" : "");
task_switch(m_current);
}
}
uintptr_t
scheduler::tick(uintptr_t rsp0)
void
scheduler::tick()
{
if (--m_current->quanta == 0) {
m_current->quanta = process_quanta;
rsp0 = schedule(rsp0);
schedule();
}
m_apic->reset_timer(m_tick_count);
return rsp0;
}
process_node *

View File

@@ -10,7 +10,9 @@ class lapic;
struct page_table;
struct cpu_state;
extern "C" uintptr_t isr_handler(uintptr_t, cpu_state*);
extern "C" void isr_handler(cpu_state*);
extern "C" void task_switch(process *next);
extern "C" void task_fork(process *child);
/// The task scheduler
@@ -46,9 +48,7 @@ public:
void start();
/// Run the scheduler, possibly switching to a new task
/// \arg rsp0 The stack pointer of the current interrupt handler
/// \returns The stack pointer to switch to
uintptr_t schedule(uintptr_t rsp0);
void schedule();
/// Get the current process.
/// \returns A pointer to the current process' process struct
@@ -65,7 +65,7 @@ public:
private:
friend uintptr_t syscall_dispatch(uintptr_t, cpu_state &);
friend uintptr_t isr_handler(uintptr_t, cpu_state*);
friend void isr_handler(cpu_state*);
friend class process;
/// Create a new process object. This process will have its pid
@@ -75,9 +75,7 @@ private:
process_node * create_process(pid_t pid = 0);
/// Handle a timer tick
/// \arg rsp0 The stack pointer of the current interrupt handler
/// \returns The stack pointer to switch to
uintptr_t tick(uintptr_t rsp0);
void tick();
void prune(uint64_t now);

View File

@@ -34,11 +34,11 @@ syscall_enable()
wrmsr(msr::ia32_fmask, 0x200);
}
uintptr_t
syscall_dispatch(uintptr_t return_rsp, cpu_state &regs)
void
syscall_dispatch(cpu_state *regs)
{
console *cons = console::get();
syscall call = static_cast<syscall>(regs.rax);
syscall call = static_cast<syscall>(regs->rax);
auto &s = scheduler::get();
auto *p = s.current();
@@ -51,7 +51,7 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state &regs)
cons->set_color(11);
cons->printf("\nProcess %d: Received DEBUG syscall\n", p->pid);
cons->set_color();
print_regs(regs);
print_regs(*regs);
cons->printf("\n Syscall enters: %8d\n", __counter_syscall_enter);
cons->printf(" Syscall sysret: %8d\n", __counter_syscall_sysret);
break;
@@ -71,7 +71,7 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state &regs)
p->wait_on_signal(-1ull);
cons->printf("\nProcess %d: Received PAUSE syscall\n", p->pid);
cons->set_color();
return_rsp = s.schedule(return_rsp);
s.schedule();
}
break;
@@ -79,11 +79,11 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state &regs)
{
cons->set_color(11);
cons->printf("\nProcess %d: Received SLEEP syscall\n", p->pid);
cons->printf("Sleeping until %lu\n", regs.rdi);
cons->printf("Sleeping until %lu\n", regs->rdi);
cons->set_color();
p->wait_on_time(regs.rdi);
return_rsp = s.schedule(return_rsp);
p->wait_on_time(regs->rdi);
s.schedule();
}
break;
@@ -91,34 +91,34 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state &regs)
cons->set_color(11);
cons->printf("\nProcess %d: Received GETPID syscall\n", p->pid);
cons->set_color();
regs.rax = p->pid;
regs->rax = p->pid;
break;
case syscall::send:
{
pid_t target = regs.rdi;
uintptr_t data = regs.rsi;
pid_t target = regs->rdi;
uintptr_t data = regs->rsi;
cons->set_color(11);
cons->printf("\nProcess %d: Received SEND syscall, target %d, data %016lx\n", p->pid, target, data);
cons->set_color();
if (p->wait_on_send(target))
return_rsp = s.schedule(return_rsp);
s.schedule();
}
break;
case syscall::receive:
{
pid_t source = regs.rdi;
uintptr_t data = regs.rsi;
pid_t source = regs->rdi;
uintptr_t data = regs->rsi;
cons->set_color(11);
cons->printf("\nProcess %d: Received RECEIVE syscall, source %d, dat %016lx\n", p->pid, source, data);
cons->set_color();
if (p->wait_on_receive(source))
return_rsp = s.schedule(return_rsp);
s.schedule();
}
break;
@@ -128,8 +128,9 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state &regs)
cons->printf("\nProcess %d: Received FORK syscall\n", p->pid);
cons->set_color();
pid_t pid = p->fork(return_rsp);
regs.rax = pid;
pid_t pid = p->fork(regs);
cons->printf("\n fork returning %d\n", pid);
regs->rax = pid;
}
break;
@@ -137,8 +138,8 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state &regs)
cons->set_color(11);
cons->printf("\nProcess %d: Received EXIT syscall\n", p->pid);
cons->set_color();
p->exit(regs.rdi);
return_rsp = s.schedule(return_rsp);
p->exit(regs->rdi);
s.schedule();
break;
default:
@@ -148,7 +149,5 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state &regs)
_halt();
break;
}
return return_rsp;
}

View File

@@ -21,5 +21,5 @@ enum class syscall : uint64_t
};
void syscall_enable();
uintptr_t syscall_dispatch(uintptr_t, cpu_state &);
void syscall_dispatch(cpu_state *);

View File

@@ -28,7 +28,6 @@ syscall_handler_prelude:
mov rdi, rsp
call syscall_handler
mov rsp, rax
mov rax, [rsp + 0x90]
and rax, 0x3

85
src/kernel/task.s Normal file
View File

@@ -0,0 +1,85 @@
%include "tasking.inc"
extern g_tss
global task_switch
task_switch:
push rbp
mov rbp, rsp
; Save the rest of the callee-saved regs
push rbx
push r12
push r13
push r14
push r15
; Update previous task's TCB
mov rax, [gs:CPU_DATA.tcb] ; rax: current task TCB
mov [rax + TCB.rsp], rsp
; Install next task's TCB
mov [gs:CPU_DATA.tcb], rdi ; rdi: next TCB (function param)
mov rsp, [rdi + TCB.rsp] ; next task's stack pointer
mov rax, 0x0000007fffffffff
and rax, [rdi + TCB.pml4] ; rax: next task's pml4 (phys portion of address)
; Update syscall/interrupt rsp
mov rcx, [rdi + TCB.rsp0] ; rcx: top of next task's kernel stack
mov [gs:CPU_DATA.rsp0], rcx
lea rdx, [rel g_tss] ; rdx: address of TSS
mov [rdx + TSS.rsp0], rcx
; check if we need to update CR3
mov rdx, cr3 ; rdx: old CR3
cmp rax, rdx
je .no_cr3
mov cr3, rax
.no_cr3:
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret
global task_fork
task_fork:
push rbp
mov rbp, rsp
; Save the rest of the callee-saved regs
push rbx
push r12
push r13
push r14
push r15
mov r14, rdi ; r14: child task TCB (function argument)
mov rax, [gs:CPU_DATA.tcb] ; rax: current task TCB
mov rax, [rax + TCB.rsp0] ; rax: current task rsp0
sub rax, rsp ; rax: size of kernel stack in bytes
mov rcx, rax
shr rcx, 3 ; rcx: size of kernel stack in qwords
mov rdi, [r14 + TCB.rsp0] ; rdi: child task rsp0
sub rdi, rax ; rdi: child task rsp
mov rsi, rsp ; rsi: current rsp
rep movsq
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret

32
src/kernel/tasking.inc Normal file
View File

@@ -0,0 +1,32 @@
struc TCB
.rsp: resq 1
.rsp0: resq 1
.pml4: resq 1
endstruc
struc CPU_DATA
.rsp0: resq 1
.rsp3: resq 1
.tcb: resq 1
endstruc
struc TSS
.res0: resd 1
.rsp0: resq 1
.rsp1: resq 1
.rsp2: resq 1
.ist0: resq 1
.ist1: resq 1
.ist2: resq 1
.ist3: resq 1
.ist4: resq 1
.ist5: resq 1
.ist6: resq 1
.ist7: resq 1
.res1: resq 1
.res2: resw 1
.iomap: resw 1
endstruc
; vim: ft=asm