Merge tag 'riscv-for-linus-6.7-mw2' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 10 Nov 2023 17:23:17 +0000 (09:23 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 10 Nov 2023 17:23:17 +0000 (09:23 -0800)
Pull more RISC-V updates from Palmer Dabbelt:

 - Support for handling misaligned accesses in S-mode

 - Probing for misaligned access support is now properly cached and
   handled in parallel

 - PTDUMP now reflects the SW reserved bits, as well as the PBMT and
   NAPOT extensions

 - Performance improvements for TLB flushing

 - Support for many new relocations in the module loader

 - Various bug fixes and cleanups

* tag 'riscv-for-linus-6.7-mw2' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux: (51 commits)
  riscv: Optimize bitops with Zbb extension
  riscv: Rearrange hwcap.h and cpufeature.h
  drivers: perf: Do not broadcast to other cpus when starting a counter
  drivers: perf: Check find_first_bit() return value
  of: property: Add fw_devlink support for msi-parent
  RISC-V: Don't fail in riscv_of_parent_hartid() for disabled HARTs
  riscv: Fix set_memory_XX() and set_direct_map_XX() by splitting huge linear mappings
  riscv: Don't use PGD entries for the linear mapping
  RISC-V: Probe misaligned access speed in parallel
  RISC-V: Remove __init on unaligned_emulation_finish()
  RISC-V: Show accurate per-hart isa in /proc/cpuinfo
  RISC-V: Don't rely on positional structure initialization
  riscv: Add tests for riscv module loading
  riscv: Add remaining module relocations
  riscv: Avoid unaligned access when relocating modules
  riscv: split cache ops out of dma-noncoherent.c
  riscv: Improve flush_tlb_kernel_range()
  riscv: Make __flush_tlb_range() loop over pte instead of flushing the whole tlb
  riscv: Improve flush_tlb_range() for hugetlb pages
  riscv: Improve tlb_flush()
  ...

12 files changed:
1  2 
Documentation/arch/riscv/uabi.rst
arch/riscv/Kconfig
arch/riscv/configs/defconfig
arch/riscv/include/asm/bitops.h
arch/riscv/include/asm/hwcap.h
arch/riscv/include/asm/processor.h
arch/riscv/include/asm/sbi.h
arch/riscv/kernel/cpufeature.c
arch/riscv/kvm/vcpu_onereg.c
arch/riscv/mm/init.c
drivers/clocksource/timer-riscv.c
drivers/firmware/efi/libstub/Makefile

index 8960fac,0000000..54d199d
mode 100644,000000..100644
--- /dev/null
@@@ -1,48 -1,0 +1,68 @@@
 +.. SPDX-License-Identifier: GPL-2.0
 +
 +RISC-V Linux User ABI
 +=====================
 +
 +ISA string ordering in /proc/cpuinfo
 +------------------------------------
 +
 +The canonical order of ISA extension names in the ISA string is defined in
 +chapter 27 of the unprivileged specification.
 +The specification uses vague wording, such as should, when it comes to ordering,
 +so for our purposes the following rules apply:
 +
 +#. Single-letter extensions come first, in canonical order.
 +   The canonical order is "IMAFDQLCBKJTPVH".
 +
 +#. All multi-letter extensions will be separated from other extensions by an
 +   underscore.
 +
 +#. Additional standard extensions (starting with 'Z') will be sorted after
 +   single-letter extensions and before any higher-privileged extensions.
 +
 +#. For additional standard extensions, the first letter following the 'Z'
 +   conventionally indicates the most closely related alphabetical
 +   extension category. If multiple 'Z' extensions are named, they will be
 +   ordered first by category, in canonical order, as listed above, then
 +   alphabetically within a category.
 +
 +#. Standard supervisor-level extensions (starting with 'S') will be listed
 +   after standard unprivileged extensions.  If multiple supervisor-level
 +   extensions are listed, they will be ordered alphabetically.
 +
 +#. Standard machine-level extensions (starting with 'Zxm') will be listed
 +   after any lower-privileged, standard extensions. If multiple machine-level
 +   extensions are listed, they will be ordered alphabetically.
 +
 +#. Non-standard extensions (starting with 'X') will be listed after all standard
 +   extensions. If multiple non-standard extensions are listed, they will be
 +   ordered alphabetically.
 +
 +An example string following the order is::
 +
 +   rv64imadc_zifoo_zigoo_zafoo_sbar_scar_zxmbaz_xqux_xrux
 +
++"isa" and "hart isa" lines in /proc/cpuinfo
++-------------------------------------------
++
++The "isa" line in /proc/cpuinfo describes the lowest common denominator of
++RISC-V ISA extensions recognized by the kernel and implemented on all harts. The
++"hart isa" line, in contrast, describes the set of extensions recognized by the
++kernel on the particular hart being described, even if those extensions may not
++be present on all harts in the system.
++
++In both lines, the presence of an extension guarantees only that the hardware
++has the described capability. Additional kernel support or policy changes may be
++required before an extension's capability is fully usable by userspace programs.
++Similarly, for S-mode extensions, presence in one of these lines does not
++guarantee that the kernel is taking advantage of the extension, or that the
++feature will be visible in guest VMs managed by this kernel.
++
++Inversely, the absence of an extension in these lines does not necessarily mean
++the hardware does not support that feature. The running kernel may not recognize
++the extension, or may have deliberately removed it from the listing.
++
 +Misaligned accesses
 +-------------------
 +
 +Misaligned accesses are supported in userspace, but they may perform poorly.
diff --combined arch/riscv/Kconfig
@@@ -280,9 -280,11 +280,9 @@@ config RISCV_DMA_NONCOHEREN
        select ARCH_HAS_SYNC_DMA_FOR_CPU
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE
        select DMA_BOUNCE_UNALIGNED_KMALLOC if SWIOTLB
 -      select DMA_DIRECT_REMAP if MMU
  
  config RISCV_NONSTANDARD_CACHE_OPS
        bool
 -      depends on RISCV_DMA_NONCOHERENT
        help
          This enables function pointer support for non-standard noncoherent
          systems to handle cache management.
@@@ -555,7 -557,6 +555,7 @@@ config RISCV_ISA_ZICBO
        depends on RISCV_ALTERNATIVE
        default y
        select RISCV_DMA_NONCOHERENT
 +      select DMA_DIRECT_REMAP
        help
           Adds support to dynamically detect the presence of the ZICBOM
           extension (Cache Block Management Operations) and enable its
@@@ -642,6 -643,15 +642,15 @@@ config THREAD_SIZE_ORDE
          Specify the Pages of thread stack size (from 4KB to 64KB), which also
          affects irq stack size, which is equal to thread stack size.
  
+ config RISCV_MISALIGNED
+       bool "Support misaligned load/store traps for kernel and userspace"
+       select SYSCTL_ARCH_UNALIGN_ALLOW
+       default y
+       help
+         Say Y here if you want the kernel to embed support for misaligned
+         load/store for both kernel and userspace. When disable, misaligned
+         accesses will generate SIGBUS in userspace and panic in kernel.
  endmenu # "Platform type"
  
  menu "Kernel features"
@@@ -700,9 -710,6 +709,9 @@@ config ARCH_SUPPORTS_KEXEC_PURGATOR
  config ARCH_SUPPORTS_CRASH_DUMP
        def_bool y
  
 +config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
 +      def_bool CRASH_CORE
 +
  config COMPAT
        bool "Kernel support for 32-bit U-mode"
        default 64BIT
@@@ -909,6 -916,9 +918,9 @@@ config PORTABL
        select MMU
        select OF
  
+ config ARCH_PROC_KCORE_TEXT
+       def_bool y
  menu "Power management options"
  
  source "kernel/power/Kconfig"
@@@ -27,11 -27,10 +27,11 @@@ CONFIG_EXPERT=
  CONFIG_PROFILING=y
  CONFIG_SOC_MICROCHIP_POLARFIRE=y
  CONFIG_ARCH_RENESAS=y
 -CONFIG_ARCH_THEAD=y
  CONFIG_SOC_SIFIVE=y
 +CONFIG_ARCH_SOPHGO=y
  CONFIG_SOC_STARFIVE=y
  CONFIG_ARCH_SUNXI=y
 +CONFIG_ARCH_THEAD=y
  CONFIG_SOC_VIRT=y
  CONFIG_SMP=y
  CONFIG_HOTPLUG_CPU=y
@@@ -215,6 -214,8 +215,8 @@@ CONFIG_MMC_SDHCI=
  CONFIG_MMC_SDHCI_PLTFM=y
  CONFIG_MMC_SDHCI_CADENCE=y
  CONFIG_MMC_SPI=y
+ CONFIG_MMC_DW=y
+ CONFIG_MMC_DW_STARFIVE=y
  CONFIG_MMC_SDHI=y
  CONFIG_MMC_SUNXI=y
  CONFIG_RTC_CLASS=y
  #include <asm/barrier.h>
  #include <asm/bitsperlong.h>
  
+ #if !defined(CONFIG_RISCV_ISA_ZBB) || defined(NO_ALTERNATIVE)
  #include <asm-generic/bitops/__ffs.h>
- #include <asm-generic/bitops/ffz.h>
- #include <asm-generic/bitops/fls.h>
  #include <asm-generic/bitops/__fls.h>
+ #include <asm-generic/bitops/ffs.h>
+ #include <asm-generic/bitops/fls.h>
+ #else
+ #include <asm/alternative-macros.h>
+ #include <asm/hwcap.h>
+ #if (BITS_PER_LONG == 64)
+ #define CTZW  "ctzw "
+ #define CLZW  "clzw "
+ #elif (BITS_PER_LONG == 32)
+ #define CTZW  "ctz "
+ #define CLZW  "clz "
+ #else
+ #error "Unexpected BITS_PER_LONG"
+ #endif
+ static __always_inline unsigned long variable__ffs(unsigned long word)
+ {
+       int num;
+       asm_volatile_goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
+                                     RISCV_ISA_EXT_ZBB, 1)
+                         : : : : legacy);
+       asm volatile (".option push\n"
+                     ".option arch,+zbb\n"
+                     "ctz %0, %1\n"
+                     ".option pop\n"
+                     : "=r" (word) : "r" (word) :);
+       return word;
+ legacy:
+       num = 0;
+ #if BITS_PER_LONG == 64
+       if ((word & 0xffffffff) == 0) {
+               num += 32;
+               word >>= 32;
+       }
+ #endif
+       if ((word & 0xffff) == 0) {
+               num += 16;
+               word >>= 16;
+       }
+       if ((word & 0xff) == 0) {
+               num += 8;
+               word >>= 8;
+       }
+       if ((word & 0xf) == 0) {
+               num += 4;
+               word >>= 4;
+       }
+       if ((word & 0x3) == 0) {
+               num += 2;
+               word >>= 2;
+       }
+       if ((word & 0x1) == 0)
+               num += 1;
+       return num;
+ }
+ /**
+  * __ffs - find first set bit in a long word
+  * @word: The word to search
+  *
+  * Undefined if no set bit exists, so code should check against 0 first.
+  */
+ #define __ffs(word)                           \
+       (__builtin_constant_p(word) ?           \
+        (unsigned long)__builtin_ctzl(word) :  \
+        variable__ffs(word))
+ static __always_inline unsigned long variable__fls(unsigned long word)
+ {
+       int num;
+       asm_volatile_goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
+                                     RISCV_ISA_EXT_ZBB, 1)
+                         : : : : legacy);
+       asm volatile (".option push\n"
+                     ".option arch,+zbb\n"
+                     "clz %0, %1\n"
+                     ".option pop\n"
+                     : "=r" (word) : "r" (word) :);
+       return BITS_PER_LONG - 1 - word;
+ legacy:
+       num = BITS_PER_LONG - 1;
+ #if BITS_PER_LONG == 64
+       if (!(word & (~0ul << 32))) {
+               num -= 32;
+               word <<= 32;
+       }
+ #endif
+       if (!(word & (~0ul << (BITS_PER_LONG - 16)))) {
+               num -= 16;
+               word <<= 16;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG - 8)))) {
+               num -= 8;
+               word <<= 8;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG - 4)))) {
+               num -= 4;
+               word <<= 4;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG - 2)))) {
+               num -= 2;
+               word <<= 2;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG - 1))))
+               num -= 1;
+       return num;
+ }
+ /**
+  * __fls - find last set bit in a long word
+  * @word: the word to search
+  *
+  * Undefined if no set bit exists, so code should check against 0 first.
+  */
+ #define __fls(word)                                                   \
+       (__builtin_constant_p(word) ?                                   \
+        (unsigned long)(BITS_PER_LONG - 1 - __builtin_clzl(word)) :    \
+        variable__fls(word))
+ static __always_inline int variable_ffs(int x)
+ {
+       int r;
+       if (!x)
+               return 0;
+       asm_volatile_goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
+                                     RISCV_ISA_EXT_ZBB, 1)
+                         : : : : legacy);
+       asm volatile (".option push\n"
+                     ".option arch,+zbb\n"
+                     CTZW "%0, %1\n"
+                     ".option pop\n"
+                     : "=r" (r) : "r" (x) :);
+       return r + 1;
+ legacy:
+       r = 1;
+       if (!(x & 0xffff)) {
+               x >>= 16;
+               r += 16;
+       }
+       if (!(x & 0xff)) {
+               x >>= 8;
+               r += 8;
+       }
+       if (!(x & 0xf)) {
+               x >>= 4;
+               r += 4;
+       }
+       if (!(x & 3)) {
+               x >>= 2;
+               r += 2;
+       }
+       if (!(x & 1)) {
+               x >>= 1;
+               r += 1;
+       }
+       return r;
+ }
+ /**
+  * ffs - find first set bit in a word
+  * @x: the word to search
+  *
+  * This is defined the same way as the libc and compiler builtin ffs routines.
+  *
+  * ffs(value) returns 0 if value is 0 or the position of the first set bit if
+  * value is nonzero. The first (least significant) bit is at position 1.
+  */
+ #define ffs(x) (__builtin_constant_p(x) ? __builtin_ffs(x) : variable_ffs(x))
+ static __always_inline int variable_fls(unsigned int x)
+ {
+       int r;
+       if (!x)
+               return 0;
+       asm_volatile_goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
+                                     RISCV_ISA_EXT_ZBB, 1)
+                         : : : : legacy);
+       asm volatile (".option push\n"
+                     ".option arch,+zbb\n"
+                     CLZW "%0, %1\n"
+                     ".option pop\n"
+                     : "=r" (r) : "r" (x) :);
+       return 32 - r;
+ legacy:
+       r = 32;
+       if (!(x & 0xffff0000u)) {
+               x <<= 16;
+               r -= 16;
+       }
+       if (!(x & 0xff000000u)) {
+               x <<= 8;
+               r -= 8;
+       }
+       if (!(x & 0xf0000000u)) {
+               x <<= 4;
+               r -= 4;
+       }
+       if (!(x & 0xc0000000u)) {
+               x <<= 2;
+               r -= 2;
+       }
+       if (!(x & 0x80000000u)) {
+               x <<= 1;
+               r -= 1;
+       }
+       return r;
+ }
+ /**
+  * fls - find last set bit in a word
+  * @x: the word to search
+  *
+  * This is defined in a similar way as ffs, but returns the position of the most
+  * significant set bit.
+  *
+  * fls(value) returns 0 if value is 0 or the position of the last set bit if
+  * value is nonzero. The last (most significant) bit is at position 32.
+  */
+ #define fls(x)                                                        \
+ ({                                                            \
+       typeof(x) x_ = (x);                                     \
+       __builtin_constant_p(x_) ?                              \
+        (int)((x_ != 0) ? (32 - __builtin_clz(x_)) : 0)        \
+        :                                                      \
+        variable_fls(x_);                                      \
+ })
+ #endif /* !defined(CONFIG_RISCV_ISA_ZBB) || defined(NO_ALTERNATIVE) */
+ #include <asm-generic/bitops/ffz.h>
  #include <asm-generic/bitops/fls64.h>
  #include <asm-generic/bitops/sched.h>
- #include <asm-generic/bitops/ffs.h>
  
  #include <asm-generic/bitops/hweight.h>
  
@@@ -191,18 -439,6 +439,18 @@@ static inline void __clear_bit_unlock
        clear_bit_unlock(nr, addr);
  }
  
 +static inline bool xor_unlock_is_negative_byte(unsigned long mask,
 +              volatile unsigned long *addr)
 +{
 +      unsigned long res;
 +      __asm__ __volatile__ (
 +              __AMO(xor) ".rl %0, %2, %1"
 +              : "=r" (res), "+A" (*addr)
 +              : "r" (__NOP(mask))
 +              : "memory");
 +      return (res & BIT(7)) != 0;
 +}
 +
  #undef __test_and_op_bit
  #undef __op_bit
  #undef __NOP
@@@ -8,9 -8,6 +8,6 @@@
  #ifndef _ASM_RISCV_HWCAP_H
  #define _ASM_RISCV_HWCAP_H
  
- #include <asm/alternative-macros.h>
- #include <asm/errno.h>
- #include <linux/bits.h>
  #include <uapi/asm/hwcap.h>
  
  #define RISCV_ISA_EXT_a               ('a' - 'a')
@@@ -58,8 -55,6 +55,8 @@@
  #define RISCV_ISA_EXT_ZICSR           40
  #define RISCV_ISA_EXT_ZIFENCEI                41
  #define RISCV_ISA_EXT_ZIHPM           42
 +#define RISCV_ISA_EXT_SMSTATEEN               43
 +#define RISCV_ISA_EXT_ZICOND          44
  
  #define RISCV_ISA_EXT_MAX             64
  
  #define RISCV_ISA_EXT_SxAIA           RISCV_ISA_EXT_SSAIA
  #endif
  
- #ifndef __ASSEMBLY__
- #include <linux/jump_label.h>
- #include <asm/cpufeature.h>
- unsigned long riscv_get_elf_hwcap(void);
- struct riscv_isa_ext_data {
-       const unsigned int id;
-       const char *name;
-       const char *property;
- };
- extern const struct riscv_isa_ext_data riscv_isa_ext[];
- extern const size_t riscv_isa_ext_count;
- extern bool riscv_isa_fallback;
- unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
- #define riscv_isa_extension_mask(ext) BIT_MASK(RISCV_ISA_EXT_##ext)
- bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit);
- #define riscv_isa_extension_available(isa_bitmap, ext)        \
-       __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext)
- static __always_inline bool
- riscv_has_extension_likely(const unsigned long ext)
- {
-       compiletime_assert(ext < RISCV_ISA_EXT_MAX,
-                          "ext must be < RISCV_ISA_EXT_MAX");
-       if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
-               asm_volatile_goto(
-               ALTERNATIVE("j  %l[l_no]", "nop", 0, %[ext], 1)
-               :
-               : [ext] "i" (ext)
-               :
-               : l_no);
-       } else {
-               if (!__riscv_isa_extension_available(NULL, ext))
-                       goto l_no;
-       }
-       return true;
- l_no:
-       return false;
- }
- static __always_inline bool
- riscv_has_extension_unlikely(const unsigned long ext)
- {
-       compiletime_assert(ext < RISCV_ISA_EXT_MAX,
-                          "ext must be < RISCV_ISA_EXT_MAX");
-       if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
-               asm_volatile_goto(
-               ALTERNATIVE("nop", "j   %l[l_yes]", 0, %[ext], 1)
-               :
-               : [ext] "i" (ext)
-               :
-               : l_yes);
-       } else {
-               if (__riscv_isa_extension_available(NULL, ext))
-                       goto l_yes;
-       }
-       return false;
- l_yes:
-       return true;
- }
- static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
- {
-       if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_likely(ext))
-               return true;
-       return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
- }
- static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext)
- {
-       if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_unlikely(ext))
-               return true;
-       return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
- }
- #endif
  #endif /* _ASM_RISCV_HWCAP_H */
