x86: allow IDT vectors to be task gates
This has one use-case: configuring the double-fault #DF exception handler to do an IA task switch to a special IA task with a known good stack, such that we can dump diagnostic information and then panic. Will be used for stack overflow detection in kernel mode, as otherwise the CPU will triple-fault and reset. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
ddf9f4be31
commit
8a102e44ed
3 changed files with 71 additions and 11 deletions
|
@ -18,6 +18,7 @@
|
|||
".long -1\n\t" /* ISR_LIST.priority */ \
|
||||
".long " STRINGIFY(vector) "\n\t" /* ISR_LIST.vec */ \
|
||||
".long 0\n\t" /* ISR_LIST.dpl */ \
|
||||
".long 0\n\t" /* ISR_LIST.tss */ \
|
||||
".popsection\n\t" \
|
||||
|
||||
/* Extra preprocessor indirection to ensure arguments get expanded before
|
||||
|
|
|
@ -76,6 +76,12 @@ typedef struct s_isrList {
|
|||
unsigned int vec;
|
||||
/** Privilege level associated with ISR/stub */
|
||||
unsigned int dpl;
|
||||
|
||||
/** If nonzero, specifies a TSS segment selector. Will configure
|
||||
* a task gate instead of an interrupt gate. fnc parameter will be
|
||||
* ignored
|
||||
*/
|
||||
unsigned int tss;
|
||||
} ISR_LIST;
|
||||
|
||||
|
||||
|
@ -106,8 +112,39 @@ typedef struct s_isrList {
|
|||
#define NANO_CPU_INT_REGISTER(r, n, p, v, d) \
|
||||
static ISR_LIST __attribute__((section(".intList"))) \
|
||||
__attribute__((used)) MK_ISR_NAME(r) = \
|
||||
{&r, n, p, v, d}
|
||||
{ \
|
||||
.fnc = &(r), \
|
||||
.irq = (n), \
|
||||
.priority = (p), \
|
||||
.vec = (v), \
|
||||
.dpl = (d), \
|
||||
.tss = 0 \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connect an IA hardware task to an interrupt vector
|
||||
*
|
||||
* This is very similar to NANO_CPU_INT_REGISTER but instead of connecting
|
||||
* a handler function, the interrupt will induce an IA hardware task
|
||||
* switch to another hardware task instead.
|
||||
*
|
||||
* @param tss_p GDT/LDT segment selector for the TSS representing the task
|
||||
* @param irq_p IRQ number
|
||||
* @param priority_p IRQ priority
|
||||
* @param vec_p Interrupt vector
|
||||
* @param dpl_p Descriptor privilege level
|
||||
*/
|
||||
#define _X86_IDT_TSS_REGISTER(tss_p, irq_p, priority_p, vec_p, dpl_p) \
|
||||
static ISR_LIST __attribute__((section(".intList"))) \
|
||||
__attribute__((used)) MK_ISR_NAME(r) = \
|
||||
{ \
|
||||
.fnc = NULL, \
|
||||
.irq = (irq_p), \
|
||||
.priority = (priority_p), \
|
||||
.vec = (vec_p), \
|
||||
.dpl = (dpl_p), \
|
||||
.tss = (tss_p) \
|
||||
}
|
||||
|
||||
/**
|
||||
* Code snippets for populating the vector ID and priority into the intList
|
||||
|
@ -172,6 +209,7 @@ typedef struct s_isrList {
|
|||
".long %c[priority]\n\t" /* ISR_LIST.priority */ \
|
||||
".long %c[vector]\n\t" /* ISR_LIST.vec */ \
|
||||
".long 0\n\t" /* ISR_LIST.dpl */ \
|
||||
".long 0\n\t" /* ISR_LIST.tss */ \
|
||||
".popsection\n\t" \
|
||||
".pushsection .text.irqstubs\n\t" \
|
||||
".global %c[isr]_irq%c[irq]_stub\n\t" \
|
||||
|
|
|
@ -27,7 +27,7 @@ def error(text):
|
|||
sys.exit(1)
|
||||
|
||||
# See Section 6.11 of the Intel Architecture Software Developer's Manual
|
||||
irq_gate_desc_format = "<HHBBH"
|
||||
gate_desc_format = "<HHBBH"
|
||||
|
||||
def create_irq_gate(handler, dpl):
|
||||
present = 1
|
||||
|
@ -37,14 +37,34 @@ def create_irq_gate(handler, dpl):
|
|||
offset_hi = handler >> 16
|
||||
offset_lo = handler & 0xFFFF
|
||||
|
||||
data = struct.pack(irq_gate_desc_format, offset_lo, KERNEL_CODE_SEG, 0,
|
||||
data = struct.pack(gate_desc_format, offset_lo, KERNEL_CODE_SEG, 0,
|
||||
type_attr, offset_hi)
|
||||
return data
|
||||
|
||||
|
||||
def create_task_gate(tss, dpl):
|
||||
present = 1
|
||||
gate_type = 0x5 # 32-bit task gate
|
||||
type_attr = gate_type | (dpl << 5) | (present << 7)
|
||||
|
||||
data = struct.pack(gate_desc_format, 0, tss, 0, type_attr, 0)
|
||||
return data
|
||||
|
||||
|
||||
def create_idt_binary(idt_config, filename):
|
||||
with open(filename, "wb") as fp:
|
||||
for handler, dpl in idt_config:
|
||||
data = create_irq_gate(handler, dpl)
|
||||
for handler, tss, dpl in idt_config:
|
||||
if handler and tss:
|
||||
error("entry specifies both handler function and tss")
|
||||
|
||||
if not handler and not tss:
|
||||
error("entry does not specify either handler or tss")
|
||||
|
||||
if handler:
|
||||
data = create_irq_gate(handler, dpl)
|
||||
else:
|
||||
data = create_task_gate(tss, dpl)
|
||||
|
||||
fp.write(data)
|
||||
|
||||
map_fmt = "<B"
|
||||
|
@ -83,7 +103,7 @@ def setup_idt(spur_code, spur_nocode, intlist, max_vec, max_irq):
|
|||
vectors = [None for i in range(max_vec)]
|
||||
|
||||
# Pass 1: sanity check and set up hard-coded interrupt vectors
|
||||
for handler, irq, prio, vec, dpl in intlist:
|
||||
for handler, irq, prio, vec, dpl, tss in intlist:
|
||||
if vec == -1:
|
||||
if prio == -1:
|
||||
error("entry does not specify vector or priority level")
|
||||
|
@ -96,11 +116,11 @@ def setup_idt(spur_code, spur_nocode, intlist, max_vec, max_irq):
|
|||
if vectors[vec] != None:
|
||||
error("Multiple assignments for vector %d" % vec)
|
||||
|
||||
vectors[vec] = (handler, dpl)
|
||||
vectors[vec] = (handler, tss, dpl)
|
||||
update_irq_vec_map(irq_vec_map, irq, vec, max_irq)
|
||||
|
||||
# Pass 2: set up priority-based interrupt vectors
|
||||
for handler, irq, prio, vec, dpl in intlist:
|
||||
for handler, irq, prio, vec, dpl, tss in intlist:
|
||||
if vec != -1:
|
||||
continue
|
||||
|
||||
|
@ -114,7 +134,7 @@ def setup_idt(spur_code, spur_nocode, intlist, max_vec, max_irq):
|
|||
if vec == -1:
|
||||
error("can't find a free vector in priority level %d" % prio)
|
||||
|
||||
vectors[vec] = (handler, dpl)
|
||||
vectors[vec] = (handler, tss, dpl)
|
||||
update_irq_vec_map(irq_vec_map, irq, vec, max_irq)
|
||||
|
||||
# Pass 3: fill in unused vectors with spurious handler at dpl=0
|
||||
|
@ -127,7 +147,7 @@ def setup_idt(spur_code, spur_nocode, intlist, max_vec, max_irq):
|
|||
else:
|
||||
handler = spur_nocode
|
||||
|
||||
vectors[i] = (handler, 0)
|
||||
vectors[i] = (handler, 0, 0)
|
||||
|
||||
return vectors, irq_vec_map
|
||||
|
||||
|
@ -154,9 +174,10 @@ intlist_header_fmt = "<IIi"
|
|||
# int32_t priority;
|
||||
# int32_t vector_id;
|
||||
# int32_t dpl;
|
||||
# int32_t tss;
|
||||
# };
|
||||
|
||||
intlist_entry_fmt = "<Iiiii"
|
||||
intlist_entry_fmt = "<Iiiiii"
|
||||
|
||||
def get_intlist(elf):
|
||||
intdata = elf.get_section_by_name("intList").data()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue