summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2018-07-08 16:45:02 +0200
committerRichard Braun <rbraun@sceen.net>2018-07-08 16:45:02 +0200
commit99a5fdb17604c0816420ef3d126beab81fc41365 (patch)
tree7675652355d487510960cb5894db8bd61a9d160c
parent2e44231008cb831edd13325fc3dbd04de6ff9115 (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.c20
-rw-r--r--arch/x86/machine/cpu_asm.S23
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 */