]> Git Repo - linux.git/commitdiff
Merge tag 'x86_microcode_for_v6.7_rc1' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <[email protected]>
Sat, 4 Nov 2023 18:46:37 +0000 (08:46 -1000)
committerLinus Torvalds <[email protected]>
Sat, 4 Nov 2023 18:46:37 +0000 (08:46 -1000)
Pull x86 microcode loading updates from Borislac Petkov:
 "Major microcode loader restructuring, cleanup and improvements by
  Thomas Gleixner:

   - Restructure the code needed for it and add a temporary initrd
     mapping on 32-bit so that the loader can access the microcode
     blobs. This in itself is a preparation for the next major
     improvement:

   - Do not load microcode on 32-bit before paging has been enabled.

     Handling this has caused an endless stream of headaches, issues,
     ugly code and unnecessary hacks in the past. And there really
     wasn't any sensible reason to do that in the first place. So switch
     the 32-bit loading to happen after paging has been enabled and turn
     the loader code "real purrty" again

   - Drop mixed microcode steppings loading on Intel - there, a single
     patch loaded on the whole system is sufficient

   - Rework late loading to track which CPUs have updated microcode
     successfully and which haven't, act accordingly

   - Move late microcode loading on Intel in NMI context in order to
     guarantee concurrent loading on all threads

   - Make the late loading CPU-hotplug-safe and have the offlined
     threads be woken up for the purpose of the update

   - Add support for a minimum revision which determines whether late
     microcode loading is safe on a machine and the microcode does not
     change software visible features which the machine cannot use
     anyway since feature detection has happened already. Roughly, the
     minimum revision is the smallest revision number which must be
     loaded currently on the system so that late updates can be allowed

   - Other nice leanups, fixess, etc all over the place"

* tag 'x86_microcode_for_v6.7_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (40 commits)
  x86/microcode/intel: Add a minimum required revision for late loading
  x86/microcode: Prepare for minimal revision check
  x86/microcode: Handle "offline" CPUs correctly
  x86/apic: Provide apic_force_nmi_on_cpu()
  x86/microcode: Protect against instrumentation
  x86/microcode: Rendezvous and load in NMI
  x86/microcode: Replace the all-in-one rendevous handler
  x86/microcode: Provide new control functions
  x86/microcode: Add per CPU control field
  x86/microcode: Add per CPU result state
  x86/microcode: Sanitize __wait_for_cpus()
  x86/microcode: Clarify the late load logic
  x86/microcode: Handle "nosmt" correctly
  x86/microcode: Clean up mc_cpu_down_prep()
  x86/microcode: Get rid of the schedule work indirection
  x86/microcode: Mop up early loading leftovers
  x86/microcode/amd: Use cached microcode for AP load
  x86/microcode/amd: Cache builtin/initrd microcode early
  x86/microcode/amd: Cache builtin microcode too
  x86/microcode/amd: Use correct per CPU ucode_cpu_info
  ...

1  2 
Documentation/admin-guide/kernel-parameters.txt
arch/x86/Kconfig
arch/x86/include/asm/apic.h
arch/x86/kernel/apic/apic_flat_64.c
arch/x86/kernel/apic/ipi.c
arch/x86/kernel/apic/x2apic_phys.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/head_32.S
arch/x86/kernel/nmi.c
arch/x86/kernel/smpboot.c
drivers/platform/x86/intel/ifs/load.c

