|  | /* 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); | 
|  | } | 
|  | } |