diff --git a/xen/arch/x86/efi/boot.c b/xen/arch/x86/efi/boot.c index 81bcc1be5d..184448c4d8 100644 --- a/xen/arch/x86/efi/boot.c +++ b/xen/arch/x86/efi/boot.c @@ -49,6 +49,7 @@ static UINT32 __initdata mdesc_ver; static struct file __initdata cfg; static struct file __initdata kernel; static struct file __initdata ramdisk; +static struct file __initdata ucode; static struct file __initdata xsm; static multiboot_info_t __initdata mbi = { @@ -174,6 +175,8 @@ static void __init __attribute__((__noreturn__)) blexit(const CHAR16 *str) efi_bs->FreePages(kernel.addr, PFN_UP(kernel.size)); if ( ramdisk.addr ) efi_bs->FreePages(ramdisk.addr, PFN_UP(ramdisk.size)); + if ( ucode.addr ) + efi_bs->FreePages(ucode.addr, PFN_UP(ucode.size)); if ( xsm.addr ) efi_bs->FreePages(xsm.addr, PFN_UP(xsm.size)); @@ -806,6 +809,17 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_bs->FreePool(name.w); } + name.s = get_value(&cfg, section.s, "ucode"); + if ( !name.s ) + name.s = get_value(&cfg, "global", "ucode"); + if ( name.s ) + { + microcode_set_module(mbi.mods_count); + split_value(name.s); + read_file(dir_handle, s2w(&name), &ucode); + efi_bs->FreePool(name.w); + } + name.s = get_value(&cfg, section.s, "xsm"); if ( name.s ) { diff --git a/xen/arch/x86/microcode.c b/xen/arch/x86/microcode.c index b71622f889..d9e6a4c58d 100644 --- a/xen/arch/x86/microcode.c +++ b/xen/arch/x86/microcode.c @@ -29,13 +29,49 @@ #include #include #include +#include #include +#include #include #include #include +#include #include +static module_t __initdata ucode_mod; +static void *(*__initdata ucode_mod_map)(const module_t *); +static unsigned int __initdata ucode_mod_idx; +static bool_t __initdata ucode_mod_forced; +static cpumask_t __initdata init_mask; + +void __init microcode_set_module(unsigned int idx) +{ + ucode_mod_idx = idx; + ucode_mod_forced = 1; +} + +static void __init parse_ucode(char *s) +{ + if ( !ucode_mod_forced ) + ucode_mod_idx = simple_strtoul(s, NULL, 0); +} +custom_param("ucode", parse_ucode); + +void __init microcode_grab_module( + unsigned long *module_map, + const multiboot_info_t *mbi, + void *(*map)(const module_t *)) +{ + module_t *mod = (module_t *)__va(mbi->mods_addr); + + if ( !ucode_mod_idx || ucode_mod_idx >= mbi->mods_count || + !__test_and_clear_bit(ucode_mod_idx, module_map) ) + return; + ucode_mod = mod[ucode_mod_idx]; + ucode_mod_map = map; +} + const struct microcode_ops *microcode_ops; static DEFINE_SPINLOCK(microcode_mutex); @@ -183,6 +219,41 @@ int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len) return continue_hypercall_on_cpu(info->cpu, do_microcode_update, info); } +static void __init _do_microcode_update(unsigned long data) +{ + microcode_update_cpu((void *)data, ucode_mod.mod_end); + cpumask_set_cpu(smp_processor_id(), &init_mask); +} + +static int __init microcode_init(void) +{ + void *data; + static struct tasklet __initdata tasklet; + unsigned int cpu; + + if ( !microcode_ops || !ucode_mod.mod_end ) + return 0; + + data = ucode_mod_map(&ucode_mod); + if ( !data ) + return -ENOMEM; + + softirq_tasklet_init(&tasklet, _do_microcode_update, (unsigned long)data); + + for_each_online_cpu ( cpu ) + { + tasklet_schedule_on_cpu(&tasklet, cpu); + do { + process_pending_softirqs(); + } while ( !cpumask_test_cpu(cpu, &init_mask) ); + } + + ucode_mod_map(NULL); + + return 0; +} +__initcall(microcode_init); + static int microcode_percpu_callback( struct notifier_block *nfb, unsigned long action, void *hcpu) { @@ -205,7 +276,20 @@ static struct notifier_block microcode_percpu_nfb = { static int __init microcode_presmp_init(void) { if ( microcode_ops ) + { + if ( ucode_mod.mod_end ) + { + void *data = ucode_mod_map(&ucode_mod); + + if ( data ) + microcode_update_cpu(data, ucode_mod.mod_end); + + ucode_mod_map(NULL); + } + register_cpu_notifier(µcode_percpu_nfb); + } + return 0; } presmp_initcall(microcode_presmp_init); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index bca36ed1aa..19a38440c9 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -550,10 +550,10 @@ void __init __start_xen(unsigned long mbi_p) { char *memmap_type = NULL; char *cmdline, *kextra, *loader; - unsigned int initrdidx = 1; + unsigned int initrdidx; multiboot_info_t *mbi = __va(mbi_p); module_t *mod = (module_t *)__va(mbi->mods_addr); - unsigned long nr_pages, modules_headroom; + unsigned long nr_pages, modules_headroom, *module_map; int i, j, e820_warn = 0, bytes = 0; bool_t acpi_boot_table_init_done = 0; struct ns16550_defaults ns16550 = { @@ -1229,7 +1229,13 @@ void __init __start_xen(unsigned long mbi_p) init_IRQ(); - xsm_init(&initrdidx, mbi, bootstrap_map); + module_map = xmalloc_array(unsigned long, BITS_TO_LONGS(mbi->mods_count)); + bitmap_fill(module_map, mbi->mods_count); + __clear_bit(0, module_map); /* Dom0 kernel is always first */ + + xsm_init(module_map, mbi, bootstrap_map); + + microcode_grab_module(module_map, mbi, bootstrap_map); timer_init(); @@ -1356,6 +1362,12 @@ void __init __start_xen(unsigned long mbi_p) if ( xen_cpuidle ) xen_processor_pmbits |= XEN_PROCESSOR_PM_CX; + initrdidx = find_first_bit(module_map, mbi->mods_count); + if ( bitmap_weight(module_map, mbi->mods_count) > 1 ) + printk(XENLOG_WARNING + "Multiple initrd candidates, picking module #%u\n", + initrdidx); + /* * We're going to setup domain0 using the module(s) that we stashed safely * above our heap. The second module, if present, is an initrd ramdisk. diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index cf10ad58db..68684b92ae 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -599,6 +599,7 @@ int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx, int rdmsr_hypervisor_regs(uint32_t idx, uint64_t *val); int wrmsr_hypervisor_regs(uint32_t idx, uint64_t val); +void microcode_set_module(unsigned int); int microcode_update(XEN_GUEST_HANDLE(const_void), unsigned long len); int microcode_resume_cpu(int cpu); diff --git a/xen/include/asm-x86/setup.h b/xen/include/asm-x86/setup.h index 874b1a323e..b684f01348 100644 --- a/xen/include/asm-x86/setup.h +++ b/xen/include/asm-x86/setup.h @@ -44,4 +44,7 @@ void discard_initial_images(void); int xen_in_range(unsigned long mfn); void arch_get_xen_caps(xen_capabilities_info_t *info); +void microcode_grab_module( + unsigned long *, const multiboot_info_t *, void *(*)(const module_t *)); + #endif diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 1f70e87c50..d294f2a51d 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -454,14 +454,15 @@ static inline long __do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) } #ifdef XSM_ENABLE -extern int xsm_init(unsigned int *initrdidx, const multiboot_info_t *mbi, +extern int xsm_init(unsigned long *module_map, const multiboot_info_t *mbi, void *(*bootstrap_map)(const module_t *)); -extern int xsm_policy_init(unsigned int *initrdidx, const multiboot_info_t *mbi, +extern int xsm_policy_init(unsigned long *module_map, + const multiboot_info_t *mbi, void *(*bootstrap_map)(const module_t *)); extern int register_xsm(struct xsm_operations *ops); extern int unregister_xsm(struct xsm_operations *ops); #else -static inline int xsm_init (unsigned int *initrdidx, +static inline int xsm_init (unsigned long *module_map, const multiboot_info_t *mbi, void *(*bootstrap_map)(const module_t *)) { diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c index 3396b3d729..96c8669ac2 100644 --- a/xen/xsm/xsm_core.c +++ b/xen/xsm/xsm_core.c @@ -43,7 +43,7 @@ static void __init do_xsm_initcalls(void) } } -int __init xsm_init(unsigned int *initrdidx, const multiboot_info_t *mbi, +int __init xsm_init(unsigned long *module_map, const multiboot_info_t *mbi, void *(*bootstrap_map)(const module_t *)) { int ret = 0; @@ -52,7 +52,7 @@ int __init xsm_init(unsigned int *initrdidx, const multiboot_info_t *mbi, if ( XSM_MAGIC ) { - ret = xsm_policy_init(initrdidx, mbi, bootstrap_map); + ret = xsm_policy_init(module_map, mbi, bootstrap_map); if ( ret ) { bootstrap_map(NULL); diff --git a/xen/xsm/xsm_policy.c b/xen/xsm/xsm_policy.c index c5b334e7e9..a419cf4e84 100644 --- a/xen/xsm/xsm_policy.c +++ b/xen/xsm/xsm_policy.c @@ -20,11 +20,12 @@ #include #include +#include char *__initdata policy_buffer = NULL; u32 __initdata policy_size = 0; -int xsm_policy_init(unsigned int *initrdidx, const multiboot_info_t *mbi, +int xsm_policy_init(unsigned long *module_map, const multiboot_info_t *mbi, void *(*bootstrap_map)(const module_t *)) { int i; @@ -35,10 +36,13 @@ int xsm_policy_init(unsigned int *initrdidx, const multiboot_info_t *mbi, /* * Try all modules and see whichever could be the binary policy. - * Adjust the initrdidx if module[1] is the binary policy. + * Adjust module_map for the module that is the binary policy. */ for ( i = mbi->mods_count-1; i >= 1; i-- ) { + if ( !test_bit(i, module_map) ) + continue; + _policy_start = bootstrap_map(mod + i); _policy_len = mod[i].mod_end; @@ -50,8 +54,7 @@ int xsm_policy_init(unsigned int *initrdidx, const multiboot_info_t *mbi, printk("Policy len 0x%lx, start at %p.\n", _policy_len,_policy_start); - if ( i == 1 ) - *initrdidx = (mbi->mods_count > 2) ? 2 : 0; + __clear_bit(i, module_map); break; }