diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c
index 9c44bbd..6c27008 100644
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -252,6 +252,8 @@ static void __init early_cpu_detect(void)
 		if (hap_paddr_bits > PADDR_BITS)
 			hap_paddr_bits = PADDR_BITS;
 	}
+
+	initialize_cpu_data(0);
 }
 
 static void generic_identify(struct cpuinfo_x86 *c)
diff --git a/xen/arch/x86/microcode.c b/xen/arch/x86/microcode.c
index 30a0806..bb2f431 100644
--- a/xen/arch/x86/microcode.c
+++ b/xen/arch/x86/microcode.c
@@ -43,7 +43,6 @@ static module_t __initdata ucode_mod;
 static void *(*__initdata ucode_mod_map)(const module_t *);
 static signed int __initdata ucode_mod_idx;
 static bool_t __initdata ucode_mod_forced;
-static cpumask_t __initdata init_mask;
 
 /*
  * If we scan the initramfs.cpio for the early microcode code
@@ -341,50 +340,23 @@ int microcode_update(XEN_GUEST_HANDLE_PARAM(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)
-{
-    void *_data = (void *)data;
-    size_t len = ucode_blob.size ? ucode_blob.size : ucode_mod.mod_end;
-
-    microcode_update_cpu(_data, len);
-    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 )
-        return 0;
-
-    if ( !ucode_mod.mod_end && !ucode_blob.size )
-        return 0;
-
-    data = ucode_blob.size ? ucode_blob.data : ucode_mod_map(&ucode_mod);
-
-    if ( !data )
-        return -ENOMEM;
-
-    if ( microcode_ops->start_update && microcode_ops->start_update() != 0 )
-        goto out;
-
-    softirq_tasklet_init(&tasklet, _do_microcode_update, (unsigned long)data);
-
-    for_each_online_cpu ( cpu )
+    /*
+     * At this point, all CPUs should have updated their microcode
+     * via the early_microcode_* paths so free the microcode blob.
+     */
+    if ( ucode_blob.size )
     {
-        tasklet_schedule_on_cpu(&tasklet, cpu);
-        do {
-            process_pending_softirqs();
-        } while ( !cpumask_test_cpu(cpu, &init_mask) );
+        xfree(ucode_blob.data);
+        ucode_blob.size = 0;
+        ucode_blob.data = NULL;
     }
-
-out:
-    if ( ucode_blob.size )
-        xfree(data);
-    else
+    else if ( ucode_mod.mod_end )
+    {
         ucode_mod_map(NULL);
+        ucode_mod.mod_end = 0;
+    }
 
     return 0;
 }
@@ -409,50 +381,55 @@ static struct notifier_block microcode_percpu_nfb = {
     .notifier_call = microcode_percpu_callback,
 };
 
-static int __init microcode_presmp_init(void)
+int __init early_microcode_update_cpu(bool_t start_update)
+{
+    int rc = 0;
+    void *data = NULL;
+    size_t len;
+
+    if ( ucode_blob.size )
+    {
+        len = ucode_blob.size;
+        data = ucode_blob.data;
+    }
+    else if ( ucode_mod.mod_end )
+    {
+        len = ucode_mod.mod_end;
+        data = ucode_mod_map(&ucode_mod);
+    }
+    if ( data )
+    {
+        if ( start_update && microcode_ops->start_update )
+            rc = microcode_ops->start_update();
+
+        if ( rc )
+            return rc;
+
+        return microcode_update_cpu(data, len);
+    }
+    else
+        return -ENOMEM;
+}
+
+int __init early_microcode_init(void)
 {
+    int rc;
+
+    rc = microcode_init_intel();
+    if ( rc )
+        return rc;
+
+    rc = microcode_init_amd();
+    if ( rc )
+        return rc;
+
     if ( microcode_ops )
     {
         if ( ucode_mod.mod_end || ucode_blob.size )
-        {
-            void *data;
-            size_t len;
-            int rc = 0;
-
-            if ( ucode_blob.size )
-            {
-                len = ucode_blob.size;
-                data = ucode_blob.data;
-            }
-            else
-            {
-                len = ucode_mod.mod_end;
-                data = ucode_mod_map(&ucode_mod);
-            }
-            if ( data )
-                rc = microcode_update_cpu(data, len);
-            else
-                rc = -ENOMEM;
-
-            if ( !ucode_blob.size )
-                ucode_mod_map(NULL);
-
-            if ( rc )
-            {
-                if ( ucode_blob.size )
-                {
-                    xfree(ucode_blob.data);
-                    ucode_blob.size = 0;
-                    ucode_blob.data = NULL;
-                }
-                else
-                    ucode_mod.mod_end = 0;
-            }
-        }
+            rc = early_microcode_update_cpu(true);
 
         register_cpu_notifier(&microcode_percpu_nfb);
     }
 
     return 0;
 }
