summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTill Straumann <strauman@slac.stanford.edu>2007-12-10 07:06:53 +0000
committerTill Straumann <strauman@slac.stanford.edu>2007-12-10 07:06:53 +0000
commitbf5742a63081a2d8ed3051b3056e4548b044eeee (patch)
treec54b378426651b30dfb1cfe230437a40e126e553
parent2007-12-08 Till Straumann <strauman@slac.stanford.edu> (diff)
downloadrtems-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.
-rw-r--r--c/src/lib/libcpu/powerpc/ChangeLog10
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/README311
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq_supp.h5
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_bspsupp.h4
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_test.c14
-rw-r--r--c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/vectors_init.c9
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))