diff options
author | Till Straumann <strauman@slac.stanford.edu> | 2007-12-10 07:06:53 +0000 |
---|---|---|
committer | Till Straumann <strauman@slac.stanford.edu> | 2007-12-10 07:06:53 +0000 |
commit | bf5742a63081a2d8ed3051b3056e4548b044eeee (patch) | |
tree | c54b378426651b30dfb1cfe230437a40e126e553 | |
parent | 2007-12-08 Till Straumann <strauman@slac.stanford.edu> (diff) | |
download | rtems-bf5742a63081a2d8ed3051b3056e4548b044eeee.tar.bz2 |
2007-12-09 Till Straumann <strauman@slac.stanford.edu>
* new-exceptions/bspsupport/ppc_exc_test.c,
new-exceptions/bspsupport/vectors_init.c,
new-exceptions/bspsupport/ppc_exc_bspsupp.h,
new-exceptions/bspsupport/README,
new-exceptions/bspsupport/irq_supp.h:
Added README and some comments; now use TRAP exception
in ppc_exc_test.c so that it works on PSIM.
6 files changed, 334 insertions, 19 deletions
diff --git a/c/src/lib/libcpu/powerpc/ChangeLog b/c/src/lib/libcpu/powerpc/ChangeLog index 5fc30ee7ed..dd51a6d79f 100644 --- a/c/src/lib/libcpu/powerpc/ChangeLog +++ b/c/src/lib/libcpu/powerpc/ChangeLog @@ -1,3 +1,13 @@ +2007-12-09 Till Straumann <strauman@slac.stanford.edu> + + * new-exceptions/bspsupport/ppc_exc_test.c, + new-exceptions/bspsupport/vectors_init.c, + new-exceptions/bspsupport/ppc_exc_bspsupp.h, + new-exceptions/bspsupport/README, + new-exceptions/bspsupport/irq_supp.h: + Added README and some comments; now use TRAP exception + in ppc_exc_test.c so that it works on PSIM. + 2007-12-08 Till Straumann <strauman@slac.stanford.edu> * irq_supp.h: was moved from libbsp/powerpc/shared/irq to diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/README b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/README new file mode 100644 index 0000000000..40d406407c --- /dev/null +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/README @@ -0,0 +1,311 @@ +$Id$ + +BSP support middleware for 'new-exception' style PPC. + +T. Straumann, 12/2007 + +EXPLANATION OF SOME TERMS +========================= + +In this README we refer to exceptions and sometimes +to 'interrupts'. Interrupts simply are asynchronous +exceptions such as 'external' exceptions or 'decrementer' +/'timer' exceptions. + +Traditionally (in the libbsp/powerpc/shared implementation), +synchronous exceptions are handled entirely in the context +of the interrupted task, i.e., the exception handlers use +the task's stack and leave thread-dispatching enabled, +i.e., scheduling is allowed to happen 'in the middle' +of an exception handler. + +Asynchronous exceptions/interrupts, OTOH, use a dedicated +interrupt stack and defer scheduling until after the last +nested ISR has finished. + +RATIONALE +========= +The 'new-exception' processing API works at a rather +low level. It provides functions for +installing low-level code (which must be written in +assembly code) directly into the PPC vector area. +It is entirely left to the BSP to implement low-level +exception handlers and to implement an API for +C-level exception handlers and to implement the +RTEMS interrupt API defined in cpukit/include/rtems/irq.h. + +The result has been a Darwinian evolution of variants +of this code which is very hard to maintain. Mostly, +the four files + +libbsp/powerpc/shared/vectors/vectors.S + (low-level handlers for 'normal' or 'synchronous' + exceptions. This code saves all registers on + the interrupted task's stack and calls a + 'global' C (high-level) exception handler. + +libbsp/powerpc/shared/vectors/vectors_init.c + (default implementation of the 'global' C + exception handler and initialization of the + vector table with trampoline code that ends up + calling the 'global' handler. + +libbsp/powerpc/shared/irq/irq_asm.S + (low-level handlers for 'IRQ'-type or 'asynchronous' + exceptions. This code is very similar to vectors.S + but does slightly more: after saving (only + the minimal set of) registers on the interrupted + task's stack it disables thread-dispatching, switches + to a dedicated ISR stack (if not already there which is + possible for nested interrupts) and then executes the high + level (C) interrupt dispatcher 'C_dispatch_irq_handler()'. + After 'C_dispatch_irq_handler()' returns the stack + is switched back (if not a nested IRQ), thread-dispatching + is re-enabled, signals are delivered and a context + switch is initiated if necessary. + +libbsp/powerpc/shared/irq/irq.c + implementation of the RTEMS ('new') IRQ API defined + in cpukit/include/rtems/irq.h. + +have been copied and modified by a myriad of BSPs leading +to many slightly different variants. + +THE BSP-SUPORT MIDDLEWARE +========================= + +The code in this directory is an attempt to provide the +functionality implemented by the aforementioned files +in a more generic way so that it can be shared by more +BSPs rather than being copied and modified. + +Another important goal was eliminating all conditional +compilation which tested for specific CPU models by means +of C-preprocessor symbols (#ifdef ppcXYZ). +Instead, appropriate run-time checks for features defined +in cpuIdent.h are used. + +The assembly code has been (almost completely) rewritten +and it tries to address a few problems while deliberately +trying to live with the existing APIs and semantics +(how these could be improved is beyond the scope but +that they could is beyond doubt...): + + - some PPCs don't fit into the classic scheme where + the exception vector addresses all were multiples of + 0x100 (some are spaced as closely as 0x10). + The API should not expose vector offsets but only + vector numbers which can be considered an abstract + entity. The mapping from vector numbers to actual + address offsets is performed inside 'raw_exception.c' + - having to provide assembly prologue code in order to + hook an exception is cumbersome. The middleware + tries to free users and BSP writers from this issue + by dealing with assembly prologues entirely inside + the middleware. The user can hook ordinary C routines. + - the advent of BookE CPUs brought interrupts with + multiple priorities: non-critical and critical + interrupts. Unfortunately, these are not entirely + trivial to deal with (unless critical interrupts + are permanently disabled [which is still the case: + ATM rtems_interrupt_enable()/rtems_interrupt_disable() + only deal with EE]). See separate section titled + 'race condition...' below for a detailed explanation. + +STRUCTURE +========= + +The middleware uses exception 'categories' or +'flavors' as defined in raw_exception.h. + +The middleware consists of the following parts: + + 1 small 'prologue' snippets that encode the + vector information and jump to appropriate + 'flavored-wrapper' code for further handling. + Some PPC exceptions are spaced only + 16-bytes apart, so the generic + prologue snippets are only 16-bytes long. + Prologues for synchronuos and asynchronous + exceptions differ. + + 2 flavored-wrappers which sets up a stack frame + and do things that are specific for + different 'flavors' of exceptions which + currently are + - classic PPC exception + - ppc405 critical exception + - bookE critical exception + - e500 machine check exception + + Assembler macros are provided and they can be + expanded to generate prologue templates and + flavored-wrappers for different flavors + of exceptions. Currently, there are two prologues + for all aforementioned flavors. One for synchronous + exceptions, the other for interrupts. + + 3 generic assembly-level code that does the bulk + of saving register context and calling C-code. + + 4 C-code (ppc_exc_hdl.c) for dispatching BSP/user + handlers. + + 5 Initialization code (vectors_init.c). All valid + exceptions for the detected CPU are determined + and a fitting prologue snippet for the exception + category (classic, critical, synchronous or IRQ, ...) + is generated from a template and the vector number + and then installed in the vector area. + + The user/BSP only has to deal with installing + high-level handlers but by default, the standard + 'C_dispatch_irq_handler' routine is hooked to + the external and 'decrementer' exceptions. + + 6 RTEMS IRQ API is implemented by 'irq.c'. It + relies on a few routines to be provided by + the BSP. + +USAGE +===== + BSP writers must provide the following routines + (declared in irq_supp.h): + Interrupt controller (PIC) support: + BSP_setup_the_pic() - initialize PIC hardware + BSP_enable_irq_at_pic() - enable/disable given irq at PIC; IGNORE if + BSP_disable_irq_at_pic() irq number out of range! + C_dispatch_irq_handler() - handle irqs and dispatch user handlers + this routine SHOULD use the inline + fragment + + bsp_irq_dispatch_list() + + provided by irq_supp.h + for calling user handlers. + + BSP initialization; call + + initialize_exceptions(); + BSP_rtems_irq_mngt_set(); + + Note that BSP_rtems_irq_mngt_set() hooks the C_dispatch_irq_handler() + to the external and decrementer (PIT exception for bookE; a decrementer + emulation is activated) exceptions for backwards compatibility reasons. + C_dispatch_irq_handler() must therefore be able to support these two + exceptions. + However, the BSP implementor is free to either disconnect + C_dispatch_irq_handler() from either of these exceptions, to connect + other handlers (e.g., for SYSMGMT exceptions) or to hook + C_dispatch_irq_handler() to yet more exceptions etc. *after* + BSP_rtems_irq_mngt_set() executed. + + Hooking exceptions: + + The API defined in ppc_exc_bspsupp.h declares routines for connecting + a C-handler to any exception. Note that the execution environment + of the C-handler depends on the exception being synchronous or + asynchronous: + + - synchronous exceptions use the task stack and do not + disable thread dispatching scheduling. + - asynchronous exceptions use a dedicated stack and do + defer thread dispatching until handling has (almost) finished. + + By inspecting the vector number stored in the exception frame + the nature of the exception can be determined: asynchronous + exceptions have the most significant bit(s) set. + + Any exception for which no dedicated handler is registered + ends up being handled by the routine addressed by the + (traditional) 'globalExcHdl' function pointer. + + Makefile.am: + - make sure the Makefile.am does NOT use any of the files + vectors.S, vectors.h, vectors_init.c, irq_asm.S, irq.c + from 'libbsp/powerpc/shared' NOR must the BSP implement + any functionality that is provided by those files (and + now the middleware). + + - (probably) remove 'vectors.rel' and anything related + + - add + + include_bsp_HEADERS += \ + ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/vectors.h \ + ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/irq_supp.h \ + ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/ppc_exc_bspsupp.h + + - add + + ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel \ + + to 'libbsp_a_LIBADD' + + + +RACE CONDITION WHEN DEALING WITH CRITICAL INTERRUPTS +==================================================== + + The problematic race condition is as follows: + + Usually, ISRs are allowed to use certain OS + primitives such as e.g., releasing a semaphore. + In order to prevent a context switch from happening + immediately (this would result in the ISR being + suspended), thread-dispatching must be disabled + around execution of the ISR. However, on the + PPC architecture it is neither possible to + atomically disable ALL interrupts nor is it + possible to atomically increment a variable + (the thread-dispatch-disable level). + Hence, the following sequence of events could + occur: + 1) low-priority interrupt (LPI) is taken + 2) before the LPI can increase the + thread-dispatch-disable level or disable + high-priority interupts, a high-priority + interrupt (HPI) happens + 3) HPI increases dispatch-disable level + 4) HPI executes high-priority ISR which e.g., + posts a semaphore + 5) HPI decreases dispatch-disable level and + realizes that a context switch is necessary + 6) context switch is performed since LPI had + not gotten to the point where it could + increase the dispatch-disable level. + At this point, the LPI has been effectively + suspended which means that the low-priority + ISR will not be executed until the task + interupted in 1) is scheduled again! + + The solution to this problem is letting the + first machine instruction of the low-priority + exception handler write a non-zero value to + a variable in memory: + + ee_vector_offset: + + stw r1, ee_lock@sdarel(r13) + .. save some registers etc.. + .. increase thread-dispatch-disable-level + .. clear 'ee_lock' variable + + The earliest a critical exception could interrupt + the 'external' exception handler is after the + 'stw r1, ee_lock@sdarel(r13)' instruction. + + After the HPI decrements the dispatch-disable level + it checks 'ee_lock' and refrains from performing + a context switch if 'ee_lock' is nonzero. Since + the LPI will complete execution subsequently it + will eventually do the context switch. + + For the single-instruction write operation we must + a) write a register that is guaranteed to be + non-zero (e.g., R1 (stack pointer) or R13 + (SVR4 short-data area). + b) use an addressing mode that doesn't require + loading any registers. The short-data area + pointer R13 is appropriate. + diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq_supp.h b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq_supp.h index a2d814aa1b..5af864806b 100644 --- a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq_supp.h +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq_supp.h @@ -48,8 +48,6 @@ extern int BSP_disable_irq_at_pic(const rtems_irq_number irqLine); /* * Initialize the PIC. - * Return nonzero on success, zero on failure (which will be treated - * as fatal by the manager). */ extern int BSP_setup_the_pic(rtems_irq_global_settings* config); @@ -73,6 +71,9 @@ int C_dispatch_irq_handler (struct _BSP_Exception_frame *frame, unsigned int exc * enables interrupts, traverses list of * shared handlers for a given interrupt * and restores original irq level + * + * Note that _ISR_Get_level() & friends are preferable to + * manipulating MSR directly. */ static inline void diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_bspsupp.h b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_bspsupp.h index de2fbb4c02..74b06b1929 100644 --- a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_bspsupp.h +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_bspsupp.h @@ -20,7 +20,7 @@ extern "C" { /********* C-Exception Handlers *********************/ /* API to be used by middleware, */ -/* BSP and application code (if necessary */ +/* BSP and application code (if necessary) */ /****************************************************/ @@ -71,7 +71,7 @@ ppc_exc_get_handler(unsigned vector); /********* Low-level Exception Handlers *************/ -/* This API is used by middleware code */ +/* This part of the API is used by middleware code */ /****************************************************/ diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_test.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_test.c index 600b23b10a..ae38b08392 100644 --- a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_test.c +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_test.c @@ -84,7 +84,7 @@ storegs(ppc_exc_int_regs *p0, ppc_exc_int_regs *p1) " mfctr 0 ;" " stw 0, %5(%0) ;" " lwz 0, %6(%0) ;" - " sc ;" + " trap ;" " stmw 0, %6(%1) ;" " mfcr 0 ;" " stw 0, %2(%1) ;" @@ -129,7 +129,7 @@ clobber() /* must not clobber R13, R1, R2 */ " stw 13, %6(2) ;" " lmw 3, %5(2) ;" - " sc ;" + " trap ;" " stmw 0, %4(2) ;" " mfcr 0 ;" " stw 0, %0(2) ;" @@ -154,7 +154,7 @@ clobber() typedef union { uint32_t u; uint8_t c[4]; } u32_a_t; /* exception handler; adds 1 to all register contents (except r1,r2,r13) */ -void +int handle_clobber_exc(BSP_Exception_frame *f, int vector) { int i; @@ -172,6 +172,8 @@ u32_a_t *p = (u32_a_t*)&f->GPR0; f->EXC_CTR++; f->EXC_XER++; f->EXC_LR++; + f->EXC_SRR0 += 4; + return 0; } @@ -180,7 +182,7 @@ u32_a_t *p = (u32_a_t*)&f->GPR0; * - clobber all registers with 0xaffe0000 + <index> * (except: r1, r2, r13, non-sticky bits in xer) * R2 is clobbered with the address of the pre area. - * - issue 'sc' -> SYS exception + * - issue 'trap' -> PROG exception * - exception handler increments all reg. contents by 1, * stores address of 'pst' area in R2 and returns control * to ppc_exc_clobber(). @@ -197,9 +199,9 @@ u32_a_t *a, *b; for ( i=0; i< sizeof(pre)/sizeof(uint32_t); i++ ) { a[i].u = 0xaffe0000 + i; } - ppc_exc_set_handler(ASM_SYS_VECTOR, handle_clobber_exc); + ppc_exc_set_handler(ASM_PROG_VECTOR, handle_clobber_exc); clobber(); - ppc_exc_set_handler(ASM_SYS_VECTOR, 0); + ppc_exc_set_handler(ASM_PROG_VECTOR, 0); for ( i=0; i< sizeof(pre)/sizeof(uint32_t); i++ ) { switch (i) { case OFF(gpr1)/sizeof(uint32_t): diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c index ada2a3c8c9..5afc2b7c64 100644 --- a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c +++ b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c @@ -88,15 +88,6 @@ void *lr; lr=(LRFrame)_read_LR(); } printk("LR: 0x%08x\n",lr); - { - uint32_t *x = (uint32_t*)sp; - uint32_t top; - asm volatile("mfspr %0, %1":"=r"(top):"i"(SPRG1)); - printk("TOS: 0x%08x\n",top); - while ( x < (uint32_t*)sp->frameLink ) { - printk(" 0x%08x\n",*x++); - } - } for (f=(LRFrame)sp, i=0; f->frameLink && i<STACK_CLAMP; f=f->frameLink) { printk("--^ 0x%08x", (long)(f->frameLink->lr)); if (!(++i%5)) |