/* * 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 #include #include #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 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 which has the following signature: * * void (*routine) (NANO_ESF *pEsf) * * The argument points to memory that the system can use to * synthesize the exception stub that calls . 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 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 which has the following signature: * * void (*routine) (NANO_ESF *pEsf) * * The argument points to memory that the system can use to * synthesize the exception stub that calls . 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); } void _common_dynamic_exc_handler(uint32_t stub_idx, NANO_ESF *pEsf) { exc_handlers[stub_idx](pEsf); } #endif /* ALL_DYN_EXC_STUBS */