diff --git a/xen/arch/x86/cpu/microcode/core.c b/xen/arch/x86/cpu/microcode/core.c index 85c05e480d..d14754e222 100644 --- a/xen/arch/x86/cpu/microcode/core.c +++ b/xen/arch/x86/cpu/microcode/core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -198,7 +199,8 @@ void __init microcode_scan_module( bootstrap_map(NULL); } } -void __init microcode_grab_module( + +static void __init microcode_grab_module( unsigned long *module_map, const multiboot_info_t *mbi) { @@ -732,25 +734,11 @@ int microcode_update_one(void) return microcode_update_cpu(NULL); } -/* BSP calls this function to parse ucode blob and then apply an update. */ -static int __init early_microcode_update_cpu(void) +static int __init early_update_cache(const void *data, size_t len) { int rc = 0; - const void *data = NULL; - size_t len; struct microcode_patch *patch; - if ( ucode_blob.size ) - { - len = ucode_blob.size; - data = ucode_blob.data; - } - else if ( ucode_mod.mod_end ) - { - len = ucode_mod.mod_end; - data = bootstrap_map(&ucode_mod); - } - if ( !data ) return -ENOMEM; @@ -770,10 +758,64 @@ static int __init early_microcode_update_cpu(void) spin_unlock(µcode_mutex); ASSERT(rc); - return microcode_update_one(); + return rc; } -int __init early_microcode_init(void) +int __init microcode_init_cache(unsigned long *module_map, + const struct multiboot_info *mbi) +{ + int rc = 0; + + if ( ucode_scan ) + /* Need to rescan the modules because they might have been relocated */ + microcode_scan_module(module_map, mbi); + + if ( ucode_mod.mod_end ) + rc = early_update_cache(bootstrap_map(&ucode_mod), + ucode_mod.mod_end); + else if ( ucode_blob.size ) + rc = early_update_cache(ucode_blob.data, ucode_blob.size); + + return rc; +} + +/* BSP calls this function to parse ucode blob and then apply an update. */ +static int __init early_microcode_update_cpu(void) +{ + const void *data = NULL; + size_t len; + struct microcode_patch *patch; + + if ( ucode_blob.size ) + { + len = ucode_blob.size; + data = ucode_blob.data; + } + else if ( ucode_mod.mod_end ) + { + len = ucode_mod.mod_end; + data = bootstrap_map(&ucode_mod); + } + + if ( !data ) + return -ENOMEM; + + patch = ucode_ops.cpu_request_microcode(data, len, false); + if ( IS_ERR(patch) ) + { + printk(XENLOG_WARNING "Parsing microcode blob error %ld\n", + PTR_ERR(patch)); + return PTR_ERR(patch); + } + + if ( !patch ) + return -ENOENT; + + return microcode_update_cpu(patch); +} + +int __init early_microcode_init(unsigned long *module_map, + const struct multiboot_info *mbi) { const struct cpuinfo_x86 *c = &boot_cpu_data; int rc = 0; @@ -797,7 +839,9 @@ int __init early_microcode_init(void) return -ENODEV; } - alternative_vcall(ucode_ops.collect_cpu_info); + microcode_grab_module(module_map, mbi); + + ucode_ops.collect_cpu_info(); if ( ucode_mod.mod_end || ucode_blob.size ) rc = early_microcode_update_cpu(); diff --git a/xen/arch/x86/include/asm/microcode.h b/xen/arch/x86/include/asm/microcode.h index 3b0234e9fa..62ce3418f7 100644 --- a/xen/arch/x86/include/asm/microcode.h +++ b/xen/arch/x86/include/asm/microcode.h @@ -6,6 +6,8 @@ #include +struct multiboot_info; + struct cpu_signature { /* CPU signature (CPUID.1.EAX). */ unsigned int sig; @@ -21,7 +23,10 @@ DECLARE_PER_CPU(struct cpu_signature, cpu_sig); void microcode_set_module(unsigned int idx); int microcode_update(XEN_GUEST_HANDLE(const_void), unsigned long len); -int early_microcode_init(void); +int early_microcode_init(unsigned long *module_map, + const struct multiboot_info *mbi); +int microcode_init_cache(unsigned long *module_map, + const struct multiboot_info *mbi); int microcode_update_one(void); #endif /* ASM_X86__MICROCODE_H */ diff --git a/xen/arch/x86/include/asm/setup.h b/xen/arch/x86/include/asm/setup.h index ae470ea12f..ae0dd3915a 100644 --- a/xen/arch/x86/include/asm/setup.h +++ b/xen/arch/x86/include/asm/setup.h @@ -44,9 +44,6 @@ void *bootstrap_map(const module_t *mod); int xen_in_range(unsigned long mfn); -void microcode_grab_module( - unsigned long *, const multiboot_info_t *); - extern uint8_t kbd_shift_flags; #ifdef NDEBUG diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 4102aae76d..566422600d 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -1173,6 +1173,12 @@ void __init noreturn __start_xen(unsigned long mbi_p) mod[i].reserved = 0; } + /* + * TODO: load ucode earlier once multiboot modules become accessible + * at an earlier stage. + */ + early_microcode_init(module_map, mbi); + if ( xen_phys_start ) { relocated = true; @@ -1755,11 +1761,9 @@ void __init noreturn __start_xen(unsigned long mbi_p) init_IRQ(); - microcode_grab_module(module_map, mbi); - timer_init(); - early_microcode_init(); + microcode_init_cache(module_map, mbi); /* Needs xmalloc() */ tsx_init(); /* Needs microcode. May change HLE/RTM feature bits. */