diff options
author | Richard Braun <rbraun@sceen.net> | 2018-07-08 16:45:02 +0200 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2018-07-08 16:45:02 +0200 |
commit | 99a5fdb17604c0816420ef3d126beab81fc41365 (patch) | |
tree | 7675652355d487510960cb5894db8bd61a9d160c | |
parent | 2e44231008cb831edd13325fc3dbd04de6ff9115 (diff) |
x86/cpu: add red zone support
Supporting the red zone is required for full ABI compliance, and in
particular to safely link against libgcc.
-rw-r--r-- | arch/x86/machine/cpu.c | 20 | ||||
-rw-r--r-- | arch/x86/machine/cpu_asm.S | 23 |
2 files changed, 38 insertions, 5 deletions
diff --git a/arch/x86/machine/cpu.c b/arch/x86/machine/cpu.c index 7edcc805..bed4e414 100644 --- a/arch/x86/machine/cpu.c +++ b/arch/x86/machine/cpu.c @@ -79,9 +79,10 @@ struct cpu_vendor { }; /* - * IST indexes (0 is reserved). + * IST indexes (0 means no stack switch). */ -#define CPU_TSS_IST_DF 1 +#define CPU_TSS_IST_INTR 1 +#define CPU_TSS_IST_DF 2 /* * MP related CMOS ports, registers and values. @@ -369,7 +370,7 @@ cpu_idt_set_intr_gate(struct cpu_idt *idt, unsigned int vector, struct cpu_gate_desc *desc; desc = cpu_idt_get_desc(idt, vector); - cpu_gate_desc_init_intr(desc, fn, 0); + cpu_gate_desc_init_intr(desc, fn, CPU_TSS_IST_INTR); } static void __init @@ -834,11 +835,13 @@ cpu_gdt_load(const struct cpu_gdt *gdt) } static void __init -cpu_tss_init(struct cpu_tss *tss, const void *df_stack_top) +cpu_tss_init(struct cpu_tss *tss, const void *intr_stack_top, + const void *df_stack_top) { memset(tss, 0, sizeof(*tss)); #ifdef __LP64__ + tss->ist[CPU_TSS_IST_INTR] = (uintptr_t)intr_stack_top; tss->ist[CPU_TSS_IST_DF] = (uintptr_t)df_stack_top; #else /* __LP64__ */ (void)df_stack_top; @@ -903,6 +906,12 @@ cpu_get_tss(struct cpu *cpu) return &cpu->tss; } +static void * __init +cpu_get_intr_stack_top(struct cpu *cpu) +{ + return &cpu->intr_stack[sizeof(cpu->intr_stack)]; +} + static struct cpu_tss * __init cpu_get_df_tss(struct cpu *cpu) { @@ -1012,7 +1021,8 @@ cpu_build(struct cpu *cpu) cpu_gdt_init(&cpu->gdt, cpu_get_tss(cpu), cpu_get_df_tss(cpu), pcpu_area); cpu_gdt_load(&cpu->gdt); cpu_load_ldt(); - cpu_tss_init(&cpu->tss, cpu_get_df_stack_top(cpu)); + cpu_tss_init(&cpu->tss, cpu_get_intr_stack_top(cpu), + cpu_get_df_stack_top(cpu)); #ifndef __LP64__ cpu_tss_init_i386_double_fault(&cpu->df_tss, cpu_get_df_stack_top(cpu)); #endif /* __LP64__ */ diff --git a/arch/x86/machine/cpu_asm.S b/arch/x86/machine/cpu_asm.S index 96511b14..04b16083 100644 --- a/arch/x86/machine/cpu_asm.S +++ b/arch/x86/machine/cpu_asm.S @@ -19,6 +19,8 @@ #include <machine/asm.h> #include <machine/cpu.h> +#define CPU_RED_ZONE_SIZE 128 + .text #ifdef __LP64__ @@ -60,7 +62,28 @@ addq $16, %rsp /* skip vector and error */ .endm +.macro cpu_ll_exc_push_word source offset buffer + movq -\offset(\source), \buffer + pushq \buffer +.endm + +.macro cpu_ll_exc_push source nr_words buffer +.set offset, 8 +.rept \nr_words + cpu_ll_exc_push_word \source offset \buffer +.set offset, offset + 8 +.endr +.endm + .macro cpu_ll_exc_enter vector + pushq %rbx /* save registers used for stack switching */ + pushq %rax + leaq 64(%rsp), %rbx /* point to the top of the exception frame */ + movq -16(%rbx), %rsp /* point to the thread stack */ + subq $CPU_RED_ZONE_SIZE, %rsp + cpu_ll_exc_push %rbx 6 %rax + movq -64(%rbx), %rax /* restore registers used for stack switching */ + movq -56(%rbx), %rbx pushq $\vector cpu_ll_exc_store_registers xorq %rbp, %rbp /* block stack tracing */ |