From 692fda47fc3873f18f291d8ec3c3fe4626bdaf82 Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Tue, 12 Nov 2019 17:56:21 -0800 Subject: [PATCH] x86: use MSRs for %gs We don't need to set up GDT data descriptors for setting %gs. Instead, we use the x86 MSRs to set GS_BASE and KERNEL_GS_BASE. We don't currently allow user mode to set %gs on its own, but later on if we do, we have everything set up to issue 'swapgs' instructions on syscall or IRQ. Unused entries in the GDT have been removed. Signed-off-by: Andrew Boie --- arch/x86/core/intel64/cpu.c | 8 +- arch/x86/core/intel64/locore.S | 91 +++++++-------------- arch/x86/core/offsets/intel64_offsets.c | 2 +- arch/x86/include/intel64/kernel_arch_data.h | 2 +- include/arch/x86/intel64/thread.h | 12 +-- 5 files changed, 40 insertions(+), 75 deletions(-) diff --git a/arch/x86/core/intel64/cpu.c b/arch/x86/core/intel64/cpu.c index 9f4a627e074..cd268cff1ad 100644 --- a/arch/x86/core/intel64/cpu.c +++ b/arch/x86/core/intel64/cpu.c @@ -65,7 +65,7 @@ extern struct x86_page_tables z_x86_flat_ptables; struct x86_cpuboot x86_cpuboot[] = { { .tr = X86_KERNEL_CPU0_TR, - .gs = X86_KERNEL_CPU0_GS, + .gs_base = &tss0, .sp = (u64_t) _interrupt_stack + CONFIG_ISR_STACK_SIZE, .fn = z_x86_prep_c, #ifdef CONFIG_X86_MMU @@ -75,19 +75,19 @@ struct x86_cpuboot x86_cpuboot[] = { #if CONFIG_MP_NUM_CPUS > 1 { .tr = X86_KERNEL_CPU1_TR, - .gs = X86_KERNEL_CPU1_GS, + .gs_base = &tss1 }, #endif #if CONFIG_MP_NUM_CPUS > 2 { .tr = X86_KERNEL_CPU2_TR, - .gs = X86_KERNEL_CPU2_GS, + .gs_base = &tss2 }, #endif #if CONFIG_MP_NUM_CPUS > 3 { .tr = X86_KERNEL_CPU3_TR, - .gs = X86_KERNEL_CPU3_GS, + .gs_base = &tss3 }, #endif }; diff --git a/arch/x86/core/intel64/locore.S b/arch/x86/core/intel64/locore.S index ef09a5188a6..31112404d03 100644 --- a/arch/x86/core/intel64/locore.S +++ b/arch/x86/core/intel64/locore.S @@ -41,7 +41,6 @@ x86_ap_start: movw %ax, %es movw %ax, %ss movw %ax, %fs - movw %ax, %gs /* * Now, reverse-map our local APIC ID to our logical CPU ID @@ -135,16 +134,24 @@ go64: movl %cr4, %eax /* enable PAE and SSE */ movw __x86_cpuboot_t_tr_OFFSET(%rbp), %ax ltr %ax - movw __x86_cpuboot_t_gs_OFFSET(%rbp), %ax - movw %ax, %gs + + /* Set up MSRs for GS / KERNEL_GS base */ + movq __x86_cpuboot_t_gs_base_OFFSET(%rbp), %rax + movq %rax, %rdx + shrq $32, %rdx + /* X86_KERNEL_GS_BASE and X86_GS_BASE are swapped by the 'swapgs' + * instruction. + */ + movl $X86_KERNEL_GS_BASE, %ecx + wrmsr + /* X86_GS_BASE shadows base fields of %gs, effectively setting %gs */ + movl $X86_GS_BASE, %ecx + wrmsr movq __x86_cpuboot_t_sp_OFFSET(%rbp), %rsp movq %rsp, %gs:__x86_tss64_t_ist1_OFFSET - /* - * finally, complete environment for the C runtime and go. - */ - + /* finally, complete environment for the C runtime and go. */ cld /* GCC presumes a clear direction flag */ #ifdef CONFIG_INIT_STACKS @@ -602,85 +609,47 @@ pdp: .long 0x00000083 /* 0x83 = 1GB, R/W, P */ /* * GDT - a single GDT is shared by all threads (and, eventually, all CPUs). - * This layout must agree with the selectors in intel64/kernel_arch_data.h. + * This layout must agree with the selectors in + * include/arch/x86/intel64/thread.h. + * + * The 64-bit kernel code and data segment descriptors must be in sequence as + * required by 'syscall' + * + * The 32-bit user code, 64-bit user code, and 64-bit user data segment + * descriptors must be in sequence as required by 'sysret' */ - .align 8 gdt: - .word 0, 0, 0, 0 /* 0x00: null descriptor */ + .word 0, 0, 0, 0 /* 0x00: null descriptor */ .word 0xFFFF, 0, 0x9A00, 0x00CF /* 0x08: 32-bit kernel code */ .word 0xFFFF, 0, 0x9200, 0x00CF /* 0x10: 32-bit kernel data */ - .word 0, 0, 0x9800, 0x0020 /* 0x18: 64-bit kernel code */ - .word 0, 0, 0x9200, 0x0000 /* 0x20: 64-bit kernel data */ + .word 0, 0, 0x9800, 0x0020 /* 0x18: 64-bit kernel code */ + .word 0, 0, 0x9200, 0x0000 /* 0x20: 64-bit kernel data */ - .word 0, 0, 0, 0 /* 0x28: unused */ + /* Remaining entries are TSS for each enabled CPU */ - /* - * CPU 0 task state segment descriptors - */ - - .word 0 /* 0x30: 64-bit TSS data (for GS) */ - .word tss0 - .word 0x9200 - .word 0 - - .word 0, 0, 0, 0 /* 0x38: unused */ - - .word __X86_TSS64_SIZEOF-1 /* 0x40: 64-bit TSS (16-byte entry) */ + .word __X86_TSS64_SIZEOF-1 /* 0x28: 64-bit TSS (16-byte entry) */ .word tss0 .word 0x8900 .word 0, 0, 0, 0, 0 #if CONFIG_MP_NUM_CPUS > 1 - /* - * CPU 1 task state segment descriptors - */ - - .word 0 /* 0x50: 64-bit TSS data (for GS) */ - .word tss1 - .word 0x9200 - .word 0 - - .word 0, 0, 0, 0 /* 0x58: unused */ - - .word __X86_TSS64_SIZEOF-1 /* 0x60: 64-bit TSS (16-byte entry) */ + .word __X86_TSS64_SIZEOF-1 /* 0x38: 64-bit TSS (16-byte entry) */ .word tss1 .word 0x8900 .word 0, 0, 0, 0, 0 #endif #if CONFIG_MP_NUM_CPUS > 2 - /* - * CPU 2 task state segment descriptors - */ - - .word 0 /* 0x70: 64-bit TSS data (for GS) */ - .word tss2 - .word 0x9200 - .word 0 - - .word 0, 0, 0, 0 /* 0x78: unused */ - - .word __X86_TSS64_SIZEOF-1 /* 0x80: 64-bit TSS (16-byte entry) */ + .word __X86_TSS64_SIZEOF-1 /* 0x48: 64-bit TSS (16-byte entry) */ .word tss2 .word 0x8900 .word 0, 0, 0, 0, 0 #endif #if CONFIG_MP_NUM_CPUS > 3 - /* - * CPU 3 task state segment descriptors - */ - - .word 0 /* 0x90: 64-bit TSS data (for GS) */ - .word tss3 - .word 0x9200 - .word 0 - - .word 0, 0, 0, 0 /* 0x98: unused */ - - .word __X86_TSS64_SIZEOF-1 /* 0xA0: 64-bit TSS (16-byte entry) */ + .word __X86_TSS64_SIZEOF-1 /* 0x58: 64-bit TSS (16-byte entry) */ .word tss3 .word 0x8900 .word 0, 0, 0, 0, 0 diff --git a/arch/x86/core/offsets/intel64_offsets.c b/arch/x86/core/offsets/intel64_offsets.c index 25ca8a96e28..308b69f4adb 100644 --- a/arch/x86/core/offsets/intel64_offsets.c +++ b/arch/x86/core/offsets/intel64_offsets.c @@ -30,7 +30,7 @@ GEN_ABSOLUTE_SYM(__X86_TSS64_SIZEOF, sizeof(x86_tss64_t)); GEN_OFFSET_SYM(x86_cpuboot_t, ready); GEN_OFFSET_SYM(x86_cpuboot_t, tr); -GEN_OFFSET_SYM(x86_cpuboot_t, gs); +GEN_OFFSET_SYM(x86_cpuboot_t, gs_base); GEN_OFFSET_SYM(x86_cpuboot_t, sp); GEN_OFFSET_SYM(x86_cpuboot_t, fn); GEN_OFFSET_SYM(x86_cpuboot_t, arg); diff --git a/arch/x86/include/intel64/kernel_arch_data.h b/arch/x86/include/intel64/kernel_arch_data.h index bfda15567e1..3fc27aa671f 100644 --- a/arch/x86/include/intel64/kernel_arch_data.h +++ b/arch/x86/include/intel64/kernel_arch_data.h @@ -21,7 +21,7 @@ extern char _locore_start[], _locore_end[]; struct x86_cpuboot { volatile int ready; /* CPU has started */ u16_t tr; /* selector for task register */ - u16_t gs; /* selector for GS */ + struct x86_tss64 *gs_base; /* Base address for GS segment */ u64_t sp; /* initial stack pointer */ void *fn; /* kernel entry function */ void *arg; /* argument for above function */ diff --git a/include/arch/x86/intel64/thread.h b/include/arch/x86/intel64/thread.h index f1bc66dfc12..6e40edb00ed 100644 --- a/include/arch/x86/intel64/thread.h +++ b/include/arch/x86/intel64/thread.h @@ -17,14 +17,10 @@ #define X86_KERNEL_CS 0x18 /* 64-bit kernel code */ #define X86_KERNEL_DS 0x20 /* 64-bit kernel data */ -#define X86_KERNEL_CPU0_GS 0x30 /* data selector covering TSS */ -#define X86_KERNEL_CPU0_TR 0x40 /* 64-bit task state segment */ -#define X86_KERNEL_CPU1_GS 0x50 /* data selector covering TSS */ -#define X86_KERNEL_CPU1_TR 0x60 /* 64-bit task state segment */ -#define X86_KERNEL_CPU2_GS 0x70 /* data selector covering TSS */ -#define X86_KERNEL_CPU2_TR 0x80 /* 64-bit task state segment */ -#define X86_KERNEL_CPU3_GS 0x90 /* data selector covering TSS */ -#define X86_KERNEL_CPU3_TR 0xA0 /* 64-bit task state segment */ +#define X86_KERNEL_CPU0_TR 0x28 /* 64-bit task state segment */ +#define X86_KERNEL_CPU1_TR 0x38 /* 64-bit task state segment */ +#define X86_KERNEL_CPU2_TR 0x48 /* 64-bit task state segment */ +#define X86_KERNEL_CPU3_TR 0x58 /* 64-bit task state segment */ /* * Some SSE definitions. Ideally these will ultimately be shared with 32-bit.