Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | /* * 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 */ |