diff options
author | Arthur Heymans <arthur@aheymans.xyz> | 2022-11-10 13:34:49 +0100 |
---|---|---|
committer | Arthur Heymans <arthur@aheymans.xyz> | 2022-11-12 14:23:51 +0000 |
commit | d4dfc21f70616bc97191969aa2b6d0196a525fce (patch) | |
tree | 7c4944b9f923710316df04bfa06f97005c9ca03b | |
parent | 407e00dca06e36d2d9b11f998a278109ff330783 (diff) |
cpu/x86: Set thread local storage in C code
Doing this in C code is way easier to understand. Also the thread local
storage is now in .bss instead of the AP stack. This makes it more
robust against stack overflows, as APs stacks overflow in each other.
TESTED: work on qemu.
Change-Id: I19d3285daf97798a2d28408b5601ad991e29e718
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/69435
Reviewed-by: Raul Rangel <rrangel@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r-- | src/arch/x86/c_start.S | 16 | ||||
-rw-r--r-- | src/arch/x86/cpu.c | 39 | ||||
-rw-r--r-- | src/arch/x86/include/arch/cpu.h | 4 | ||||
-rw-r--r-- | src/cpu/x86/cpu_info.S.inc | 72 | ||||
-rw-r--r-- | src/cpu/x86/mp_init.c | 10 | ||||
-rw-r--r-- | src/cpu/x86/sipi_vector.S | 24 |
6 files changed, 55 insertions, 110 deletions
diff --git a/src/arch/x86/c_start.S b/src/arch/x86/c_start.S index 02a9b8933a..5b7052ef58 100644 --- a/src/arch/x86/c_start.S +++ b/src/arch/x86/c_start.S @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -#include <cpu/x86/cpu_info.S.inc> #include <cpu/x86/post_code.h> #include <arch/ram_segs.h> @@ -78,21 +77,6 @@ _start: movl $_estack, %esp andl $(~(CONFIG_STACK_SIZE-1)), %esp - push_cpu_info - - /* Allocate the per_cpu_segment_data on the stack */ - push_per_cpu_segment_data - - /* - * Update the BSP's per_cpu_segment_descriptor to point to the - * per_cpu_segment_data that was allocated on the stack. - */ - set_segment_descriptor_base $per_cpu_segment_descriptors, %esp - - mov $per_cpu_segment_selector, %eax - movl (%eax), %eax - mov %eax, %gs - /* * Now we are finished. Memory is up, data is copied and * bss is cleared. Now we call the main routine and diff --git a/src/arch/x86/cpu.c b/src/arch/x86/cpu.c index f4cb83a4dd..6a8ddefa14 100644 --- a/src/arch/x86/cpu.c +++ b/src/arch/x86/cpu.c @@ -6,6 +6,7 @@ #include <cpu/cpu.h> #include <post.h> #include <string.h> +#include <cpu/x86/gdt.h> #include <cpu/x86/mp.h> #include <cpu/x86/lapic.h> #include <cpu/x86/tsc.h> @@ -340,3 +341,41 @@ int cpu_index(void) } return -1; } + +/* cpu_info() looks at address 0 at the base of %gs for a pointer to struct cpu_info */ +static struct per_cpu_segment_data segment_data[CONFIG_MAX_CPUS]; +static struct cpu_info cpu_infos[CONFIG_MAX_CPUS]; + +enum cb_err set_cpu_info(unsigned int index, struct device *cpu) +{ + if (index >= ARRAY_SIZE(cpu_infos)) + return CB_ERR; + + if (!cpu) + return CB_ERR; + + const struct cpu_info info = { .cpu = cpu, .index = index}; + cpu_infos[index] = info; + segment_data[index].cpu_info = &cpu_infos[index]; + + struct segment_descriptor { + uint16_t segment_limit_0_15; + uint16_t base_address_0_15; + uint8_t base_address_16_23; + uint8_t attrs[2]; + uint8_t base_address_24_31; + } *segment_descriptor = (void *)&per_cpu_segment_descriptors; + + segment_descriptor[index].base_address_0_15 = (uintptr_t)&segment_data[index] & 0xffff; + segment_descriptor[index].base_address_16_23 = ((uintptr_t)&segment_data[index] >> 16) & 0xff; + segment_descriptor[index].base_address_24_31 = ((uintptr_t)&segment_data[index] >> 24) & 0xff; + + const unsigned int cpu_segment = per_cpu_segment_selector + (index << 3); + + __asm__ __volatile__ ("mov %0, %%gs\n" + : + : "r" (cpu_segment) + : ); + + return CB_SUCCESS; +} diff --git a/src/arch/x86/include/arch/cpu.h b/src/arch/x86/include/arch/cpu.h index 0087a795ec..c7c6b4e074 100644 --- a/src/arch/x86/include/arch/cpu.h +++ b/src/arch/x86/include/arch/cpu.h @@ -147,11 +147,13 @@ struct per_cpu_segment_data { struct cpu_info *cpu_info; }; +enum cb_err set_cpu_info(unsigned int index, struct device *cpu); + static inline struct cpu_info *cpu_info(void) { struct cpu_info *ci = NULL; - __asm__("mov %%gs:%c[offset], %[ci]" + __asm__ __volatile__("mov %%gs:%c[offset], %[ci]" : [ci] "=r" (ci) : [offset] "i" (offsetof(struct per_cpu_segment_data, cpu_info)) ); diff --git a/src/cpu/x86/cpu_info.S.inc b/src/cpu/x86/cpu_info.S.inc deleted file mode 100644 index 6dca920ba0..0000000000 --- a/src/cpu/x86/cpu_info.S.inc +++ /dev/null @@ -1,72 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/* - * Pushes a 32-bit register onto the stack. - * - * There are two possible code sections where this code can be included: - * .code32 and .code64 - * - * Doing a `push %eax` while in a .code64 section will result in a compiler - * error. This macro manually pushes the 32-bit register onto the stack so we - * can share the code between 32 and 64 bit builds. - */ -.macro pushr reg:req -#if ENV_X86_64 - movl $0, -4(%esp) - movl \reg, -8(%esp) - sub $8, %esp -#else - push \reg -#endif -.endm - -/* Push struct cpu_info */ -.macro push_cpu_info index=$0 - pushr \index /* index (size_t) */ - pushr $0 /* *cpu */ -.endm - -/* Push struct per_cpu_segment_data */ -.macro push_per_cpu_segment_data cpu_info_pointer=%esp - pushr \cpu_info_pointer /* *cpu_info */ -.endm - -/* - * Sets the base address in the segment descriptor array. - * - * A segment descriptor has the following structure: - * struct { - * uint16_t segment_limit_0_15; - * uint16_t base_address_0_15; - * uint8_t base_address_16_23; - * uint8_t attrs[2]; - * uint8_t base_address_24_31; - * }; - * - * @desc_array: Address of the descriptor table - * @base: Address to set in the descriptor - * @desc_index: Index of the descriptor in the table. Defaults to 0. Must be a - * register if specified. - * - * Clobbers %eax, %ebx. - */ -.macro set_segment_descriptor_base desc_array:req, base:req, desc_index - mov \base, %eax - - mov \desc_array, %ebx - -.ifb \desc_index - movw %ax, 2(%ebx) - shr $16, %eax - movb %al, 4(%ebx) - shr $8, %eax - movb %al, 7(%ebx) -.else - movw %ax, 2(%ebx, \desc_index, 8) - shr $16, %eax - movb %al, 4(%ebx, \desc_index, 8) - shr $8, %eax - movb %al, 7(%ebx, \desc_index, 8) -.endif - -.endm diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c index 0e4a571e96..758550c43d 100644 --- a/src/cpu/x86/mp_init.c +++ b/src/cpu/x86/mp_init.c @@ -176,20 +176,19 @@ static struct bus *g_cpu_bus; /* By the time APs call ap_init() caching has been setup, and microcode has * been loaded. */ -static void asmlinkage ap_init(void) +static asmlinkage void ap_init(unsigned int index) { - struct cpu_info *info = cpu_info(); - /* Ensure the local APIC is enabled */ enable_lapic(); setup_lapic_interrupts(); struct device *dev = g_cpu_bus->children; - for (unsigned int i = info->index; i > 0; i--) + for (unsigned int i = index; i > 0; i--) dev = dev->sibling; - info->cpu = dev; + set_cpu_info(index, dev); + struct cpu_info *info = cpu_info(); cpu_add_map_entry(info->index); /* Fix up APIC id with reality. */ @@ -540,6 +539,7 @@ static enum cb_err init_bsp(struct bus *cpu_bus) } /* Find the device structure for the boot CPU. */ + set_cpu_info(0, bsp); info = cpu_info(); info->cpu = bsp; info->cpu->name = processor_name; diff --git a/src/cpu/x86/sipi_vector.S b/src/cpu/x86/sipi_vector.S index b8cac96341..39973dbc8b 100644 --- a/src/cpu/x86/sipi_vector.S +++ b/src/cpu/x86/sipi_vector.S @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -#include <cpu/x86/cpu_info.S.inc> #include <cpu/x86/cr.h> #include <cpu/amd/mtrr.h> #include <cpu/x86/msr.h> @@ -104,19 +103,8 @@ _start: subl %eax, %edx mov %edx, %esp - push_cpu_info index=%ecx - push_per_cpu_segment_data - - /* - * Update the AP's per_cpu_segment_descriptor to point to the - * per_cpu_segment_data that was allocated on the stack. - */ - set_segment_descriptor_base per_cpu_segment_descriptors, %esp, %ecx - - mov %ecx, %eax - shl $3, %eax /* The index is << 3 in the segment selector */ - add per_cpu_segment_selector, %eax - mov %eax, %gs + /* Save CPU number for calling the AP entry */ + push %ecx /* * The following code only needs to run on Intel platforms and thus the caller @@ -230,15 +218,19 @@ load_msr: mov %eax, %cr4 #endif + pop %edi /* Retrieve cpu index */ andl $0xfffffff0, %esp /* ensure stack alignment */ #if ENV_X86_64 - /* entry64.inc preserves ebx. */ + /* entry64.inc preserves ebx, esi, edi, ebp */ #include <cpu/x86/64bit/entry64.inc> - movabs c_handler, %eax call *%rax #else + push $0 + push $0 + push $0 + push %edi mov c_handler, %eax call *%eax #endif |