@@@ -8,6 -8,7 +8,7 @@@
  
  #include <linux/const.h>
  #include <linux/cache.h>
+ #include <linux/prctl.h>
  
  #include <vdso/processor.h>
  
@@@ -82,6 -83,7 +83,7 @@@ struct thread_struct 
        unsigned long bad_cause;
        unsigned long vstate_ctrl;
        struct __riscv_v_ext_state vstate;
+       unsigned long align_ctl;
  };
  
  /* Whitelist the fstate from the task_struct for hardened usercopy */
@@@ -94,6 -96,7 +96,7 @@@ static inline void arch_thread_struct_w
  
  #define INIT_THREAD {                                 \
        .sp = sizeof(init_stack) + (long)&init_stack,   \
+       .align_ctl = PR_UNALIGN_NOPRINT,                \
  }
  
  #define task_pt_regs(tsk)                                             \
@@@ -116,8 -119,6 +119,8 @@@ static inline void wait_for_interrupt(v
        __asm__ __volatile__ ("wfi");
  }
  
 +extern phys_addr_t dma32_phys_limit;
 +
  struct device_node;
  int riscv_of_processor_hartid(struct device_node *node, unsigned long *hartid);
  int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hartid);
@@@ -136,6 -137,12 +139,12 @@@ extern long riscv_v_vstate_ctrl_set_cur
  extern long riscv_v_vstate_ctrl_get_current(void);
  #endif /* CONFIG_RISCV_ISA_V */
  
+ extern int get_unalign_ctl(struct task_struct *tsk, unsigned long addr);
+ extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val);
+ #define GET_UNALIGN_CTL(tsk, addr)    get_unalign_ctl((tsk), (addr))
+ #define SET_UNALIGN_CTL(tsk, val)     set_unalign_ctl((tsk), (val))
  #endif /* __ASSEMBLY__ */
  
  #endif /* _ASM_RISCV_PROCESSOR_H */
@@@ -30,7 -30,6 +30,7 @@@ enum sbi_ext_id 
        SBI_EXT_HSM = 0x48534D,
        SBI_EXT_SRST = 0x53525354,
        SBI_EXT_PMU = 0x504D55,
 +      SBI_EXT_DBCN = 0x4442434E,
  
        /* Experimentals extensions must lie within this range */
        SBI_EXT_EXPERIMENTAL_START = 0x08000000,
@@@ -237,12 -236,6 +237,12 @@@ enum sbi_pmu_ctr_type 
  /* Flags defined for counter stop function */
  #define SBI_PMU_STOP_FLAG_RESET (1 << 0)
  
 +enum sbi_ext_dbcn_fid {
 +      SBI_EXT_DBCN_CONSOLE_WRITE = 0,
 +      SBI_EXT_DBCN_CONSOLE_READ = 1,
 +      SBI_EXT_DBCN_CONSOLE_WRITE_BYTE = 2,
 +};
 +
  #define SBI_SPEC_VERSION_DEFAULT      0x1
  #define SBI_SPEC_VERSION_MAJOR_SHIFT  24
  #define SBI_SPEC_VERSION_MAJOR_MASK   0x7f
