Merge tag 'x86_microcode_for_v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 13 Dec 2022 23:05:29 +0000 (15:05 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 13 Dec 2022 23:05:29 +0000 (15:05 -0800)
Pull x86 microcode and IFS updates from Borislav Petkov:
 "The IFS (In-Field Scan) stuff goes through tip because the IFS driver
  uses the same structures and similar functionality as the microcode
  loader and it made sense to route it all through this branch so that
  there are no conflicts.

   - Add support for multiple testing sequences to the Intel In-Field
     Scan driver in order to be able to run multiple different test
     patterns. Rework things and remove the BROKEN dependency so that
     the driver can be enabled (Jithu Joseph)

   - Remove the subsys interface usage in the microcode loader because
     it is not really needed

   - A couple of smaller fixes and cleanups"

* tag 'x86_microcode_for_v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits)
  x86/microcode/intel: Do not retry microcode reloading on the APs
  x86/microcode/intel: Do not print microcode revision and processor flags
  platform/x86/intel/ifs: Add missing kernel-doc entry
  Revert "platform/x86/intel/ifs: Mark as BROKEN"
  Documentation/ABI: Update IFS ABI doc
  platform/x86/intel/ifs: Add current_batch sysfs entry
  platform/x86/intel/ifs: Remove reload sysfs entry
  platform/x86/intel/ifs: Add metadata validation
  platform/x86/intel/ifs: Use generic microcode headers and functions
  platform/x86/intel/ifs: Add metadata support
  x86/microcode/intel: Use a reserved field for metasize
  x86/microcode/intel: Add hdr_type to intel_microcode_sanity_check()
  x86/microcode/intel: Reuse microcode_sanity_check()
  x86/microcode/intel: Use appropriate type in microcode_sanity_check()
  x86/microcode/intel: Reuse find_matching_signature()
  platform/x86/intel/ifs: Remove memory allocation from load path
  platform/x86/intel/ifs: Remove image loading during init
  platform/x86/intel/ifs: Return a more appropriate error code
  platform/x86/intel/ifs: Remove unused selection
  x86/microcode: Drop struct ucode_cpu_info.valid
  ...

1  2 
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/microcode/amd.c
arch/x86/kernel/cpu/microcode/intel.c

@@@ -210,12 -210,154 +210,154 @@@ int intel_cpu_collect_info(struct ucode
        csig.rev = intel_get_microcode_revision();
  
        uci->cpu_sig = csig;
-       uci->valid = 1;
  
        return 0;
  }
  EXPORT_SYMBOL_GPL(intel_cpu_collect_info);
  
