| /* |
| * Copyright (c) 2010-2014 Wind River Systems, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @file |
| * @brief Exception management support for IA-32 arch |
| * |
| * This module provides routines to manage exceptions (synchronous interrupts) |
| * on the IA-32 architecture. |
| * |
| * This module provides the public routine nanoCpuExcConnect(). |
| * |
| * INTERNAL |
| * An exception is defined as a synchronous interrupt, i.e. an interrupt |
| * asserted as a direct result of program execution as opposed to a |
| * hardware device asserting an interrupt. |
| * |
| * Many (but not all) exceptions are handled by an "exception stub" whose code |
| * is generated by the system itself. The stub performs various actions before |
| * and after invoking the application (or operating system) specific exception |
| * handler; for example, a thread or ISR context save is performed prior to |
| * invoking the exception handler. |
| * |
| * The IA-32 code that makes up a "full" exception stub is shown below. A full |
| * exception stub is one that pushes a dummy error code at the start of |
| * exception processing. Exception types where the processor automatically |
| * pushes an error code when handling an exception utilize similar exception |
| * stubs, however the first instruction is omitted. The use of the dummy error |
| * code means that _ExcEnt() and _ExcExit() do not have to worry about whether |
| * an error code is present on the stack or not. |
| * |
| * |
| * 0x00 pushl $0 /@ push dummy error code @/ |
| * Machine code: 0x68, 0x00, 0x00, 0x00, 0x00 |
| * |
| * 0x05 call _ExcEnt /@ inform kernel of exception @/ |
| * Machine code: 0xe8, 0x00, 0x00, 0x00, 0x00 |
| * |
| * 0x0a call ExcHandler /@ invoke exception handler @/ |
| * Machine code: 0xe8, 0x00, 0x00, 0x00, 0x00 |
| * |
| * /@ _ExcExit() will adjust the stack to discard the error code @/ |
| * |
| * 0x0f jmp _ExcExit /@ restore thread context @/ |
| * Machine code: 0xe9, 0x00, 0x00, 0x00, 0x00 |
| * |
| * NOTE: Be sure to update the arch specific definition of the _EXC_STUB_SIZE |
| * macro to reflect the size of the full exception stub (as shown above). |
| * The _EXC_STUB_SIZE macro is defined in arch/x86/include/nano_private.h. |
| */ |
| |
| |
| #include <nanokernel.h> |
| #include <nano_private.h> |
| #include <misc/__assert.h> |
| |
| #if ALL_DYN_EXC_STUBS > 0 |
| |
| static void (*exc_handlers[ALL_DYN_EXC_STUBS])(NANO_ESF *pEsf); |
| |
| static unsigned int next_exc_stub; |
| static unsigned int next_exc_noerr_stub; |
| |
| extern void *_DynExcStubsBegin; |
| extern void *_DynExcStubsNoErrBegin; |
| |
| void _NanoCpuExcConnectAtDpl(unsigned int vector, |
| void (*routine)(NANO_ESF * pEsf), |
| unsigned int dpl); |
| |
| /** |
| * |
| * @brief Connect a C routine to an exception |
| * |
| * This routine connects an exception handler coded in C to the specified |
| * interrupt vector. An exception is defined as a synchronous interrupt, i.e. |
| * an interrupt asserted as a direct result of program execution as opposed |
| * to a hardware device asserting an interrupt. |
| * |
| * When the exception specified by <vector> is asserted, the current thread |
| * is saved on the current stack, i.e. a switch to some other stack is not |
| * performed, followed by executing <routine> which has the following signature: |
| * |
| * void (*routine) (NANO_ESF *pEsf) |
| * |
| * The <pExcStubMem> argument points to memory that the system can use to |
| * synthesize the exception stub that calls <routine>. The memory need not be |
| * initialized, but must be persistent (i.e. it cannot be on the caller's stack). |
| * Declaring a global or static variable of type NANO_EXC_STUB will provide a |
| * suitable area of the proper size. |
| * |
| * The handler is connected via an interrupt-gate descriptor having a |
| * descriptor privilege level (DPL) equal to zero. |
| * |
| * @return N/A |
| * |
| * INTERNAL |
| * The function prototype for nanoCpuExcConnect() only exists in nano_private.h, |
| * in other words, it's still considered private since the definitions for |
| * the NANO_ESF structures have not been completed. |
| */ |
| |
| void nanoCpuExcConnect(unsigned int vector, /* interrupt vector: 0 to 255 on |
| * IA-32 |
| */ |
| void (*routine)(NANO_ESF * pEsf)) |
| { |
| _NanoCpuExcConnectAtDpl(vector, routine, 0); |
| } |
| |
| /** |
| * |
| * @brief Connect a C routine to an exception |
| * |
| * This routine connects an exception handler coded in C to the specified |
| * interrupt vector. An exception is defined as a synchronous interrupt, i.e. |
| * an interrupt asserted as a direct result of program execution as opposed |
| * to a hardware device asserting an interrupt. |
| * |
| * When the exception specified by <vector> is asserted, the current thread |
| * is saved on the current stack, i.e. a switch to some other stack is not |
| * performed, followed by executing <routine> which has the following signature: |
| * |
| * void (*routine) (NANO_ESF *pEsf) |
| * |
| * The <pExcStubMem> argument points to memory that the system can use to |
| * synthesize the exception stub that calls <routine>. The memory need not be |
| * initialized, but must be persistent (i.e. it cannot be on the caller's stack). |
| * Declaring a global or static variable of type NANO_EXC_STUB will provide a |
| * suitable area of the proper size. |
| * |
| * The handler is connected via an interrupt-gate descriptor having the supplied |
| * descriptor privilege level (DPL). |
| * |
| * WARNING memory will leak if the vector was already connected to a different |
| * dynamic handler |
| * |
| * @return N/A |
| * |
| * INTERNAL |
| * The function prototype for nanoCpuExcConnect() only exists in nano_private.h, |
| * in other words, it's still considered private since the definitions for |
| * the NANO_ESF structures have not been completed. |
| */ |
| |
| void _NanoCpuExcConnectAtDpl( |
| unsigned int vector, /* interrupt vector: 0 to 255 on IA-32 */ |
| void (*routine)(NANO_ESF * pEsf), |
| unsigned int dpl /* priv level for interrupt-gate descriptor */ |
| ) |
| { |
| int stub_idx, limit, offset; |
| unsigned int *next_p; |
| void *base_ptr; |
| |
| /* |
| * Check to see if this exception type takes an error code, we |
| * have different stubs for that |
| */ |
| if (((1 << vector) & _EXC_ERROR_CODE_FAULTS) == 0) { |
| base_ptr = &_DynExcStubsNoErrBegin; |
| next_p = &next_exc_noerr_stub; |
| limit = CONFIG_NUM_DYNAMIC_EXC_NOERR_STUBS; |
| offset = CONFIG_NUM_DYNAMIC_EXC_STUBS; |
| } else { |
| base_ptr = &_DynExcStubsBegin; |
| next_p = &next_exc_stub; |
| limit = CONFIG_NUM_DYNAMIC_EXC_STUBS; |
| offset = 0; |
| } |
| |
| stub_idx = _stub_alloc(next_p, limit); |
| __ASSERT(stub_idx != -1, "No available execption stubs"); |
| /* |
| * We have the same array for both error code and non error code |
| * exceptions, the second half is reserved for the non error code |
| * handlers |
| */ |
| exc_handlers[stub_idx + offset] = routine; |
| _IntVecSet(vector, _get_dynamic_stub(stub_idx, base_ptr), dpl); |
| } |
| |
| #if CONFIG_X86_IAMCU |
| void _common_dynamic_exc_handler(NANO_ESF *pEsf, uint32_t stub_idx) |
| #else |
| void _common_dynamic_exc_handler(uint32_t stub_idx, NANO_ESF *pEsf) |
| #endif |
| { |
| exc_handlers[stub_idx](pEsf); |
| } |
| |
| #endif /* ALL_DYN_EXC_STUBS */ |
| |