index 01c7082ee999b2f923ff5fb76cb3b3cb3749e623,d762e17fd3149d9e30cffc4e54994dd92f58f1a0..2a4bc78c27ecb77419ecd9d853280b7ab633e1a0
                        named mounts. Specifying both "all" and "named" disables
                        all v1 hierarchies.
  
 +      cgroup_favordynmods= [KNL] Enable or Disable favordynmods.
 +                      Format: { "true" | "false" }
 +                      Defaults to the value of CONFIG_CGROUP_FAVOR_DYNMODS.
 +
        cgroup.memory=  [KNL] Pass options to the cgroup memory controller.
                        Format: <string>
                        nosocket -- Disable socket memory accounting.
                        earlyprintk=dbgp[debugController#]
                        earlyprintk=pciserial[,force],bus:device.function[,baudrate]
                        earlyprintk=xdbc[xhciController#]
 +                      earlyprintk=bios
  
                        earlyprintk is useful when the kernel crashes before
                        the normal console is initialized. It is not enabled by
  
                        The sclp output can only be used on s390.
  
 +                      The bios output can only be used on SuperH.
 +
                        The optional "force" to "pciserial" enables use of a
                        PCI device even when its classcode is not of the
                        UART class.
                        See comment before function elanfreq_setup() in
                        arch/x86/kernel/cpu/cpufreq/elanfreq.c.
  
 -      elfcorehdr=[size[KMG]@]offset[KMG] [IA64,PPC,SH,X86,S390]
 +      elfcorehdr=[size[KMG]@]offset[KMG] [PPC,SH,X86,S390]
                        Specifies physical address of start of kernel core
                        image elf header and optionally the size. Generally
                        kexec loader will pass this option to capture kernel.
        floppy=         [HW]
                        See Documentation/admin-guide/blockdev/floppy.rst.
  
 -      force_pal_cache_flush
 -                      [IA-64] Avoid check_sal_cache_flush which may hang on
 -                      buggy SAL_CACHE_FLUSH implementations. Using this
 -                      parameter will force ia64_sal_cache_flush to call
 -                      ia64_pal_cache_flush instead of SAL_CACHE_FLUSH.
 -
        forcepae        [X86-32]
                        Forcefully enable Physical Address Extension (PAE).
                        Many Pentium M systems disable PAE but may have a
                         0 -- machine default
                         1 -- force brightness inversion
  
 +      ia32_emulation= [X86-64]
 +                      Format: <bool>
 +                      When true, allows loading 32-bit programs and executing 32-bit
 +                      syscalls, essentially overriding IA32_EMULATION_DEFAULT_DISABLED at
 +                      boot time. When false, unconditionally disables IA32 emulation.
 +
        icn=            [HW,ISDN]
                        Format: <io>[,<membase>[,<icn_id>[,<icn_id2>]]]
  
                        to extract confidential information from the kernel
                        are also disabled.
  
 +      locktorture.acq_writer_lim= [KNL]
 +                      Set the time limit in jiffies for a lock
 +                      acquisition.  Acquisitions exceeding this limit
 +                      will result in a splat once they do complete.
 +
 +      locktorture.bind_readers= [KNL]
 +                      Specify the list of CPUs to which the readers are
 +                      to be bound.
 +
 +      locktorture.bind_writers= [KNL]
 +                      Specify the list of CPUs to which the writers are
 +                      to be bound.
 +
 +      locktorture.call_rcu_chains= [KNL]
 +                      Specify the number of self-propagating call_rcu()
 +                      chains to set up.  These are used to ensure that
 +                      there is a high probability of an RCU grace period
 +                      in progress at any given time.  Defaults to 0,
 +                      which disables these call_rcu() chains.
 +
 +      locktorture.long_hold= [KNL]
 +                      Specify the duration in milliseconds for the
 +                      occasional long-duration lock hold time.  Defaults
 +                      to 100 milliseconds.  Select 0 to disable.
 +
 +      locktorture.nested_locks= [KNL]
 +                      Specify the maximum lock nesting depth that
 +                      locktorture is to exercise, up to a limit of 8
 +                      (MAX_NESTED_LOCKS).  Specify zero to disable.
 +                      Note that this parameter is ineffective on types
 +                      of locks that do not support nested acquisition.
 +
        locktorture.nreaders_stress= [KNL]
                        Set the number of locking read-acquisition kthreads.
                        Defaults to being automatically set based on the
                        Set time (s) between CPU-hotplug operations, or
                        zero to disable CPU-hotplug testing.
  
 +      locktorture.rt_boost= [KNL]
 +                      Do periodic testing of real-time lock priority
 +                      boosting.  Select 0 to disable, 1 to boost
 +                      only rt_mutex, and 2 to boost unconditionally.
 +                      Defaults to 2, which might seem to be an
 +                      odd choice, but which should be harmless for
 +                      non-real-time spinlocks, due to their disabling
 +                      of preemption.  Note that non-realtime mutexes
 +                      disable boosting.
 +
 +      locktorture.rt_boost_factor= [KNL]
 +                      Number that determines how often and for how
 +                      long priority boosting is exercised.  This is
 +                      scaled down by the number of writers, so that the
 +                      number of boosts per unit time remains roughly
 +                      constant as the number of writers increases.
 +                      On the other hand, the duration of each boost
 +                      increases with the number of writers.
 +
        locktorture.shuffle_interval= [KNL]
                        Set task-shuffle interval (jiffies).  Shuffling
                        tasks allows some CPUs to go into dyntick-idle
        locktorture.torture_type= [KNL]
                        Specify the locking implementation to test.
  
 +      locktorture.verbose= [KNL]
 +                      Enable additional printk() statements.
 +
        locktorture.writer_fifo= [KNL]
                        Run the write-side locktorture kthreads at
                        sched_set_fifo() real-time priority.
  
 -      locktorture.verbose= [KNL]
 -                      Enable additional printk() statements.
 -
        logibm.irq=     [HW,MOUSE] Logitech Bus Mouse Driver
                        Format: <irq>
  
  
        mga=            [HW,DRM]
  
+       microcode.force_minrev= [X86]
+                       Format: <bool>
+                       Enable or disable the microcode minimal revision
+                       enforcement for the runtime microcode loader.
        min_addr=nn[KMG]        [KNL,BOOT,IA-64] All physical memory below this
                        physical address is ignored.
  
                        Set maximum number of finished RCU callbacks to
                        process in one batch.
  
 +      rcutree.do_rcu_barrier= [KNL]
 +                      Request a call to rcu_barrier().  This is
 +                      throttled so that userspace tests can safely
 +                      hammer on the sysfs variable if they so choose.
 +                      If triggered before the RCU grace-period machinery
 +                      is fully active, this will error out with EAGAIN.
 +
        rcutree.dump_tree=      [KNL]
                        Dump the structure of the rcu_node combining tree
                        out at early boot.  This is used for diagnostic
                        test until boot completes in order to avoid
                        interference.
  
 +      refscale.lookup_instances= [KNL]
 +                      Number of data elements to use for the forms of
 +                      SLAB_TYPESAFE_BY_RCU testing.  A negative number
 +                      is negated and multiplied by nr_cpu_ids, while
 +                      zero specifies nr_cpu_ids.
 +
        refscale.loops= [KNL]
                        Set the number of loops over the synchronization
                        primitive under test.  Increasing this number
                        This feature may be more efficiently disabled
                        using the csdlock_debug- kernel parameter.
  
 +      smp.panic_on_ipistall= [KNL]
 +                      If a csd_lock_timeout extends for more than
 +                      the specified number of milliseconds, panic the
 +                      system.  By default, let CSD-lock acquisition
 +                      take as long as they take.  Specifying 300,000
 +                      for this value provides a 5-minute timeout.
 +
        smsc-ircc2.nopnp        [HW] Don't use PNP to discover SMC devices
        smsc-ircc2.ircc_cfg=    [HW] Device configuration I/O port
        smsc-ircc2.ircc_sir=    [HW] SIR base I/O port
diff --combined arch/x86/Kconfig
index 6a917f62eff2068e83900577df2cde1fadbb6e92,cadea3f3161ef9f89e16c0f2a479e7d567b642b5..3762f41bb092971e3f6180f057b49742014e5f11
@@@ -28,6 -28,7 +28,6 @@@ config X86_6
        select ARCH_HAS_GIGANTIC_PAGE
        select ARCH_SUPPORTS_INT128 if CC_HAS_INT128
        select ARCH_SUPPORTS_PER_VMA_LOCK
 -      select ARCH_USE_CMPXCHG_LOCKREF
        select HAVE_ARCH_SOFT_DIRTY
        select MODULES_USE_ELF_RELA
        select NEED_DMA_MAP_STATE
@@@ -117,7 -118,6 +117,7 @@@ config X8
        select ARCH_SUPPORTS_LTO_CLANG
        select ARCH_SUPPORTS_LTO_CLANG_THIN
        select ARCH_USE_BUILTIN_BSWAP
 +      select ARCH_USE_CMPXCHG_LOCKREF         if X86_CMPXCHG64
        select ARCH_USE_MEMTEST
        select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_USE_QUEUED_SPINLOCKS
@@@ -1313,16 -1313,41 +1313,41 @@@ config MICROCOD
        def_bool y
        depends on CPU_SUP_AMD || CPU_SUP_INTEL
  
+ config MICROCODE_INITRD32
+       def_bool y
+       depends on MICROCODE && X86_32 && BLK_DEV_INITRD
  config MICROCODE_LATE_LOADING
        bool "Late microcode loading (DANGEROUS)"
        default n
-       depends on MICROCODE
+       depends on MICROCODE && SMP
        help
          Loading microcode late, when the system is up and executing instructions
          is a tricky business and should be avoided if possible. Just the sequence
          of synchronizing all cores and SMT threads is one fragile dance which does
          not guarantee that cores might not softlock after the loading. Therefore,
-         use this at your own risk. Late loading taints the kernel too.
+         use this at your own risk. Late loading taints the kernel unless the
+         microcode header indicates that it is safe for late loading via the
+         minimal revision check. This minimal revision check can be enforced on
+         the kernel command line with "microcode.minrev=Y".
+ config MICROCODE_LATE_FORCE_MINREV
+       bool "Enforce late microcode loading minimal revision check"
+       default n
+       depends on MICROCODE_LATE_LOADING
+       help
+         To prevent that users load microcode late which modifies already
+         in use features, newer microcode patches have a minimum revision field
+         in the microcode header, which tells the kernel which minimum
+         revision must be active in the CPU to safely load that new microcode
+         late into the running system. If disabled the check will not
+         be enforced but the kernel will be tainted when the minimal
+         revision check fails.
+         This minimal revision check can also be controlled via the
+         "microcode.minrev" parameter on the kernel command line.
+         If unsure say Y.
  
  config X86_MSR
        tristate "/dev/cpu/*/msr - Model-specific register support"
@@@ -1534,7 -1559,6 +1559,7 @@@ config NUM
        depends on X86_64 || (X86_32 && HIGHMEM64G && X86_BIGSMP)
        default y if X86_BIGSMP
        select USE_PERCPU_NUMA_NODE_ID
 +      select OF_NUMA if OF
        help
          Enable NUMA (Non-Uniform Memory Access) support.
  
@@@ -1940,18 -1964,6 +1965,18 @@@ config X86_USER_SHADOW_STAC
  
          If unsure, say N.
  
 +config INTEL_TDX_HOST
 +      bool "Intel Trust Domain Extensions (TDX) host support"
 +      depends on CPU_SUP_INTEL
 +      depends on X86_64
 +      depends on KVM_INTEL
 +      help
 +        Intel Trust Domain Extensions (TDX) protects guest VMs from malicious
 +        host and certain physical attacks.  This option enables necessary TDX
 +        support in the host kernel to run confidential VMs.
 +
 +        If unsure, say N.
 +
  config EFI
        bool "EFI runtime service support"
        depends on ACPI
@@@ -2075,9 -2087,6 +2100,9 @@@ config ARCH_SUPPORTS_CRASH_DUM
  config ARCH_SUPPORTS_CRASH_HOTPLUG
        def_bool y
  
 +config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
 +      def_bool CRASH_CORE
 +
  config PHYSICAL_START
        hex "Physical address where the kernel is loaded" if (EXPERT || CRASH_DUMP)
        default "0x1000000"
@@@ -2970,15 -2979,6 +2995,15 @@@ config IA32_EMULATIO
          64-bit kernel. You should likely turn this on, unless you're
          100% sure that you don't have any 32-bit programs left.
  
 +config IA32_EMULATION_DEFAULT_DISABLED
 +      bool "IA32 emulation disabled by default"
 +      default n
 +      depends on IA32_EMULATION
 +      help
 +        Make IA32 emulation disabled by default. This prevents loading 32-bit
 +        processes and access to 32-bit syscalls. If unsure, leave it to its
 +        default value.
 +
  config X86_X32_ABI
        bool "x32 ABI for 64-bit mode"
        depends on X86_64
index b0d192f613b7b4e7621221ab7f4297b7f9a91065,17f2f28a495ec6f9e7bc54d659fba260ea30d96d..d21f48f1c242e06ba9139be346f1af40d4c1084d
@@@ -54,7 -54,7 +54,7 @@@ extern int local_apic_timer_c2_ok
  extern bool apic_is_disabled;
  extern unsigned int lapic_timer_period;
  
 -extern int cpuid_to_apicid[];
 +extern u32 cpuid_to_apicid[];
  
  extern enum apic_intr_mode_id apic_intr_mode;
  enum apic_intr_mode_id {
@@@ -276,7 -276,8 +276,8 @@@ struct apic 
  
        u32     disable_esr             : 1,
                dest_mode_logical       : 1,
-               x2apic_set_max_apicid   : 1;
+               x2apic_set_max_apicid   : 1,
+               nmi_to_offline_cpu      : 1;
  
        u32     (*calc_dest_apicid)(unsigned int cpu);
  
        int     (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
        bool    (*apic_id_registered)(void);
  
 -      bool    (*check_apicid_used)(physid_mask_t *map, int apicid);
 +      bool    (*check_apicid_used)(physid_mask_t *map, u32 apicid);
        void    (*init_apic_ldr)(void);
        void    (*ioapic_phys_id_map)(physid_mask_t *phys_map, physid_mask_t *retmap);
 -      int     (*cpu_present_to_apicid)(int mps_cpu);
 -      int     (*phys_pkg_id)(int cpuid_apic, int index_msb);
 +      u32     (*cpu_present_to_apicid)(int mps_cpu);
 +      u32     (*phys_pkg_id)(u32 cpuid_apic, int index_msb);
  
 -      u32     (*get_apic_id)(unsigned long x);
 -      u32     (*set_apic_id)(unsigned int id);
 +      u32     (*get_apic_id)(u32 id);
 +      u32     (*set_apic_id)(u32 apicid);
  
        /* wakeup_secondary_cpu */
 -      int     (*wakeup_secondary_cpu)(int apicid, unsigned long start_eip);
 +      int     (*wakeup_secondary_cpu)(u32 apicid, unsigned long start_eip);
        /* wakeup secondary CPU using 64-bit wakeup point */
 -      int     (*wakeup_secondary_cpu_64)(int apicid, unsigned long start_eip);
 +      int     (*wakeup_secondary_cpu_64)(u32 apicid, unsigned long start_eip);
  
        char    *name;
  };
@@@ -322,8 -323,8 +323,8 @@@ struct apic_override 
        void    (*send_IPI_self)(int vector);
        u64     (*icr_read)(void);
        void    (*icr_write)(u32 low, u32 high);
 -      int     (*wakeup_secondary_cpu)(int apicid, unsigned long start_eip);
 -      int     (*wakeup_secondary_cpu_64)(int apicid, unsigned long start_eip);
 +      int     (*wakeup_secondary_cpu)(u32 apicid, unsigned long start_eip);
 +      int     (*wakeup_secondary_cpu_64)(u32 apicid, unsigned long start_eip);
  };
  
  /*
@@@ -493,6 -494,16 +494,6 @@@ static inline bool lapic_vector_set_in_
        return !!(irr & (1U << (vector % 32)));
  }
  
 -static inline unsigned default_get_apic_id(unsigned long x)
 -{
 -      unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
 -
 -      if (APIC_XAPIC(ver) || boot_cpu_has(X86_FEATURE_EXTD_APICID))
 -              return (x >> 24) & 0xFF;
 -      else
 -              return (x >> 24) & 0x0F;
 -}
 -
  /*
   * Warm reset vector position:
   */
@@@ -507,9 -518,9 +508,9 @@@ extern void generic_bigsmp_probe(void)
  
  extern struct apic apic_noop;
  
 -static inline unsigned int read_apic_id(void)
 +static inline u32 read_apic_id(void)
  {
 -      unsigned int reg = apic_read(APIC_ID);
 +      u32 reg = apic_read(APIC_ID);
  
        return apic->get_apic_id(reg);
  }
@@@ -528,12 -539,15 +529,14 @@@ extern int default_apic_id_valid(u32 ap
  extern u32 apic_default_calc_apicid(unsigned int cpu);
  extern u32 apic_flat_calc_apicid(unsigned int cpu);
  
 -extern bool default_check_apicid_used(physid_mask_t *map, int apicid);
  extern void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap);
 -extern int default_cpu_present_to_apicid(int mps_cpu);
 +extern u32 default_cpu_present_to_apicid(int mps_cpu);
  
+ void apic_send_nmi_to_offline_cpu(unsigned int cpu);
  #else /* CONFIG_X86_LOCAL_APIC */
  
 -static inline unsigned int read_apic_id(void) { return 0; }
 +static inline u32 read_apic_id(void) { return 0; }
  
  #endif /* !CONFIG_X86_LOCAL_APIC */
  
index 37daa3fd68199b95d8f1a69b8dee93b1097e3e54,cd16228611ce8fcd356e281c1003391963674049..7139867d69cd2d1acce95a1cec45ebe04c01ed4e
@@@ -56,17 -56,17 +56,17 @@@ flat_send_IPI_mask_allbutself(const str
        _flat_send_IPI_mask(mask, vector);
  }
  
 -static unsigned int flat_get_apic_id(unsigned long x)
 +static u32 flat_get_apic_id(u32 x)
  {
        return (x >> 24) & 0xFF;
  }
  
 -static u32 set_apic_id(unsigned int id)
 +static u32 set_apic_id(u32 id)
  {
        return (id & 0xFF) << 24;
  }
  
 -static int flat_phys_pkg_id(int initial_apic_id, int index_msb)
 +static u32 flat_phys_pkg_id(u32 initial_apic_id, int index_msb)
  {
        return initial_apic_id >> index_msb;
  }
@@@ -103,6 -103,7 +103,7 @@@ static struct apic apic_flat __ro_after
        .send_IPI_allbutself            = default_send_IPI_allbutself,
        .send_IPI_all                   = default_send_IPI_all,
        .send_IPI_self                  = default_send_IPI_self,
+       .nmi_to_offline_cpu             = true,
  
        .read                           = native_apic_mem_read,
        .write                          = native_apic_mem_write,
@@@ -158,6 -159,8 +159,6 @@@ static struct apic apic_physflat __ro_a
  
        .disable_esr                    = 0,
  
 -      .check_apicid_used              = NULL,
 -      .ioapic_phys_id_map             = NULL,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
        .phys_pkg_id                    = flat_phys_pkg_id,
  
        .send_IPI_allbutself            = default_send_IPI_allbutself,
        .send_IPI_all                   = default_send_IPI_all,
        .send_IPI_self                  = default_send_IPI_self,
+       .nmi_to_offline_cpu             = true,
  
        .read                           = native_apic_mem_read,
        .write                          = native_apic_mem_write,
index 0078730a512e2b524753e06401bc6dbe2e0da93c,edad86f32e38cb5fb36656494f4d2472d8ab7030..5da693d633b7801599cedddbd05c8cbb9689ac43
@@@ -97,6 -97,14 +97,14 @@@ sendmask
        __apic_send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
  }
  
+ void apic_send_nmi_to_offline_cpu(unsigned int cpu)
+ {
+       if (WARN_ON_ONCE(!apic->nmi_to_offline_cpu))
+               return;
+       if (WARN_ON_ONCE(!cpumask_test_cpu(cpu, &cpus_booted_once_mask)))
+               return;
+       apic->send_IPI(cpu, NMI_VECTOR);
+ }
  #endif /* CONFIG_SMP */
  
  static inline int __prepare_ICR2(unsigned int mask)
@@@ -281,7 -289,7 +289,7 @@@ void default_send_IPI_mask_logical(cons
  }
  
  #ifdef CONFIG_SMP
 -static int convert_apicid_to_cpu(int apic_id)
 +static int convert_apicid_to_cpu(u32 apic_id)
  {
        int i;
  
  
  int safe_smp_processor_id(void)
  {
 -      int apicid, cpuid;
 +      u32 apicid;
 +      int cpuid;
  
        if (!boot_cpu_has(X86_FEATURE_APIC))
                return 0;
index 7c9fe28f742f51999db374f4f13d3fc47a3ab5fa,c8ac1b12b8ac6c2f8e68cecbc61237e30195babc..558a4a8824f478938570413dd55672687370c39a
@@@ -124,17 -124,17 +124,17 @@@ static int x2apic_phys_probe(void
        return apic == &apic_x2apic_phys;
  }
  
 -unsigned int x2apic_get_apic_id(unsigned long id)
 +u32 x2apic_get_apic_id(u32 id)
  {
        return id;
  }
  
 -u32 x2apic_set_apic_id(unsigned int id)
 +u32 x2apic_set_apic_id(u32 id)
  {
        return id;
  }
  
 -int x2apic_phys_pkg_id(int initial_apicid, int index_msb)
 +u32 x2apic_phys_pkg_id(u32 initial_apicid, int index_msb)
  {
        return initial_apicid >> index_msb;
  }
@@@ -166,6 -166,7 +166,7 @@@ static struct apic apic_x2apic_phys __r
        .send_IPI_allbutself            = x2apic_send_IPI_allbutself,
        .send_IPI_all                   = x2apic_send_IPI_all,
        .send_IPI_self                  = x2apic_send_IPI_self,
+       .nmi_to_offline_cpu             = true,
  
        .read                           = native_apic_msr_read,
        .write                          = native_apic_msr_write,
index 5d9591146244d37d267929ef665f68a46b1a8f05,bd631f1320ce6de243beae966d6465d6187cc8f0..b14fc8c1c9538fb7dc827ed93e3174dacbc6d204
@@@ -62,7 -62,6 +62,7 @@@
  #include <asm/intel-family.h>
  #include <asm/cpu_device_id.h>
  #include <asm/uv/uv.h>
 +#include <asm/ia32.h>
  #include <asm/set_memory.h>
  #include <asm/traps.h>
  #include <asm/sev.h>
@@@ -75,6 -74,18 +75,6 @@@ u32 elf_hwcap2 __read_mostly
  int smp_num_siblings = 1;
  EXPORT_SYMBOL(smp_num_siblings);
  
 -/* Last level cache ID of each logical CPU */
 -DEFINE_PER_CPU_READ_MOSTLY(u16, cpu_llc_id) = BAD_APICID;
 -
 -u16 get_llc_id(unsigned int cpu)
 -{
 -      return per_cpu(cpu_llc_id, cpu);
 -}
 -EXPORT_SYMBOL_GPL(get_llc_id);
 -
 -/* L2 cache ID of each logical CPU */
 -DEFINE_PER_CPU_READ_MOSTLY(u16, cpu_l2c_id) = BAD_APICID;
 -
  static struct ppin_info {
        int     feature;
        int     msr_ppin_ctl;
@@@ -903,7 -914,7 +903,7 @@@ void detect_ht(struct cpuinfo_x86 *c
                return;
  
        index_msb = get_count_order(smp_num_siblings);
 -      c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, index_msb);
 +      c->topo.pkg_id = apic->phys_pkg_id(c->topo.initial_apicid, index_msb);
  
        smp_num_siblings = smp_num_siblings / c->x86_max_cores;
  
  
        core_bits = get_count_order(c->x86_max_cores);
  
 -      c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, index_msb) &
 -                                     ((1 << core_bits) - 1);
 +      c->topo.core_id = apic->phys_pkg_id(c->topo.initial_apicid, index_msb) &
 +              ((1 << core_bits) - 1);
  #endif
  }
  
@@@ -1103,34 -1114,18 +1103,34 @@@ void get_cpu_cap(struct cpuinfo_x86 *c
  void get_cpu_address_sizes(struct cpuinfo_x86 *c)
  {
        u32 eax, ebx, ecx, edx;
 +      bool vp_bits_from_cpuid = true;
  
 -      if (c->extended_cpuid_level >= 0x80000008) {
 +      if (!cpu_has(c, X86_FEATURE_CPUID) ||
 +          (c->extended_cpuid_level < 0x80000008))
 +              vp_bits_from_cpuid = false;
 +
 +      if (vp_bits_from_cpuid) {
                cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
  
                c->x86_virt_bits = (eax >> 8) & 0xff;
                c->x86_phys_bits = eax & 0xff;
 +      } else {
 +              if (IS_ENABLED(CONFIG_X86_64)) {
 +                      c->x86_clflush_size = 64;
 +                      c->x86_phys_bits = 36;
 +                      c->x86_virt_bits = 48;
 +              } else {
 +                      c->x86_clflush_size = 32;
 +                      c->x86_virt_bits = 32;
 +                      c->x86_phys_bits = 32;
 +
 +                      if (cpu_has(c, X86_FEATURE_PAE) ||
 +                          cpu_has(c, X86_FEATURE_PSE36))
 +                              c->x86_phys_bits = 36;
 +              }
        }
 -#ifdef CONFIG_X86_32
 -      else if (cpu_has(c, X86_FEATURE_PAE) || cpu_has(c, X86_FEATURE_PSE36))
 -              c->x86_phys_bits = 36;
 -#endif
        c->x86_cache_bits = c->x86_phys_bits;
 +      c->x86_cache_alignment = c->x86_clflush_size;
  }
  
  static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
@@@ -1584,6 -1579,17 +1584,6 @@@ static void __init cpu_parse_early_para
   */
  static void __init early_identify_cpu(struct cpuinfo_x86 *c)
  {
 -#ifdef CONFIG_X86_64
 -      c->x86_clflush_size = 64;
 -      c->x86_phys_bits = 36;
 -      c->x86_virt_bits = 48;
 -#else
 -      c->x86_clflush_size = 32;
 -      c->x86_phys_bits = 32;
 -      c->x86_virt_bits = 32;
 -#endif
 -      c->x86_cache_alignment = c->x86_clflush_size;
 -
        memset(&c->x86_capability, 0, sizeof(c->x86_capability));
        c->extended_cpuid_level = 0;
  
                cpu_detect(c);
                get_cpu_vendor(c);
                get_cpu_cap(c);
 -              get_cpu_address_sizes(c);
                setup_force_cpu_cap(X86_FEATURE_CPUID);
                cpu_parse_early_param();
  
                setup_clear_cpu_cap(X86_FEATURE_CPUID);
        }
  
 +      get_cpu_address_sizes(c);
 +
        setup_force_cpu_cap(X86_FEATURE_ALWAYS);
  
        cpu_set_bug_bits(c);
@@@ -1756,15 -1761,15 +1756,15 @@@ static void generic_identify(struct cpu
        get_cpu_address_sizes(c);
  
        if (c->cpuid_level >= 0x00000001) {
 -              c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xFF;
 +              c->topo.initial_apicid = (cpuid_ebx(1) >> 24) & 0xFF;
  #ifdef CONFIG_X86_32
  # ifdef CONFIG_SMP
 -              c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
 +              c->topo.apicid = apic->phys_pkg_id(c->topo.initial_apicid, 0);
  # else
 -              c->apicid = c->initial_apicid;
 +              c->topo.apicid = c->topo.initial_apicid;
  # endif
  #endif
 -              c->phys_proc_id = c->initial_apicid;
 +              c->topo.pkg_id = c->topo.initial_apicid;
        }
  
        get_model_name(c); /* Default name */
  static void validate_apic_and_package_id(struct cpuinfo_x86 *c)
  {
  #ifdef CONFIG_SMP
 -      unsigned int apicid, cpu = smp_processor_id();
 +      unsigned int cpu = smp_processor_id();
 +      u32 apicid;
  
        apicid = apic->cpu_present_to_apicid(cpu);
  
 -      if (apicid != c->apicid) {
 +      if (apicid != c->topo.apicid) {
                pr_err(FW_BUG "CPU%u: APIC id mismatch. Firmware: %x APIC: %x\n",
 -                     cpu, apicid, c->initial_apicid);
 +                     cpu, apicid, c->topo.initial_apicid);
        }
 -      BUG_ON(topology_update_package_map(c->phys_proc_id, cpu));
 -      BUG_ON(topology_update_die_map(c->cpu_die_id, cpu));
 +      BUG_ON(topology_update_package_map(c->topo.pkg_id, cpu));
 +      BUG_ON(topology_update_die_map(c->topo.die_id, cpu));
  #else
 -      c->logical_proc_id = 0;
 +      c->topo.logical_pkg_id = 0;
  #endif
  }
  
@@@ -1825,9 -1829,7 +1825,9 @@@ static void identify_cpu(struct cpuinfo
        c->x86_model_id[0] = '\0';  /* Unset */
        c->x86_max_cores = 1;
        c->x86_coreid_bits = 0;
 -      c->cu_id = 0xff;
 +      c->topo.cu_id = 0xff;
 +      c->topo.llc_id = BAD_APICID;
 +      c->topo.l2c_id = BAD_APICID;
  #ifdef CONFIG_X86_64
        c->x86_clflush_size = 64;
        c->x86_phys_bits = 36;
        apply_forced_caps(c);
  
  #ifdef CONFIG_X86_64
 -      c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
 +      c->topo.apicid = apic->phys_pkg_id(c->topo.initial_apicid, 0);
  #endif
  
        /*
@@@ -2072,24 -2074,24 +2072,24 @@@ void syscall_init(void
        wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
        wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
  
 -#ifdef CONFIG_IA32_EMULATION
 -      wrmsrl_cstar((unsigned long)entry_SYSCALL_compat);
 -      /*
 -       * This only works on Intel CPUs.
 -       * On AMD CPUs these MSRs are 32-bit, CPU truncates MSR_IA32_SYSENTER_EIP.
 -       * This does not cause SYSENTER to jump to the wrong location, because
 -       * AMD doesn't allow SYSENTER in long mode (either 32- or 64-bit).
 -       */
 -      wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
 -      wrmsrl_safe(MSR_IA32_SYSENTER_ESP,
 -                  (unsigned long)(cpu_entry_stack(smp_processor_id()) + 1));
 -      wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat);
 -#else
 -      wrmsrl_cstar((unsigned long)ignore_sysret);
 -      wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)GDT_ENTRY_INVALID_SEG);
 -      wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
 -      wrmsrl_safe(MSR_IA32_SYSENTER_EIP, 0ULL);
 -#endif
 +      if (ia32_enabled()) {
 +              wrmsrl_cstar((unsigned long)entry_SYSCALL_compat);
 +              /*
 +               * This only works on Intel CPUs.
 +               * On AMD CPUs these MSRs are 32-bit, CPU truncates MSR_IA32_SYSENTER_EIP.
 +               * This does not cause SYSENTER to jump to the wrong location, because
 +               * AMD doesn't allow SYSENTER in long mode (either 32- or 64-bit).
 +               */
 +              wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
 +              wrmsrl_safe(MSR_IA32_SYSENTER_ESP,
 +                          (unsigned long)(cpu_entry_stack(smp_processor_id()) + 1));
 +              wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat);
 +      } else {
 +              wrmsrl_cstar((unsigned long)entry_SYSCALL32_ignore);
 +              wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)GDT_ENTRY_INVALID_SEG);
 +              wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
 +              wrmsrl_safe(MSR_IA32_SYSENTER_EIP, 0ULL);
 +      }
  
        /*
         * Flags to clear on syscall; clear as much as possible
@@@ -2164,8 -2166,6 +2164,6 @@@ static inline void setup_getcpu(int cpu
  }
  
  #ifdef CONFIG_X86_64
- static inline void ucode_cpu_init(int cpu) { }
  static inline void tss_setup_ist(struct tss_struct *tss)
  {
        /* Set up the per-CPU TSS IST stacks */
        /* Only mapped when SEV-ES is active */
        tss->x86_tss.ist[IST_INDEX_VC] = __this_cpu_ist_top_va(VC);
  }
  #else /* CONFIG_X86_64 */
