Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/46821 )
Change subject: cpu/x86/mpinit/sipi_vector: Move code to C ......................................................................
cpu/x86/mpinit/sipi_vector: Move code to C
Use a C helper function to do early x86 CPU init. The code is compiled without SSE and without optimizations.
Use existing code to update microcode.
Tested on Supermicro X11SSH: * The microcode is still updated on all core * All cores call into MPinit code
Change-Id: Ib6c2ffa2ce8c42eee9f3fe8ec8cff933942207ca Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/cpu/x86/Makefile.inc M src/cpu/x86/mp_init.c M src/cpu/x86/sipi_vector.S A src/cpu/x86/sipi_vector_c_handler.c M src/include/cpu/x86/mp.h 5 files changed, 150 insertions(+), 124 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/46821/1
diff --git a/src/cpu/x86/Makefile.inc b/src/cpu/x86/Makefile.inc index 66b1a68..54e2397 100644 --- a/src/cpu/x86/Makefile.inc +++ b/src/cpu/x86/Makefile.inc @@ -26,8 +26,11 @@
$(eval $(call create_class_compiler,sipi_vec,$(ARCH-$(TARGET_STAGE)-y))) sipi_vec-generic-ccopts = $(rmodule_$(ARCH-$(TARGET_STAGE)-y)-generic-ccopts) +sipi_vec-generic-ccopts += -mno-sse -O0
sipi_vec-$(CONFIG_PARALLEL_MP) += sipi_vector.S +sipi_vec-$(CONFIG_PARALLEL_MP) += sipi_vector_c_handler.c +sipi_vec-$(CONFIG_PARALLEL_MP) += $(top)/src/cpu/intel/microcode/microcode.c
$(SIPI_DOTO): $$(sipi_vec-objs) $(COMPILER_RT_sipi_vec) $(LD_sipi_vec) -nostdlib -r -o $@ $(COMPILER_RT_FLAGS_sipi_vec) --whole-archive --start-group $(sipi_vec-objs) --no-whole-archive $(COMPILER_RT_sipi_vec) --end-group diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c index 4870529..83d71190 100644 --- a/src/cpu/x86/mp_init.c +++ b/src/cpu/x86/mp_init.c @@ -83,29 +83,6 @@ int num_records; };
-/* This needs to match the layout in the .module_parametrs section. */ -struct sipi_params { - uint16_t gdtlimit; - uint32_t gdt; - uint16_t unused; - uint32_t idt_ptr; - uint32_t stack_top; - uint32_t stack_size; - uint32_t microcode_lock; /* 0xffffffff means parallel loading. */ - uint32_t microcode_ptr; - uint32_t msr_table_ptr; - uint32_t msr_count; - uint32_t c_handler; - atomic_t ap_count; -} __packed; - -/* This also needs to match the assembly code for saved MSR encoding. */ -struct saved_msr { - uint32_t index; - uint32_t lo; - uint32_t hi; -} __packed; - /* The sipi vector rmodule is included in the ramstage using 'objdump -B'. */ extern char _binary_sipi_vector_start[];
diff --git a/src/cpu/x86/sipi_vector.S b/src/cpu/x86/sipi_vector.S index ba1ecb7..52ca6ba 100644 --- a/src/cpu/x86/sipi_vector.S +++ b/src/cpu/x86/sipi_vector.S @@ -1,10 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-only */
#include <cpu/x86/cr.h> -#include <cpu/amd/mtrr.h> #include <cpu/x86/msr.h> #include <arch/ram_segs.h>
+#define CR0_CLEAR_FLAGS_CACHE_ENABLE (CR0_CD | CR0_NW) +#define CR0_CLEAR_FLAGS \ + (CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_TS | CR0_EM | CR0_MP) +#define CR0_SET_FLAGS (CR0_CLEAR_FLAGS_CACHE_ENABLE | CR0_PE) + /* The SIPI vector is responsible for initializing the APs in the system. It * loads microcode, sets up MSRs, and enables caching before calling into * C code. */ @@ -34,11 +38,6 @@ ap_count: .long 0
-#define CR0_CLEAR_FLAGS_CACHE_ENABLE (CR0_CD | CR0_NW) -#define CR0_SET_FLAGS (CR0_CLEAR_FLAGS_CACHE_ENABLE | CR0_PE) -#define CR0_CLEAR_FLAGS \ - (CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_TS | CR0_EM | CR0_MP) - .text .code16 .global _start @@ -101,102 +100,13 @@ /* Save CPU number. */ mov %ecx, %esi
- /* Determine if one should check microcode versions. */ - mov microcode_ptr, %edi - test %edi, %edi - jz microcode_done /* Bypass if no microde exists. */ + /* sipi_secondary_early_entry(ap_start_params), preserve proper stack alignment */ + sub $8, %esp + push %esi + leal ap_start_params, %eax + push %eax + call sipi_secondary_early_entry
- /* Get the Microcode version. */ - mov $1, %eax - cpuid - mov $IA32_BIOS_SIGN_ID, %ecx - rdmsr - /* If something already loaded skip loading again. */ - test %edx, %edx - jnz microcode_done - - /* Determine if parallel microcode loading is allowed. */ - cmpl $0xffffffff, microcode_lock - je load_microcode - - /* Protect microcode loading. */ -lock_microcode: - lock bts $0, microcode_lock - jc lock_microcode - -load_microcode: - /* Load new microcode. */ - mov $IA32_BIOS_UPDT_TRIG, %ecx - xor %edx, %edx - mov %edi, %eax - /* The microcode pointer is passed in pointing to the header. Adjust - * pointer to reflect the payload (header size is 48 bytes). */ - add $48, %eax - pusha - wrmsr - popa - - /* Unconditionally unlock microcode loading. */ - cmpl $0xffffffff, microcode_lock - je microcode_done - - xor %eax, %eax - mov %eax, microcode_lock - -microcode_done: - /* - * Load MSRs. Each entry in the table consists of: - * 0: index, - * 4: value[31:0] - * 8: value[63:32] - */ - mov msr_table_ptr, %edi - mov msr_count, %ebx - test %ebx, %ebx - jz 1f - -#if CONFIG(X86_AMD_FIXED_MTRRS) - /* Allow modification of RdDram and WrDram bits */ - mov $SYSCFG_MSR, %ecx - rdmsr - or $SYSCFG_MSR_MtrrFixDramModEn, %eax - wrmsr -#endif - -load_msr: - mov (%edi), %ecx - mov 4(%edi), %eax - mov 8(%edi), %edx - wrmsr - add $12, %edi - dec %ebx - jnz load_msr - -#if CONFIG(X86_AMD_FIXED_MTRRS) - mov $SYSCFG_MSR, %ecx - rdmsr - and $~SYSCFG_MSR_MtrrFixDramModEn, %eax - wrmsr -#endif - -1: - /* Enable caching. */ - mov %cr0, %eax - and $~(CR0_CLEAR_FLAGS_CACHE_ENABLE), %eax - mov %eax, %cr0 - -#if CONFIG(SSE) - /* Enable sse instructions. */ - mov %cr4, %eax - orl $(CR4_OSFXSR | CR4_OSXMMEXCPT), %eax - mov %eax, %cr4 -#endif - - /* c_handler(cpu_num), preserve proper stack alignment */ - sub $12, %esp - push %esi /* cpu_num */ - mov c_handler, %eax - call *%eax halt_jump: hlt jmp halt_jump diff --git a/src/cpu/x86/sipi_vector_c_handler.c b/src/cpu/x86/sipi_vector_c_handler.c new file mode 100644 index 0000000..dab6c65 --- /dev/null +++ b/src/cpu/x86/sipi_vector_c_handler.c @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <cpu/x86/mp.h> +#include <cpu/x86/msr.h> +#include <cpu/x86/cr.h> +#include <arch/cpu.h> +#include <cpu/intel/microcode.h> +#include <cpu/amd/mtrr.h> + +asmlinkage void sipi_secondary_early_entry(struct sipi_params *params, int cpu_num); + +#define CR0_CLEAR_FLAGS_CACHE_ENABLE (CR0_CD | CR0_NW) + +static void sipi_update_microcode(struct sipi_params *params) +{ + /* Determine if one should check microcode versions. */ + if (!params->microcode_ptr) + return; + + /* Get the Microcode version. */ + const uint32_t rev = get_current_microcode_rev(); + + /* If something already loaded skip loading again. */ + if (rev) + return; + + /* Determine if parallel microcode loading is allowed. */ + if (params->microcode_lock != 0xffffffff) { + + /* Protect microcode loading. */ + asm volatile( + "\tlock_microcode:\n" + "\tlock bts $0, %0\n" + "\tjc lock_microcode\n" + : "=m"(params->microcode_lock) + : "m"(params->microcode_lock)); + } + + /* Load new microcode. */ + intel_microcode_load_unlocked((void *)((uintptr_t)params->microcode_ptr)); + + /* Unconditionally unlock microcode loading. */ + if (params->microcode_lock != 0xffffffff) + params->microcode_lock = 0; +} + +static void sipi_set_mtrrs(struct sipi_params *params) +{ + struct saved_msr *smsr; + if (!params->msr_count) + return; + + if (CONFIG(X86_AMD_FIXED_MTRRS)) { + msr_t msr; + /* Enable access to AMD RdDram and WrDram extension bits */ + msr = rdmsr(SYSCFG_MSR); + msr.lo |= SYSCFG_MSR_MtrrFixDramModEn; + wrmsr(SYSCFG_MSR, msr); + } + + /* Load MSRs */ + smsr = (struct saved_msr *)params->msr_table_ptr; + for (size_t i = 0; i < params->msr_count; i++) { + msr_t msr = {.lo = smsr->lo, .hi = smsr->hi}; + wrmsr(smsr->index, msr); + } + + if (CONFIG(X86_AMD_FIXED_MTRRS)) { + msr_t msr; + /* Enable access to AMD RdDram and WrDram extension bits */ + msr = rdmsr(SYSCFG_MSR); + msr.lo &= ~SYSCFG_MSR_MtrrFixDramModEn; + wrmsr(SYSCFG_MSR, msr); + } +} + +static void sipi_enable_caches(struct sipi_params *params) +{ + /* Enable caches */ + CRx_TYPE cr0 = read_cr0(); + cr0 &= ~(CR0_CLEAR_FLAGS_CACHE_ENABLE); + write_cr0(cr0); +} + +static void sipi_enable_sse(struct sipi_params *params) +{ + /* Enable sse instructions. */ + if (CONFIG(SSE)) { + CRx_TYPE cr4 = read_cr4(); + cr4 &= (CR4_OSFXSR | CR4_OSXMMEXCPT); + write_cr4(cr4); + } +} + +/* + * Early CPU bringup hook. + * - No Microcode has been loaded + * - Caches are disabled + * - SSE is disabled + * - MTRR haven't been set up + * + * You have been warned, expect the unexpected! + */ +asmlinkage void sipi_secondary_early_entry(struct sipi_params *params, int cpu_num) +{ + sipi_update_microcode(params); + sipi_set_mtrrs(params); + sipi_enable_caches(params); + sipi_enable_sse(params); + + void (*doit)(int) = (void (*)(int))params->c_handler; + doit(cpu_num); +} \ No newline at end of file diff --git a/src/include/cpu/x86/mp.h b/src/include/cpu/x86/mp.h index b2704eb..75cbe26 100644 --- a/src/include/cpu/x86/mp.h +++ b/src/include/cpu/x86/mp.h @@ -143,4 +143,27 @@ /* Send SMI to self with single execution. */ void smm_initiate_relocation(void);
+/* This needs to match the layout in the .module_parametrs section. */ +struct sipi_params { + uint16_t gdtlimit; + uint32_t gdt; + uint16_t unused; + uint32_t idt_ptr; + uint32_t stack_top; + uint32_t stack_size; + uint32_t microcode_lock; /* 0xffffffff means parallel loading. */ + uint32_t microcode_ptr; + uint32_t msr_table_ptr; + uint32_t msr_count; + uint32_t c_handler; + atomic_t ap_count; +} __packed; + +/* This also needs to match the assembly code for saved MSR encoding. */ +struct saved_msr { + uint32_t index; + uint32_t lo; + uint32_t hi; +} __packed; + #endif /* _X86_MP_H_ */