diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-03-13 16:24:16 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-03-19 07:00:20 +0100 |
commit | bd1508019cfb219b41da7cb6f1a9895a69c64534 (patch) | |
tree | 6c3f15e745ef11dc3d7c3b706fde54c95dac055d /c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/README | |
parent | bsps/powerpc: Remove unused files (diff) | |
download | rtems-bd1508019cfb219b41da7cb6f1a9895a69c64534.tar.bz2 |
bsps/powerpc: Move exceptions support to bsps
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/README')
-rw-r--r-- | c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/README | 431 |
1 files changed, 0 insertions, 431 deletions
diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/README b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/README deleted file mode 100644 index eb5f9c7cb7..0000000000 --- a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/README +++ /dev/null @@ -1,431 +0,0 @@ - -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 vectors 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 - - rtems_status_code sc = ppc_exc_initialize( - PPC_INTERRUPT_DISABLE_MASK_DEFAULT, - interrupt_stack_begin, - interrupt_stack_size - ); - if (sc != RTEMS_SUCCESSFUL) { - BSP_panic("cannot 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 vectors.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 - - ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/vectors.h - ../../../libcpu/@RTEMS_CPU@/@exceptions@/bspsupport/irq_supp.h - - to 'include_bsp_HEADERS' - - - add - - ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel - ../../../libcpu/@RTEMS_CPU@/@exceptions@/irq_bspsupport.rel - - to 'libbsp_a_LIBADD' - - (irq.c is in a separate '.rel' so that you can get support - for exceptions only). - -CAVEATS -======= - -On classic PPCs, early (and late) parts of the low-level -exception handling code run with the MMU disabled which mean -that the default caching attributes (write-back) are in effect -(thanks to Thomas Doerfler for bringing this up). -The code currently assumes that the MMU translations -for the task and interrupt stacks as well as some -variables in the data-area MATCH THE DEFAULT CACHING -ATTRIBUTES (this assumption also holds for the old code -in libbsp/powepc/shared/vectors ../irq). - -During initialization of exception handling, a crude test -is performed to check if memory seems to have the write-back -attribute. The 'dcbz' instruction should - on most PPCs - cause -an alignment exception if the tested cache-line does not -have this attribute. - -BSPs which entirely disable caching (e.g., by physically -disabling the cache(s)) should set the variable - ppc_exc_cache_wb_check = 0 -prior to calling initialize_exceptions(). -Note that this check does not catch all possible -misconfigurations (e.g., on the 860, the default attribute -is AFAIK [libcpu/powerpc/mpc8xx/mmu/mmu_init.c] set to -'caching-disabled' which is potentially harmful but -this situation is not detected). - - -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 - - 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. - - CAVEAT: unfortunately, this method by itself - is *NOT* enough because raising a low-priority - exception and executing the first instruction - of the handler is *NOT* atomic. Hence, the following - could occur: - - 1) LPI is taken - 2) PC is saved in SRR0, PC is loaded with - address of 'locking instruction' - stw r1, ee_lock@sdarel(r13) - 3) ==> critical interrupt happens - 4) PC (containing address of locking instruction) - is saved in CSRR0 - 5) HPI is dispatched - - For the HPI to correctly handle this situation - it does the following: - - - a) increase thread-dispatch disable level - b) do interrupt work - c) decrease thread-dispatch disable level - d) if ( dispatch-disable level == 0 ) - d1) check ee_lock - d2) check instruction at *CSRR0 - d3) do a context switch if necessary ONLY IF - ee_lock is NOT set AND *CSRR0 is NOT the - 'locking instruction' - - this works because the address of 'ee_lock' - is embedded in the locking instruction - 'stw r1, ee_lock@sdarel(r13)' and because the - registers r1/r13 have a special purpose - (stack-pointer, SDA-pointer). Hence it is safe - to assume that the particular instruction - 'stw r1,ee_lock&sdarel(r13)' never occurs - anywhere else. - - Another note: this algorithm also makes sure - that ONLY nested ASYNCHRONOUS interrupts which - enable/disable thread-dispatching and check if - thread-dispatching is required before returning - control engage in this locking protocol. It is - important that when a critical, asynchronous - interrupt interrupts a 'synchronous' exception - (which does not disable thread-dispatching) - the thread-dispatching operation upon return of - the HPI is NOT deferred (because the synchronous - handler would not, eventually, check for a - dispatch requirement). - - And one more note: We never want to disable - machine-check exceptions to avoid a checkstop. - This means that we cannot use enabling/disabling - this type of exception for protection of critical - OS data structures. - Therefore, calling OS primitives from a asynchronous - machine-check handler is ILLEGAL and not supported. - Since machine-checks can happen anytime it is not - legal to test if a deferred context switch should - be performed when the asynchronous machine-check - handler returns (since _Context_Switch_is_necessary - could have been set by a IRQ-protected section of - code that was hit by the machine-check). - Note that synchronous machine-checks can legally - use OS primitives and currently there are no - asynchronous machine-checks defined. - - Epilogue: - - You have to disable all asynchronous exceptions which may cause a context - switch before the restoring of the SRRs and the RFI. Reason: - - Suppose we are in the epilogue code of an EE between the move to SRRs and - the RFI. Here EE is disabled but CE is enabled. Now a CE happens. The - handler decides that a thread dispatch is necessary. The CE checks if - this is possible: - - o The thread dispatch disable level is 0, because the EE has already - decremented it. - o The EE lock variable is cleared. - o The EE executes not the first instruction. - - Hence a thread dispatch is allowed. The CE issues a context switch to a - task with EE enabled (for example a task waiting for a semaphore). Now a - EE happens and the current content of the SRRs is lost. |