- static inline void ucode_cpu_init(int cpu)
- {
-       show_ucode_info_early();
- }
  static inline void tss_setup_ist(struct tss_struct *tss) { }
  #endif /* !CONFIG_X86_64 */
  
  static inline void tss_setup_io_bitmap(struct tss_struct *tss)
@@@ -2241,8 -2233,6 +2231,6 @@@ void cpu_init(void
        struct task_struct *cur = current;
        int cpu = raw_smp_processor_id();
  
-       ucode_cpu_init(cpu);
  #ifdef CONFIG_NUMA
        if (this_cpu_read(numa_node) == 0 &&
            early_cpu_to_node(cpu) != NUMA_NO_NODE)
index b6554212b7c7432ee56a66e95c985876fa3545f0,63f6ff4b28eb17bdea42085476ed6dff47f1ed2b..487ac57e2c81fbcdfc80ac67c40db2826c69ec05
@@@ -8,7 -8,6 +8,7 @@@
   */
  
  .text
 +#include <linux/export.h>
  #include <linux/threads.h>
  #include <linux/init.h>
  #include <linux/linkage.h>
@@@ -26,6 -25,7 +26,6 @@@
  #include <asm/nops.h>
  #include <asm/nospec-branch.h>
  #include <asm/bootparam.h>
 -#include <asm/export.h>
  #include <asm/pgtable_32.h>
  
  /* Physical address */
@@@ -118,11 -118,6 +118,6 @@@ SYM_CODE_START(startup_32
        movl %eax, pa(olpc_ofw_pgd)
  #endif
  
- #ifdef CONFIG_MICROCODE
-       /* Early load ucode on BSP. */
-       call load_ucode_bsp
- #endif
        /* Create early pagetables. */
        call  mk_early_pgtbl_32
  
@@@ -157,11 -152,6 +152,6 @@@ SYM_FUNC_START(startup_32_smp
        movl %eax,%ss
        leal -__PAGE_OFFSET(%ecx),%esp
  
- #ifdef CONFIG_MICROCODE
-       /* Early load ucode on AP. */
-       call load_ucode_ap
- #endif
  .Ldefault_entry:
        movl $(CR0_STATE & ~X86_CR0_PG),%eax
        movl %eax,%cr0
diff --combined arch/x86/kernel/nmi.c
index 4766b6bed4439330a8cb10bd53abc25331bc3230,2c6ede434a3b65bb4c9f62ece2a0e4e30200974e..17e955ab69feda933cca3708822f6f9f598e31bf
@@@ -33,6 -33,7 +33,7 @@@
  #include <asm/reboot.h>
  #include <asm/cache.h>
  #include <asm/nospec-branch.h>
+ #include <asm/microcode.h>
  #include <asm/sev.h>
  
  #define CREATE_TRACE_POINTS
@@@ -343,6 -344,9 +344,9 @@@ static noinstr void default_do_nmi(stru
  
        instrumentation_begin();
  
+       if (microcode_nmi_handler_enabled() && microcode_nmi_handler())
+               goto out;
        handled = nmi_handle(NMI_LOCAL, regs);
        __this_cpu_add(nmi_stats.normal, handled);
        if (handled) {
@@@ -498,8 -502,11 +502,11 @@@ DEFINE_IDTENTRY_RAW(exc_nmi
        if (IS_ENABLED(CONFIG_NMI_CHECK_CPU))
                raw_atomic_long_inc(&nsp->idt_calls);
  
-       if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id()))
+       if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id())) {
+               if (microcode_nmi_handler_enabled())
+                       microcode_offline_nmi_handler();
                return;
+       }
  
        if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) {
                this_cpu_write(nmi_state, NMI_LATCHED);
        }
        this_cpu_write(nmi_state, NMI_EXECUTING);
        this_cpu_write(nmi_cr2, read_cr2());
 +
 +nmi_restart:
        if (IS_ENABLED(CONFIG_NMI_CHECK_CPU)) {
                WRITE_ONCE(nsp->idt_seq, nsp->idt_seq + 1);
                WARN_ON_ONCE(!(nsp->idt_seq & 0x1));
                WRITE_ONCE(nsp->recv_jiffies, jiffies);
        }
 -nmi_restart:
  
        /*
         * Needs to happen before DR7 is accessed, because the hypervisor can
  
        if (unlikely(this_cpu_read(nmi_cr2) != read_cr2()))
                write_cr2(this_cpu_read(nmi_cr2));
 -      if (this_cpu_dec_return(nmi_state))
 -              goto nmi_restart;
 -
 -      if (user_mode(regs))
 -              mds_user_clear_cpu_buffers();
        if (IS_ENABLED(CONFIG_NMI_CHECK_CPU)) {
                WRITE_ONCE(nsp->idt_seq, nsp->idt_seq + 1);
                WARN_ON_ONCE(nsp->idt_seq & 0x1);
                WRITE_ONCE(nsp->recv_jiffies, jiffies);
        }
 +      if (this_cpu_dec_return(nmi_state))
 +              goto nmi_restart;
 +
 +      if (user_mode(regs))
 +              mds_user_clear_cpu_buffers();
  }
  
  #if IS_ENABLED(CONFIG_KVM_INTEL)
index c4aca66f090205cae721529287f3b18124bb0776,75163c80f0559c02005da60b551238b73a84842f..2cc2aa120b4b390550178e1df5b916a2bdfacf2f
@@@ -87,7 -87,6 +87,7 @@@
  #include <asm/hw_irq.h>
  #include <asm/stackprotector.h>
  #include <asm/sev.h>
 +#include <asm/spec-ctrl.h>
  
  /* representing HT siblings of each logical CPU */
  DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
@@@ -125,20 -124,7 +125,20 @@@ struct mwait_cpu_dead 
   */
  static DEFINE_PER_CPU_ALIGNED(struct mwait_cpu_dead, mwait_cpu_dead);
  
 -/* Logical package management. We might want to allocate that dynamically */
 +/* Logical package management. */
 +struct logical_maps {
 +      u32     phys_pkg_id;
 +      u32     phys_die_id;
 +      u32     logical_pkg_id;
 +      u32     logical_die_id;
 +};
 +
 +/* Temporary workaround until the full topology mechanics is in place */
 +static DEFINE_PER_CPU_READ_MOSTLY(struct logical_maps, logical_maps) = {
 +      .phys_pkg_id    = U32_MAX,
 +      .phys_die_id    = U32_MAX,
 +};
 +
  unsigned int __max_logical_packages __read_mostly;
  EXPORT_SYMBOL(__max_logical_packages);
  static unsigned int logical_packages __read_mostly;
@@@ -272,12 -258,9 +272,9 @@@ static void notrace start_secondary(voi
        cpu_init_exception_handling();
  
        /*
-        * 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.
+        * Load the microcode 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
         * CPUID, MSRs etc. must be strictly serialized to maintain
         * software state correctness.
         */
-       if (IS_ENABLED(CONFIG_X86_64))
-               load_ucode_ap();
+       load_ucode_ap();
  
        /*
         * Synchronization point with the hotplug core. Sets this CPUs
  
        cpu_init();
        fpu__init_cpu();
 -      rcu_cpu_starting(raw_smp_processor_id());
 +      rcutree_report_cpu_starting(raw_smp_processor_id());
        x86_cpuinit.early_percpu_clock_init();
  
        ap_starting();
@@@ -351,8 -333,10 +347,8 @@@ int topology_phys_to_logical_pkg(unsign
        int cpu;
  
        for_each_possible_cpu(cpu) {
 -              struct cpuinfo_x86 *c = &cpu_data(cpu);
 -
 -              if (c->initialized && c->phys_proc_id == phys_pkg)
 -                      return c->logical_proc_id;
 +              if (per_cpu(logical_maps.phys_pkg_id, cpu) == phys_pkg)
 +                      return per_cpu(logical_maps.logical_pkg_id, cpu);
        }
        return -1;
  }
@@@ -367,12 -351,14 +363,12 @@@ EXPORT_SYMBOL(topology_phys_to_logical_
   */
  static int topology_phys_to_logical_die(unsigned int die_id, unsigned int cur_cpu)
  {
 -      int cpu, proc_id = cpu_data(cur_cpu).phys_proc_id;
 +      int cpu, proc_id = cpu_data(cur_cpu).topo.pkg_id;
  
        for_each_possible_cpu(cpu) {
 -              struct cpuinfo_x86 *c = &cpu_data(cpu);
 -
 -              if (c->initialized && c->cpu_die_id == die_id &&
 -                  c->phys_proc_id == proc_id)
 -                      return c->logical_die_id;
 +              if (per_cpu(logical_maps.phys_pkg_id, cpu) == proc_id &&
 +                  per_cpu(logical_maps.phys_die_id, cpu) == die_id)
 +                      return per_cpu(logical_maps.logical_die_id, cpu);
        }
        return -1;
  }
@@@ -397,9 -383,7 +393,9 @@@ int topology_update_package_map(unsigne
                        cpu, pkg, new);
        }
  found:
 -      cpu_data(cpu).logical_proc_id = new;
 +      per_cpu(logical_maps.phys_pkg_id, cpu) = pkg;
 +      per_cpu(logical_maps.logical_pkg_id, cpu) = new;
 +      cpu_data(cpu).topo.logical_pkg_id = new;
        return 0;
  }
  /**
@@@ -422,9 -406,7 +418,9 @@@ int topology_update_die_map(unsigned in
                        cpu, die, new);
        }
  found:
 -      cpu_data(cpu).logical_die_id = new;
 +      per_cpu(logical_maps.phys_die_id, cpu) = die;
 +      per_cpu(logical_maps.logical_die_id, cpu) = new;
 +      cpu_data(cpu).topo.logical_die_id = new;
        return 0;
  }
  
@@@ -435,8 -417,8 +431,8 @@@ static void __init smp_store_boot_cpu_i
  
        *c = boot_cpu_data;
        c->cpu_index = id;
 -      topology_update_package_map(c->phys_proc_id, id);
 -      topology_update_die_map(c->cpu_die_id, id);
 +      topology_update_package_map(c->topo.pkg_id, id);
 +      topology_update_die_map(c->topo.die_id, id);
        c->initialized = true;
  }
  
@@@ -490,21 -472,21 +486,21 @@@ static bool match_smt(struct cpuinfo_x8
        if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
                int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
  
 -              if (c->phys_proc_id == o->phys_proc_id &&
 -                  c->cpu_die_id == o->cpu_die_id &&
 -                  per_cpu(cpu_llc_id, cpu1) == per_cpu(cpu_llc_id, cpu2)) {
 -                      if (c->cpu_core_id == o->cpu_core_id)
 +              if (c->topo.pkg_id == o->topo.pkg_id &&
 +                  c->topo.die_id == o->topo.die_id &&
 +                  per_cpu_llc_id(cpu1) == per_cpu_llc_id(cpu2)) {
 +                      if (c->topo.core_id == o->topo.core_id)
                                return topology_sane(c, o, "smt");
  
 -                      if ((c->cu_id != 0xff) &&
 -                          (o->cu_id != 0xff) &&
 -                          (c->cu_id == o->cu_id))
 +                      if ((c->topo.cu_id != 0xff) &&
 +                          (o->topo.cu_id != 0xff) &&
 +                          (c->topo.cu_id == o->topo.cu_id))
                                return topology_sane(c, o, "smt");
                }
  
 -      } else if (c->phys_proc_id == o->phys_proc_id &&
 -                 c->cpu_die_id == o->cpu_die_id &&
 -                 c->cpu_core_id == o->cpu_core_id) {
 +      } else if (c->topo.pkg_id == o->topo.pkg_id &&
 +                 c->topo.die_id == o->topo.die_id &&
 +                 c->topo.core_id == o->topo.core_id) {
                return topology_sane(c, o, "smt");
        }
  
  
  static bool match_die(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
  {
 -      if (c->phys_proc_id == o->phys_proc_id &&
 -          c->cpu_die_id == o->cpu_die_id)
 +      if (c->topo.pkg_id == o->topo.pkg_id &&
 +          c->topo.die_id == o->topo.die_id)
                return true;
        return false;
  }
@@@ -524,11 -506,11 +520,11 @@@ static bool match_l2c(struct cpuinfo_x8
        int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
  
        /* If the arch didn't set up l2c_id, fall back to SMT */
 -      if (per_cpu(cpu_l2c_id, cpu1) == BAD_APICID)
 +      if (per_cpu_l2c_id(cpu1) == BAD_APICID)
                return match_smt(c, o);
  
        /* Do not match if L2 cache id does not match: */
 -      if (per_cpu(cpu_l2c_id, cpu1) != per_cpu(cpu_l2c_id, cpu2))
 +      if (per_cpu_l2c_id(cpu1) != per_cpu_l2c_id(cpu2))
                return false;
  
        return topology_sane(c, o, "l2c");
   */
  static bool match_pkg(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
  {
 -      if (c->phys_proc_id == o->phys_proc_id)
 +      if (c->topo.pkg_id == o->topo.pkg_id)
                return true;
        return false;
  }
@@@ -574,11 -556,11 +570,11 @@@ static bool match_llc(struct cpuinfo_x8
        bool intel_snc = id && id->driver_data;
  
        /* Do not match if we do not have a valid APICID for cpu: */
 -      if (per_cpu(cpu_llc_id, cpu1) == BAD_APICID)
 +      if (per_cpu_llc_id(cpu1) == BAD_APICID)
                return false;
  
        /* Do not match if LLC id does not match: */
 -      if (per_cpu(cpu_llc_id, cpu1) != per_cpu(cpu_llc_id, cpu2))
 +      if (per_cpu_llc_id(cpu1) != per_cpu_llc_id(cpu2))
                return false;
  
        /*
@@@ -654,13 -636,13 +650,13 @@@ static void __init build_sched_topology
        };
  #endif
        /*
 -       * When there is NUMA topology inside the package skip the DIE domain
 +       * When there is NUMA topology inside the package skip the PKG domain
         * since the NUMA domains will auto-magically create the right spanning
         * domains based on the SLIT.
         */
        if (!x86_has_numa_in_package) {
                x86_topology[i++] = (struct sched_domain_topology_level){
 -                      cpu_cpu_mask, x86_die_flags, SD_INIT_NAME(DIE)
 +                      cpu_cpu_mask, x86_die_flags, SD_INIT_NAME(PKG)
                };
        }
  
@@@ -823,7 -805,7 +819,7 @@@ static void __init smp_quirk_init_udela
  /*
   * Wake up AP by INIT, INIT, STARTUP sequence.
   */
 -static void send_init_sequence(int phys_apicid)
 +static void send_init_sequence(u32 phys_apicid)
  {
        int maxlvt = lapic_get_maxlvt();
  
  /*
   * Wake up AP by INIT, INIT, STARTUP sequence.
   */
 -static int wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 +static int wakeup_secondary_cpu_via_init(u32 phys_apicid, unsigned long start_eip)
  {
        unsigned long send_status = 0, accept_status = 0;
        int num_starts, j, maxlvt;
@@@ -996,7 -978,7 +992,7 @@@ int common_cpu_up(unsigned int cpu, str
   * Returns zero if startup was successfully sent, else error code from
   * ->wakeup_secondary_cpu.
   */
 -static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
 +static int do_boot_cpu(u32 apicid, int cpu, struct task_struct *idle)
  {
        unsigned long start_ip = real_mode_header->trampoline_start;
        int ret;
  
  int native_kick_ap(unsigned int cpu, struct task_struct *tidle)
  {
 -      int apicid = apic->cpu_present_to_apicid(cpu);
 +      u32 apicid = apic->cpu_present_to_apicid(cpu);
        int err;
  
        lockdep_assert_irqs_enabled();
@@@ -1419,7 -1401,7 +1415,7 @@@ static void remove_siblinginfo(int cpu
        cpumask_clear(topology_sibling_cpumask(cpu));
        cpumask_clear(topology_core_cpumask(cpu));
        cpumask_clear(topology_die_cpumask(cpu));
 -      c->cpu_core_id = 0;
 +      c->topo.core_id = 0;
        c->booted_cores = 0;
        cpumask_clear_cpu(cpu, cpu_sibling_setup_mask);
        recompute_smt_state();
@@@ -1610,15 -1592,8 +1606,15 @@@ void __noreturn hlt_play_dead(void
                native_halt();
  }
  
 +/*
 + * native_play_dead() is essentially a __noreturn function, but it can't
 + * be marked as such as the compiler may complain about it.
 + */
  void native_play_dead(void)
  {
 +      if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS))
 +              __update_spec_ctrl(0);
 +
        play_dead_common();
        tboot_shutdown(TB_SHUTDOWN_WFS);
  
index 959b1878cae62f8f5f05874cfaa7a2cf5794ec1c,3e1880f8e12af5dd3ed8487658a1cce2c3090977..a1ee1a74fc3c4cb7e7bc62cda0297acdbe942d54
@@@ -2,7 -2,6 +2,7 @@@
  /* Copyright(c) 2022 Intel Corporation. */
  
  #include <linux/firmware.h>
 +#include <linux/sizes.h>
  #include <asm/cpu.h>
  #include <asm/microcode.h>
  
@@@ -27,11 -26,6 +27,11 @@@ union meta_data 
  
  #define IFS_HEADER_SIZE       (sizeof(struct microcode_header_intel))
  #define META_TYPE_IFS 1
 +#define INVALIDATE_STRIDE     0x1UL
 +#define IFS_GEN_STRIDE_AWARE  2
 +#define AUTH_INTERRUPTED_ERROR        5
 +#define IFS_AUTH_RETRY_CT     10
 +
  static  struct microcode_header_intel *ifs_header_ptr;        /* pointer to the ifs image header */
  static u64 ifs_hash_ptr;                      /* Address of ifs metadata (hash) */
  static u64 ifs_test_image_ptr;                        /* 256B aligned address of test pattern */
@@@ -50,10 -44,7 +50,10 @@@ static const char * const scan_hash_sta
  static const char * const scan_authentication_status[] = {
        [0] = "No error reported",
        [1] = "Attempt to authenticate a chunk which is already marked as authentic",
 -      [2] = "Chunk authentication error. The hash of chunk did not match expected value"
 +      [2] = "Chunk authentication error. The hash of chunk did not match expected value",
 +      [3] = "Reserved",
 +      [4] = "Chunk outside the current stride",
 +      [5] = "Authentication flow interrupted",
  };
  
  #define MC_HEADER_META_TYPE_END               (0)
@@@ -89,23 -80,6 +89,23 @@@ static struct metadata_header *find_met
        return NULL;
  }
  
 +static void hashcopy_err_message(struct device *dev, u32 err_code)
 +{
 +      if (err_code >= ARRAY_SIZE(scan_hash_status))
 +              dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code);
 +      else
 +              dev_err(dev, "Hash copy error : %s\n", scan_hash_status[err_code]);
 +}
 +
 +static void auth_err_message(struct device *dev, u32 err_code)
 +{
 +      if (err_code >= ARRAY_SIZE(scan_authentication_status))
 +              dev_err(dev, "invalid error code 0x%x for authentication\n", err_code);
 +      else
 +              dev_err(dev, "Chunk authentication error : %s\n",
 +                      scan_authentication_status[err_code]);
 +}
 +
  /*
   * To copy scan hashes and authenticate test chunks, the initiating cpu must point
   * to the EDX:EAX to the test image in linear address.
@@@ -135,7 -109,11 +135,7 @@@ static void copy_hashes_authenticate_ch
  
        if (!hashes_status.valid) {
                ifsd->loading_error = true;
 -              if (err_code >= ARRAY_SIZE(scan_hash_status)) {
 -                      dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code);
 -                      goto done;
 -              }
 -              dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]);
 +              hashcopy_err_message(dev, err_code);
                goto done;
        }
  
  
                if (err_code) {
                        ifsd->loading_error = true;
 -                      if (err_code >= ARRAY_SIZE(scan_authentication_status)) {
 -                              dev_err(dev,
 -                                      "invalid error code 0x%x for authentication\n", err_code);
 -                              goto done;
 -                      }
 -                      dev_err(dev, "Chunk authentication error %s\n",
 -                              scan_authentication_status[err_code]);
 +                      auth_err_message(dev, err_code);
                        goto done;
                }
        }
@@@ -163,102 -147,6 +163,102 @@@ done
        complete(&ifs_done);
  }
  
 +static int get_num_chunks(int gen, union ifs_scan_hashes_status_gen2 status)
 +{
 +      return gen >= IFS_GEN_STRIDE_AWARE ? status.chunks_in_stride : status.num_chunks;
 +}
 +
 +static bool need_copy_scan_hashes(struct ifs_data *ifsd)
 +{
 +      return !ifsd->loaded ||
 +              ifsd->generation < IFS_GEN_STRIDE_AWARE ||
 +              ifsd->loaded_version != ifs_header_ptr->rev;
 +}
 +
 +static int copy_hashes_authenticate_chunks_gen2(struct device *dev)
 +{
 +      union ifs_scan_hashes_status_gen2 hashes_status;
 +      union ifs_chunks_auth_status_gen2 chunk_status;
 +      u32 err_code, valid_chunks, total_chunks;
 +      int i, num_chunks, chunk_size;
 +      union meta_data *ifs_meta;
 +      int starting_chunk_nr;
 +      struct ifs_data *ifsd;
 +      u64 linear_addr, base;
 +      u64 chunk_table[2];
 +      int retry_count;
 +
 +      ifsd = ifs_get_data(dev);
 +
 +      if (need_copy_scan_hashes(ifsd)) {
 +              wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr);
 +              rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data);
 +
 +              /* enumerate the scan image information */
 +              chunk_size = hashes_status.chunk_size * SZ_1K;
 +              err_code = hashes_status.error_code;
 +
 +              num_chunks = get_num_chunks(ifsd->generation, hashes_status);
 +
 +              if (!hashes_status.valid) {
 +                      hashcopy_err_message(dev, err_code);
 +                      return -EIO;
 +              }
 +              ifsd->loaded_version = ifs_header_ptr->rev;
 +              ifsd->chunk_size = chunk_size;
 +      } else {
 +              num_chunks = ifsd->valid_chunks;
 +              chunk_size = ifsd->chunk_size;
 +      }
 +
 +      if (ifsd->generation >= IFS_GEN_STRIDE_AWARE) {
 +              wrmsrl(MSR_SAF_CTRL, INVALIDATE_STRIDE);
 +              rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
 +              if (chunk_status.valid_chunks != 0) {
 +                      dev_err(dev, "Couldn't invalidate installed stride - %d\n",
 +                              chunk_status.valid_chunks);
 +                      return -EIO;
 +              }
 +      }
 +
 +      base = ifs_test_image_ptr;
 +      ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS);
 +      starting_chunk_nr = ifs_meta->starting_chunk;
 +
 +      /* scan data authentication and copy chunks to secured memory */
 +      for (i = 0; i < num_chunks; i++) {
 +              retry_count = IFS_AUTH_RETRY_CT;
 +              linear_addr = base + i * chunk_size;
 +
 +              chunk_table[0] = starting_chunk_nr + i;
 +              chunk_table[1] = linear_addr;
 +              do {
 +                      wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table);
 +                      rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
 +                      err_code = chunk_status.error_code;
 +              } while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count);
 +
 +              if (err_code) {
 +                      ifsd->loading_error = true;
 +                      auth_err_message(dev, err_code);
 +                      return -EIO;
 +              }
 +      }
 +
 +      valid_chunks = chunk_status.valid_chunks;
 +      total_chunks = chunk_status.total_chunks;
 +
 +      if (valid_chunks != total_chunks) {
 +              ifsd->loading_error = true;
 +              dev_err(dev, "Couldn't authenticate all the chunks. Authenticated %d total %d.\n",
 +                      valid_chunks, total_chunks);
 +              return -EIO;
 +      }
 +      ifsd->valid_chunks = valid_chunks;
 +
 +      return 0;
 +}
 +
  static int validate_ifs_metadata(struct device *dev)
  {
        struct ifs_data *ifsd = ifs_get_data(dev);
                return ret;
        }
  
 +      if (ifs_meta->chunks_per_stride &&
 +          (ifs_meta->starting_chunk % ifs_meta->chunks_per_stride != 0)) {
 +              dev_warn(dev, "Starting chunk num %u not a multiple of chunks_per_stride %u\n",
 +                       ifs_meta->starting_chunk, ifs_meta->chunks_per_stride);
 +              return ret;
 +      }
 +
        return 0;
  }
  
@@@ -318,9 -199,7 +318,9 @@@ static int scan_chunks_sanity_check(str
                return ret;
  
        ifsd->loading_error = false;
 -      ifsd->loaded_version = ifs_header_ptr->rev;
 +
 +      if (ifsd->generation > 0)
 +              return copy_hashes_authenticate_chunks_gen2(dev);
  
        /* copy the scan hash and authenticate per package */
        cpus_read_lock();
                ifs_pkg_auth[curr_pkg] = 1;
        }
        ret = 0;
 +      ifsd->loaded_version = ifs_header_ptr->rev;
  out:
        cpus_read_unlock();
  
  
  static int image_sanity_check(struct device *dev, const struct microcode_header_intel *data)
  {
-       struct ucode_cpu_info uci;
+       struct cpu_signature sig;
  
        /* Provide a specific error message when loading an older/unsupported image */
        if (data->hdrver != MC_HEADER_TYPE_IFS) {
                return -EINVAL;
        }
  
-       intel_cpu_collect_info(&uci);
+       intel_collect_cpu_info(&sig);
  
-       if (!intel_find_matching_signature((void *)data,
-                                          uci.cpu_sig.sig,
-                                          uci.cpu_sig.pf)) {
+       if (!intel_find_matching_signature((void *)data, &sig)) {
                dev_err(dev, "cpu signature, processor flags not matching\n");
                return -EINVAL;
        }
@@@ -382,7 -258,6 +380,7 @@@ int ifs_load_firmware(struct device *de
  {
        const struct ifs_test_caps *test = ifs_get_test_caps(dev);
        struct ifs_data *ifsd = ifs_get_data(dev);
 +      unsigned int expected_size;
        const struct firmware *fw;
        char scan_path[64];
        int ret = -EINVAL;
                goto done;
        }
  
 +      expected_size = ((struct microcode_header_intel *)fw->data)->totalsize;
 +      if (fw->size != expected_size) {
 +              dev_err(dev, "File size mismatch (expected %u, actual %zu). Corrupted IFS image.\n",
 +                      expected_size, fw->size);
 +              return -EINVAL;
 +      }
 +
        ret = image_sanity_check(dev, (struct microcode_header_intel *)fw->data);
        if (ret)
                goto release;
This page took 0.167251 seconds and 4 git commands to generate.