Initial commit: Schunix as it stands before the SchOS rename
An x86-64 operating system built from xv6, now largely rewritten: SMP, a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF rasteriser, and a Linux-numbered syscall ABI. No history before this point -- the tree was never under version control. This commit exists so the rename that follows has something to undo to.
This commit is contained in:
commit
d0f7acf9eb
275 changed files with 51417 additions and 0 deletions
159
kernel/arch/x86_64/trap.c
Normal file
159
kernel/arch/x86_64/trap.c
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
#include "types.h"
|
||||
#include "defs.h"
|
||||
#include "irq.h"
|
||||
#include "param.h"
|
||||
#include "memlayout.h"
|
||||
#include "mmu.h"
|
||||
#include "proc.h"
|
||||
#include "x86.h"
|
||||
#include "traps.h"
|
||||
#include "spinlock.h"
|
||||
#include "posix.h"
|
||||
|
||||
uint *idt;
|
||||
extern addr_t vectors[];
|
||||
struct spinlock tickslock;
|
||||
uint ticks;
|
||||
|
||||
static void
|
||||
mkgate(uint *idt, uint n, addr_t kva, uint pl)
|
||||
{
|
||||
uint64 addr = (uint64) kva;
|
||||
|
||||
n *= 4;
|
||||
idt[n+0] = (addr & 0xFFFF) | (KERNEL_CS << 16);
|
||||
idt[n+1] = (addr & 0xFFFF0000) | 0x8E00 | ((pl & 3) << 13);
|
||||
idt[n+2] = addr >> 32;
|
||||
idt[n+3] = 0;
|
||||
}
|
||||
|
||||
void idtinit(void)
|
||||
{
|
||||
struct {
|
||||
ushort limit;
|
||||
uint64 base;
|
||||
} __attribute__((packed)) idtdesc;
|
||||
|
||||
idtdesc.limit = PGSIZE - 1;
|
||||
idtdesc.base = (uint64)idt;
|
||||
|
||||
asm volatile("lidt %0" : : "m" (idtdesc));
|
||||
}
|
||||
|
||||
void tvinit(void)
|
||||
{
|
||||
int n;
|
||||
idt = (uint*) kalloc();
|
||||
memset(idt, 0, PGSIZE);
|
||||
for (n = 0; n < 256; n++)
|
||||
mkgate(idt, n, vectors[n], 0);
|
||||
mkgate(idt, T_SYSCALL, vectors[T_SYSCALL], 3);
|
||||
}
|
||||
|
||||
uint
|
||||
uptime(void)
|
||||
{
|
||||
uint xticks;
|
||||
|
||||
acquire(&tickslock);
|
||||
xticks = ticks;
|
||||
release(&tickslock);
|
||||
return xticks;
|
||||
}
|
||||
|
||||
// Which signal a CPU fault corresponds to, so a process killed by a fault is
|
||||
// reported to wait() as died-by-signal with a sensible cause rather than a
|
||||
// blanket SIGKILL.
|
||||
static int
|
||||
trapsig(uint64 trapno)
|
||||
{
|
||||
switch(trapno){
|
||||
case T_DIVIDE: return SIGFPE;
|
||||
case T_ILLOP: return SIGILL;
|
||||
case T_GPFLT: return SIGSEGV;
|
||||
case T_PGFLT: return SIGSEGV;
|
||||
case T_BRKPT: return SIGTRAP;
|
||||
case T_DEBUG: return SIGTRAP;
|
||||
default: return SIGSEGV;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
trap(struct trapframe *tf)
|
||||
{
|
||||
kstack_check_canary("trap entry");
|
||||
switch(tf->trapno){
|
||||
case T_IRQ0 + IRQ_TIMER:
|
||||
if(cpunum() == 0){
|
||||
acquire(&tickslock);
|
||||
ticks++;
|
||||
wakeup(&ticks);
|
||||
release(&tickslock);
|
||||
}
|
||||
lapiceoi();
|
||||
break;
|
||||
case T_IRQ0 + IRQ_SPURIOUS:
|
||||
cprintf("cpu%d: spurious interrupt at %p:%p\n",
|
||||
cpunum(), tf->cs, tf->rip);
|
||||
lapiceoi();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Every other IOAPIC pin goes through the registration table. The device
|
||||
// interrupts used to be listed here one case at a time, which cannot work
|
||||
// for anything found on the PCI bus: a driver does not know its line
|
||||
// until it reads the device's config space at probe time, so there is no
|
||||
// constant to write a case label for. See include/irq.h.
|
||||
if(tf->trapno >= T_IRQ0 && tf->trapno < T_IRQ0 + NIRQ){
|
||||
irq_dispatch(tf->trapno - T_IRQ0);
|
||||
lapiceoi();
|
||||
break;
|
||||
}
|
||||
|
||||
if(myproc() == 0 || (tf->cs&3) == 0){
|
||||
cprintf("unexpected trap %d from cpu %d rip %p (cr2=0x%p) err=0x%p\n",
|
||||
tf->trapno, cpunum(), tf->rip, rcr2(), tf->err);
|
||||
if (myproc())
|
||||
cprintf("proc id: %d\n", myproc()->pid);
|
||||
if (tf->trapno == T_GPFLT) {
|
||||
uint64 *iretframe = (uint64*)tf->rsp;
|
||||
cprintf("iretq frame @ %p: rip=%p cs=%p rflags=%p rsp=%p ss=%p\n",
|
||||
iretframe, iretframe[0], iretframe[1], iretframe[2],
|
||||
iretframe[3], iretframe[4]);
|
||||
if (myproc())
|
||||
cprintf("this tf=%p myproc()->tf=%p myproc()->kstack=%p (tf-kstack=%p)\n",
|
||||
tf, myproc()->tf, myproc()->kstack, (uint64)tf - (uint64)myproc()->kstack);
|
||||
}
|
||||
panic("trap");
|
||||
}
|
||||
cprintf("pid %d %s: trap %d err %d on cpu %d "
|
||||
"rip 0x%p addr 0x%p--kill proc\n",
|
||||
myproc()->pid, myproc()->name, tf->trapno, tf->err, cpunum(), tf->rip,
|
||||
rcr2());
|
||||
// General-purpose register dump. This used to be followed by ~25 lines
|
||||
// that walked musl's mallocng group/meta structures out of rax/rdi and
|
||||
// dumped the user stack -- scaffolding for the boot-crash investigation
|
||||
// recorded in docs/architecture/kernel-history.md section 1. That
|
||||
// investigation is closed and the underlying kernel bugs are fixed, so
|
||||
// the allocator-specific part is gone; the registers stay, since they are
|
||||
// useful for any fault.
|
||||
if (tf->trapno == T_GPFLT) {
|
||||
cprintf(" rax=%p rbx=%p rcx=%p rdx=%p rsi=%p rdi=%p rbp=%p rsp=%p\n",
|
||||
tf->rax, tf->rbx, tf->rcx, tf->rdx, tf->rsi, tf->rdi, tf->rbp, tf->rsp);
|
||||
}
|
||||
myproc()->killed = 1;
|
||||
if(myproc()->killsig == 0)
|
||||
myproc()->killsig = trapsig(tf->trapno);
|
||||
}
|
||||
|
||||
if(myproc() && myproc()->killed && (tf->cs&3) == DPL_USER)
|
||||
exit(W_EXITCODE(0, myproc()->killsig ? myproc()->killsig : SIGKILL));
|
||||
|
||||
if(myproc() && myproc()->state == RUNNING && tf->trapno == T_IRQ0+IRQ_TIMER)
|
||||
yield();
|
||||
|
||||
if(myproc() && myproc()->killed && (tf->cs&3) == DPL_USER)
|
||||
exit(W_EXITCODE(0, myproc()->killsig ? myproc()->killsig : SIGKILL));
|
||||
|
||||
kstack_check_canary("trap exit");
|
||||
}
|
||||
Loading…
Reference in a new issue