203 lines
7.1 KiB
C
203 lines
7.1 KiB
C
/*
|
|
* 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);
|
|
}
|
|
|
|
void _common_dynamic_exc_handler(uint32_t stub_idx, NANO_ESF *pEsf)
|
|
{
|
|
exc_handlers[stub_idx](pEsf);
|
|
}
|
|
|
|
#endif /* ALL_DYN_EXC_STUBS */
|
|
|