@@@ -280,9 -273,6 +280,6 @@@ void sbi_set_timer(uint64_t stime_value
  void sbi_shutdown(void);
  void sbi_send_ipi(unsigned int cpu);
  int sbi_remote_fence_i(const struct cpumask *cpu_mask);
- int sbi_remote_sfence_vma(const struct cpumask *cpu_mask,
-                          unsigned long start,
-                          unsigned long size);
  
  int sbi_remote_sfence_vma_asid(const struct cpumask *cpu_mask,
                                unsigned long start,
@@@ -8,6 -8,7 +8,7 @@@
  
  #include <linux/acpi.h>
  #include <linux/bitmap.h>
+ #include <linux/cpuhotplug.h>
  #include <linux/ctype.h>
  #include <linux/log2.h>
  #include <linux/memory.h>
@@@ -29,6 -30,7 +30,7 @@@
  
  #define MISALIGNED_ACCESS_JIFFIES_LG2 1
  #define MISALIGNED_BUFFER_SIZE 0x4000
+ #define MISALIGNED_BUFFER_ORDER get_order(MISALIGNED_BUFFER_SIZE)
  #define MISALIGNED_COPY_SIZE ((MISALIGNED_BUFFER_SIZE / 2) - 0x80)
  
  unsigned long elf_hwcap __read_mostly;
@@@ -167,7 -169,6 +169,7 @@@ const struct riscv_isa_ext_data riscv_i
        __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM),
        __RISCV_ISA_EXT_DATA(zicboz, RISCV_ISA_EXT_ZICBOZ),
        __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR),
 +      __RISCV_ISA_EXT_DATA(zicond, RISCV_ISA_EXT_ZICOND),
        __RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR),
        __RISCV_ISA_EXT_DATA(zifencei, RISCV_ISA_EXT_ZIFENCEI),
        __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
        __RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB),
        __RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS),
        __RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA),
 +      __RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN),
        __RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
        __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
        __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
@@@ -559,23 -559,21 +561,21 @@@ unsigned long riscv_get_elf_hwcap(void
        return hwcap;
  }
  
void check_unaligned_access(int cpu)
static int check_unaligned_access(void *param)
  {
+       int cpu = smp_processor_id();
        u64 start_cycles, end_cycles;
        u64 word_cycles;
        u64 byte_cycles;
        int ratio;
        unsigned long start_jiffies, now;
-       struct page *page;
+       struct page *page = param;
        void *dst;
        void *src;
        long speed = RISCV_HWPROBE_MISALIGNED_SLOW;
  
-       page = alloc_pages(GFP_NOWAIT, get_order(MISALIGNED_BUFFER_SIZE));
-       if (!page) {
-               pr_warn("Can't alloc pages to measure memcpy performance");
-               return;
-       }
+       if (check_unaligned_access_emulated(cpu))
+               return 0;
  
        /* Make an unaligned destination buffer. */
        dst = (void *)((unsigned long)page_address(page) | 0x1);
                pr_warn("cpu%d: rdtime lacks granularity needed to measure unaligned access speed\n",
                        cpu);
  
-               goto out;
+               return 0;
        }
  
        if (word_cycles < byte_cycles)
                (speed == RISCV_HWPROBE_MISALIGNED_FAST) ? "fast" : "slow");
  
        per_cpu(misaligned_access_speed, cpu) = speed;
+       return 0;
+ }
  
- out:
-       __free_pages(page, get_order(MISALIGNED_BUFFER_SIZE));
+ static void check_unaligned_access_nonboot_cpu(void *param)
+ {
+       unsigned int cpu = smp_processor_id();
+       struct page **pages = param;
+       if (smp_processor_id() != 0)
+               check_unaligned_access(pages[cpu]);
  }
  
- static int check_unaligned_access_boot_cpu(void)
+ static int riscv_online_cpu(unsigned int cpu)
  {
-       check_unaligned_access(0);
+       static struct page *buf;
+       /* We are already set since the last check */
+       if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN)
+               return 0;
+       buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
+       if (!buf) {
+               pr_warn("Allocation failure, not measuring misaligned performance\n");
+               return -ENOMEM;
+       }
+       check_unaligned_access(buf);
+       __free_pages(buf, MISALIGNED_BUFFER_ORDER);
+       return 0;
+ }
+ /* Measure unaligned access on all CPUs present at boot in parallel. */
+ static int check_unaligned_access_all_cpus(void)
+ {
+       unsigned int cpu;
+       unsigned int cpu_count = num_possible_cpus();
+       struct page **bufs = kzalloc(cpu_count * sizeof(struct page *),
+                                    GFP_KERNEL);
+       if (!bufs) {
+               pr_warn("Allocation failure, not measuring misaligned performance\n");
+               return 0;
+       }
+       /*
+        * Allocate separate buffers for each CPU so there's no fighting over
+        * cache lines.
+        */
+       for_each_cpu(cpu, cpu_online_mask) {
+               bufs[cpu] = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
+               if (!bufs[cpu]) {
+                       pr_warn("Allocation failure, not measuring misaligned performance\n");
+                       goto out;
+               }
+       }
+       /* Check everybody except 0, who stays behind to tend jiffies. */
+       on_each_cpu(check_unaligned_access_nonboot_cpu, bufs, 1);
+       /* Check core 0. */
+       smp_call_on_cpu(0, check_unaligned_access, bufs[0], true);
+       /* Setup hotplug callback for any new CPUs that come online. */
+       cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "riscv:online",
+                                 riscv_online_cpu, NULL);
+ out:
+       unaligned_emulation_finish();
+       for_each_cpu(cpu, cpu_online_mask) {
+               if (bufs[cpu])
+                       __free_pages(bufs[cpu], MISALIGNED_BUFFER_ORDER);
+       }
+       kfree(bufs);
        return 0;
  }
  
