arch/x86: add nested interrupt support to Intel64
Add support for multiple IRQ stacks and interrupt nesting. Signed-off-by: Charles E. Youse <charles.youse@intel.com>
This commit is contained in:
parent
cdb9ac3895
commit
2bb59fc84e
3 changed files with 66 additions and 16 deletions
|
@ -32,4 +32,10 @@ config EXCEPTION_STACK_SIZE
|
||||||
support limited call-tree depth and must fit into the low core,
|
support limited call-tree depth and must fit into the low core,
|
||||||
so they are typically smaller than the ISR stacks.
|
so they are typically smaller than the ISR stacks.
|
||||||
|
|
||||||
|
config ISR_DEPTH
|
||||||
|
int "Maximum IRQ nesting depth"
|
||||||
|
default 4
|
||||||
|
help
|
||||||
|
The more nesting allowed, the more room is required for IRQ stacks.
|
||||||
|
|
||||||
endif # X86_LONGMODE
|
endif # X86_LONGMODE
|
||||||
|
|
|
@ -30,7 +30,7 @@ void *x86_irq_args[NR_IRQ_VECTORS];
|
||||||
* Interrupt stack.
|
* Interrupt stack.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char __aligned(STACK_ALIGN) ist[CONFIG_ISR_STACK_SIZE];
|
char __aligned(STACK_ALIGN) ist[CONFIG_ISR_DEPTH][CONFIG_ISR_STACK_SIZE];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a free IRQ vector at the specified priority, or return -1 if none left.
|
* Find a free IRQ vector at the specified priority, or return -1 if none left.
|
||||||
|
|
|
@ -233,17 +233,17 @@ gdt48:
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
tss: .long 0
|
tss: .long 0
|
||||||
.long 0, 0 /* RSP0 */
|
rsp0: .long 0, 0
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long (ist + CONFIG_ISR_STACK_SIZE), 0 /* IST1 */
|
ist1: .long (ist + CONFIG_ISR_STACK_SIZE), 0
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long (exception_stack + CONFIG_EXCEPTION_STACK_SIZE), 0 /* IST7 */
|
ist7: .long (exception_stack + CONFIG_EXCEPTION_STACK_SIZE), 0
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long 0
|
.long 0
|
||||||
|
|
||||||
|
@ -370,8 +370,8 @@ EXCEPT (24); EXCEPT (25); EXCEPT (26); EXCEPT (27)
|
||||||
EXCEPT (28); EXCEPT (29); EXCEPT (30); EXCEPT (31)
|
EXCEPT (28); EXCEPT (29); EXCEPT (30); EXCEPT (31)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When we arrive at 'irq' from one of the IRQ(X)
|
* When we arrive at 'irq' from one of the IRQ(X) stubs,
|
||||||
* stubs, we're on IST1 and it contains:
|
* we're on the "freshest" IRQ stack and it contains:
|
||||||
*
|
*
|
||||||
* SS
|
* SS
|
||||||
* RSP
|
* RSP
|
||||||
|
@ -380,11 +380,6 @@ EXCEPT (28); EXCEPT (29); EXCEPT (30); EXCEPT (31)
|
||||||
* RIP
|
* RIP
|
||||||
* (vector number - IV_IRQS) <-- RSP points here
|
* (vector number - IV_IRQS) <-- RSP points here
|
||||||
* RSI <-- we push this on entry
|
* RSI <-- we push this on entry
|
||||||
*
|
|
||||||
* Our job is to save the state of the interrupted thread so that
|
|
||||||
* __resume can restart it where it left off, then service the IRQ.
|
|
||||||
* We can then EOI the local APIC and head out via __resume - which
|
|
||||||
* may resume a different thread, if the scheduler decided to preempt.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.globl x86_irq_funcs /* see irq_manage.c .. */
|
.globl x86_irq_funcs /* see irq_manage.c .. */
|
||||||
|
@ -393,11 +388,42 @@ EXCEPT (28); EXCEPT (29); EXCEPT (30); EXCEPT (31)
|
||||||
irq:
|
irq:
|
||||||
pushq %rsi
|
pushq %rsi
|
||||||
movq $_kernel, %rsi
|
movq $_kernel, %rsi
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bump the IRQ nesting count and move to the next IRQ stack.
|
||||||
|
* That's sufficient to safely re-enable interrupts, so if we
|
||||||
|
* haven't reached the maximum nesting depth yet, do it.
|
||||||
|
*/
|
||||||
|
|
||||||
incl _kernel_offset_to_nested(%rsi)
|
incl _kernel_offset_to_nested(%rsi)
|
||||||
|
addq $CONFIG_ISR_STACK_SIZE, ist1
|
||||||
|
cmpl $CONFIG_ISR_DEPTH, _kernel_offset_to_nested(%rsi)
|
||||||
|
jz 1f
|
||||||
|
sti
|
||||||
|
1: cmpl $1, _kernel_offset_to_nested(%rsi)
|
||||||
|
je irq_enter_unnested
|
||||||
|
|
||||||
|
irq_enter_nested: /* Nested IRQ: dump register state to stack. */
|
||||||
|
pushq %rcx
|
||||||
|
movq 16(%rsp), %rcx /* RCX = vector */
|
||||||
|
movq %rax, 16(%rsp) /* looks like we pushed RAX, not the vector */
|
||||||
|
pushq %rdx
|
||||||
|
pushq %rbx
|
||||||
|
pushq %rdi
|
||||||
|
pushq %rbp
|
||||||
|
pushq %r8
|
||||||
|
pushq %r9
|
||||||
|
pushq %r10
|
||||||
|
pushq %r11
|
||||||
|
pushq %r12
|
||||||
|
pushq %r13
|
||||||
|
pushq %r14
|
||||||
|
pushq %r15
|
||||||
|
jmp irq_dispatch
|
||||||
|
|
||||||
|
irq_enter_unnested: /* Not nested: dump state to thread struct for __resume */
|
||||||
movq _kernel_offset_to_current(%rsi), %rsi
|
movq _kernel_offset_to_current(%rsi), %rsi
|
||||||
|
|
||||||
andb $(~_THREAD_SWAPPED), _thread_offset_to_thread_state(%rsi)
|
andb $(~_THREAD_SWAPPED), _thread_offset_to_thread_state(%rsi)
|
||||||
|
|
||||||
movq %rbx, _thread_offset_to_rbx(%rsi)
|
movq %rbx, _thread_offset_to_rbx(%rsi)
|
||||||
movq %rbp, _thread_offset_to_rbp(%rsi)
|
movq %rbp, _thread_offset_to_rbp(%rsi)
|
||||||
movq %r12, _thread_offset_to_r12(%rsi)
|
movq %r12, _thread_offset_to_r12(%rsi)
|
||||||
|
@ -405,7 +431,6 @@ irq:
|
||||||
movq %r14, _thread_offset_to_r14(%rsi)
|
movq %r14, _thread_offset_to_r14(%rsi)
|
||||||
movq %r15, _thread_offset_to_r15(%rsi)
|
movq %r15, _thread_offset_to_r15(%rsi)
|
||||||
movq %rax, _thread_offset_to_rax(%rsi)
|
movq %rax, _thread_offset_to_rax(%rsi)
|
||||||
|
|
||||||
movq %rcx, _thread_offset_to_rcx(%rsi)
|
movq %rcx, _thread_offset_to_rcx(%rsi)
|
||||||
movq %rdx, _thread_offset_to_rdx(%rsi)
|
movq %rdx, _thread_offset_to_rdx(%rsi)
|
||||||
movq %rdi, _thread_offset_to_rdi(%rsi)
|
movq %rdi, _thread_offset_to_rdi(%rsi)
|
||||||
|
@ -413,7 +438,6 @@ irq:
|
||||||
movq %r9, _thread_offset_to_r9(%rsi)
|
movq %r9, _thread_offset_to_r9(%rsi)
|
||||||
movq %r10, _thread_offset_to_r10(%rsi)
|
movq %r10, _thread_offset_to_r10(%rsi)
|
||||||
movq %r11, _thread_offset_to_r11(%rsi)
|
movq %r11, _thread_offset_to_r11(%rsi)
|
||||||
|
|
||||||
popq %rax /* RSI */
|
popq %rax /* RSI */
|
||||||
movq %rax, _thread_offset_to_rsi(%rsi)
|
movq %rax, _thread_offset_to_rsi(%rsi)
|
||||||
popq %rcx /* vector number */
|
popq %rcx /* vector number */
|
||||||
|
@ -426,6 +450,7 @@ irq:
|
||||||
movq %rax, _thread_offset_to_rsp(%rsi)
|
movq %rax, _thread_offset_to_rsp(%rsi)
|
||||||
popq %rax /* SS: discard */
|
popq %rax /* SS: discard */
|
||||||
|
|
||||||
|
irq_dispatch:
|
||||||
movq x86_irq_funcs(,%rcx,8), %rbx
|
movq x86_irq_funcs(,%rcx,8), %rbx
|
||||||
movq x86_irq_args(,%rcx,8), %rdi
|
movq x86_irq_args(,%rcx,8), %rdi
|
||||||
call *%rbx
|
call *%rbx
|
||||||
|
@ -438,9 +463,28 @@ irq:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
movq $_kernel, %rsi
|
movq $_kernel, %rsi
|
||||||
|
cli
|
||||||
|
subq $CONFIG_ISR_STACK_SIZE, ist1
|
||||||
decl _kernel_offset_to_nested(%rsi)
|
decl _kernel_offset_to_nested(%rsi)
|
||||||
|
jz __resume /* not nested, just __resume (might change threads) */
|
||||||
|
|
||||||
jmp __resume
|
irq_exit_nested:
|
||||||
|
popq %r15
|
||||||
|
popq %r14
|
||||||
|
popq %r13
|
||||||
|
popq %r12
|
||||||
|
popq %r11
|
||||||
|
popq %r10
|
||||||
|
popq %r9
|
||||||
|
popq %r8
|
||||||
|
popq %rbp
|
||||||
|
popq %rdi
|
||||||
|
popq %rbx
|
||||||
|
popq %rdx
|
||||||
|
popq %rcx
|
||||||
|
popq %rsi
|
||||||
|
popq %rax
|
||||||
|
iretq
|
||||||
|
|
||||||
#define IRQ(nr) vector_ ## nr: pushq $(nr - IV_IRQS); jmp irq
|
#define IRQ(nr) vector_ ## nr: pushq $(nr - IV_IRQS); jmp irq
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue