summaryrefslogtreecommitdiff
path: root/src/arch/x86
diff options
context:
space:
mode:
authorArthur Heymans <arthur@aheymans.xyz>2022-11-10 13:34:49 +0100
committerArthur Heymans <arthur@aheymans.xyz>2022-11-12 14:23:51 +0000
commitd4dfc21f70616bc97191969aa2b6d0196a525fce (patch)
tree7c4944b9f923710316df04bfa06f97005c9ca03b /src/arch/x86
parent407e00dca06e36d2d9b11f998a278109ff330783 (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>
Diffstat (limited to 'src/arch/x86')
-rw-r--r--src/arch/x86/c_start.S16
-rw-r--r--src/arch/x86/cpu.c39
-rw-r--r--src/arch/x86/include/arch/cpu.h4
3 files changed, 42 insertions, 17 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))
);