- arch_initcall(check_unaligned_access_boot_cpu);
+ arch_initcall(check_unaligned_access_all_cpus);
  
  void riscv_user_isa_enable(void)
  {
@@@ -13,7 -13,7 +13,7 @@@
  #include <linux/uaccess.h>
  #include <linux/kvm_host.h>
  #include <asm/cacheflush.h>
- #include <asm/hwcap.h>
+ #include <asm/cpufeature.h>
  #include <asm/kvm_vcpu_vector.h>
  #include <asm/vector.h>
  
@@@ -34,7 -34,6 +34,7 @@@ static const unsigned long kvm_isa_ext_
        [KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m,
        [KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v,
        /* Multi letter extensions (alphabetically sorted) */
 +      KVM_ISA_EXT_ARR(SMSTATEEN),
        KVM_ISA_EXT_ARR(SSAIA),
        KVM_ISA_EXT_ARR(SSTC),
        KVM_ISA_EXT_ARR(SVINVAL),
@@@ -46,7 -45,6 +46,7 @@@
        KVM_ISA_EXT_ARR(ZICBOM),
        KVM_ISA_EXT_ARR(ZICBOZ),
        KVM_ISA_EXT_ARR(ZICNTR),
 +      KVM_ISA_EXT_ARR(ZICOND),
        KVM_ISA_EXT_ARR(ZICSR),
        KVM_ISA_EXT_ARR(ZIFENCEI),
        KVM_ISA_EXT_ARR(ZIHINTPAUSE),
@@@ -82,11 -80,11 +82,11 @@@ static bool kvm_riscv_vcpu_isa_enable_a
  static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext)
  {
        switch (ext) {
 +      /* Extensions which don't have any mechanism to disable */
        case KVM_RISCV_ISA_EXT_A:
        case KVM_RISCV_ISA_EXT_C:
        case KVM_RISCV_ISA_EXT_I:
        case KVM_RISCV_ISA_EXT_M:
 -      case KVM_RISCV_ISA_EXT_SSAIA:
        case KVM_RISCV_ISA_EXT_SSTC:
        case KVM_RISCV_ISA_EXT_SVINVAL:
        case KVM_RISCV_ISA_EXT_SVNAPOT:
        case KVM_RISCV_ISA_EXT_ZBB:
        case KVM_RISCV_ISA_EXT_ZBS:
        case KVM_RISCV_ISA_EXT_ZICNTR:
 +      case KVM_RISCV_ISA_EXT_ZICOND:
        case KVM_RISCV_ISA_EXT_ZICSR:
        case KVM_RISCV_ISA_EXT_ZIFENCEI:
        case KVM_RISCV_ISA_EXT_ZIHINTPAUSE:
        case KVM_RISCV_ISA_EXT_ZIHPM:
                return false;
 +      /* Extensions which can be disabled using Smstateen */
 +      case KVM_RISCV_ISA_EXT_SSAIA:
 +              return riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN);
        default:
                break;
        }
@@@ -384,34 -378,6 +384,34 @@@ static int kvm_riscv_vcpu_general_set_c
        return 0;
  }
  
 +static inline int kvm_riscv_vcpu_smstateen_set_csr(struct kvm_vcpu *vcpu,
 +                                                 unsigned long reg_num,
 +                                                 unsigned long reg_val)
 +{
 +      struct kvm_vcpu_smstateen_csr *csr = &vcpu->arch.smstateen_csr;
 +
 +      if (reg_num >= sizeof(struct kvm_riscv_smstateen_csr) /
 +              sizeof(unsigned long))
 +              return -EINVAL;
 +
 +      ((unsigned long *)csr)[reg_num] = reg_val;
 +      return 0;
 +}
 +
 +static int kvm_riscv_vcpu_smstateen_get_csr(struct kvm_vcpu *vcpu,
 +                                          unsigned long reg_num,
 +                                          unsigned long *out_val)
 +{
 +      struct kvm_vcpu_smstateen_csr *csr = &vcpu->arch.smstateen_csr;
 +
 +      if (reg_num >= sizeof(struct kvm_riscv_smstateen_csr) /
 +              sizeof(unsigned long))
 +              return -EINVAL;
 +
 +      *out_val = ((unsigned long *)csr)[reg_num];
 +      return 0;
 +}
 +
  static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu,
                                      const struct kvm_one_reg *reg)
  {
        case KVM_REG_RISCV_CSR_AIA:
                rc = kvm_riscv_vcpu_aia_get_csr(vcpu, reg_num, &reg_val);
                break;
 +      case KVM_REG_RISCV_CSR_SMSTATEEN:
 +              rc = -EINVAL;
 +              if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
 +                      rc = kvm_riscv_vcpu_smstateen_get_csr(vcpu, reg_num,
 +                                                            &reg_val);
 +              break;
        default:
                rc = -ENOENT;
                break;
@@@ -480,12 -440,6 +480,12 @@@ static int kvm_riscv_vcpu_set_reg_csr(s
        case KVM_REG_RISCV_CSR_AIA:
                rc = kvm_riscv_vcpu_aia_set_csr(vcpu, reg_num, reg_val);
                break;
 +      case KVM_REG_RISCV_CSR_SMSTATEEN:
 +              rc = -EINVAL;
 +              if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
 +                      rc = kvm_riscv_vcpu_smstateen_set_csr(vcpu, reg_num,
 +                                                            reg_val);
 +break;
        default:
                rc = -ENOENT;
                break;
@@@ -506,11 -460,8 +506,11 @@@ static int riscv_vcpu_get_isa_ext_singl
            reg_num >= ARRAY_SIZE(kvm_isa_ext_arr))
                return -ENOENT;
  
 -      *reg_val = 0;
        host_isa_ext = kvm_isa_ext_arr[reg_num];
 +      if (!__riscv_isa_extension_available(NULL, host_isa_ext))
 +              return -ENOENT;
 +
 +      *reg_val = 0;
        if (__riscv_isa_extension_available(vcpu->arch.isa, host_isa_ext))
                *reg_val = 1; /* Mark the given extension as available */
  
@@@ -742,8 -693,6 +742,8 @@@ static inline unsigned long num_csr_reg
  
        if (riscv_isa_extension_available(vcpu->arch.isa, SSAIA))
                n += sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
 +      if (riscv_isa_extension_available(vcpu->arch.isa, SMSTATEEN))
 +              n += sizeof(struct kvm_riscv_smstateen_csr) / sizeof(unsigned long);
  
        return n;
  }
