diff options
Diffstat (limited to 'src/arch')
-rw-r--r-- | src/arch/x86/c_start.S | 35 | ||||
-rw-r--r-- | src/arch/x86/include/arch/cpu.h | 29 |
2 files changed, 63 insertions, 1 deletions
diff --git a/src/arch/x86/c_start.S b/src/arch/x86/c_start.S index cb7d5045ff..9e718fcab0 100644 --- a/src/arch/x86/c_start.S +++ b/src/arch/x86/c_start.S @@ -80,6 +80,20 @@ _start: push_cpu_info +#if CONFIG(CPU_INFO_V2) + /* 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 + mov %eax, %gs +#endif + /* * Now we are finished. Memory is up, data is copied and * bss is cleared. Now we call the main routine and @@ -127,6 +141,7 @@ gdb_stub_breakpoint: #endif .globl gdt, gdt_end + .global per_cpu_segment_descriptors, per_cpu_segment_selector gdtaddr: .word gdt_end - gdt - 1 @@ -136,7 +151,7 @@ gdtaddr: .long gdt /* we know the offset */ #endif - .data + .data /* This is the gdt for GCC part of coreboot. * It is different from the gdt in ASM part of coreboot @@ -206,8 +221,26 @@ gdt: .word 0xffff, 0x0000 .byte 0x00, 0x9b, 0xaf, 0x00 #endif +#if CONFIG(CPU_INFO_V2) +per_cpu_segment_descriptors: + .rept CONFIG_MAX_CPUS + /* flat data segment */ + .word 0xffff, 0x0000 +#if ENV_X86_64 + .byte 0x00, 0x92, 0xcf, 0x00 +#else + .byte 0x00, 0x93, 0xcf, 0x00 +#endif + .endr +#endif /* CPU_INFO_V2 */ gdt_end: +#if CONFIG(CPU_INFO_V2) +/* Segment selector pointing to the first per_cpu_segment_descriptor. */ +per_cpu_segment_selector: + .long per_cpu_segment_descriptors - gdt +#endif /* CPU_INFO_V2 */ + .section ".text._start", "ax", @progbits #if ENV_X86_64 SetCodeSelector: diff --git a/src/arch/x86/include/arch/cpu.h b/src/arch/x86/include/arch/cpu.h index f736a147fe..8e96fae2c2 100644 --- a/src/arch/x86/include/arch/cpu.h +++ b/src/arch/x86/include/arch/cpu.h @@ -236,11 +236,40 @@ struct cpu_info { #endif }; +/* + * This structure describes the data allocated in the %gs segment for each CPU. + * In order to read from this structure you will need to use assembly to + * reference the segment. + * + * e.g., Reading the cpu_info pointer: + * %%gs:0 + */ +struct per_cpu_segment_data { + /* + * Instead of keeping a `struct cpu_info`, we actually keep a pointer + * pointing to the cpu_info struct located in %ds. This prevents + * needing specific access functions to read the fields in the cpu_info. + */ + struct cpu_info *cpu_info; +}; + static inline struct cpu_info *cpu_info(void) { +/* We use a #if because we don't want to mess with the &s below. */ +#if CONFIG(CPU_INFO_V2) + struct cpu_info *ci = NULL; + + __asm__("mov %%gs:%c[offset], %[ci]" + : [ci] "=r" (ci) + : [offset] "i" (offsetof(struct per_cpu_segment_data, cpu_info)) + ); + + return ci; +#else char s; uintptr_t info = ALIGN_UP((uintptr_t)&s, CONFIG_STACK_SIZE) - sizeof(struct cpu_info); return (struct cpu_info *)info; +#endif /* CPU_INFO_V2 */ } struct cpuinfo_x86 { |