-presmp_initcall(microcode_presmp_init);
diff --git a/xen/arch/x86/microcode_amd.c b/xen/arch/x86/microcode_amd.c
index 4759911..b54b0b9 100644
--- a/xen/arch/x86/microcode_amd.c
+++ b/xen/arch/x86/microcode_amd.c
@@ -627,10 +627,9 @@ static const struct microcode_ops microcode_amd_ops = {
     .start_update                     = start_update,
 };
 
-static __init int microcode_init_amd(void)
+int __init microcode_init_amd(void)
 {
     if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
         microcode_ops = &microcode_amd_ops;
     return 0;
 }
-presmp_initcall(microcode_init_amd);
diff --git a/xen/arch/x86/microcode_intel.c b/xen/arch/x86/microcode_intel.c
index ba3971a..c6b67e4 100644
--- a/xen/arch/x86/microcode_intel.c
+++ b/xen/arch/x86/microcode_intel.c
@@ -404,10 +404,9 @@ static const struct microcode_ops microcode_intel_ops = {
     .apply_microcode                  = apply_microcode,
 };
 
-static __init int microcode_init_intel(void)
+int __init microcode_init_intel(void)
 {
     if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
         microcode_ops = &microcode_intel_ops;
     return 0;
 }
-presmp_initcall(microcode_init_intel);
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index c3d99e9..f7b9278 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -1461,6 +1461,8 @@ void __init noreturn __start_xen(unsigned long mbi_p)
 
     timer_init();
 
+    early_microcode_init();
+
     identify_cpu(&boot_cpu_data);
 
     set_in_cr4(X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT);
diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
index 82559ed..4e01c7b 100644
--- a/xen/arch/x86/smpboot.c
+++ b/xen/arch/x86/smpboot.c
@@ -83,22 +83,22 @@ static enum cpu_state {
 
 void *stack_base[NR_CPUS];
 
+void initialize_cpu_data(unsigned int cpu)
+{
+    *(cpu_data + cpu) = boot_cpu_data;
+}
+
 static void smp_store_cpu_info(int id)
 {
-    struct cpuinfo_x86 *c = cpu_data + id;
     unsigned int socket;
 
-    *c = boot_cpu_data;
-    if ( id != 0 )
-    {
-        identify_cpu(c);
+    identify_cpu(cpu_data + id);
 
-        socket = cpu_to_socket(id);
-        if ( !socket_cpumask[socket] )
-        {
-            socket_cpumask[socket] = secondary_socket_cpumask;
-            secondary_socket_cpumask = NULL;
-        }
+    socket = cpu_to_socket(id);
+    if ( !socket_cpumask[socket] )
+    {
+        socket_cpumask[socket] = secondary_socket_cpumask;
+        secondary_socket_cpumask = NULL;
     }
 }
 
@@ -332,6 +332,13 @@ void start_secondary(void *unused)
 
     cpu_init();
 
+    initialize_cpu_data(cpu);
+
+    if ( system_state <= SYS_STATE_smp_boot )
+        early_microcode_update_cpu(false);
+    else
+        microcode_resume_cpu(cpu);
+
     smp_callin();
 
     init_percpu_time();
@@ -364,8 +371,6 @@ void start_secondary(void *unused)
     local_irq_enable();
     mtrr_ap_init();
 
-    microcode_resume_cpu(cpu);
-
     wmb();
     startup_cpu_idle_loop();
 }
@@ -780,7 +785,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
     mtrr_aps_sync_begin();
 
     /* Setup boot CPU information */
-    smp_store_cpu_info(0); /* Final full version of the data */
+    initialize_cpu_data(0); /* Final full version of the data */
     print_cpu_info(0);
 
     boot_cpu_physical_apicid = get_apic_id();
diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h
index 75632d9..7762356 100644
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -563,6 +563,10 @@ int wrmsr_hypervisor_regs(uint32_t idx, uint64_t val);
 void microcode_set_module(unsigned int);
 int microcode_update(XEN_GUEST_HANDLE_PARAM(const_void), unsigned long len);
 int microcode_resume_cpu(unsigned int cpu);
+int early_microcode_update_cpu(bool_t start_update);
+int early_microcode_init(void);
+int microcode_init_intel(void);
+int microcode_init_amd(void);
 
 enum get_cpu_vendor {
     gcv_host,
diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h
index 6febb56..c55f57f 100644
--- a/xen/include/xen/smp.h
+++ b/xen/include/xen/smp.h
@@ -71,4 +71,6 @@ int alloc_cpu_id(void);
 
 extern void *stack_base[NR_CPUS];
 
+void initialize_cpu_data(unsigned int cpu);
+
 #endif /* __XEN_SMP_H__ */