@@@ -752,7 -701,7 +752,7 @@@ static int copy_csr_reg_indices(const s
                                u64 __user *uindices)
  {
        int n1 = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
 -      int n2 = 0;
 +      int n2 = 0, n3 = 0;
  
        /* copy general csr regs */
        for (int i = 0; i < n1; i++) {
                }
        }
  
 -      return n1 + n2;
 +      /* copy Smstateen csr regs */
 +      if (riscv_isa_extension_available(vcpu->arch.isa, SMSTATEEN)) {
 +              n3 = sizeof(struct kvm_riscv_smstateen_csr) / sizeof(unsigned long);
 +
 +              for (int i = 0; i < n3; i++) {
 +                      u64 size = IS_ENABLED(CONFIG_32BIT) ?
 +                                 KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
 +                      u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CSR |
 +                                        KVM_REG_RISCV_CSR_SMSTATEEN | i;
 +
 +                      if (uindices) {
 +                              if (put_user(reg, uindices))
 +                                      return -EFAULT;
 +                              uindices++;
 +                      }
 +              }
 +      }
 +
 +      return n1 + n2 + n3;
  }
  
  static inline unsigned long num_timer_regs(void)
@@@ -911,7 -842,7 +911,7 @@@ static int copy_isa_ext_reg_indices(con
                u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_ISA_EXT | i;
  
                isa_ext = kvm_isa_ext_arr[i];
 -              if (!__riscv_isa_extension_available(vcpu->arch.isa, isa_ext))
 +              if (!__riscv_isa_extension_available(NULL, isa_ext))
                        continue;
  
                if (uindices) {
diff --combined arch/riscv/mm/init.c
@@@ -67,7 -67,7 +67,7 @@@ extern char _start[]
  void *_dtb_early_va __initdata;
  uintptr_t _dtb_early_pa __initdata;
  
 -static phys_addr_t dma32_phys_limit __initdata;
 +phys_addr_t dma32_phys_limit __initdata;
  
  static void __init zone_sizes_init(void)
  {
@@@ -666,16 -666,16 +666,16 @@@ void __init create_pgd_mapping(pgd_t *p
  static uintptr_t __init best_map_size(phys_addr_t pa, uintptr_t va,
                                      phys_addr_t size)
  {
-       if (!(pa & (PGDIR_SIZE - 1)) && !(va & (PGDIR_SIZE - 1)) && size >= PGDIR_SIZE)
-               return PGDIR_SIZE;
-       if (!(pa & (P4D_SIZE - 1)) && !(va & (P4D_SIZE - 1)) && size >= P4D_SIZE)
+       if (pgtable_l5_enabled &&
+           !(pa & (P4D_SIZE - 1)) && !(va & (P4D_SIZE - 1)) && size >= P4D_SIZE)
                return P4D_SIZE;
  
-       if (!(pa & (PUD_SIZE - 1)) && !(va & (PUD_SIZE - 1)) && size >= PUD_SIZE)
+       if (pgtable_l4_enabled &&
+           !(pa & (PUD_SIZE - 1)) && !(va & (PUD_SIZE - 1)) && size >= PUD_SIZE)
                return PUD_SIZE;
  
-       if (!(pa & (PMD_SIZE - 1)) && !(va & (PMD_SIZE - 1)) && size >= PMD_SIZE)
+       if (IS_ENABLED(CONFIG_64BIT) &&
+           !(pa & (PMD_SIZE - 1)) && !(va & (PMD_SIZE - 1)) && size >= PMD_SIZE)
                return PMD_SIZE;
  
        return PAGE_SIZE;
@@@ -1335,6 -1335,28 +1335,6 @@@ static inline void setup_vm_final(void
  }
  #endif /* CONFIG_MMU */
  
 -/* Reserve 128M low memory by default for swiotlb buffer */
 -#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
 -
 -static int __init reserve_crashkernel_low(unsigned long long low_size)
 -{
 -      unsigned long long low_base;
 -
 -      low_base = memblock_phys_alloc_range(low_size, PMD_SIZE, 0, dma32_phys_limit);
 -      if (!low_base) {
 -              pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
 -              return -ENOMEM;
 -      }
 -
 -      pr_info("crashkernel low memory reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
 -              low_base, low_base + low_size, low_size >> 20);
 -
 -      crashk_low_res.start = low_base;
 -      crashk_low_res.end = low_base + low_size - 1;
 -
 -      return 0;
 -}
 -
  /*
   * reserve_crashkernel() - reserves memory for crash kernel
   *
   * line parameter. The memory reserved is used by dump capture kernel when
   * primary kernel is crashing.
   */
 -static void __init reserve_crashkernel(void)
 +static void __init arch_reserve_crashkernel(void)
  {
 -      unsigned long long crash_base = 0;
 -      unsigned long long crash_size = 0;
 -      unsigned long long crash_low_size = 0;
 -      unsigned long search_start = memblock_start_of_DRAM();
 -      unsigned long search_end = (unsigned long)dma32_phys_limit;
 +      unsigned long long low_size = 0;
 +      unsigned long long crash_base, crash_size;
        char *cmdline = boot_command_line;
 -      bool fixed_base = false;
        bool high = false;
 -
 -      int ret = 0;
 +      int ret;
  
        if (!IS_ENABLED(CONFIG_KEXEC_CORE))
                return;
 -      /*
 -       * Don't reserve a region for a crash kernel on a crash kernel
 -       * since it doesn't make much sense and we have limited memory
 -       * resources.
 -       */
 -      if (is_kdump_kernel()) {
 -              pr_info("crashkernel: ignoring reservation request\n");
 -              return;
 -      }
  
        ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
 -                              &crash_size, &crash_base);
 -      if (ret == -ENOENT) {
 -              /* Fallback to crashkernel=X,[high,low] */
 -              ret = parse_crashkernel_high(cmdline, 0, &crash_size, &crash_base);
 -              if (ret || !crash_size)
 -                      return;
 -
 -              /*
 -               * crashkernel=Y,low is valid only when crashkernel=X,high
 -               * is passed.
 -               */
 -              ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base);
 -              if (ret == -ENOENT)
 -                      crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
 -              else if (ret)
 -                      return;
 -
 -              search_start = (unsigned long)dma32_phys_limit;
 -              search_end = memblock_end_of_DRAM();
 -              high = true;
 -      } else if (ret || !crash_size) {
 -              /* Invalid argument value specified */
 +                              &crash_size, &crash_base,
 +                              &low_size, &high);
 +      if (ret)
                return;
 -      }
 -
 -      crash_size = PAGE_ALIGN(crash_size);
 -
 -      if (crash_base) {
 -              fixed_base = true;
 -              search_start = crash_base;
 -              search_end = crash_base + crash_size;
 -      }
 -
 -      /*
 -       * Current riscv boot protocol requires 2MB alignment for
 -       * RV64 and 4MB alignment for RV32 (hugepage size)
 -       *
 -       * Try to alloc from 32bit addressible physical memory so that
 -       * swiotlb can work on the crash kernel.
 -       */
 -      crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE,
 -                                             search_start, search_end);
 -      if (crash_base == 0) {
 -              /*
 -               * For crashkernel=size[KMG]@offset[KMG], print out failure
 -               * message if can't reserve the specified region.
 -               */
 -              if (fixed_base) {
 -                      pr_warn("crashkernel: allocating failed with given size@offset\n");
 -                      return;
 -              }
 -
 -              if (high) {
 -                      /*
 -                       * For crashkernel=size[KMG],high, if the first attempt was
 -                       * for high memory, fall back to low memory.
 -                       */
 -                      search_start = memblock_start_of_DRAM();
 -                      search_end = (unsigned long)dma32_phys_limit;
 -              } else {
 -                      /*
 -                       * For crashkernel=size[KMG], if the first attempt was for
 -                       * low memory, fall back to high memory, the minimum required
 -                       * low memory will be reserved later.
 -                       */
 -                      search_start = (unsigned long)dma32_phys_limit;
 -                      search_end = memblock_end_of_DRAM();
 -                      crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
 -              }
 -
 -              crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE,
 -                                                     search_start, search_end);
 -              if (crash_base == 0) {
 -                      pr_warn("crashkernel: couldn't allocate %lldKB\n",
 -                              crash_size >> 10);
 -                      return;
 -              }
 -      }
 -
 -      if ((crash_base >= dma32_phys_limit) && crash_low_size &&
 -           reserve_crashkernel_low(crash_low_size)) {
 -              memblock_phys_free(crash_base, crash_size);
 -              return;
 -      }
 -
 -      pr_info("crashkernel: reserved 0x%016llx - 0x%016llx (%lld MB)\n",
 -              crash_base, crash_base + crash_size, crash_size >> 20);
  
 -      crashk_res.start = crash_base;
 -      crashk_res.end = crash_base + crash_size - 1;
 +      reserve_crashkernel_generic(cmdline, crash_size, crash_base,
 +                                  low_size, high);
  }
  
  void __init paging_init(void)