+ /*
+  * Returns 1 if update has been found, 0 otherwise.
+  */
+ int intel_find_matching_signature(void *mc, unsigned int csig, int cpf)
+ {
+       struct microcode_header_intel *mc_hdr = mc;
+       struct extended_sigtable *ext_hdr;
+       struct extended_signature *ext_sig;
+       int i;
+       if (intel_cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf))
+               return 1;
+       /* Look for ext. headers: */
+       if (get_totalsize(mc_hdr) <= get_datasize(mc_hdr) + MC_HEADER_SIZE)
+               return 0;
+       ext_hdr = mc + get_datasize(mc_hdr) + MC_HEADER_SIZE;
+       ext_sig = (void *)ext_hdr + EXT_HEADER_SIZE;
+       for (i = 0; i < ext_hdr->count; i++) {
+               if (intel_cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf))
+                       return 1;
+               ext_sig++;
+       }
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(intel_find_matching_signature);
+ /**
+  * intel_microcode_sanity_check() - Sanity check microcode file.
+  * @mc: Pointer to the microcode file contents.
+  * @print_err: Display failure reason if true, silent if false.
+  * @hdr_type: Type of file, i.e. normal microcode file or In Field Scan file.
+  *            Validate if the microcode header type matches with the type
+  *            specified here.
+  *
+  * Validate certain header fields and verify if computed checksum matches
+  * with the one specified in the header.
+  *
+  * Return: 0 if the file passes all the checks, -EINVAL if any of the checks
+  * fail.
+  */
+ int intel_microcode_sanity_check(void *mc, bool print_err, int hdr_type)
+ {
+       unsigned long total_size, data_size, ext_table_size;
+       struct microcode_header_intel *mc_header = mc;
+       struct extended_sigtable *ext_header = NULL;
+       u32 sum, orig_sum, ext_sigcount = 0, i;
+       struct extended_signature *ext_sig;
+       total_size = get_totalsize(mc_header);
+       data_size = get_datasize(mc_header);
+       if (data_size + MC_HEADER_SIZE > total_size) {
+               if (print_err)
+                       pr_err("Error: bad microcode data file size.\n");
+               return -EINVAL;
+       }
+       if (mc_header->ldrver != 1 || mc_header->hdrver != hdr_type) {
+               if (print_err)
+                       pr_err("Error: invalid/unknown microcode update format. Header type %d\n",
+                              mc_header->hdrver);
+               return -EINVAL;
+       }
+       ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+       if (ext_table_size) {
+               u32 ext_table_sum = 0;
+               u32 *ext_tablep;
+               if (ext_table_size < EXT_HEADER_SIZE ||
+                   ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+                       if (print_err)
+                               pr_err("Error: truncated extended signature table.\n");
+                       return -EINVAL;
+               }
+               ext_header = mc + MC_HEADER_SIZE + data_size;
+               if (ext_table_size != exttable_size(ext_header)) {
+                       if (print_err)
+                               pr_err("Error: extended signature table size mismatch.\n");
+                       return -EFAULT;
+               }
+               ext_sigcount = ext_header->count;
+               /*
+                * Check extended table checksum: the sum of all dwords that
+                * comprise a valid table must be 0.
+                */
+               ext_tablep = (u32 *)ext_header;
+               i = ext_table_size / sizeof(u32);
+               while (i--)
+                       ext_table_sum += ext_tablep[i];
+               if (ext_table_sum) {
+                       if (print_err)
+                               pr_warn("Bad extended signature table checksum, aborting.\n");
+                       return -EINVAL;
+               }
+       }
+       /*
+        * Calculate the checksum of update data and header. The checksum of
+        * valid update data and header including the extended signature table
+        * must be 0.
+        */
+       orig_sum = 0;
+       i = (MC_HEADER_SIZE + data_size) / sizeof(u32);
+       while (i--)
+               orig_sum += ((u32 *)mc)[i];
+       if (orig_sum) {
+               if (print_err)
+                       pr_err("Bad microcode data checksum, aborting.\n");
+               return -EINVAL;
+       }
+       if (!ext_table_size)
+               return 0;
+       /*
+        * Check extended signature checksum: 0 => valid.
+        */
+       for (i = 0; i < ext_sigcount; i++) {
+               ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
+                         EXT_SIGNATURE_SIZE * i;
+               sum = (mc_header->sig + mc_header->pf + mc_header->cksum) -
+                     (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
+               if (sum) {
+                       if (print_err)
+                               pr_err("Bad extended signature checksum, aborting.\n");
+                       return -EINVAL;
+               }
+       }
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(intel_microcode_sanity_check);
  static void early_init_intel(struct cpuinfo_x86 *c)
  {
        u64 misc_enable;
@@@ -1034,32 -1176,8 +1176,32 @@@ static const struct 
  
  static struct ratelimit_state bld_ratelimit;
  
 +static unsigned int sysctl_sld_mitigate = 1;
  static DEFINE_SEMAPHORE(buslock_sem);
  
 +#ifdef CONFIG_PROC_SYSCTL
 +static struct ctl_table sld_sysctls[] = {
 +      {
 +              .procname       = "split_lock_mitigate",
 +              .data           = &sysctl_sld_mitigate,
 +              .maxlen         = sizeof(unsigned int),
 +              .mode           = 0644,
 +              .proc_handler   = proc_douintvec_minmax,
 +              .extra1         = SYSCTL_ZERO,
 +              .extra2         = SYSCTL_ONE,
 +      },
 +      {}
 +};
 +
 +static int __init sld_mitigate_sysctl_init(void)
 +{
 +      register_sysctl_init("kernel", sld_sysctls);
 +      return 0;
 +}
 +
 +late_initcall(sld_mitigate_sysctl_init);
 +#endif
 +
  static inline bool match_option(const char *arg, int arglen, const char *opt)
  {
        int len = strlen(opt), ratelimit;
@@@ -1170,20 -1288,12 +1312,20 @@@ static void split_lock_init(void
                split_lock_verify_msr(sld_state != sld_off);
  }
  
 -static void __split_lock_reenable(struct work_struct *work)
 +static void __split_lock_reenable_unlock(struct work_struct *work)
  {
        sld_update_msr(true);
        up(&buslock_sem);
  }
  
 +static DECLARE_DELAYED_WORK(sl_reenable_unlock, __split_lock_reenable_unlock);
 +
 +static void __split_lock_reenable(struct work_struct *work)
 +{
 +      sld_update_msr(true);
 +}
 +static DECLARE_DELAYED_WORK(sl_reenable, __split_lock_reenable);
 +
  /*
   * If a CPU goes offline with pending delayed work to re-enable split lock
   * detection then the delayed work will be executed on some other CPU. That
@@@ -1201,9 -1311,10 +1343,9 @@@ static int splitlock_cpu_offline(unsign
        return 0;
  }
  
 -static DECLARE_DELAYED_WORK(split_lock_reenable, __split_lock_reenable);
 -
  static void split_lock_warn(unsigned long ip)
  {
 +      struct delayed_work *work;
        int cpu;
  
        if (!current->reported_split_lock)
                                    current->comm, current->pid, ip);
        current->reported_split_lock = 1;
  
 -      /* misery factor #1, sleep 10ms before trying to execute split lock */
 -      if (msleep_interruptible(10) > 0)
 -              return;
 -      /* Misery factor #2, only allow one buslocked disabled core at a time */
 -      if (down_interruptible(&buslock_sem) == -EINTR)
 -              return;
 +      if (sysctl_sld_mitigate) {
 +              /*
 +               * misery factor #1:
 +               * sleep 10ms before trying to execute split lock.
 +               */
 +              if (msleep_interruptible(10) > 0)
 +                      return;
 +              /*
 +               * Misery factor #2:
 +               * only allow one buslocked disabled core at a time.
 +               */
 +              if (down_interruptible(&buslock_sem) == -EINTR)
 +                      return;
 +              work = &sl_reenable_unlock;
 +      } else {
 +              work = &sl_reenable;
 +      }
 +
        cpu = get_cpu();
 -      schedule_delayed_work_on(cpu, &split_lock_reenable, 2);
 +      schedule_delayed_work_on(cpu, work, 2);
  
        /* Disable split lock detection on this CPU to make progress */
        sld_update_msr(false);
@@@ -440,13 -440,7 +440,13 @@@ apply_microcode_early_amd(u32 cpuid_1_e
                return ret;
  
        native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
 -      if (rev >= mc->hdr.patch_id)
 +
 +      /*
 +       * Allow application of the same revision to pick up SMT-specific
 +       * changes even if the revision of the other SMT thread is already
 +       * up-to-date.
 +       */
 +      if (rev > mc->hdr.patch_id)
                return ret;
  
        if (!__apply_microcode_amd(mc)) {
@@@ -534,12 -528,8 +534,12 @@@ void load_ucode_amd_ap(unsigned int cpu
  
        native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
  
 -      /* Check whether we have saved a new patch already: */
 -      if (*new_rev && rev < mc->hdr.patch_id) {
 +      /*
 +       * Check whether a new patch has been saved already. Also, allow application of
 +       * the same revision in order to pick up SMT-thread-specific configuration even
 +       * if the sibling SMT thread already has an up-to-date revision.
 +       */
 +      if (*new_rev && rev <= mc->hdr.patch_id) {
                if (!__apply_microcode_amd(mc)) {
                        *new_rev = mc->hdr.patch_id;
                        return;
@@@ -901,8 -891,7 +901,7 @@@ load_microcode_amd(bool save, u8 family
   *
   * These might be larger than 2K.
   */
- static enum ucode_state request_microcode_amd(int cpu, struct device *device,
-                                             bool refresh_fw)
+ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
  {
        char fw_name[36] = "amd-ucode/microcode_amd.bin";
        struct cpuinfo_x86 *c = &cpu_data(cpu);
        const struct firmware *fw;
  
        /* reload ucode container only on the boot cpu */
-       if (!refresh_fw || !bsp)
+       if (!bsp)
                return UCODE_OK;
  
        if (c->x86 >= 0x15)
@@@ -48,34 -48,6 +48,6 @@@ static int llc_size_per_core
  /*
   * Returns 1 if update has been found, 0 otherwise.
   */
- static int find_matching_signature(void *mc, unsigned int csig, int cpf)
- {
-       struct microcode_header_intel *mc_hdr = mc;
-       struct extended_sigtable *ext_hdr;
-       struct extended_signature *ext_sig;
-       int i;
-       if (intel_cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf))
-               return 1;
-       /* Look for ext. headers: */
-       if (get_totalsize(mc_hdr) <= get_datasize(mc_hdr) + MC_HEADER_SIZE)
-               return 0;
-       ext_hdr = mc + get_datasize(mc_hdr) + MC_HEADER_SIZE;
-       ext_sig = (void *)ext_hdr + EXT_HEADER_SIZE;
-       for (i = 0; i < ext_hdr->count; i++) {
-               if (intel_cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf))
-                       return 1;
-               ext_sig++;
-       }
-       return 0;
- }
- /*
-  * Returns 1 if update has been found, 0 otherwise.
-  */
  static int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev)
  {
        struct microcode_header_intel *mc_hdr = mc;
@@@ -83,7 -55,7 +55,7 @@@
        if (mc_hdr->rev <= new_rev)
                return 0;
  
-       return find_matching_signature(mc, csig, cpf);
+       return intel_find_matching_signature(mc, csig, cpf);
  }
  
  static struct ucode_patch *memdup_patch(void *data, unsigned int size)
@@@ -117,7 -89,7 +89,7 @@@ static void save_microcode_patch(struc
                sig          = mc_saved_hdr->sig;
                pf           = mc_saved_hdr->pf;
  
-               if (find_matching_signature(data, sig, pf)) {
+               if (intel_find_matching_signature(data, sig, pf)) {
                        prev_found = true;
  
                        if (mc_hdr->rev <= mc_saved_hdr->rev)
        if (!p)
                return;
  
-       if (!find_matching_signature(p->data, uci->cpu_sig.sig, uci->cpu_sig.pf))
+       if (!intel_find_matching_signature(p->data, uci->cpu_sig.sig, uci->cpu_sig.pf))
                return;
  
        /*
                intel_ucode_patch = p->data;
  }
  
- static int microcode_sanity_check(void *mc, int print_err)
- {
-       unsigned long total_size, data_size, ext_table_size;
-       struct microcode_header_intel *mc_header = mc;
-       struct extended_sigtable *ext_header = NULL;
-       u32 sum, orig_sum, ext_sigcount = 0, i;
-       struct extended_signature *ext_sig;
-       total_size = get_totalsize(mc_header);
-       data_size = get_datasize(mc_header);
-       if (data_size + MC_HEADER_SIZE > total_size) {
-               if (print_err)
-                       pr_err("Error: bad microcode data file size.\n");
-               return -EINVAL;
-       }
-       if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
-               if (print_err)
-                       pr_err("Error: invalid/unknown microcode update format.\n");
-               return -EINVAL;
-       }
-       ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
-       if (ext_table_size) {
-               u32 ext_table_sum = 0;
-               u32 *ext_tablep;
-               if ((ext_table_size < EXT_HEADER_SIZE)
-                || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
-                       if (print_err)
-                               pr_err("Error: truncated extended signature table.\n");
-                       return -EINVAL;
-               }
-               ext_header = mc + MC_HEADER_SIZE + data_size;
-               if (ext_table_size != exttable_size(ext_header)) {
-                       if (print_err)
-                               pr_err("Error: extended signature table size mismatch.\n");
-                       return -EFAULT;
-               }
-               ext_sigcount = ext_header->count;
-               /*
-                * Check extended table checksum: the sum of all dwords that
-                * comprise a valid table must be 0.
-                */
-               ext_tablep = (u32 *)ext_header;
-               i = ext_table_size / sizeof(u32);
-               while (i--)
-                       ext_table_sum += ext_tablep[i];
-               if (ext_table_sum) {
-                       if (print_err)
-                               pr_warn("Bad extended signature table checksum, aborting.\n");
-                       return -EINVAL;
-               }
-       }
-       /*
-        * Calculate the checksum of update data and header. The checksum of
-        * valid update data and header including the extended signature table
-        * must be 0.
-        */
-       orig_sum = 0;
-       i = (MC_HEADER_SIZE + data_size) / sizeof(u32);
-       while (i--)
-               orig_sum += ((u32 *)mc)[i];
-       if (orig_sum) {
-               if (print_err)
-                       pr_err("Bad microcode data checksum, aborting.\n");
-               return -EINVAL;
-       }
-       if (!ext_table_size)
-               return 0;
-       /*
-        * Check extended signature checksum: 0 => valid.
-        */
-       for (i = 0; i < ext_sigcount; i++) {
-               ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
-                         EXT_SIGNATURE_SIZE * i;
-               sum = (mc_header->sig + mc_header->pf + mc_header->cksum) -
-                     (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
-               if (sum) {
-                       if (print_err)
-                               pr_err("Bad extended signature checksum, aborting.\n");
-                       return -EINVAL;
-               }
-       }
-       return 0;
- }
  /*
   * Get microcode matching with BSP's model. Only CPUs with the same model as
   * BSP can stay in the platform.
@@@ -281,13 -155,13 +155,13 @@@ scan_microcode(void *data, size_t size
                mc_size = get_totalsize(mc_header);
                if (!mc_size ||
                    mc_size > size ||
-                   microcode_sanity_check(data, 0) < 0)
+                   intel_microcode_sanity_check(data, false, MC_HEADER_TYPE_MICROCODE) < 0)
                        break;
  
                size -= mc_size;
  
-               if (!find_matching_signature(data, uci->cpu_sig.sig,
-                                            uci->cpu_sig.pf)) {
+               if (!intel_find_matching_signature(data, uci->cpu_sig.sig,
+                                                  uci->cpu_sig.pf)) {
                        data += mc_size;
                        continue;
                }
@@@ -621,7 -495,6 +495,6 @@@ void load_ucode_intel_ap(void
        else
                iup = &intel_ucode_patch;
  
- reget:
        if (!*iup) {
                patch = __load_ucode_intel(&uci);
                if (!patch)
  
        uci.mc = *iup;
  
-       if (apply_microcode_early(&uci, true)) {
-               /* Mixed-silicon system? Try to refetch the proper patch: */
-               *iup = NULL;
-               goto reget;
-       }
+       apply_microcode_early(&uci, true);
  }
  
  static struct microcode_intel *find_patch(struct ucode_cpu_info *uci)
                if (phdr->rev <= uci->cpu_sig.rev)
                        continue;
  
-               if (!find_matching_signature(phdr,
-                                            uci->cpu_sig.sig,
-                                            uci->cpu_sig.pf))
+               if (!intel_find_matching_signature(phdr,
+                                                  uci->cpu_sig.sig,
+                                                  uci->cpu_sig.pf))
                        continue;
  
                return iter->data;
@@@ -680,7 -548,6 +548,6 @@@ void reload_ucode_intel(void
  
  static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
  {
-       static struct cpu_signature prev;
        struct cpuinfo_x86 *c = &cpu_data(cpu_num);
        unsigned int val[2];
  
  
        csig->rev = c->microcode;
  
-       /* No extra locking on prev, races are harmless. */
-       if (csig->sig != prev.sig || csig->pf != prev.pf || csig->rev != prev.rev) {
-               pr_info("sig=0x%x, pf=0x%x, revision=0x%x\n",
-                       csig->sig, csig->pf, csig->rev);
-               prev = *csig;
-       }
        return 0;
  }
  
@@@ -820,7 -680,7 +680,7 @@@ static enum ucode_state generic_load_mi
                memcpy(mc, &mc_header, sizeof(mc_header));
                data = mc + sizeof(mc_header);
                if (!copy_from_iter_full(data, data_size, iter) ||
-                   microcode_sanity_check(mc, 1) < 0) {
+                   intel_microcode_sanity_check(mc, true, MC_HEADER_TYPE_MICROCODE) < 0) {
                        break;
                }
  
@@@ -885,8 -745,7 +745,7 @@@ static bool is_blacklisted(unsigned in
        return false;
  }
  
- static enum ucode_state request_microcode_fw(int cpu, struct device *device,
-                                            bool refresh_fw)
+ static enum ucode_state request_microcode_fw(int cpu, struct device *device)
  {
        struct cpuinfo_x86 *c = &cpu_data(cpu);
        const struct firmware *firmware;
  
        kvec.iov_base = (void *)firmware->data;
        kvec.iov_len = firmware->size;
 -      iov_iter_kvec(&iter, WRITE, &kvec, 1, firmware->size);
 +      iov_iter_kvec(&iter, ITER_SOURCE, &kvec, 1, firmware->size);
        ret = generic_load_microcode(cpu, &iter);
  
        release_firmware(firmware);