Skip to content

Commit 7e728a8

Browse files
irq-x86: irq stack allocation
Signed-off-by: Leon <[email protected]>
1 parent d9291d1 commit 7e728a8

File tree

1 file changed

+70
-3
lines changed

1 file changed

+70
-3
lines changed

kernel/irq_x86-64.md

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,73 @@ struct irq_stack {
9797
2. 软件保存被中断进程的通用目的寄存器在当前进程栈,然后清除 GPRs 的内容
9898
3. 软件将栈切换到预设好的 per-CPU 的中断栈,栈的地址由 per-CPU 变量来记录,类似`moveq PER_CPU_VAR(irq_stack_ptr), %rsp`
9999

100+
### 中断栈的分配和初始化
101+
```cpp
102+
start_kernel()
103+
-> init_IRQ()
104+
-> irq_init_percpu_irqstack(smp_processor_id())
105+
-> map_irq_stack()
106+
// arch/x86/kernel/x86_init.c
107+
-> x86_init.irqs.intr_init()
108+
// arch/x86/kernel/irqinit.c
109+
=> native_init_IRQ()
110+
-> idt_setup_apic_and_irq_gates()
111+
```
112+
* arch/x86/kernel/irq_64.c
113+
```c
114+
DEFINE_PER_CPU_PAGE_ALIGNED(struct irq_stack, irq_stack_backing_store) __visible;
115+
DECLARE_INIT_PER_CPU(irq_stack_backing_store);
116+
...
117+
#ifdef CONFIG_VMAP_STACK
118+
...
119+
#else
120+
static int map_irq_stack(unsigned int cpu)
121+
{
122+
void *va = per_cpu_ptr(&irq_stack_backing_store, cpu);
123+
124+
per_cpu(hardirq_stack_ptr, cpu) = va + IRQ_STACK_SIZE;
125+
return 0;
126+
}
127+
#endif
128+
```
129+
* 因此`hardirq_stack_ptr`指向的是栈顶(高地址)
130+
131+
### 切换中断栈
132+
* v5.4
133+
```cpp
134+
irq_entries_start
135+
jmp common_interrupt
136+
call interrupt_entry
137+
ENTER_IRQ_STACK old_rsp=%rdi save_ret=1
138+
movq \old_rsp, PER_CPU_VAR(irq_stack_backing_store + IRQ_STACK_SIZE - 8)
139+
movq PER_CPU_VAR(hardirq_stack_ptr), %rsp
140+
```
141+
* v6.0
142+
```cpp
143+
irq_entries_start
144+
jmp asm_common_interrupt
145+
call common_interrupt
146+
-> irqentry_state_t state = irqentry_enter(regs);
147+
u32 vector = (u32)(u8)error_code;
148+
run_irq_on_irqstack_cond(__##func, regs, vector)
149+
call_on_irqstack_cond(func, regs, ASM_CALL_IRQ, IRQ_CONSTRAINTS, regs, vector);
150+
call_on_irqstack(func, asm_call, constr);
151+
call_on_stack(__this_cpu_read(hardirq_stack_ptr), func, asm_call, argconstr)
152+
register void *tos asm("r11");
153+
tos = ((void *)(stack));
154+
"movq %%rsp, (%[tos]) \n"
155+
"movq %[tos], %%rsp \n"
156+
asm_call
157+
=> __common_interrupt()
158+
-> irqentry_exit(regs, state)
159+
```
160+
* 在这个 commit 后中断栈的使用发生了一些变化,
161+
* [[patch V2 00_13] x86_irq_64 Inline irq stack switching](https://lore.kernel.org/all/[email protected]/)
162+
* [x86/entry: Convert system vectors to irq stack macro](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=569dd8b4eb7ef666b467c41b8e8e4f2820d07f67)
163+
* 对于用户程序被中断或者已经有中断正在 per-CPU 的中断栈上被处理的情况,直接调用`__common_interrupt()`
164+
* 中断的是用户程序,用的应该是 trampoline stack
165+
* 已经有中断正在 per-CPU 中断栈上被处理,则使用 *当前内核栈*
166+
100167
## 异常栈
101168
* 对于无需进行 privilege-level 变化的情况,比如异常发生时 CPU 运行在内核态
102169
1. CPU 依然会将被中断进程的`ss``rsp``rflags``cs``rip``error code`等压入 *当前内核栈*
@@ -239,7 +306,7 @@ start_kernel()
239306
-> trap_init()
240307
-> cpu_init_exception_handling() /* Initialize TSS before setting up traps so ISTs work */
241308
```
242-
* 通过以下方式设定 PerCPU 的 `cpu_tss_rw` 的 `x86_tss.ist[]` 数组元素的值,指示的不同类型的 IST 异常的栈顶(高地址)
309+
* 通过以下方式设定 per-CPU 的 `cpu_tss_rw` 的 `x86_tss.ist[]` 数组元素的值,指示的不同类型的 IST 异常的栈顶(高地址)
243310
```cpp
244311
static inline void tss_setup_ist(struct tss_struct *tss)
245312
{
@@ -340,7 +407,7 @@ struct entry_stack_page {
340407
} __aligned(PAGE_SIZE);
341408
```
342409
### Trampoline stack 的设置
343-
* Trampoline stack 的值由启动时`cpu_init()`调用`load_sp0()`设置 TSS 的`sp0``entry_stack_storage`的地址
410+
* Trampoline stack 的值由启动时`cpu_init()`调用`load_sp0()`设置 TSS 的`sp0``entry_stack_storage + PAGE_SIZE`的地址,也就是栈顶(高地址)
344411
* arch/x86/kernel/cpu/common.c
345412
```cpp
346413
void cpu_init(void)
@@ -538,7 +605,7 @@ PAGE DIRECTORY: 4201067
538605
ffd4000001fe8500 7fa14000 0 0 1 fffffc0001000 reserved
539606
crash>
540607
```
541-
* `0xfffffe0000003000`是 trampoline stack 的栈顶,故栈实为`0xfffffe0000002000 - 0xfffffe0000002fff`
608+
* `0xfffffe0000003000`是 trampoline stack 的栈顶(高地址),故栈实为`0xfffffe0000002000 - 0xfffffe0000002fff`
542609
* `0xff1100007fa14000`为实际存储的 per-CPU 变量`entry_stack_storage`的地址
543610
* `vtop`的结果观察到它们都映射到了同一个物理页`0x7fa14000`
544611

0 commit comments

Comments
 (0)