diff options
Diffstat (limited to 'src/arch')
-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 |
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)) ); |