summaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/x86/c_start.S35
-rw-r--r--src/arch/x86/include/arch/cpu.h29
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 {