blob: c50a5186955cddf14ae9e694d8c6c3fcc86b993c [file] [log] [blame] [edit]
/* Copyright (c) 2009-13 The Regents of the University of California
* Barret Rhoden <brho@cs.berkeley.edu>
* See LICENSE for details.
*
* x86 trap.c bit-specific functions. */
#include <arch/mmu.h>
#include <arch/x86.h>
#include <arch/arch.h>
#include <arch/console.h>
#include <arch/apic.h>
#include <ros/common.h>
#include <smp.h>
#include <assert.h>
#include <pmap.h>
#include <trap.h>
#include <monitor.h>
#include <process.h>
#include <mm.h>
#include <stdio.h>
#include <slab.h>
#include <syscall.h>
#include <kdebug.h>
#include <kmalloc.h>
/* Starts running the current TF, just using ret. */
void pop_kernel_ctx(struct kernel_ctx *ctx)
{
struct sw_trapframe *tf = &ctx->sw_tf;
/* We're starting at rbx's spot in the sw_tf */
asm volatile ("movq %0, %%rsp; "
"popq %%rbx; "
"popq %%rbp; "
"popq %%r12; "
"popq %%r13; "
"popq %%r14; "
"popq %%r15; "
"popq %%rax; " /* pop rip */
"popq %%rsp; "
"jmp *%%rax; " /* stored rip */
: : "g"(&ctx->sw_tf.tf_rbx) : "memory");
panic("ret failed");
}
void print_trapframe(struct hw_trapframe *hw_tf)
{
static spinlock_t ptf_lock = SPINLOCK_INITIALIZER_IRQSAVE;
struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
/* This is only called in debug scenarios, and often when the kernel trapped
* and needs to tell us about it. Disable the lock checker so it doesn't go
* nuts when we print/panic */
pcpui->__lock_checking_enabled--;
spin_lock_irqsave(&ptf_lock);
printk("HW TRAP frame at %p on core %d\n", hw_tf, core_id());
printk(" rax 0x%016lx\n", hw_tf->tf_rax);
printk(" rbx 0x%016lx\n", hw_tf->tf_rbx);
printk(" rcx 0x%016lx\n", hw_tf->tf_rcx);
printk(" rdx 0x%016lx\n", hw_tf->tf_rdx);
printk(" rbp 0x%016lx\n", hw_tf->tf_rbp);
printk(" rsi 0x%016lx\n", hw_tf->tf_rsi);
printk(" rdi 0x%016lx\n", hw_tf->tf_rdi);
printk(" r8 0x%016lx\n", hw_tf->tf_r8);
printk(" r9 0x%016lx\n", hw_tf->tf_r9);
printk(" r10 0x%016lx\n", hw_tf->tf_r10);
printk(" r11 0x%016lx\n", hw_tf->tf_r11);
printk(" r12 0x%016lx\n", hw_tf->tf_r12);
printk(" r13 0x%016lx\n", hw_tf->tf_r13);
printk(" r14 0x%016lx\n", hw_tf->tf_r14);
printk(" r15 0x%016lx\n", hw_tf->tf_r15);
printk(" trap 0x%08x %s\n", hw_tf->tf_trapno,
x86_trapname(hw_tf->tf_trapno));
/* FYI: these aren't physically adjacent to trap and err */
if (hw_tf->tf_cs == GD_KT)
printk(" gsbs 0x%016lx\n", read_msr(MSR_GS_BASE));
else
printk(" gsbs 0x%016lx\n", hw_tf->tf_gsbase);
printk(" fsbs 0x%016lx\n", hw_tf->tf_fsbase);
printk(" err 0x--------%08x\n", hw_tf->tf_err);
printk(" rip 0x%016lx\n", hw_tf->tf_rip);
printk(" cs 0x------------%04x\n", hw_tf->tf_cs);
printk(" flag 0x%016lx\n", hw_tf->tf_rflags);
printk(" rsp 0x%016lx\n", hw_tf->tf_rsp);
printk(" ss 0x------------%04x\n", hw_tf->tf_ss);
spin_unlock_irqsave(&ptf_lock);
pcpui->__lock_checking_enabled++;
/* Used in trapentry64.S */
static_assert(offsetof(struct hw_trapframe, tf_cs) -
offsetof(struct hw_trapframe, tf_rax) == 0x90);
/* Used in trap64.h */
static_assert(offsetof(struct per_cpu_info, stacktop) == 0);
}
void print_swtrapframe(struct sw_trapframe *sw_tf)
{
static spinlock_t ptf_lock = SPINLOCK_INITIALIZER_IRQSAVE;
struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
pcpui->__lock_checking_enabled--;
spin_lock_irqsave(&ptf_lock);
printk("SW TRAP frame at %p on core %d\n", sw_tf, core_id());
printk(" rbx 0x%016lx\n", sw_tf->tf_rbx);
printk(" rbp 0x%016lx\n", sw_tf->tf_rbp);
printk(" r12 0x%016lx\n", sw_tf->tf_r12);
printk(" r13 0x%016lx\n", sw_tf->tf_r13);
printk(" r14 0x%016lx\n", sw_tf->tf_r14);
printk(" r15 0x%016lx\n", sw_tf->tf_r15);
printk(" gsbs 0x%016lx\n", sw_tf->tf_gsbase);
printk(" fsbs 0x%016lx\n", sw_tf->tf_fsbase);
printk(" rip 0x%016lx\n", sw_tf->tf_rip);
printk(" rsp 0x%016lx\n", sw_tf->tf_rsp);
printk(" mxcsr 0x%08x\n", sw_tf->tf_mxcsr);
printk(" fpucw 0x%04x\n", sw_tf->tf_fpucw);
spin_unlock_irqsave(&ptf_lock);
pcpui->__lock_checking_enabled++;
}
void page_fault_handler(struct hw_trapframe *hw_tf)
{
uintptr_t fault_va = rcr2();
int prot = hw_tf->tf_err & PF_ERROR_WRITE ? PROT_WRITE : PROT_READ;
int err;
/* TODO - handle kernel page faults */
if ((hw_tf->tf_cs & 3) == 0) {
print_trapframe(hw_tf);
backtrace_kframe(hw_tf);
panic("Page Fault in the Kernel at 0x%08x!", fault_va);
/* if we want to do something like kill a process or other code, be
* aware we are in a sort of irq-like context, meaning the main kernel
* code we 'interrupted' could be holding locks - even irqsave locks. */
}
/* safe to reenable after rcr2 */
enable_irq();
if ((err = handle_page_fault(current, fault_va, prot))) {
/* Destroy the faulting process */
printk("[%08x] user %s fault va %p ip %p on core %d with err %d\n",
current->pid, prot & PROT_READ ? "READ" : "WRITE", fault_va,
hw_tf->tf_rip, core_id(), err);
print_trapframe(hw_tf);
/* Turn this on to help debug bad function pointers */
printd("rsp %p\n\t 0(rsp): %p\n\t 8(rsp): %p\n\t 16(rsp): %p\n"
"\t24(rsp): %p\n", hw_tf->tf_rsp,
*(uintptr_t*)(hw_tf->tf_rsp + 0),
*(uintptr_t*)(hw_tf->tf_rsp + 8),
*(uintptr_t*)(hw_tf->tf_rsp + 16),
*(uintptr_t*)(hw_tf->tf_rsp + 24));
proc_destroy(current);
}
}