Pause syscall and int 0xee interrupt syscalls

The syscall/sysret instructions don't swap stacks. This was bad but
passable until syscalls caused the scheduler to run, and scheduling a
task that paused due to interrupt.

Adding a new (hopefully temporary) syscall interrupt `int 0xee` to allow
me to test syscalls without stack issues before I tackle the
syscall/sysret issue.

Also implemented a basic `pause` syscall that causes the calling process
to become unready. Because nothing can wake a process yet, it never
returns.
This commit is contained in:
Justin C. Miller
2018-09-12 20:59:08 -07:00
parent c2f85ce61b
commit 62c559043d
13 changed files with 233 additions and 136 deletions

View File

@@ -52,6 +52,7 @@ cpu_id::cpu_id()
}
cpu_id::regs
cpu_id::get(uint32_t leaf, uint32_t sub) const
{

68
src/kernel/debug.cpp Normal file
View File

@@ -0,0 +1,68 @@
#include "console.h"
#include "cpu.h"
#include "debug.h"
#include "gdt.h"
#define print_reg(name, value) cons->printf(" %s: %016lx\n", name, (value));
void
print_regs(const cpu_state &regs)
{
console *cons = console::get();
print_reg("rax", regs.rax);
print_reg("rbx", regs.rbx);
print_reg("rcx", regs.rcx);
print_reg("rdx", regs.rdx);
print_reg("rdi", regs.rdi);
print_reg("rsi", regs.rsi);
cons->puts("\n");
print_reg(" r8", regs.r8);
print_reg(" r9", regs.r9);
print_reg("r10", regs.r10);
print_reg("r11", regs.r11);
print_reg("r12", regs.r12);
print_reg("r13", regs.r13);
print_reg("r14", regs.r14);
print_reg("r15", regs.r15);
cons->puts("\n");
print_reg("rbp", regs.rbp);
print_reg("rsp", regs.user_rsp);
print_reg("sp0", tss_get_stack(0));
cons->puts("\n");
print_reg(" ds", regs.ds);
print_reg(" cs", regs.cs);
print_reg(" ss", regs.ss);
cons->puts("\n");
print_reg("rip", regs.rip);
}
void
print_stacktrace(int skip)
{
console *cons = console::get();
int frame = 0;
uint64_t bp = get_frame(skip);
while (bp) {
cons->printf(" frame %2d: %lx\n", frame, bp);
bp = get_frame(++frame + skip);
}
}
void
print_stack(const cpu_state &regs)
{
console *cons = console::get();
cons->puts("\nStack:\n");
uint64_t sp = regs.user_rsp;
while (sp <= regs.rbp) {
cons->printf("%016x: %016x\n", sp, *reinterpret_cast<uint64_t *>(sp));
sp += sizeof(uint64_t);
}
}

19
src/kernel/debug.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
/// \file debug.h
/// Debugging utilities
#include "kutil/memory.h"
extern "C" {
addr_t get_rsp();
addr_t get_rip();
addr_t get_frame(int frame);
}
void print_regs(const cpu_state &regs);
void print_stack(const cpu_state &regs);
void print_stacktrace(int skip = 0);
#define print_reg(name, value) cons->printf(" %s: %016lx\n", name, (value));

View File

@@ -237,12 +237,13 @@ IRQ (0xde, 0xbe, irqBE)
IRQ (0xdf, 0xbf, irqBF)
ISR (0xe7, isrAssert)
ISR (0xe0, isrTimer)
ISR (0xe1, isrLINT0)
ISR (0xe2, isrLINT1)
ISR (0xe3, isrSpurious)
ISR (0xe4, isrAssert)
ISR (0xec, isrTimer)
ISR (0xed, isrLINT0)
ISR (0xee, isrLINT1)
ISR (0xef, isrSpurious)
UISR(0xee, isrSyscall)
ISR (0xf0, isrIgnore0)
ISR (0xf1, isrIgnore1)

View File

@@ -1,7 +1,9 @@
#include <stdint.h>
#include "kutil/memory.h"
#include "console.h"
#include "cpu.h"
#include "debug.h"
#include "device_manager.h"
#include "gdt.h"
#include "interrupts.h"
@@ -19,9 +21,11 @@ extern "C" {
#define ISR(i, name) extern void name ();
#define EISR(i, name) extern void name ();
#define UISR(i, name) extern void name ();
#define IRQ(i, q, name) extern void name ();
#include "interrupt_isrs.inc"
#undef IRQ
#undef UISR
#undef EISR
#undef ISR
}
@@ -39,9 +43,11 @@ get_irq(unsigned vector)
switch (vector) {
#define ISR(i, name)
#define EISR(i, name)
#define UISR(i, name)
#define IRQ(i, q, name) case i : return q;
#include "interrupt_isrs.inc"
#undef IRQ
#undef UISR
#undef EISR
#undef ISR
@@ -52,7 +58,6 @@ get_irq(unsigned vector)
static void
disable_legacy_pic()
{
static const uint16_t PIC1 = 0x20;
static const uint16_t PIC2 = 0xa0;
@@ -85,9 +90,11 @@ interrupts_init()
{
#define ISR(i, name) idt_set_entry(i, reinterpret_cast<uint64_t>(& name), 0x08, 0x8e);
#define EISR(i, name) idt_set_entry(i, reinterpret_cast<uint64_t>(& name), 0x08, 0x8e);
#define UISR(i, name) idt_set_entry(i, reinterpret_cast<uint64_t>(& name), 0x08, 0xee);
#define IRQ(i, q, name) idt_set_entry(i, reinterpret_cast<uint64_t>(& name), 0x08, 0x8e);
#include "interrupt_isrs.inc"
#undef IRQ
#undef UISR
#undef EISR
#undef ISR
@@ -97,71 +104,6 @@ interrupts_init()
log::info(logs::boot, "Interrupts enabled.");
}
#define print_reg(name, value) cons->printf(" %s: %016lx\n", name, (value));
extern "C" uint64_t get_frame(int frame);
void
print_stacktrace(int skip = 0)
{
console *cons = console::get();
int frame = 0;
uint64_t bp = get_frame(skip);
while (bp) {
cons->printf(" frame %2d: %lx\n", frame, bp);
bp = get_frame(++frame + skip);
}
}
void
print_regs(const cpu_state &regs)
{
console *cons = console::get();
print_reg("rax", regs.rax);
print_reg("rbx", regs.rbx);
print_reg("rcx", regs.rcx);
print_reg("rdx", regs.rdx);
print_reg("rdi", regs.rdi);
print_reg("rsi", regs.rsi);
cons->puts("\n");
print_reg(" r8", regs.r8);
print_reg(" r9", regs.r9);
print_reg("r10", regs.r10);
print_reg("r11", regs.r11);
print_reg("r12", regs.r12);
print_reg("r13", regs.r13);
print_reg("r14", regs.r14);
print_reg("r15", regs.r15);
cons->puts("\n");
print_reg("rbp", regs.rbp);
print_reg("rsp", regs.user_rsp);
print_reg("sp0", tss_get_stack(0));
cons->puts("\n");
print_reg(" ds", regs.ds);
print_reg(" cs", regs.cs);
print_reg(" ss", regs.ss);
cons->puts("\n");
print_reg("rip", regs.rip);
}
void
print_stack(const cpu_state &regs)
{
console *cons = console::get();
cons->puts("\nStack:\n");
uint64_t sp = regs.user_rsp;
while (sp <= regs.rbp) {
cons->printf("%016x: %016x\n", sp, *reinterpret_cast<uint64_t *>(sp));
sp += sizeof(uint64_t);
}
}
addr_t
isr_handler(addr_t return_rsp, cpu_state regs)
{
@@ -197,33 +139,35 @@ isr_handler(addr_t return_rsp, cpu_state regs)
cons->puts("\nGeneral Protection Fault:\n");
cons->set_color();
cons->puts(" flags:");
cons->printf(" errorcode: %lx", regs.errorcode);
if (regs.errorcode & 0x01) cons->puts(" external");
int index = (regs.errorcode & 0xf8) >> 3;
int index = (regs.errorcode & 0xffff) >> 4;
if (index) {
switch (regs.errorcode & 0x06) {
switch ((regs.errorcode & 0x07) >> 1) {
case 0:
cons->printf(" GDT[%d]\n", index);
cons->printf(" GDT[%x]\n", index);
gdt_dump();
break;
case 1:
case 3:
cons->printf(" IDT[%d]\n", index);
cons->printf(" IDT[%x]\n", index);
idt_dump();
break;
default:
cons->printf(" LDT[%d]??\n", index);
cons->printf(" LDT[%x]??\n", index);
break;
}
} else {
cons->putc('\n');
}
print_regs(regs);
/*
print_stacktrace(2);
print_stack(regs);
*/
}
_halt();
@@ -263,17 +207,22 @@ isr_handler(addr_t return_rsp, cpu_state regs)
_halt();
break;
case isr::isrSyscall: {
return_rsp = syscall_dispatch(return_rsp, regs);
}
break;
default:
cons->set_color(9);
cons->puts("\nReceived ISR interrupt:\n");
cons->set_color();
cons->printf("\nReceived %02x interrupt:\n",
(static_cast<isr>(regs.interrupt)));
cons->printf(" ISR: %02lx\n", regs.interrupt);
cons->printf(" ERR: %lx\n", regs.errorcode);
cons->puts("\n");
cons->set_color();
cons->printf(" ISR: %02lx ERR: %lx\n\n",
regs.interrupt, regs.errorcode);
print_regs(regs);
print_stacktrace(2);
//print_stacktrace(2);
_halt();
}
*reinterpret_cast<uint32_t *>(0xffffff80fee000b0) = 0;
@@ -302,34 +251,5 @@ irq_handler(addr_t return_rsp, cpu_state regs)
addr_t
syscall_handler(addr_t return_rsp, cpu_state regs)
{
console *cons = console::get();
syscall call = static_cast<syscall>(regs.rax);
switch (call) {
case syscall::noop:
break;
case syscall::debug:
cons->set_color(11);
cons->printf("\nReceived DEBUG syscall\n");
cons->set_color();
print_regs(regs);
break;
case syscall::message:
cons->set_color(11);
cons->printf("\nReceived MESSAGE syscall\n");
cons->set_color();
break;
default:
cons->set_color(9);
cons->printf("\nReceived unknown syscall: %02x\n", call);
cons->set_color();
print_regs(regs);
_halt();
break;
}
return return_rsp;
return syscall_dispatch(return_rsp, regs);
}

View File

@@ -9,9 +9,11 @@ enum class isr : uint8_t
{
#define ISR(i, name) name = i,
#define EISR(i, name) name = i,
#define UISR(i, name) name = i,
#define IRQ(i, q, name) name = i,
#include "interrupt_isrs.inc"
#undef IRQ
#undef UISR
#undef EISR
#undef ISR

View File

@@ -57,6 +57,7 @@ irq_handler_prelude:
%endmacro
%define EISR(i, name) EMIT_EISR name, i
%define UISR(i, name) EMIT_ISR name, i
%define ISR(i, name) EMIT_ISR name, i
%define IRQ(i, q, name) EMIT_IRQ name, i

View File

@@ -266,7 +266,7 @@ page_manager::get_table_page()
}
reinterpret_cast<free_page_header *>(virt)->next = nullptr;
log::info(logs::memory, "Mappd %d new page table pages at %lx", n, phys);
log::debug(logs::memory, "Mappd %d new page table pages at %lx", n, phys);
}
free_page_header *page = m_page_cache;

View File

@@ -3,6 +3,7 @@
#include "cpu.h"
#include "gdt.h"
#include "interrupts.h"
#include "io.h"
#include "log.h"
#include "page_manager.h"
#include "scheduler.h"
@@ -11,8 +12,8 @@
#include "kutil/assert.h"
scheduler scheduler::s_instance(nullptr);
//static const uint32_t quantum = 2000000;
static const uint32_t quantum = 20000000;
static const uint32_t quantum = 2000000;
//static const uint32_t quantum = 20000000;
const int stack_size = 0x1000;
const uint64_t rflags_noint = 0x002;
@@ -69,7 +70,7 @@ load_process(const void *image_start, size_t bytes, process *proc, cpu_state sta
size_t size = (header->vaddr + header->mem_size) - aligned;
size_t pages = page_manager::page_count(size);
log::debug(logs::task, " Loadable segment %02d: vaddr %016lx size %016lx",
log::debug(logs::task, " Loadable segment %02u: vaddr %016lx size %016lx",
i, header->vaddr, header->mem_size);
log::debug(logs::task, " - aligned to: vaddr %016lx pages %d",
@@ -89,7 +90,7 @@ load_process(const void *image_start, size_t bytes, process *proc, cpu_state sta
!bitfield_has(header->flags, elf::section_flags::alloc))
continue;
log::debug(logs::task, " Loadable section %u: vaddr %016lx size %016lx",
log::debug(logs::task, " Loadable section %02u: vaddr %016lx size %016lx",
i, header->addr, header->size);
void *dest = reinterpret_cast<void *>(header->addr);
@@ -100,12 +101,7 @@ load_process(const void *image_start, size_t bytes, process *proc, cpu_state sta
state.rip = image.entrypoint();
proc->flags &= ~process_flags::loading;
log::debug(logs::task, "Loaded! New process state:");
log::debug(logs::task, " CS: %d [%d]", state.cs >> 3, state.cs & 0x07);
log::debug(logs::task, " SS: %d [%d]", state.ss >> 3, state.ss & 0x07);
log::debug(logs::task, " RFLAGS: %08x", state.rflags);
log::debug(logs::task, " RIP: %016lx", state.rip);
log::debug(logs::task, " uRSP: %016lx", state.user_rsp);
log::debug(logs::task, " Loaded! New process rip: %016lx", state.rip);
}
void
@@ -166,13 +162,9 @@ scheduler::create_process(const char *name, const void *data, size_t size)
loader_state->rcx = reinterpret_cast<uint64_t>(proc);
log::debug(logs::task, "Creating process %s:", name);
log::debug(logs::task, " PID %d", pid);
log::debug(logs::task, " Pri %d", pid);
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, " RSP3 %016lx", state->user_rsp);
log::debug(logs::task, " PML4 %016lx", pml4);
log::debug(logs::task, " Loading %016lx [%d]", loader_state->rax, loader_state->rbx);
}
void
@@ -187,7 +179,11 @@ scheduler::schedule(addr_t rsp0)
{
m_current->rsp = rsp0;
m_runlists[m_current->priority].remove(m_current);
m_runlists[m_current->priority].push_back(m_current);
if (m_current->flags && process_flags::ready)
m_runlists[m_current->priority].push_back(m_current);
else
m_blocked.push_back(m_current);
uint8_t pri = 0;
while (m_runlists[pri].empty()) {
@@ -198,14 +194,18 @@ scheduler::schedule(addr_t rsp0)
m_current = m_runlists[pri].pop_front();
rsp0 = m_current->rsp;
static const uint64_t ia32_gs_base = 0xc0000101;
static const uint64_t ia32_kernel_gs_base = 0xc0000102;
// Set rsp0 to after the end of the about-to-be-popped cpu state
tss_set_stack(0, rsp0 + sizeof(cpu_state));
wrmsr(ia32_gs_base, rsp0);
// Swap page tables
page_table *pml4 = m_current->pml4;
page_manager::set_pml4(pml4);
bool loading = bitfield_has(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.",
m_current->pid, m_current->priority, loading ? " (loading)" : "");

View File

@@ -25,6 +25,7 @@ enum class process_flags : uint32_t
};
IS_BITFIELD(process_flags);
/// A process
struct process
{
uint32_t pid;
@@ -39,6 +40,10 @@ struct process
addr_t rsp;
page_table *pml4;
/// Helper to check if this process is ready
/// \returns true if the process has the ready flag
inline bool ready() { return bitfield_has(flags, process_flags::ready); }
};
using process_list = kutil::linked_list<process>;
@@ -79,7 +84,6 @@ public:
/// \returns A reference to the global system scheduler
static scheduler & get() { return s_instance; }
private:
friend addr_t isr_handler(addr_t, cpu_state);
/// Handle a timer tick
@@ -87,6 +91,7 @@ private:
/// \returns The stack pointer to switch to
addr_t tick(addr_t rsp0);
private:
lapic *m_apic;
uint32_t m_next_pid;
@@ -94,6 +99,7 @@ private:
process_node *m_current;
process_slab m_process_allocator;
process_list m_runlists[num_priorities];
process_list m_blocked;
static scheduler s_instance;
};

60
src/kernel/syscall.cpp Normal file
View File

@@ -0,0 +1,60 @@
#include "console.h"
#include "cpu.h"
#include "debug.h"
#include "scheduler.h"
#include "syscall.h"
extern "C" {
void _halt();
}
addr_t
syscall_dispatch(addr_t return_rsp, const cpu_state &regs)
{
console *cons = console::get();
syscall call = static_cast<syscall>(regs.rax);
switch (call) {
case syscall::noop:
break;
case syscall::debug:
cons->set_color(11);
cons->printf("\nReceived DEBUG syscall\n");
cons->set_color();
print_regs(regs);
break;
case syscall::message:
cons->set_color(11);
cons->printf("\nReceived MESSAGE syscall\n");
cons->set_color();
break;
case syscall::pause:
{
cons->set_color(11);
auto &s = scheduler::get();
auto *p = s.current();
p->flags -= process_flags::ready;
//log::debug(logs::task, "Pausing process %d, flags: %08x", p->pid, p->flags);
cons->printf("\nReceived PAUSE syscall\n");
return_rsp = s.tick(return_rsp);
//log::debug(logs::task, "Switching to stack %016lx", return_rsp);
cons->printf("\nDONE WITH PAUSE syscall\n");
cons->set_color();
}
break;
default:
cons->set_color(9);
cons->printf("\nReceived unknown syscall: %02x\n", call);
cons->set_color();
_halt();
break;
}
return return_rsp;
}

View File

@@ -1,10 +1,18 @@
#pragma once
#include <stdint.h>
#include "kutil/memory.h"
enum class syscall : uint64_t
{
noop,
debug,
message,
pause,
last_syscall
};
struct cpu_state;
addr_t syscall_dispatch(addr_t, const cpu_state &);