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:
@@ -41,6 +41,7 @@ modules:
|
|||||||
- src/kernel/serial.cpp
|
- src/kernel/serial.cpp
|
||||||
- src/kernel/syscall.cpp
|
- src/kernel/syscall.cpp
|
||||||
- src/kernel/syscall.s
|
- src/kernel/syscall.s
|
||||||
|
- src/kernel/task.s
|
||||||
- src/kernel/crtn.s
|
- src/kernel/crtn.s
|
||||||
|
|
||||||
boot:
|
boot:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
int32_t getpid();
|
int32_t getpid();
|
||||||
|
int32_t fork();
|
||||||
void sleep(uint64_t til);
|
void sleep(uint64_t til);
|
||||||
void debug();
|
void debug();
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ int
|
|||||||
main(int argc, const char **argv)
|
main(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
int32_t pid = getpid();
|
int32_t pid = getpid();
|
||||||
|
//int32_t child = fork();
|
||||||
debug();
|
debug();
|
||||||
for (int i = 1; i < 5; ++i)
|
for (int i = 1; i < 5; ++i)
|
||||||
sleep(i*10);
|
sleep(i*10);
|
||||||
|
|||||||
@@ -39,6 +39,18 @@ sleep:
|
|||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
global fork
|
||||||
|
fork:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
|
||||||
|
mov rax, 8
|
||||||
|
syscall ; pid left in rax
|
||||||
|
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
global _start
|
global _start
|
||||||
_start:
|
_start:
|
||||||
xor rbp, rbp ; Sentinel rbp
|
xor rbp, rbp ; Sentinel rbp
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct process;
|
||||||
|
|
||||||
struct cpu_state
|
struct cpu_state
|
||||||
{
|
{
|
||||||
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
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;
|
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
|
struct cpu_data
|
||||||
{
|
{
|
||||||
uintptr_t rsp0;
|
uintptr_t rsp0;
|
||||||
uintptr_t rsp3;
|
uintptr_t rsp3;
|
||||||
|
process *tcb;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern cpu_data bsp_cpu_data;
|
extern cpu_data bsp_cpu_data;
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ print_regs(const cpu_state ®s)
|
|||||||
{
|
{
|
||||||
console *cons = console::get();
|
console *cons = console::get();
|
||||||
|
|
||||||
|
uint64_t cr2 = 0;
|
||||||
|
__asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2));
|
||||||
|
|
||||||
print_regL("rax", regs.rax);
|
print_regL("rax", regs.rax);
|
||||||
print_regM("rbx", regs.rbx);
|
print_regM("rbx", regs.rbx);
|
||||||
print_regR("rcx", regs.rcx);
|
print_regR("rcx", regs.rcx);
|
||||||
@@ -36,7 +39,9 @@ print_regs(const cpu_state ®s)
|
|||||||
|
|
||||||
print_regL("rip", regs.rip);
|
print_regL("rip", regs.rip);
|
||||||
print_regM("cr3", page_manager::get()->get_pml4());
|
print_regM("cr3", page_manager::get()->get_pml4());
|
||||||
cons->puts("\n\n");
|
print_regR("cr2", cr2);
|
||||||
|
|
||||||
|
cons->puts("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct frame
|
struct frame
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ extern "C" {
|
|||||||
uintptr_t get_rip();
|
uintptr_t get_rip();
|
||||||
uintptr_t get_frame(int frame);
|
uintptr_t get_frame(int frame);
|
||||||
uintptr_t get_gsbase();
|
uintptr_t get_gsbase();
|
||||||
|
void _halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern size_t __counter_syscall_enter;
|
extern size_t __counter_syscall_enter;
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ static const uint16_t PIC2 = 0xa0;
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
void _halt();
|
void _halt();
|
||||||
|
|
||||||
uintptr_t isr_handler(uintptr_t, cpu_state*);
|
void isr_handler(cpu_state*);
|
||||||
uintptr_t irq_handler(uintptr_t, cpu_state*);
|
void irq_handler(cpu_state*);
|
||||||
uintptr_t syscall_handler(uintptr_t, cpu_state);
|
void syscall_handler(cpu_state*);
|
||||||
|
|
||||||
#define ISR(i, name) extern void name ();
|
#define ISR(i, name) extern void name ();
|
||||||
#define EISR(i, name) extern void name ();
|
#define EISR(i, name) extern void name ();
|
||||||
@@ -104,8 +104,8 @@ interrupts_init()
|
|||||||
log::info(logs::boot, "Interrupts enabled.");
|
log::info(logs::boot, "Interrupts enabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t
|
void
|
||||||
isr_handler(uintptr_t return_rsp, cpu_state *regs)
|
isr_handler(cpu_state *regs)
|
||||||
{
|
{
|
||||||
console *cons = console::get();
|
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 & 0x08) cons->puts(" reserved");
|
||||||
if (regs->errorcode & 0x10) cons->puts(" ip");
|
if (regs->errorcode & 0x10) cons->puts(" ip");
|
||||||
cons->puts("\n");
|
cons->puts("\n");
|
||||||
|
print_regs(*regs);
|
||||||
uint64_t cr2 = 0;
|
print_stacktrace(2);
|
||||||
__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);
|
|
||||||
}
|
}
|
||||||
_halt();
|
_halt();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case isr::isrTimer: {
|
case isr::isrTimer:
|
||||||
scheduler &s = scheduler::get();
|
scheduler::get().tick();
|
||||||
return_rsp = s.tick(return_rsp);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case isr::isrLINT0:
|
case isr::isrLINT0:
|
||||||
@@ -226,14 +219,13 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs)
|
|||||||
_halt();
|
_halt();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case isr::isrSyscall: {
|
case isr::isrSyscall:
|
||||||
return_rsp = syscall_dispatch(return_rsp, *regs);
|
syscall_dispatch(regs);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case isr::isrSpurious:
|
case isr::isrSpurious:
|
||||||
// No EOI for the spurious interrupt
|
// No EOI for the spurious interrupt
|
||||||
return return_rsp;
|
return;
|
||||||
|
|
||||||
case isr::isrIgnore0:
|
case isr::isrIgnore0:
|
||||||
case isr::isrIgnore1:
|
case isr::isrIgnore1:
|
||||||
@@ -274,12 +266,10 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs)
|
|||||||
_halt();
|
_halt();
|
||||||
}
|
}
|
||||||
*reinterpret_cast<uint32_t *>(0xffffff80fee000b0) = 0;
|
*reinterpret_cast<uint32_t *>(0xffffff80fee000b0) = 0;
|
||||||
|
|
||||||
return return_rsp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t
|
void
|
||||||
irq_handler(uintptr_t return_rsp, cpu_state *regs)
|
irq_handler(cpu_state *regs)
|
||||||
{
|
{
|
||||||
console *cons = console::get();
|
console *cons = console::get();
|
||||||
uint8_t irq = get_irq(regs->interrupt);
|
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;
|
*reinterpret_cast<uint32_t *>(0xffffff80fee000b0) = 0;
|
||||||
return return_rsp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t
|
void
|
||||||
syscall_handler(uintptr_t return_rsp, cpu_state regs)
|
syscall_handler(cpu_state *regs)
|
||||||
{
|
{
|
||||||
return syscall_dispatch(return_rsp, regs);
|
syscall_dispatch(regs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ isr_handler_prelude:
|
|||||||
mov rdi, rsp
|
mov rdi, rsp
|
||||||
mov rsi, rsp
|
mov rsi, rsp
|
||||||
call isr_handler
|
call isr_handler
|
||||||
mov rsp, rax
|
|
||||||
jmp isr_handler_return
|
jmp isr_handler_return
|
||||||
|
|
||||||
extern irq_handler
|
extern irq_handler
|
||||||
@@ -21,7 +20,6 @@ irq_handler_prelude:
|
|||||||
mov rdi, rsp
|
mov rdi, rsp
|
||||||
mov rsi, rsp
|
mov rsi, rsp
|
||||||
call irq_handler
|
call irq_handler
|
||||||
mov rsp, rax
|
|
||||||
; fall through to isr_handler_return
|
; fall through to isr_handler_return
|
||||||
|
|
||||||
global isr_handler_return
|
global isr_handler_return
|
||||||
|
|||||||
@@ -7,12 +7,11 @@ ramdisk_process_loader:
|
|||||||
; create_process already pushed a cpu_state onto the stack for us, this
|
; 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
|
; acts both as the cpu_state parameter to load_process, and the saved
|
||||||
; state for the following iretq
|
; state for the following iretq
|
||||||
;
|
|
||||||
; Additional parameters:
|
pop rdi ; the address of the program image
|
||||||
; rdi - the address of the program image
|
pop rsi ; the size of the program image
|
||||||
; rsi - the size of the program image
|
pop rdx ; the address of this process' process structure
|
||||||
; rdx - the address of this process' process structure
|
pop rcx ; the cpu_state
|
||||||
; rcx - the stack pointer, which points at the cpu_state
|
|
||||||
call load_process
|
call load_process
|
||||||
|
|
||||||
swapgs
|
swapgs
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "kutil/memory.h"
|
#include "kutil/memory.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
|
||||||
namespace logs {
|
namespace logs {
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ output_log(log::area_t area, log::level severity, const char *message)
|
|||||||
{
|
{
|
||||||
auto *cons = console::get();
|
auto *cons = console::get();
|
||||||
cons->set_color(level_colors[static_cast<int>(severity)]);
|
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.area_name(area),
|
||||||
g_logger.level_name(severity),
|
g_logger.level_name(severity),
|
||||||
message);
|
message);
|
||||||
@@ -35,21 +36,23 @@ logger_task()
|
|||||||
auto *ent = reinterpret_cast<log::logger::entry *>(buffer);
|
auto *ent = reinterpret_cast<log::logger::entry *>(buffer);
|
||||||
auto *cons = console::get();
|
auto *cons = console::get();
|
||||||
|
|
||||||
g_logger.set_immediate(nullptr);
|
//g_logger.set_immediate(nullptr);
|
||||||
log::info(logs::task, "Starting kernel logger task");
|
log::info(logs::task, "Starting kernel logger task");
|
||||||
|
|
||||||
|
scheduler &s = scheduler::get();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
__asm__ ("cli");
|
|
||||||
if(g_logger.get_entry(buffer, sizeof(buffer))) {
|
if(g_logger.get_entry(buffer, sizeof(buffer))) {
|
||||||
buffer[ent->bytes] = 0;
|
buffer[ent->bytes] = 0;
|
||||||
cons->set_color(level_colors[static_cast<int>(ent->severity)]);
|
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.area_name(ent->area),
|
||||||
g_logger.level_name(ent->severity),
|
g_logger.level_name(ent->severity),
|
||||||
ent->message);
|
ent->message);
|
||||||
cons->set_color();
|
cons->set_color();
|
||||||
|
} else {
|
||||||
|
s.schedule();
|
||||||
}
|
}
|
||||||
__asm__ ("sti");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
LOG(apic, info);
|
LOG(apic, info);
|
||||||
LOG(device, debug);
|
LOG(device, info);
|
||||||
LOG(paging, info);
|
LOG(paging, debug);
|
||||||
LOG(driver, debug);
|
LOG(driver, info);
|
||||||
LOG(memory, debug);
|
LOG(memory, debug);
|
||||||
LOG(fs, debug);
|
LOG(fs, info);
|
||||||
LOG(task, debug);
|
LOG(task, debug);
|
||||||
LOG(boot, debug);
|
LOG(boot, debug);
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ page_manager::delete_process_map(page_table *pml4)
|
|||||||
void
|
void
|
||||||
page_manager::map_offset_pointer(void **pointer, size_t length)
|
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);
|
*pointer = kutil::offset_pointer(*pointer, page_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +185,7 @@ page_manager::get_table_page()
|
|||||||
|
|
||||||
free_page_header *page = m_page_cache;
|
free_page_header *page = m_page_cache;
|
||||||
m_page_cache = page->next;
|
m_page_cache = page->next;
|
||||||
|
|
||||||
return reinterpret_cast<page_table *>(page);
|
return reinterpret_cast<page_table *>(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,8 +295,10 @@ page_manager::check_needs_page(page_table *table, unsigned index, bool user)
|
|||||||
void
|
void
|
||||||
page_manager::page_in(page_table *pml4, uintptr_t phys_addr, uintptr_t virt_addr, size_t count, bool user, bool large)
|
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",
|
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);
|
pml4, phys_addr, virt_addr, count, user, large);
|
||||||
|
*/
|
||||||
|
|
||||||
page_table_indices idx{virt_addr};
|
page_table_indices idx{virt_addr};
|
||||||
page_table *tables[4] = {pml4, nullptr, nullptr, nullptr};
|
page_table *tables[4] = {pml4, nullptr, nullptr, nullptr};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
@@ -12,7 +13,7 @@ process::exit(uint32_t code)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pid_t
|
pid_t
|
||||||
process::fork(uintptr_t in_rsp)
|
process::fork(cpu_state *regs)
|
||||||
{
|
{
|
||||||
auto &sched = scheduler::get();
|
auto &sched = scheduler::get();
|
||||||
auto *child = sched.create_process();
|
auto *child = sched.create_process();
|
||||||
@@ -25,40 +26,49 @@ process::fork(uintptr_t in_rsp)
|
|||||||
|
|
||||||
sched.m_runlists[child->priority].push_back(child);
|
sched.m_runlists[child->priority].push_back(child);
|
||||||
|
|
||||||
child->rsp = in_rsp;
|
|
||||||
|
|
||||||
child->pml4 = page_manager::get()->copy_table(pml4);
|
child->pml4 = page_manager::get()->copy_table(pml4);
|
||||||
kassert(child->pml4, "process::fork() got null 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.",
|
log::debug(logs::task, "Copied process %d to %d, new PML4 %016lx.",
|
||||||
pid, child->pid, child->pml4);
|
pid, child->pid, child->pml4);
|
||||||
log::debug(logs::task, " copied stack %016lx to %016lx, rsp %016lx to %016lx.",
|
log::debug(logs::task, " copied stack %016lx to %016lx, rsp %016lx.",
|
||||||
kernel_stack, child->kernel_stack, in_rsp, child->rsp);
|
kernel_stack, child->kernel_stack, child->rsp);
|
||||||
|
|
||||||
// Add in the faked fork return value
|
child->setup_kernel_stack();
|
||||||
cpu_state *regs = reinterpret_cast<cpu_state *>(child->rsp);
|
task_fork(child); // Both parent and child will return from this
|
||||||
regs->rax = 0;
|
|
||||||
|
if (bsp_cpu_data.tcb->pid == child->pid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return child->pid;
|
return child->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
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)
|
void *stack_bottom = kutil::malloc(initial_stack_size);
|
||||||
kutil::memcpy(stack0, reinterpret_cast<void*>(orig), size);
|
kutil::memset(stack_bottom, 0, initial_stack_size);
|
||||||
else
|
|
||||||
kutil::memset(stack0, 0, size);
|
|
||||||
|
|
||||||
kernel_stack_size = size;
|
log::debug(logs::memory, "Created kernel stack at %016lx size 0x%lx",
|
||||||
kernel_stack = reinterpret_cast<uintptr_t>(stack0);
|
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
|
bool
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "page_manager.h"
|
#include "page_manager.h"
|
||||||
|
|
||||||
typedef int32_t pid_t;
|
typedef int32_t pid_t;
|
||||||
|
struct cpu_state;
|
||||||
|
|
||||||
|
|
||||||
enum class process_flags : uint32_t
|
enum class process_flags : uint32_t
|
||||||
@@ -32,9 +33,19 @@ enum class process_wait : uint8_t
|
|||||||
receive
|
receive
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A process
|
/// A process.
|
||||||
|
///
|
||||||
struct 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 pid;
|
||||||
pid_t ppid;
|
pid_t ppid;
|
||||||
|
|
||||||
@@ -51,9 +62,6 @@ struct process
|
|||||||
|
|
||||||
uint32_t reserved1;
|
uint32_t reserved1;
|
||||||
|
|
||||||
uintptr_t rsp;
|
|
||||||
page_table *pml4;
|
|
||||||
|
|
||||||
uintptr_t kernel_stack;
|
uintptr_t kernel_stack;
|
||||||
size_t kernel_stack_size;
|
size_t kernel_stack_size;
|
||||||
|
|
||||||
@@ -62,10 +70,10 @@ struct process
|
|||||||
void exit(unsigned code);
|
void exit(unsigned code);
|
||||||
|
|
||||||
/// Copy this process.
|
/// 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
|
/// \returns Returns the child's pid to the parent, and
|
||||||
/// 0 to the child.
|
/// 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
|
/// Unready this process until it gets a signal
|
||||||
/// \arg sigmask A bitfield of signals to wake on
|
/// \arg sigmask A bitfield of signals to wake on
|
||||||
@@ -122,13 +130,10 @@ struct process
|
|||||||
private:
|
private:
|
||||||
friend class scheduler;
|
friend class scheduler;
|
||||||
|
|
||||||
/// Set up a new kernel stack for this process, optionally copying the
|
/// Set up a new empty kernel stack for this process. Sets rsp0 on this
|
||||||
/// given stack. Sets the kernel stack on the process object, but also
|
/// process object, but also returns it.
|
||||||
/// returns it.
|
/// \returns The new rsp0 as a pointer
|
||||||
/// \arg size Size of the stack to allocate
|
void * setup_kernel_stack();
|
||||||
/// \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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using process_list = kutil::linked_list<process>;
|
using process_list = kutil::linked_list<process>;
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ using memory::initial_stack;
|
|||||||
|
|
||||||
scheduler scheduler::s_instance(nullptr);
|
scheduler scheduler::s_instance(nullptr);
|
||||||
|
|
||||||
const int stack_size = 0x1000;
|
|
||||||
const uint64_t rflags_noint = 0x002;
|
const uint64_t rflags_noint = 0x002;
|
||||||
const uint64_t rflags_int = 0x202;
|
const uint64_t rflags_int = 0x202;
|
||||||
|
|
||||||
@@ -32,6 +31,7 @@ scheduler::scheduler(lapic *apic) :
|
|||||||
m_next_pid(1)
|
m_next_pid(1)
|
||||||
{
|
{
|
||||||
auto *idle = m_process_allocator.pop();
|
auto *idle = m_process_allocator.pop();
|
||||||
|
idle->setup_kernel_stack();
|
||||||
|
|
||||||
uint8_t last_pri = num_priorities - 1;
|
uint8_t last_pri = num_priorities - 1;
|
||||||
|
|
||||||
@@ -49,6 +49,9 @@ scheduler::scheduler(lapic *apic) :
|
|||||||
|
|
||||||
m_runlists[last_pri].push_back(idle);
|
m_runlists[last_pri].push_back(idle);
|
||||||
m_current = idle;
|
m_current = idle;
|
||||||
|
|
||||||
|
bsp_cpu_data.rsp0 = idle->rsp0;
|
||||||
|
bsp_cpu_data.tcb = idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -120,6 +123,24 @@ scheduler::create_process(pid_t pid)
|
|||||||
return proc;
|
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
|
void
|
||||||
scheduler::load_process(const char *name, const void *data, size_t size)
|
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
|
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
|
// Set up the page tables - this also allocates an initial user stack
|
||||||
page_table *pml4 = page_manager::get()->create_process_map();
|
proc->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);
|
|
||||||
|
|
||||||
|
// Create an initial kernel stack space
|
||||||
|
void *sp0 = proc->setup_kernel_stack();
|
||||||
cpu_state *state = reinterpret_cast<cpu_state *>(sp0) - 1;
|
cpu_state *state = reinterpret_cast<cpu_state *>(sp0) - 1;
|
||||||
|
|
||||||
// Highest state in the stack is the process' kernel stack for the loader
|
// 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->rip = 0; // to be filled by the loader
|
||||||
state->user_rsp = initial_stack;
|
state->user_rsp = initial_stack;
|
||||||
|
|
||||||
// Next state in the stack is the loader's kernel stack. The scheduler will
|
// Pass args to ramdisk_process_loader on the stack
|
||||||
// iret to this which will kick off the loading:
|
uintptr_t *stack = reinterpret_cast<uintptr_t *>(state) - 4;
|
||||||
cpu_state *loader_state = reinterpret_cast<cpu_state *>(sp0) - 2;
|
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;
|
proc->rsp = add_fake_stack_return(
|
||||||
loader_state->cs = kcs;
|
reinterpret_cast<uintptr_t>(stack),
|
||||||
loader_state->rflags = rflags_noint;
|
proc->rsp0,
|
||||||
loader_state->rip = reinterpret_cast<uint64_t>(ramdisk_process_loader);
|
reinterpret_cast<uintptr_t>(ramdisk_process_loader));
|
||||||
loader_state->user_rsp = reinterpret_cast<uint64_t>(state);
|
|
||||||
|
|
||||||
// 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->quanta = process_quanta;
|
||||||
proc->flags =
|
proc->flags =
|
||||||
process_flags::running |
|
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);
|
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, "Creating process %s: pid %d pri %d", name, proc->pid, proc->priority);
|
||||||
log::debug(logs::task, " RSP0 %016lx", state);
|
log::debug(logs::task, " RSP0 %016lx", state);
|
||||||
log::debug(logs::task, " PML4 %016lx", pml4);
|
log::debug(logs::task, " PML4 %016lx", proc->pml4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 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
|
uint16_t kss = (2 << 3) | 0; // Kernel SS is GDT entry 2, ring 0
|
||||||
|
|
||||||
// Create a one-page kernel stack space
|
// Create an initial kernel stack space
|
||||||
void *stack0 = proc->setup_kernel_stack(stack_size, 0);
|
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->pml4 = page_manager::get()->get_kernel_pml4();
|
||||||
proc->quanta = process_quanta;
|
proc->quanta = process_quanta;
|
||||||
proc->flags =
|
proc->flags =
|
||||||
@@ -218,7 +215,8 @@ scheduler::create_kernel_task(pid_t pid, void (*task)())
|
|||||||
m_runlists[default_priority].push_back(proc);
|
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, "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
|
void
|
||||||
@@ -278,17 +276,15 @@ void scheduler::prune(uint64_t now)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t
|
void
|
||||||
scheduler::schedule(uintptr_t rsp0)
|
scheduler::schedule()
|
||||||
{
|
{
|
||||||
// TODO: lol a real clock
|
// TODO: lol a real clock
|
||||||
static uint64_t now = 0;
|
static uint64_t now = 0;
|
||||||
|
|
||||||
pid_t lastpid = m_current->pid;
|
pid_t lastpid = m_current->pid;
|
||||||
|
|
||||||
m_current->rsp = rsp0;
|
|
||||||
m_runlists[m_current->priority].remove(m_current);
|
m_runlists[m_current->priority].remove(m_current);
|
||||||
|
|
||||||
if (m_current->flags && process_flags::ready) {
|
if (m_current->flags && process_flags::ready) {
|
||||||
m_runlists[m_current->priority].push_back(m_current);
|
m_runlists[m_current->priority].push_back(m_current);
|
||||||
} else {
|
} else {
|
||||||
@@ -304,34 +300,25 @@ scheduler::schedule(uintptr_t rsp0)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_current = m_runlists[pri].pop_front();
|
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) {
|
if (lastpid != m_current->pid) {
|
||||||
|
|
||||||
bool loading = m_current->flags && process_flags::loading;
|
bool loading = m_current->flags && process_flags::loading;
|
||||||
log::debug(logs::task, "Scheduler switched to process %d, priority %d%s.",
|
log::debug(logs::task, "Scheduler switching to process %d, priority %d%s.",
|
||||||
m_current->pid, m_current->priority, loading ? " (loading)" : "");
|
m_current->pid, m_current->priority, loading ? " (loading)" : "");
|
||||||
|
|
||||||
|
task_switch(m_current);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rsp0;
|
void
|
||||||
}
|
scheduler::tick()
|
||||||
|
|
||||||
uintptr_t
|
|
||||||
scheduler::tick(uintptr_t rsp0)
|
|
||||||
{
|
{
|
||||||
if (--m_current->quanta == 0) {
|
if (--m_current->quanta == 0) {
|
||||||
m_current->quanta = process_quanta;
|
m_current->quanta = process_quanta;
|
||||||
rsp0 = schedule(rsp0);
|
schedule();
|
||||||
}
|
}
|
||||||
m_apic->reset_timer(m_tick_count);
|
m_apic->reset_timer(m_tick_count);
|
||||||
return rsp0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
process_node *
|
process_node *
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ class lapic;
|
|||||||
struct page_table;
|
struct page_table;
|
||||||
struct cpu_state;
|
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
|
/// The task scheduler
|
||||||
@@ -46,9 +48,7 @@ public:
|
|||||||
void start();
|
void start();
|
||||||
|
|
||||||
/// Run the scheduler, possibly switching to a new task
|
/// Run the scheduler, possibly switching to a new task
|
||||||
/// \arg rsp0 The stack pointer of the current interrupt handler
|
void schedule();
|
||||||
/// \returns The stack pointer to switch to
|
|
||||||
uintptr_t schedule(uintptr_t rsp0);
|
|
||||||
|
|
||||||
/// Get the current process.
|
/// Get the current process.
|
||||||
/// \returns A pointer to the current process' process struct
|
/// \returns A pointer to the current process' process struct
|
||||||
@@ -65,7 +65,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend uintptr_t syscall_dispatch(uintptr_t, cpu_state &);
|
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;
|
friend class process;
|
||||||
|
|
||||||
/// Create a new process object. This process will have its pid
|
/// Create a new process object. This process will have its pid
|
||||||
@@ -75,9 +75,7 @@ private:
|
|||||||
process_node * create_process(pid_t pid = 0);
|
process_node * create_process(pid_t pid = 0);
|
||||||
|
|
||||||
/// Handle a timer tick
|
/// Handle a timer tick
|
||||||
/// \arg rsp0 The stack pointer of the current interrupt handler
|
void tick();
|
||||||
/// \returns The stack pointer to switch to
|
|
||||||
uintptr_t tick(uintptr_t rsp0);
|
|
||||||
|
|
||||||
void prune(uint64_t now);
|
void prune(uint64_t now);
|
||||||
|
|
||||||
|
|||||||
@@ -34,11 +34,11 @@ syscall_enable()
|
|||||||
wrmsr(msr::ia32_fmask, 0x200);
|
wrmsr(msr::ia32_fmask, 0x200);
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t
|
void
|
||||||
syscall_dispatch(uintptr_t return_rsp, cpu_state ®s)
|
syscall_dispatch(cpu_state *regs)
|
||||||
{
|
{
|
||||||
console *cons = console::get();
|
console *cons = console::get();
|
||||||
syscall call = static_cast<syscall>(regs.rax);
|
syscall call = static_cast<syscall>(regs->rax);
|
||||||
|
|
||||||
auto &s = scheduler::get();
|
auto &s = scheduler::get();
|
||||||
auto *p = s.current();
|
auto *p = s.current();
|
||||||
@@ -51,7 +51,7 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state ®s)
|
|||||||
cons->set_color(11);
|
cons->set_color(11);
|
||||||
cons->printf("\nProcess %d: Received DEBUG syscall\n", p->pid);
|
cons->printf("\nProcess %d: Received DEBUG syscall\n", p->pid);
|
||||||
cons->set_color();
|
cons->set_color();
|
||||||
print_regs(regs);
|
print_regs(*regs);
|
||||||
cons->printf("\n Syscall enters: %8d\n", __counter_syscall_enter);
|
cons->printf("\n Syscall enters: %8d\n", __counter_syscall_enter);
|
||||||
cons->printf(" Syscall sysret: %8d\n", __counter_syscall_sysret);
|
cons->printf(" Syscall sysret: %8d\n", __counter_syscall_sysret);
|
||||||
break;
|
break;
|
||||||
@@ -71,7 +71,7 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state ®s)
|
|||||||
p->wait_on_signal(-1ull);
|
p->wait_on_signal(-1ull);
|
||||||
cons->printf("\nProcess %d: Received PAUSE syscall\n", p->pid);
|
cons->printf("\nProcess %d: Received PAUSE syscall\n", p->pid);
|
||||||
cons->set_color();
|
cons->set_color();
|
||||||
return_rsp = s.schedule(return_rsp);
|
s.schedule();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -79,11 +79,11 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state ®s)
|
|||||||
{
|
{
|
||||||
cons->set_color(11);
|
cons->set_color(11);
|
||||||
cons->printf("\nProcess %d: Received SLEEP syscall\n", p->pid);
|
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();
|
cons->set_color();
|
||||||
|
|
||||||
p->wait_on_time(regs.rdi);
|
p->wait_on_time(regs->rdi);
|
||||||
return_rsp = s.schedule(return_rsp);
|
s.schedule();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -91,34 +91,34 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state ®s)
|
|||||||
cons->set_color(11);
|
cons->set_color(11);
|
||||||
cons->printf("\nProcess %d: Received GETPID syscall\n", p->pid);
|
cons->printf("\nProcess %d: Received GETPID syscall\n", p->pid);
|
||||||
cons->set_color();
|
cons->set_color();
|
||||||
regs.rax = p->pid;
|
regs->rax = p->pid;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case syscall::send:
|
case syscall::send:
|
||||||
{
|
{
|
||||||
pid_t target = regs.rdi;
|
pid_t target = regs->rdi;
|
||||||
uintptr_t data = regs.rsi;
|
uintptr_t data = regs->rsi;
|
||||||
|
|
||||||
cons->set_color(11);
|
cons->set_color(11);
|
||||||
cons->printf("\nProcess %d: Received SEND syscall, target %d, data %016lx\n", p->pid, target, data);
|
cons->printf("\nProcess %d: Received SEND syscall, target %d, data %016lx\n", p->pid, target, data);
|
||||||
cons->set_color();
|
cons->set_color();
|
||||||
|
|
||||||
if (p->wait_on_send(target))
|
if (p->wait_on_send(target))
|
||||||
return_rsp = s.schedule(return_rsp);
|
s.schedule();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case syscall::receive:
|
case syscall::receive:
|
||||||
{
|
{
|
||||||
pid_t source = regs.rdi;
|
pid_t source = regs->rdi;
|
||||||
uintptr_t data = regs.rsi;
|
uintptr_t data = regs->rsi;
|
||||||
|
|
||||||
cons->set_color(11);
|
cons->set_color(11);
|
||||||
cons->printf("\nProcess %d: Received RECEIVE syscall, source %d, dat %016lx\n", p->pid, source, data);
|
cons->printf("\nProcess %d: Received RECEIVE syscall, source %d, dat %016lx\n", p->pid, source, data);
|
||||||
cons->set_color();
|
cons->set_color();
|
||||||
|
|
||||||
if (p->wait_on_receive(source))
|
if (p->wait_on_receive(source))
|
||||||
return_rsp = s.schedule(return_rsp);
|
s.schedule();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -128,8 +128,9 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state ®s)
|
|||||||
cons->printf("\nProcess %d: Received FORK syscall\n", p->pid);
|
cons->printf("\nProcess %d: Received FORK syscall\n", p->pid);
|
||||||
cons->set_color();
|
cons->set_color();
|
||||||
|
|
||||||
pid_t pid = p->fork(return_rsp);
|
pid_t pid = p->fork(regs);
|
||||||
regs.rax = pid;
|
cons->printf("\n fork returning %d\n", pid);
|
||||||
|
regs->rax = pid;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -137,8 +138,8 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state ®s)
|
|||||||
cons->set_color(11);
|
cons->set_color(11);
|
||||||
cons->printf("\nProcess %d: Received EXIT syscall\n", p->pid);
|
cons->printf("\nProcess %d: Received EXIT syscall\n", p->pid);
|
||||||
cons->set_color();
|
cons->set_color();
|
||||||
p->exit(regs.rdi);
|
p->exit(regs->rdi);
|
||||||
return_rsp = s.schedule(return_rsp);
|
s.schedule();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -148,7 +149,5 @@ syscall_dispatch(uintptr_t return_rsp, cpu_state ®s)
|
|||||||
_halt();
|
_halt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return return_rsp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ enum class syscall : uint64_t
|
|||||||
};
|
};
|
||||||
|
|
||||||
void syscall_enable();
|
void syscall_enable();
|
||||||
uintptr_t syscall_dispatch(uintptr_t, cpu_state &);
|
void syscall_dispatch(cpu_state *);
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ syscall_handler_prelude:
|
|||||||
|
|
||||||
mov rdi, rsp
|
mov rdi, rsp
|
||||||
call syscall_handler
|
call syscall_handler
|
||||||
mov rsp, rax
|
|
||||||
|
|
||||||
mov rax, [rsp + 0x90]
|
mov rax, [rsp + 0x90]
|
||||||
and rax, 0x3
|
and rax, 0x3
|
||||||
|
|||||||
85
src/kernel/task.s
Normal file
85
src/kernel/task.s
Normal 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
32
src/kernel/tasking.inc
Normal 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
|
||||||
Reference in New Issue
Block a user