#include <linux/overflow.h>
 #include <linux/stackprotector.h>
 #include <linux/cpuhotplug.h>
+#include <linux/mc146818rtc.h>
 
 #include <asm/acpi.h>
 #include <asm/cacheinfo.h>
 #include <asm/fpu/api.h>
 #include <asm/setup.h>
 #include <asm/uv/uv.h>
-#include <linux/mc146818rtc.h>
+#include <asm/microcode.h>
 #include <asm/i8259.h>
 #include <asm/misc.h>
 #include <asm/qspinlock.h>
        return retval;
 }
 
-
 static unsigned int smpboot_warm_reset_vector_count;
 
 static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
         */
        cr4_init();
 
-#ifdef CONFIG_X86_32
-       /* switch away from the initial page table */
-       load_cr3(swapper_pg_dir);
-       __flush_tlb_all();
-#endif
+       /*
+        * 32-bit specific. 64-bit reaches this code with the correct page
+        * table established. Yet another historical divergence.
+        */
+       if (IS_ENABLED(CONFIG_X86_32)) {
+               /* switch away from the initial page table */
+               load_cr3(swapper_pg_dir);
+               __flush_tlb_all();
+       }
+
        cpu_init_exception_handling();
 
        /*
-        * Synchronization point with the hotplug core. Sets the
-        * synchronization state to ALIVE and waits for the control CPU to
+        * 32-bit systems load the microcode from the ASM startup code for
+        * historical reasons.
+        *
+        * On 64-bit systems load it before reaching the AP alive
+        * synchronization point below so it is not part of the full per
+        * CPU serialized bringup part when "parallel" bringup is enabled.
+        *
+        * That's even safe when hyperthreading is enabled in the CPU as
+        * the core code starts the primary threads first and leaves the
+        * secondary threads waiting for SIPI. Loading microcode on
+        * physical cores concurrently is a safe operation.
+        *
+        * This covers both the Intel specific issue that concurrent
+        * microcode loading on SMT siblings must be prohibited and the
+        * vendor independent issue`that microcode loading which changes
+        * CPUID, MSRs etc. must be strictly serialized to maintain
+        * software state correctness.
+        */
+       if (IS_ENABLED(CONFIG_X86_64))
+               load_ucode_ap();
+
+       /*
+        * Synchronization point with the hotplug core. Sets this CPUs
+        * synchronization state to ALIVE and spin-waits for the control CPU to
         * release this CPU for further bringup.
         */
        cpuhp_ap_sync_alive();
 /* reduce the number of lines printed when booting a large cpu count system */
 static void announce_cpu(int cpu, int apicid)
 {
+       static int width, node_width, first = 1;
        static int current_node = NUMA_NO_NODE;
        int node = early_cpu_to_node(cpu);
-       static int width, node_width;
 
        if (!width)
                width = num_digits(num_possible_cpus()) + 1; /* + '#' sign */
        if (!node_width)
                node_width = num_digits(num_possible_nodes()) + 1; /* + '#' */
 
-       if (cpu == 1)
-               printk(KERN_INFO "x86: Booting SMP configuration:\n");
-
        if (system_state < SYSTEM_RUNNING) {
+               if (first)
+                       pr_info("x86: Booting SMP configuration:\n");
+
                if (node != current_node) {
                        if (current_node > (-1))
                                pr_cont("\n");
                }
 
                /* Add padding for the BSP */
-               if (cpu == 1)
+               if (first)
                        pr_cont("%*s", width + 1, " ");
+               first = 0;
 
                pr_cont("%*s#%d", width - num_digits(cpu), " ", cpu);
-
        } else
                pr_info("Booting Node %d Processor %d APIC 0x%x\n",
                        node, cpu, apicid);
        set_cpu_sibling_map(0);
 }
 
+#ifdef CONFIG_X86_64
+/* Establish whether parallel bringup can be supported. */
+bool __init arch_cpuhp_init_parallel_bringup(void)
+{
+       /*
+        * Encrypted guests require special handling. They enforce X2APIC
+        * mode but the RDMSR to read the APIC ID is intercepted and raises
+        * #VC or #VE which cannot be handled in the early startup code.
+        *
+        * AMD-SEV does not provide a RDMSR GHCB protocol so the early
+        * startup code cannot directly communicate with the secure
+        * firmware. The alternative solution to retrieve the APIC ID via
+        * CPUID(0xb), which is covered by the GHCB protocol, is not viable
+        * either because there is no enforcement of the CPUID(0xb)
+        * provided "initial" APIC ID to be the same as the real APIC ID.
+        *
+        * Intel-TDX has a secure RDMSR hypercall, but that needs to be
+        * implemented seperately in the low level startup ASM code.
+        */
+       if (cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT)) {
+               pr_info("Parallel CPU startup disabled due to guest state encryption\n");
+               return false;
+       }
+
+       smpboot_control = STARTUP_READ_APICID;
+       pr_debug("Parallel CPU startup enabled: 0x%08x\n", smpboot_control);
+       return true;
+}
+#endif
+
 /*
  * Prepare for SMP bootup.
  * @max_cpus: configured maximum number of CPUs, It is a legacy parameter