blob: 3638833cf4f370c6dc030e0a0dc8d538aca0474d [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)
{
asm volatile ("movl %1,%%esp; " /* move to future stack */
"pushl %2; " /* push cs */
"movl %0,%%esp; " /* move to TF */
"addl $0x20,%%esp; " /* move to tf_gs slot */
"movl %1,(%%esp); " /* write future esp */
"subl $0x20,%%esp; " /* move back to tf start */
"popal; " /* restore regs */
"popl %%esp; " /* set stack ptr */
"subl $0x4,%%esp; " /* jump down past CS */
"ret " /* return to the EIP */
:
: "g"(&ctx->hw_tf), "r"(ctx->hw_tf.tf_esp),
"r"(ctx->hw_tf.tf_eip)
: "memory");
panic("ret failed"); /* mostly to placate your mom */
}
static void print_regs(push_regs_t *regs)
{
printk(" edi 0x%08x\n", regs->reg_edi);
printk(" esi 0x%08x\n", regs->reg_esi);
printk(" ebp 0x%08x\n", regs->reg_ebp);
printk(" oesp 0x%08x\n", regs->reg_oesp);
printk(" ebx 0x%08x\n", regs->reg_ebx);
printk(" edx 0x%08x\n", regs->reg_edx);
printk(" ecx 0x%08x\n", regs->reg_ecx);
printk(" eax 0x%08x\n", regs->reg_eax);
}
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("TRAP frame at %p on core %d\n", hw_tf, core_id());
print_regs(&hw_tf->tf_regs);
printk(" gs 0x----%04x\n", hw_tf->tf_gs);
printk(" fs 0x----%04x\n", hw_tf->tf_fs);
printk(" es 0x----%04x\n", hw_tf->tf_es);
printk(" ds 0x----%04x\n", hw_tf->tf_ds);
printk(" trap 0x%08x %s\n", hw_tf->tf_trapno,
x86_trapname(hw_tf->tf_trapno));
printk(" err 0x%08x\n", hw_tf->tf_err);
printk(" eip 0x%08x\n", hw_tf->tf_eip);
printk(" cs 0x----%04x\n", hw_tf->tf_cs);
printk(" flag 0x%08x\n", hw_tf->tf_eflags);
/* Prevents us from thinking these mean something for nested interrupts. */
if (hw_tf->tf_cs != GD_KT) {
printk(" esp 0x%08x\n", hw_tf->tf_esp);
printk(" ss 0x----%04x\n", hw_tf->tf_ss);
}
spin_unlock_irqsave(&ptf_lock);
pcpui->__lock_checking_enabled++;
}
void page_fault_handler(struct hw_trapframe *hw_tf)
{
uint32_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 %08x ip %08x on core %d with err %d\n",
current->pid, prot & PROT_READ ? "READ" : "WRITE", fault_va,
hw_tf->tf_eip, core_id(), err);
print_trapframe(hw_tf);
/* Turn this on to help debug bad function pointers */
printd("esp %p\n\t 0(esp): %p\n\t 4(esp): %p\n\t 8(esp): %p\n"
"\t12(esp): %p\n", hw_tf->tf_esp,
*(uintptr_t*)(hw_tf->tf_esp + 0),
*(uintptr_t*)(hw_tf->tf_esp + 4),
*(uintptr_t*)(hw_tf->tf_esp + 8),
*(uintptr_t*)(hw_tf->tf_esp + 12));
proc_destroy(current);
}
}