@@@ -1378,7 -1497,7 +1378,7 @@@ void __init misc_mem_init(void
        arch_numa_init();
        sparse_init();
        zone_sizes_init();
 -      reserve_crashkernel();
 +      arch_reserve_crashkernel();
        memblock_dump_all();
  }
  
@@@ -25,7 -25,7 +25,7 @@@
  #include <linux/limits.h>
  #include <clocksource/timer-riscv.h>
  #include <asm/smp.h>
- #include <asm/hwcap.h>
+ #include <asm/cpufeature.h>
  #include <asm/sbi.h>
  #include <asm/timex.h>
  
@@@ -225,10 -225,6 +225,10 @@@ TIMER_OF_DECLARE(riscv_timer, "riscv", 
  #ifdef CONFIG_ACPI
  static int __init riscv_timer_acpi_init(struct acpi_table_header *table)
  {
 +      struct acpi_table_rhct *rhct = (struct acpi_table_rhct *)table;
 +
 +      riscv_timer_cannot_wake_cpu = rhct->flags & ACPI_RHCT_TIMER_CANNOT_WAKEUP_CPU;
 +
        return riscv_timer_init_common();
  }
  
@@@ -28,7 -28,7 +28,7 @@@ cflags-$(CONFIG_ARM)          += -DEFI_HAVE_STR
                                   -DEFI_HAVE_MEMCHR -DEFI_HAVE_STRRCHR \
                                   -DEFI_HAVE_STRCMP -fno-builtin -fpic \
                                   $(call cc-option,-mno-single-pic-base)
- cflags-$(CONFIG_RISCV)                += -fpic
+ cflags-$(CONFIG_RISCV)                += -fpic -DNO_ALTERNATIVE
  cflags-$(CONFIG_LOONGARCH)    += -fpie
  
  cflags-$(CONFIG_EFI_PARAMS_FROM_FDT)  += -I$(srctree)/scripts/dtc/libfdt
@@@ -108,6 -108,13 +108,6 @@@ lib-y                             := $(patsubst %.o,%.stub.o,$(l
  # https://bugs.llvm.org/show_bug.cgi?id=46480
  STUBCOPY_FLAGS-y              += --remove-section=.note.gnu.property
  
 -#
 -# For x86, bootloaders like systemd-boot or grub-efi do not zero-initialize the
 -# .bss section, so the .bss section of the EFI stub needs to be included in the
 -# .data section of the compressed kernel to ensure initialization. Rename the
 -# .bss section here so it's easy to pick out in the linker script.
 -#
 -STUBCOPY_FLAGS-$(CONFIG_X86)  += --rename-section .bss=.bss.efistub,load,alloc
  STUBCOPY_RELOC-$(CONFIG_X86_32)       := R_386_32
  STUBCOPY_RELOC-$(CONFIG_X86_64)       := R_X86_64_64