/* * Copyright (c) 2012-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 IA-32 IDT Entry code * * This header file provides code for constructing an IA-32 interrupt * descriptor. */ #ifndef _IDTENT_H #define _IDTENT_H #ifdef __cplusplus extern "C" { #endif /** * Bitmask used to determine which exceptions result in an error code being * pushed onto the stack. The following exception vectors push an error code: * * Vector Mnemonic Description * ------ ------- ---------------------- * 8 #DF Double Fault * 10 #TS Invalid TSS * 11 #NP Segment Not Present * 12 #SS Stack Segment Fault * 13 #GP General Protection Fault * 14 #PF Page Fault * 17 #AC Alignment Check */ #define _EXC_ERROR_CODE_FAULTS 0x27d00 /** * @brief Interrupt Descriptor Table (IDT) entry structure * * See section 6.11 in x86 CPU manual vol. 3A */ typedef struct idt_entry { union { uint16_t offset_low; uint16_t reserved_task_gate_0; }; uint16_t segment_selector; union { struct { uint8_t reserved:5; uint8_t always_0_0:3; }; uint8_t reserved_task_gate_1; }; uint8_t type:3; /* task:101, irq:110, trap:111 */ uint8_t gate_size:1; /* size of gate, 1: 32-bit, 0:16-bit */ uint8_t always_0_1:1; uint8_t dpl:2; /* Descriptor privilege level */ uint8_t present:1; /* present yes/no */ union { uint16_t offset_high; uint16_t reserved_task_gate_2; }; } __packed IDT_ENTRY; /** * * @brief Create an IDT entry * * This routine creates an interrupt-gate descriptor at the location defined by * @a pIdtEntry. The entry is created such that @a routine is invoked when an * interrupt vector is asserted. The @a dpl argument specifies the privilege * level for the interrupt-gate descriptor; (hardware) interrupts and exceptions * should specify a level of 0, whereas handlers for user-mode software generated * interrupts should specify 3. * * @param pIdtEntry Pointer to where the entry is be built * @param routine Routine to call when interrupt occurs * @param dpl Private level for interrupt descriptor * @return N/A * * INTERNAL * This is a shared routine between the IA-32 nanokernel runtime code and the * genIdt host tool code. It is done this way to keep the two sides in sync. * * The runtime passes a pointer directly to the IDT entry to update whereas the * host side simply passes a pointer to a local variable. * */ static inline void _IdtEntCreate(unsigned long long *pIdtEntry, void (*routine)(void *), unsigned int dpl) { unsigned long *pIdtEntry32 = (unsigned long *)pIdtEntry; pIdtEntry32[0] = (KERNEL_CODE_SEG_SELECTOR << 16) | ((unsigned short)(unsigned int)routine); /* * The constant 0x8e00 results from the following: * * Segment Present = 1 * * Descriptor Privilege Level (DPL) = 0 (dpl arg will be or'ed in) * * Interrupt Gate Indicator = 0xE * The _IntEnt() and _ExcEnt() stubs assume that an interrupt-gate * descriptor is used, and thus they do not issue a 'cli' instruction * given that the processor automatically clears the IF flag when * accessing the interrupt/exception handler via an interrupt-gate. * * Size of Gate (D) = 1 * * Reserved = 0 */ pIdtEntry32[1] = ((unsigned int) routine & 0xffff0000) | (0x8e00 | (dpl << 13)); } #ifdef __cplusplus } #endif #endif /* _IDTENT_H */