diff options
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/exception.C | 13 | ||||
-rw-r--r-- | src/kernel/intmsghandler.C | 125 | ||||
-rw-r--r-- | src/kernel/makefile | 2 | ||||
-rw-r--r-- | src/kernel/start.S | 2 | ||||
-rw-r--r-- | src/kernel/syscall.C | 43 |
5 files changed, 177 insertions, 8 deletions
diff --git a/src/kernel/exception.C b/src/kernel/exception.C index 863743f06..6ce01bc96 100644 --- a/src/kernel/exception.C +++ b/src/kernel/exception.C @@ -28,6 +28,7 @@ #include <arch/ppc.H> #include <kernel/vmmmgr.H> #include <kernel/cpuid.H> +#include <kernel/intmsghandler.H> namespace ExceptionHandles { @@ -221,6 +222,16 @@ void kernel_execute_machine_check() "\tSRR0 = %lx, SRR1 = %lx\n" "\tDSISR = %lx, DAR = %lx\n", t->tid, getPIR(), - getSRR0(), getSRR0(), getDSISR(), getDAR()); + getSRR0(), getSRR1(), getDSISR(), getDAR()); kassert(false); } + +extern "C" +void kernel_execute_external() +{ + // SRR0 set to the effective addr the thread + // would have attempted to execute next + // SRR1 [33:36,42:47] set to zero + // all others copied from MSR + InterruptMsgHdlr::handleInterrupt(); +} diff --git a/src/kernel/intmsghandler.C b/src/kernel/intmsghandler.C new file mode 100644 index 000000000..b7b86c2f5 --- /dev/null +++ b/src/kernel/intmsghandler.C @@ -0,0 +1,125 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/kernel/intmsghandler.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#include <kernel/intmsghandler.H> +#include <sys/msg.h> +#include <util/singleton.H> +#include <kernel/console.H> +#include <sys/interrupt.h> +#include <util/lockfree/atomic_construct.H> + +const char* INTR_MSGQ = "/msg/interrupt"; + +InterruptMsgHdlr * InterruptMsgHdlr::cv_instance = NULL; + + +void InterruptMsgHdlr::create(MessageQueue * i_msgQ) +{ + if(cv_instance) + { + // TODO should this be considered an unrecoverable error? + // i_msgQ has already been changed by the syscall, so we either have to + // make a new InterrupMsgHdlr object to match the new queue or we halt + // the system. + printk("WARNING replacing existing Interrupt handler!\n"); + + InterruptMsgHdlr* instance = cv_instance; + while(instance != NULL) + { + if(__sync_bool_compare_and_swap(&cv_instance, instance, NULL)) + { + delete instance; + } + instance = cv_instance; + } + } + + // Atomically construct. + if (__sync_bool_compare_and_swap(&cv_instance, NULL, NULL)) + { + InterruptMsgHdlr* instance = new InterruptMsgHdlr(i_msgQ); + if (!__sync_bool_compare_and_swap(&cv_instance, NULL, instance)) + { + delete instance; + } + } +} + + +void InterruptMsgHdlr::handleInterrupt() +{ + + // TODO will this always be processor 0 core 0 thread 0? + // Need a way to pass this addr down from user code? + uint64_t xirrAddress = (static_cast<uint64_t>(ICPBAR_VAL) << 20) + 4; + + // Ignore HRMOR setting + xirrAddress |= 0x8000000000000000ul; + + uint32_t xirr = 0; + printkd ("XirrAddr %lx\n",xirrAddress); + + // Reading this register acknowledges the interrupt and deactivates the + // external interrupt signal to the processor. The XIRR is now locked + // and can't be pre-empted by a "more favored" interrupt. + // This is a cache-inhibited load from hypervisor state. + // lwzcix BOP1,Ref_G0,BOP2 + asm volatile("lwzcix %0, 0, %1" + : "=r" (xirr) // output, %0 + : "r" (xirrAddress) // input, %1 + : ); // no impacts + + if(cv_instance) + { + cv_instance->sendMessage(MSG_INTR_EXTERN, + (void *)xirr, + NULL, + NULL); + } + + // else we got an external interrupt before we got things set up. + // TODO Is there anything that can be done other than + // leave the interrupt presenter locked. + // Does the code that sets up the IP registers need to check to see if + // there is an interrupt sitting there and send an EOI? +} + + +void InterruptMsgHdlr::addCpuCore(uint64_t i_pir) +{ + if(cv_instance) + { + cv_instance->sendMessage(MSG_INTR_ADD_CPU,(void *)i_pir,NULL,NULL); + } +} + +MessageHandler::HandleResult InterruptMsgHdlr::handleResponse +( + msg_sys_types_t i_type, + void* i_key, + task_t* i_task, + int i_rc + ) +{ + return UNHANDLED_RC; +} + diff --git a/src/kernel/makefile b/src/kernel/makefile index 05c15115a..06c7536be 100644 --- a/src/kernel/makefile +++ b/src/kernel/makefile @@ -26,7 +26,7 @@ OBJS = start.o kernel.o console.o pagemgr.o heapmgr.o taskmgr.o cpumgr.o OBJS += syscall.o scheduler.o spinlock.o exception.o vmmmgr.o timemgr.o OBJS += futexmgr.o ptmgr.o segmentmgr.o devicesegment.o basesegment.o OBJS += block.o cpuid.o misc.o msghandler.o blockmsghdlr.o stacksegment.o -OBJS += softpatch_p7.o barrier.o idebug.o +OBJS += softpatch_p7.o barrier.o idebug.o intmsghandler.o include ${ROOTPATH}/config.mk diff --git a/src/kernel/start.S b/src/kernel/start.S index 71f3b6db9..bcb770a58 100644 --- a/src/kernel/start.S +++ b/src/kernel/start.S @@ -151,7 +151,7 @@ STD_INTERRUPT(data_storage, 0x300) STD_INTERRUPT(data_segment, 0x380) STD_INTERRUPT(inst_storage, 0x400) STD_INTERRUPT(inst_segment, 0x480) -UNIMPL_INTERRUPT(external, 0x500) +STD_INTERRUPT(external, 0x500) STD_INTERRUPT(alignment, 0x600) STD_INTERRUPT(prog_ex, 0x700) STD_INTERRUPT(fp_unavail, 0x800) diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index 013ffc78c..561218b00 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -39,6 +39,7 @@ #include <kernel/vmmmgr.H> #include <kernel/stacksegment.H> #include <kernel/heapmgr.H> +#include <kernel/intmsghandler.H> extern "C" void kernel_execute_decrementer() @@ -121,8 +122,8 @@ namespace Systemcalls &FutexWait, // FUTEX_WAIT &FutexWake, // FUTEX_WAKE - &Shutdown, // MISC_SHUTDOWN - &CpuCoreType, // MISC_CPUCORETYPE + &Shutdown, // MISC_SHUTDOWN + &CpuCoreType, // MISC_CPUCORETYPE &CpuDDLevel, // MISC_CPUDDLEVEL &MmAllocBlock, // MM_ALLOC_BLOCK @@ -246,16 +247,47 @@ namespace Systemcalls } static MessageQueue* msgQRoot = NULL; + static MessageQueue* msgQIntr = NULL; void MsgQRegisterRoot(task_t* t) { - msgQRoot = (MessageQueue*) TASK_GETARG0(t); - TASK_SETRTN(t, 0); + switch(TASK_GETARG0(t)) + { + case MSGQ_ROOT_VFS: + msgQRoot = (MessageQueue*) TASK_GETARG1(t); + TASK_SETRTN(t,0); + break; + + case MSGQ_ROOT_INTR: + msgQIntr = (MessageQueue*) TASK_GETARG1(t); + InterruptMsgHdlr::create(msgQIntr); + TASK_SETRTN(t,0); + break; + + default: + printk("ERROR MsgRegisterRoot invalid type %ld\n", + TASK_GETARG0(t)); + TASK_SETRTN(t,-EINVAL); + } } void MsgQResolveRoot(task_t* t) { - TASK_SETRTN(t, (uint64_t) msgQRoot); + switch(TASK_GETARG0(t)) + { + case MSGQ_ROOT_VFS: + TASK_SETRTN(t, (uint64_t) msgQRoot); + break; + + case MSGQ_ROOT_INTR: + TASK_SETRTN(t, (uint64_t) msgQIntr); + break; + + default: + printk("ERROR MsgQResolveRoot invalid type %ld\n", + TASK_GETARG0(t)); + TASK_SETRTN(t,0); + } } void MsgSend(task_t* t) @@ -563,3 +595,4 @@ namespace Systemcalls } }; + |