From 261aa2b9b790868a16a6cee0f19c73221ddc81d5 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 22 Jun 2010 16:41:25 -0500 Subject: Program exception handling and emulated instruction for mfsprg3. --- src/include/kernel/ppcarch.H | 14 +++++++++++ src/kernel/exception.C | 58 ++++++++++++++++++++++++++++++++++++++++++++ src/kernel/makefile | 2 +- src/kernel/start.S | 2 +- src/lib/syscall_task.C | 9 ++++++- 5 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 src/include/kernel/ppcarch.H create mode 100644 src/kernel/exception.C diff --git a/src/include/kernel/ppcarch.H b/src/include/kernel/ppcarch.H new file mode 100644 index 000000000..f6b80ea6f --- /dev/null +++ b/src/include/kernel/ppcarch.H @@ -0,0 +1,14 @@ +#ifndef __KERNEL_PPCARCH_H +#define __KERNEL_PPCARCH_H + +#include + +__attribute__((always_inline)) +inline uint64_t ppc_getSRR1() +{ + register uint64_t srr1 = 0; + asm volatile("mfsrr1 %0" : "=r" (srr1)); + return srr1; +} + +#endif diff --git a/src/kernel/exception.C b/src/kernel/exception.C new file mode 100644 index 000000000..98d36c35c --- /dev/null +++ b/src/kernel/exception.C @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include + +namespace Systemcalls { void TaskEnd(task_t*); } +namespace ExceptionHandles +{ + bool HvEmulation(task_t*); +} + +const uint64_t EXCEPTION_SRR1_MASK = 0x00000000783F0000; +const uint64_t EXCEPTION_SRR1_HVEMUL = 0x0000000000080000; + +extern "C" +void kernel_execute_prog_ex() +{ + task_t* t = TaskManager::getCurrentTask(); + uint64_t exception = ppc_getSRR1() & EXCEPTION_SRR1_MASK; + + bool handled = false; + switch(exception) + { + case EXCEPTION_SRR1_HVEMUL: + handled = ExceptionHandles::HvEmulation(t); + break; + } + if (!handled) + { + printk("Program exception, killing task %d\n", t->tid); + Systemcalls::TaskEnd(t); + } +} + +namespace ExceptionHandles +{ + bool HvEmulation(task_t* t) + { + /*printk("NIP = %llx : Inst = %lx\n", + t->context.nip, + (*(uint32_t*)t->context.nip));*/ + + uint32_t instruction = *(uint32_t*)t->context.nip; + + // check for mfsprg3 + if ((instruction & 0xfc1fffff) == 0x7c1342a6) + { + t->context.gprs[(instruction & 0x03E00000) >> 21] = + (uint64_t) t; + t->context.nip = (void*) (((uint64_t)t->context.nip)+4); + return true; + } + + return false; + } + +} diff --git a/src/kernel/makefile b/src/kernel/makefile index 629c39bcb..4bdc0d02d 100644 --- a/src/kernel/makefile +++ b/src/kernel/makefile @@ -2,7 +2,7 @@ OBJDIR = ../../obj include ../../config.mk OBJS = start.o kernel.o console.o pagemgr.o heapmgr.o taskmgr.o cpumgr.o -OBJS += syscall.o scheduler.o spinlock.o +OBJS += syscall.o scheduler.o spinlock.o exception.o OBJECTS = $(addprefix ${OBJDIR}/, ${OBJS}) all: ${OBJECTS} diff --git a/src/kernel/start.S b/src/kernel/start.S index 93cc0156e..774c62f67 100644 --- a/src/kernel/start.S +++ b/src/kernel/start.S @@ -103,7 +103,7 @@ UNIMPL_INTERRUPT(inst_storage, 0x400) UNIMPL_INTERRUPT(inst_segment, 0x480) UNIMPL_INTERRUPT(external, 0x500) UNIMPL_INTERRUPT(alignment, 0x600) -UNIMPL_INTERRUPT(program, 0x700) +STD_INTERRUPT(prog_ex, 0x700) UNIMPL_INTERRUPT(fp_unavail, 0x800) STD_INTERRUPT(decrementer, 0x900) UNIMPL_INTERRUPT(hype_decrementer, 0x980) diff --git a/src/lib/syscall_task.C b/src/lib/syscall_task.C index d07ea3f19..405e4f202 100644 --- a/src/lib/syscall_task.C +++ b/src/lib/syscall_task.C @@ -1,6 +1,7 @@ #include #include #include +#include using namespace Systemcalls; @@ -23,5 +24,11 @@ void task_end() tid_t task_gettid() { - return (tid_t)_syscall0(TASK_GETTID); + // Even though we have a syscall for GETTID, we can implement this as a + // direct access to SPRG3. On processor that do not support unprivilaged + // access to this SPR, we implement it as an emulated instruction in the + // exception handler. + + return TaskManager::getCurrentTask()->tid; + //return (tid_t)_syscall0(TASK_GETTID); } -- cgit v1.2.1