diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-24 09:54:45 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-24 09:54:45 -0700 |
| commit | ff57d59200baadfdb41f94a49fed7d161a9a8124 (patch) | |
| tree | ba3e10b29fe41a53e6b5c2f6f555189962859e56 | |
| parent | 64edfa65062dc4509ba75978116b2f6d392346f5 (diff) | |
| parent | 7939f96f26e96b69db1fe4e7c18537a679696358 (diff) | |
Merge tag 'loongarch-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
Pull LoongArch updates from Huacai Chen:
- Adjust build infrastructure for 32BIT/64BIT
- Add HIGHMEM (PKMAP and FIX_KMAP) support
- Show and handle CPU vulnerabilites correctly
- Batch the icache maintenance for jump_label
- Add more atomic instructions support for BPF JIT
- Add more features (e.g. fsession) support for BPF trampoline
- Some bug fixes and other small changes
* tag 'loongarch-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson: (21 commits)
selftests/bpf: Enable CAN_USE_LOAD_ACQ_STORE_REL for LoongArch
LoongArch: BPF: Add fsession support for trampolines
LoongArch: BPF: Introduce emit_store_stack_imm64() helper
LoongArch: BPF: Support up to 12 function arguments for trampoline
LoongArch: BPF: Support small struct arguments for trampoline
LoongArch: BPF: Open code and remove invoke_bpf_mod_ret()
LoongArch: BPF: Support load-acquire and store-release instructions
LoongArch: BPF: Support 8 and 16 bit read-modify-write instructions
LoongArch: BPF: Add the default case in emit_atomic() and rename it
LoongArch: Define instruction formats for AM{SWAP/ADD}.{B/H} and DBAR
LoongArch: Batch the icache maintenance for jump_label
LoongArch: Add flush_icache_all()/local_flush_icache_all()
LoongArch: Add spectre boundry for syscall dispatch table
LoongArch: Show CPU vulnerabilites correctly
LoongArch: Make arch_irq_work_has_interrupt() true only if IPI HW exist
LoongArch: Use get_random_canary() for stack canary init
LoongArch: Improve the logging of disabling KASLR
LoongArch: Align FPU register state to 32 bytes
LoongArch: Handle CONFIG_32BIT in syscall_get_arch()
LoongArch: Add HIGHMEM (PKMAP and FIX_KMAP) support
...
39 files changed, 726 insertions, 201 deletions
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index ac714d14133a..3b042dbb2c41 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -20,11 +20,11 @@ config LOONGARCH select ARCH_HAS_FAST_MULTIPLIER select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_KCOV - select ARCH_HAS_KERNEL_FPU_SUPPORT if CPU_HAS_FPU + select ARCH_HAS_KERNEL_FPU_SUPPORT if 64BIT && CPU_HAS_FPU select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_PREEMPT_LAZY - select ARCH_HAS_PTE_SPECIAL + select ARCH_HAS_PTE_SPECIAL if 64BIT select ARCH_HAS_SET_MEMORY select ARCH_HAS_SET_DIRECT_MAP select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST @@ -59,16 +59,15 @@ config LOONGARCH select ARCH_KEEP_MEMBLOCK select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO - select ARCH_SPARSEMEM_ENABLE select ARCH_STACKWALK select ARCH_SUPPORTS_ACPI select ARCH_SUPPORTS_ATOMIC_RMW - select ARCH_SUPPORTS_HUGETLBFS + select ARCH_SUPPORTS_HUGETLBFS if 64BIT select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 select ARCH_SUPPORTS_LTO_CLANG select ARCH_SUPPORTS_LTO_CLANG_THIN select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS - select ARCH_SUPPORTS_NUMA_BALANCING + select ARCH_SUPPORTS_NUMA_BALANCING if NUMA select ARCH_SUPPORTS_PER_VMA_LOCK select ARCH_SUPPORTS_RT select ARCH_SUPPORTS_SCHED_SMT if SMP @@ -78,10 +77,10 @@ config LOONGARCH select ARCH_USE_MEMTEST select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS - select ARCH_WANT_DEFAULT_BPF_JIT + select ARCH_WANT_DEFAULT_BPF_JIT if HAVE_EBPF_JIT select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT select ARCH_WANT_LD_ORPHAN_WARN - select ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP + select ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP if 64BIT select ARCH_WANTS_NO_INSTR select ARCH_WANTS_THP_SWAP if HAVE_ARCH_TRANSPARENT_HUGEPAGE select BUILDTIME_TABLE_SORT @@ -89,13 +88,14 @@ config LOONGARCH select CPU_PM select EDAC_SUPPORT select EFI + select GENERIC_ATOMIC64 if 32BIT select GENERIC_CLOCKEVENTS select GENERIC_CMOS_UPDATE select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_DEVICES select GENERIC_CPU_VULNERABILITIES select GENERIC_ENTRY - select GENERIC_GETTIMEOFDAY + select GENERIC_GETTIMEOFDAY if 64BIT select GENERIC_IOREMAP if !ARCH_IOREMAP select GENERIC_IRQ_MATRIX_ALLOCATOR select GENERIC_IRQ_MULTI_HANDLER @@ -110,16 +110,16 @@ config LOONGARCH select GENERIC_PCI_IOMAP select GENERIC_SCHED_CLOCK select GENERIC_SMP_IDLE_THREAD - select GENERIC_TIME_VSYSCALL + select GENERIC_TIME_VSYSCALL if GENERIC_GETTIMEOFDAY select GPIOLIB select HAS_IOPORT - select HAVE_ALIGNED_STRUCT_PAGE + select HAVE_ALIGNED_STRUCT_PAGE if 64BIT select HAVE_ARCH_AUDITSYSCALL - select HAVE_ARCH_BITREVERSE + select HAVE_ARCH_BITREVERSE if 64BIT select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE - select HAVE_ARCH_KASAN - select HAVE_ARCH_KFENCE + select HAVE_ARCH_KASAN if 64BIT + select HAVE_ARCH_KFENCE if 64BIT select HAVE_ARCH_KGDB if PERF_EVENTS select HAVE_ARCH_KSTACK_ERASE select HAVE_ARCH_MMAP_RND_BITS if MMU @@ -127,8 +127,8 @@ config LOONGARCH select HAVE_ARCH_SECCOMP select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK - select HAVE_ARCH_TRANSPARENT_HUGEPAGE - select HAVE_ARCH_USERFAULTFD_MINOR if USERFAULTFD + select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT + select HAVE_ARCH_USERFAULTFD_MINOR if 64BIT && USERFAULTFD select HAVE_ASM_MODVERSIONS select HAVE_CMPXCHG_DOUBLE select HAVE_CMPXCHG_LOCAL @@ -142,7 +142,7 @@ config LOONGARCH select HAVE_FTRACE_REGS_HAVING_PT_REGS select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS select HAVE_DYNAMIC_FTRACE_WITH_REGS - select HAVE_EBPF_JIT + select HAVE_EBPF_JIT if 64BIT select HAVE_EFFICIENT_UNALIGNED_ACCESS if !ARCH_STRICT_ALIGN select HAVE_EXIT_THREAD select HAVE_GENERIC_TIF_BITS @@ -165,9 +165,9 @@ config LOONGARCH select HAVE_LIVEPATCH select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI - select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS && AS_HAS_THIN_ADD_SUB + select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS && AS_HAS_THIN_ADD_SUB && 64BIT select HAVE_PCI - select HAVE_PERF_EVENTS + select HAVE_PERF_EVENTS if 64BIT select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP select HAVE_POSIX_CPU_TIMERS_TASK_WORK @@ -209,18 +209,50 @@ config LOONGARCH select SYSCTL_ARCH_UNALIGN_ALLOW select SYSCTL_ARCH_UNALIGN_NO_WARN select SYSCTL_EXCEPTION_TRACE - select SWIOTLB + select SWIOTLB if 64BIT select TRACE_IRQFLAGS_SUPPORT select USE_PERCPU_NUMA_NODE_ID select USER_STACKTRACE_SUPPORT select VDSO_GETRANDOM - select ZONE_DMA32 + select ZONE_DMA32 if 64BIT + +menu "Kernel type and options" + +choice + prompt "Kernel type" config 32BIT - bool + bool "32-bit kernel" + help + Select this option if you want to build a 32-bit kernel. config 64BIT - def_bool y + bool "64-bit kernel" + help + Select this option if you want to build a 64-bit kernel. + +endchoice + +if 32BIT + +choice + prompt "32-bit kernel sub-type" + +config 32BIT_REDUCED + bool "32-bit kernel for LA32R" + help + Select this option if you want to build a 32-bit kernel for + LoongArch32 Reduced (LA32R). + +config 32BIT_STANDARD + bool "32-bit kernel for LA32S" + help + Select this option if you want to build a 32-bit kernel for + LoongArch32 Standard (LA32S). + +endchoice + +endif config GENERIC_BUG def_bool y @@ -313,10 +345,13 @@ config RUSTC_HAS_ANNOTATE_TABLEJUMP depends on RUST def_bool $(rustc-option,-Cllvm-args=--loongarch-annotate-tablejump) -menu "Kernel type and options" - source "kernel/Kconfig.hz" +config HIGHMEM + bool "High Memory Support" + depends on 32BIT + select KMAP_LOCAL + choice prompt "Page Table Layout" default 16KB_2LEVEL if 32BIT @@ -326,8 +361,17 @@ choice of page size and page table levels. The size of virtual memory address space are determined by the page table layout. +config 4KB_2LEVEL + bool "4KB with 2 levels" + select HAVE_PAGE_SIZE_4KB + select PGTABLE_2LEVEL + help + This option selects 4KB page size with 2 level page tables, which + support a maximum of 32 bits of application virtual memory. + config 4KB_3LEVEL bool "4KB with 3 levels" + depends on 64BIT select HAVE_PAGE_SIZE_4KB select PGTABLE_3LEVEL help @@ -336,6 +380,7 @@ config 4KB_3LEVEL config 4KB_4LEVEL bool "4KB with 4 levels" + depends on 64BIT select HAVE_PAGE_SIZE_4KB select PGTABLE_4LEVEL help @@ -352,6 +397,7 @@ config 16KB_2LEVEL config 16KB_3LEVEL bool "16KB with 3 levels" + depends on 64BIT select HAVE_PAGE_SIZE_16KB select PGTABLE_3LEVEL help @@ -368,6 +414,7 @@ config 64KB_2LEVEL config 64KB_3LEVEL bool "64KB with 3 levels" + depends on 64BIT select HAVE_PAGE_SIZE_64KB select PGTABLE_3LEVEL help @@ -465,6 +512,7 @@ config EFI_STUB config SMP bool "Multi-Processing support" + depends on 64BIT help This enables support for systems with more than one CPU. If you have a system with only one CPU, say N. If you have a system with more @@ -503,6 +551,7 @@ config NR_CPUS config NUMA bool "NUMA Support" select SMP + depends on 64BIT help Say Y to compile the kernel with NUMA (Non-Uniform Memory Access) support. This option improves performance on systems with more @@ -585,7 +634,7 @@ config CPU_HAS_FPU config CPU_HAS_LSX bool "Support for the Loongson SIMD Extension" - depends on AS_HAS_LSX_EXTENSION + depends on AS_HAS_LSX_EXTENSION && 64BIT help Loongson SIMD Extension (LSX) introduces 128 bit wide vector registers and a set of SIMD instructions to operate on them. When this option @@ -600,7 +649,7 @@ config CPU_HAS_LSX config CPU_HAS_LASX bool "Support for the Loongson Advanced SIMD Extension" depends on CPU_HAS_LSX - depends on AS_HAS_LASX_EXTENSION + depends on AS_HAS_LASX_EXTENSION && 64BIT help Loongson Advanced SIMD Extension (LASX) introduces 256 bit wide vector registers and a set of SIMD instructions to operate on them. When this @@ -614,7 +663,7 @@ config CPU_HAS_LASX config CPU_HAS_LBT bool "Support for the Loongson Binary Translation Extension" - depends on AS_HAS_LBT_EXTENSION + depends on AS_HAS_LBT_EXTENSION && 64BIT help Loongson Binary Translation (LBT) introduces 4 scratch registers (SCR0 to SCR3), x86/ARM eflags (eflags) and x87 fpu stack pointer (ftop). @@ -642,13 +691,13 @@ config ARCH_SELECTS_KEXEC_FILE select HAVE_IMA_KEXEC if IMA config ARCH_SUPPORTS_CRASH_DUMP - def_bool y + def_bool 64BIT config ARCH_DEFAULT_CRASH_DUMP - def_bool y + def_bool 64BIT config ARCH_SELECTS_CRASH_DUMP - def_bool y + def_bool 64BIT depends on CRASH_DUMP select RELOCATABLE @@ -657,6 +706,7 @@ config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION config RELOCATABLE bool "Relocatable kernel" + depends on 64BIT select ARCH_HAS_RELR help This builds the kernel as a Position Independent Executable (PIE), @@ -693,7 +743,7 @@ source "kernel/livepatch/Kconfig" config PARAVIRT bool "Enable paravirtualization code" - depends on AS_HAS_LVZ_EXTENSION + depends on AS_HAS_LVZ_EXTENSION && 64BIT select HAVE_PV_STEAL_CLOCK_GEN help This changes the kernel so it can modify itself when it is run @@ -722,7 +772,7 @@ config ARCH_FLATMEM_ENABLE depends on !NUMA config ARCH_SPARSEMEM_ENABLE - def_bool y + def_bool 64BIT select SPARSEMEM_VMEMMAP_ENABLE help Say Y to support efficient handling of sparse physical memory, @@ -739,10 +789,12 @@ config MMU default y config ARCH_MMAP_RND_BITS_MIN - default 12 + default 10 if 32BIT + default 12 if 64BIT config ARCH_MMAP_RND_BITS_MAX - default 18 + default 15 if 32BIT + default 20 if 64BIT config ARCH_SUPPORTS_UPROBES def_bool y diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile index 8d45b860fe56..47516aeea9d2 100644 --- a/arch/loongarch/Makefile +++ b/arch/loongarch/Makefile @@ -25,6 +25,7 @@ endif # # Select the object file format to substitute into the linker script. # +32bit-tool-archpref = loongarch32 64bit-tool-archpref = loongarch64 32bit-bfd = elf32-loongarch 64bit-bfd = elf64-loongarch @@ -51,7 +52,10 @@ KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY CC_FLAGS_FTRACE := -fpatchable-function-entry=2 endif -ifdef CONFIG_64BIT +ifdef CONFIG_32BIT +tool-archpref = $(32bit-tool-archpref) +UTS_MACHINE := loongarch32 +else tool-archpref = $(64bit-tool-archpref) UTS_MACHINE := loongarch64 endif @@ -62,9 +66,19 @@ ifneq ($(SUBARCH),$(ARCH)) endif endif +ifdef CONFIG_32BIT +ifdef CONFIG_32BIT_STANDARD +ld-emul = $(32bit-emul) +cflags-y += -march=la32v1.0 -mabi=ilp32s -mcmodel=normal +else # CONFIG_32BIT_REDUCED +ld-emul = $(32bit-emul) +cflags-y += -march=la32rv1.0 -mabi=ilp32s -mcmodel=normal +endif +endif + ifdef CONFIG_64BIT ld-emul = $(64bit-emul) -cflags-y += -mabi=lp64s -mcmodel=normal +cflags-y += -march=loongarch64 -mabi=lp64s -mcmodel=normal endif cflags-y += -pipe $(CC_FLAGS_NO_FPU) @@ -140,7 +154,12 @@ ifndef CONFIG_KASAN cflags-y += -fno-builtin-memcpy -fno-builtin-memmove -fno-builtin-memset endif +ifdef CONFIG_32BIT +load-y = 0xa0200000 +else load-y = 0x9000000000200000 +endif + bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) drivers-$(CONFIG_PCI) += arch/loongarch/pci/ diff --git a/arch/loongarch/boot/Makefile b/arch/loongarch/boot/Makefile index 4e1c374c5782..8b6d9b42b5f0 100644 --- a/arch/loongarch/boot/Makefile +++ b/arch/loongarch/boot/Makefile @@ -20,7 +20,13 @@ $(obj)/vmlinux.efi: vmlinux FORCE $(call if_changed,objcopy) EFI_ZBOOT_PAYLOAD := vmlinux.efi + +ifdef CONFIG_32BIT +EFI_ZBOOT_BFD_TARGET := elf32-loongarch +EFI_ZBOOT_MACH_TYPE := LOONGARCH32 +else EFI_ZBOOT_BFD_TARGET := elf64-loongarch EFI_ZBOOT_MACH_TYPE := LOONGARCH64 +endif include $(srctree)/drivers/firmware/efi/libstub/Makefile.zboot diff --git a/arch/loongarch/include/asm/cacheflush.h b/arch/loongarch/include/asm/cacheflush.h index f8754d08a31a..190651be9546 100644 --- a/arch/loongarch/include/asm/cacheflush.h +++ b/arch/loongarch/include/asm/cacheflush.h @@ -32,8 +32,22 @@ static inline unsigned int cpu_last_level_cache_line_size(void) } asmlinkage void __flush_cache_all(void); -void local_flush_icache_range(unsigned long start, unsigned long end); +/* + * LoongArch maintains ICache/DCache coherency by hardware, + * we just need "ibar" to avoid instruction hazard here. + */ +static inline void local_flush_icache_all(void) +{ + asm volatile ("ibar\t0\n"::); +} + +static inline void local_flush_icache_range(unsigned long start, unsigned long end) +{ + asm volatile ("ibar\t0\n"::); +} + +#define flush_icache_all local_flush_icache_all #define flush_icache_range local_flush_icache_range #define flush_icache_user_range local_flush_icache_range diff --git a/arch/loongarch/include/asm/cpu-features.h b/arch/loongarch/include/asm/cpu-features.h index 8eefe7a2098b..62059c5551b9 100644 --- a/arch/loongarch/include/asm/cpu-features.h +++ b/arch/loongarch/include/asm/cpu-features.h @@ -35,6 +35,7 @@ */ #define cpu_has_cpucfg cpu_opt(LOONGARCH_CPU_CPUCFG) #define cpu_has_lam cpu_opt(LOONGARCH_CPU_LAM) +#define cpu_has_lam_bh cpu_opt(LOONGARCH_CPU_LAM_BH) #define cpu_has_scq cpu_opt(LOONGARCH_CPU_SCQ) #define cpu_has_ual cpu_opt(LOONGARCH_CPU_UAL) #define cpu_has_fpu cpu_opt(LOONGARCH_CPU_FPU) diff --git a/arch/loongarch/include/asm/cpu.h b/arch/loongarch/include/asm/cpu.h index 1e60ab264cd0..91b96938861e 100644 --- a/arch/loongarch/include/asm/cpu.h +++ b/arch/loongarch/include/asm/cpu.h @@ -95,40 +95,42 @@ static inline char *id_to_core_name(unsigned int id) */ #define CPU_FEATURE_CPUCFG 0 /* CPU has CPUCFG */ #define CPU_FEATURE_LAM 1 /* CPU has Atomic instructions */ -#define CPU_FEATURE_SCQ 2 /* CPU has SC.Q instruction */ -#define CPU_FEATURE_UAL 3 /* CPU supports unaligned access */ -#define CPU_FEATURE_FPU 4 /* CPU has FPU */ -#define CPU_FEATURE_LSX 5 /* CPU has LSX (128-bit SIMD) */ -#define CPU_FEATURE_LASX 6 /* CPU has LASX (256-bit SIMD) */ -#define CPU_FEATURE_CRC32 7 /* CPU has CRC32 instructions */ -#define CPU_FEATURE_COMPLEX 8 /* CPU has Complex instructions */ -#define CPU_FEATURE_CRYPTO 9 /* CPU has Crypto instructions */ -#define CPU_FEATURE_LVZ 10 /* CPU has Virtualization extension */ -#define CPU_FEATURE_LBT_X86 11 /* CPU has X86 Binary Translation */ -#define CPU_FEATURE_LBT_ARM 12 /* CPU has ARM Binary Translation */ -#define CPU_FEATURE_LBT_MIPS 13 /* CPU has MIPS Binary Translation */ -#define CPU_FEATURE_TLB 14 /* CPU has TLB */ -#define CPU_FEATURE_CSR 15 /* CPU has CSR */ -#define CPU_FEATURE_IOCSR 16 /* CPU has IOCSR */ -#define CPU_FEATURE_WATCH 17 /* CPU has watchpoint registers */ -#define CPU_FEATURE_VINT 18 /* CPU has vectored interrupts */ -#define CPU_FEATURE_CSRIPI 19 /* CPU has CSR-IPI */ -#define CPU_FEATURE_EXTIOI 20 /* CPU has EXT-IOI */ -#define CPU_FEATURE_PREFETCH 21 /* CPU has prefetch instructions */ -#define CPU_FEATURE_PMP 22 /* CPU has perfermance counter */ -#define CPU_FEATURE_SCALEFREQ 23 /* CPU supports cpufreq scaling */ -#define CPU_FEATURE_FLATMODE 24 /* CPU has flat mode */ -#define CPU_FEATURE_EIODECODE 25 /* CPU has EXTIOI interrupt pin decode mode */ -#define CPU_FEATURE_GUESTID 26 /* CPU has GuestID feature */ -#define CPU_FEATURE_HYPERVISOR 27 /* CPU has hypervisor (running in VM) */ -#define CPU_FEATURE_PTW 28 /* CPU has hardware page table walker */ -#define CPU_FEATURE_LSPW 29 /* CPU has LSPW (lddir/ldpte instructions) */ -#define CPU_FEATURE_MSGINT 30 /* CPU has MSG interrupt */ -#define CPU_FEATURE_AVECINT 31 /* CPU has AVEC interrupt */ -#define CPU_FEATURE_REDIRECTINT 32 /* CPU has interrupt remapping */ +#define CPU_FEATURE_LAM_BH 2 /* CPU has AM{SWAP/ADD}[_DB].{B/H} instructions */ +#define CPU_FEATURE_SCQ 3 /* CPU has SC.Q instruction */ +#define CPU_FEATURE_UAL 4 /* CPU supports unaligned access */ +#define CPU_FEATURE_FPU 5 /* CPU has FPU */ +#define CPU_FEATURE_LSX 6 /* CPU has LSX (128-bit SIMD) */ +#define CPU_FEATURE_LASX 7 /* CPU has LASX (256-bit SIMD) */ +#define CPU_FEATURE_CRC32 8 /* CPU has CRC32 instructions */ +#define CPU_FEATURE_COMPLEX 9 /* CPU has Complex instructions */ +#define CPU_FEATURE_CRYPTO 10 /* CPU has Crypto instructions */ +#define CPU_FEATURE_LVZ 11 /* CPU has Virtualization extension */ +#define CPU_FEATURE_LBT_X86 12 /* CPU has X86 Binary Translation */ +#define CPU_FEATURE_LBT_ARM 13 /* CPU has ARM Binary Translation */ +#define CPU_FEATURE_LBT_MIPS 14 /* CPU has MIPS Binary Translation */ +#define CPU_FEATURE_TLB 15 /* CPU has TLB */ +#define CPU_FEATURE_CSR 16 /* CPU has CSR */ +#define CPU_FEATURE_IOCSR 17 /* CPU has IOCSR */ +#define CPU_FEATURE_WATCH 18 /* CPU has watchpoint registers */ +#define CPU_FEATURE_VINT 19 /* CPU has vectored interrupts */ +#define CPU_FEATURE_CSRIPI 20 /* CPU has CSR-IPI */ +#define CPU_FEATURE_EXTIOI 21 /* CPU has EXT-IOI */ +#define CPU_FEATURE_PREFETCH 22 /* CPU has prefetch instructions */ +#define CPU_FEATURE_PMP 23 /* CPU has perfermance counter */ +#define CPU_FEATURE_SCALEFREQ 24 /* CPU supports cpufreq scaling */ +#define CPU_FEATURE_FLATMODE 25 /* CPU has flat mode */ +#define CPU_FEATURE_EIODECODE 26 /* CPU has EXTIOI interrupt pin decode mode */ +#define CPU_FEATURE_GUESTID 27 /* CPU has GuestID feature */ +#define CPU_FEATURE_HYPERVISOR 28 /* CPU has hypervisor (running in VM) */ +#define CPU_FEATURE_PTW 29 /* CPU has hardware page table walker */ +#define CPU_FEATURE_LSPW 30 /* CPU has LSPW (lddir/ldpte instructions) */ +#define CPU_FEATURE_MSGINT 31 /* CPU has MSG interrupt */ +#define CPU_FEATURE_AVECINT 32 /* CPU has AVEC interrupt */ +#define CPU_FEATURE_REDIRECTINT 33 /* CPU has interrupt remapping */ #define LOONGARCH_CPU_CPUCFG BIT_ULL(CPU_FEATURE_CPUCFG) #define LOONGARCH_CPU_LAM BIT_ULL(CPU_FEATURE_LAM) +#define LOONGARCH_CPU_LAM_BH BIT_ULL(CPU_FEATURE_LAM_BH) #define LOONGARCH_CPU_SCQ BIT_ULL(CPU_FEATURE_SCQ) #define LOONGARCH_CPU_UAL BIT_ULL(CPU_FEATURE_UAL) #define LOONGARCH_CPU_FPU BIT_ULL(CPU_FEATURE_FPU) diff --git a/arch/loongarch/include/asm/fixmap.h b/arch/loongarch/include/asm/fixmap.h index d2e55ae55bb9..dce2da6ba787 100644 --- a/arch/loongarch/include/asm/fixmap.h +++ b/arch/loongarch/include/asm/fixmap.h @@ -8,10 +8,19 @@ #ifndef _ASM_FIXMAP_H #define _ASM_FIXMAP_H +#ifdef CONFIG_HIGHMEM +#include <linux/threads.h> +#include <asm/kmap_size.h> +#endif + #define NR_FIX_BTMAPS 64 enum fixed_addresses { FIX_HOLE, +#ifdef CONFIG_HIGHMEM + FIX_KMAP_BEGIN, + FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_MAX_IDX * NR_CPUS) - 1, +#endif FIX_EARLYCON_MEM_BASE, __end_of_fixed_addresses }; @@ -25,4 +34,9 @@ extern void __set_fixmap(enum fixed_addresses idx, #include <asm-generic/fixmap.h> +/* + * Called from pagetable_init() + */ +extern void fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base); + #endif diff --git a/arch/loongarch/include/asm/highmem.h b/arch/loongarch/include/asm/highmem.h new file mode 100644 index 000000000000..e6d7a662d340 --- /dev/null +++ b/arch/loongarch/include/asm/highmem.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * highmem.h: virtual kernel memory mappings for high memory + * + * Used in CONFIG_HIGHMEM systems for memory pages which + * are not addressable by direct kernel virtual addresses. + * + * Copyright (C) 2025 Loongson Technology Corporation Limited + */ +#ifndef _ASM_HIGHMEM_H +#define _ASM_HIGHMEM_H + +#ifdef __KERNEL__ + +#include <asm/kmap_size.h> + +#ifndef __ASSEMBLER__ + +extern pte_t *pkmap_page_table; + +#define ARCH_HAS_KMAP_FLUSH_TLB +void kmap_flush_tlb(unsigned long addr); + +#endif /* !__ASSEMBLER__ */ + +/* + * Right now we initialize only a single pte table. It can be extended + * easily, subsequent pte tables have to be allocated in one physical + * chunk of RAM. + */ +#define LAST_PKMAP 1024 +#define LAST_PKMAP_MASK (LAST_PKMAP - 1) +#define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) + +#define flush_cache_kmaps() do {} while (0) + +#define arch_kmap_local_post_map(vaddr, pteval) local_flush_tlb_one(vaddr) +#define arch_kmap_local_post_unmap(vaddr) local_flush_tlb_one(vaddr) + +#endif /* __KERNEL__ */ + +#endif /* _ASM_HIGHMEM_H */ diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h index f9f207082d0e..76b723590023 100644 --- a/arch/loongarch/include/asm/inst.h +++ b/arch/loongarch/include/asm/inst.h @@ -36,6 +36,7 @@ enum reg0i15_op { break_op = 0x54, + dbar_op = 0x70e4, }; enum reg0i26_op { @@ -194,6 +195,10 @@ enum reg3_op { fstxs_op = 0x7070, fstxd_op = 0x7078, scq_op = 0x70ae, + amswapb_op = 0x70b8, + amswaph_op = 0x70b9, + amaddb_op = 0x70ba, + amaddh_op = 0x70bb, amswapw_op = 0x70c0, amswapd_op = 0x70c1, amaddw_op = 0x70c2, @@ -543,6 +548,7 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \ } DEF_EMIT_REG0I15_FORMAT(break, break_op) +DEF_EMIT_REG0I15_FORMAT(dbar, dbar_op) /* like emit_break(imm) but returns a constant expression */ #define __emit_break(imm) ((u32)((imm) | (break_op << 15))) @@ -763,6 +769,8 @@ DEF_EMIT_REG3_FORMAT(stxb, stxb_op) DEF_EMIT_REG3_FORMAT(stxh, stxh_op) DEF_EMIT_REG3_FORMAT(stxw, stxw_op) DEF_EMIT_REG3_FORMAT(stxd, stxd_op) +DEF_EMIT_REG3_FORMAT(amaddb, amaddb_op) +DEF_EMIT_REG3_FORMAT(amaddh, amaddh_op) DEF_EMIT_REG3_FORMAT(amaddw, amaddw_op) DEF_EMIT_REG3_FORMAT(amaddd, amaddd_op) DEF_EMIT_REG3_FORMAT(amandw, amandw_op) @@ -771,6 +779,8 @@ DEF_EMIT_REG3_FORMAT(amorw, amorw_op) DEF_EMIT_REG3_FORMAT(amord, amord_op) DEF_EMIT_REG3_FORMAT(amxorw, amxorw_op) DEF_EMIT_REG3_FORMAT(amxord, amxord_op) +DEF_EMIT_REG3_FORMAT(amswapb, amswapb_op) +DEF_EMIT_REG3_FORMAT(amswaph, amswaph_op) DEF_EMIT_REG3_FORMAT(amswapw, amswapw_op) DEF_EMIT_REG3_FORMAT(amswapd, amswapd_op) diff --git a/arch/loongarch/include/asm/irq_work.h b/arch/loongarch/include/asm/irq_work.h index d63076e9160d..63aee0335d1a 100644 --- a/arch/loongarch/include/asm/irq_work.h +++ b/arch/loongarch/include/asm/irq_work.h @@ -4,7 +4,7 @@ static inline bool arch_irq_work_has_interrupt(void) { - return IS_ENABLED(CONFIG_SMP); + return IS_ENABLED(CONFIG_SMP) && cpu_opt(LOONGARCH_CPU_CSRIPI); } #endif /* _ASM_LOONGARCH_IRQ_WORK_H */ diff --git a/arch/loongarch/include/asm/jump_label.h b/arch/loongarch/include/asm/jump_label.h index dcaecf69ea5a..7ef4ae3abf08 100644 --- a/arch/loongarch/include/asm/jump_label.h +++ b/arch/loongarch/include/asm/jump_label.h @@ -13,6 +13,8 @@ #include <linux/stringify.h> #include <asm/asm.h> +#define HAVE_JUMP_LABEL_BATCH + #define JUMP_LABEL_NOP_SIZE 4 #ifdef CONFIG_32BIT diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h index 79235f4fc399..b9d61f7c032c 100644 --- a/arch/loongarch/include/asm/page.h +++ b/arch/loongarch/include/asm/page.h @@ -36,10 +36,6 @@ extern unsigned long shm_align_mask; struct page; struct vm_area_struct; -void copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr, struct vm_area_struct *vma); - -#define __HAVE_ARCH_COPY_USER_HIGHPAGE typedef struct { unsigned long pte; } pte_t; #define pte_val(x) ((x).pte) diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h index 155f70e93460..2a0b63ae421f 100644 --- a/arch/loongarch/include/asm/pgtable.h +++ b/arch/loongarch/include/asm/pgtable.h @@ -23,6 +23,10 @@ #include <asm-generic/pgtable-nop4d.h> #endif +#ifdef CONFIG_HIGHMEM +#include <asm/highmem.h> +#endif + #if CONFIG_PGTABLE_LEVELS == 2 #define PGDIR_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - PTRLOG)) #elif CONFIG_PGTABLE_LEVELS == 3 @@ -77,7 +81,15 @@ struct vm_area_struct; #ifdef CONFIG_32BIT #define VMALLOC_START (vm_map_base + PCI_IOSIZE + (2 * PAGE_SIZE)) + +#ifdef CONFIG_HIGHMEM +#define VMALLOC_END (PKMAP_BASE - (2 * PAGE_SIZE)) +#else #define VMALLOC_END (FIXADDR_START - (2 * PAGE_SIZE)) +#endif + +#define PKMAP_BASE (PKMAP_END - (PAGE_SIZE * LAST_PKMAP)) +#define PKMAP_END ((FIXADDR_START) & ~((LAST_PKMAP << PAGE_SHIFT)-1)) #endif diff --git a/arch/loongarch/include/asm/processor.h b/arch/loongarch/include/asm/processor.h index c3bc44b5f5b3..ce8b953f8c79 100644 --- a/arch/loongarch/include/asm/processor.h +++ b/arch/loongarch/include/asm/processor.h @@ -80,10 +80,10 @@ BUILD_FPR_ACCESS(32) BUILD_FPR_ACCESS(64) struct loongarch_fpu { + union fpureg fpr[NUM_FPU_REGS]; uint64_t fcc; /* 8x8 */ uint32_t fcsr; uint32_t ftop; - union fpureg fpr[NUM_FPU_REGS]; }; struct loongarch_lbt { diff --git a/arch/loongarch/include/asm/stackprotector.h b/arch/loongarch/include/asm/stackprotector.h index a1a965751a7b..42f6c3f69115 100644 --- a/arch/loongarch/include/asm/stackprotector.h +++ b/arch/loongarch/include/asm/stackprotector.h @@ -12,9 +12,6 @@ #ifndef _ASM_STACKPROTECTOR_H #define _ASM_STACKPROTECTOR_H -#include <linux/random.h> -#include <linux/version.h> - extern unsigned long __stack_chk_guard; /* @@ -25,11 +22,7 @@ extern unsigned long __stack_chk_guard; */ static __always_inline void boot_init_stack_canary(void) { - unsigned long canary; - - /* Try to get a semi random initial value. */ - get_random_bytes(&canary, sizeof(canary)); - canary ^= LINUX_VERSION_CODE; + unsigned long canary = get_random_canary(); current->stack_canary = canary; __stack_chk_guard = current->stack_canary; diff --git a/arch/loongarch/include/asm/syscall.h b/arch/loongarch/include/asm/syscall.h index 81d2733f7b94..df8ea223c77b 100644 --- a/arch/loongarch/include/asm/syscall.h +++ b/arch/loongarch/include/asm/syscall.h @@ -78,7 +78,11 @@ static inline void syscall_set_arguments(struct task_struct *task, static inline int syscall_get_arch(struct task_struct *task) { +#ifdef CONFIG_32BIT + return AUDIT_ARCH_LOONGARCH32; +#else return AUDIT_ARCH_LOONGARCH64; +#endif } static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs) diff --git a/arch/loongarch/include/uapi/asm/hwcap.h b/arch/loongarch/include/uapi/asm/hwcap.h index 49519b4362c6..90e96113ba51 100644 --- a/arch/loongarch/include/uapi/asm/hwcap.h +++ b/arch/loongarch/include/uapi/asm/hwcap.h @@ -19,5 +19,6 @@ #define HWCAP_LOONGARCH_PTW (1 << 13) #define HWCAP_LOONGARCH_LSPW (1 << 14) #define HWCAP_LOONGARCH_SCQ (1 << 15) +#define HWCAP_LOONGARCH_LAM_BH (1 << 16) #endif /* _UAPI_ASM_HWCAP_H */ diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c index 657bbae6c1c7..74d31f260dfd 100644 --- a/arch/loongarch/kernel/cpu-probe.c +++ b/arch/loongarch/kernel/cpu-probe.c @@ -7,6 +7,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/ptrace.h> +#include <linux/cpu.h> #include <linux/smp.h> #include <linux/stddef.h> #include <linux/export.h> @@ -177,6 +178,10 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c) c->options |= LOONGARCH_CPU_LAM; elf_hwcap |= HWCAP_LOONGARCH_LAM; } + if (config & CPUCFG2_LAM_BH) { + c->options |= LOONGARCH_CPU_LAM_BH; + elf_hwcap |= HWCAP_LOONGARCH_LAM_BH; + } if (config & CPUCFG2_SCQ) { c->options |= LOONGARCH_CPU_SCQ; elf_hwcap |= HWCAP_LOONGARCH_SCQ; @@ -402,3 +407,9 @@ void cpu_probe(void) cpu_report(); } + +ssize_t cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "Mitigation: __user pointer sanitization\n"); +} diff --git a/arch/loongarch/kernel/fpu.S b/arch/loongarch/kernel/fpu.S index f225dcc5b530..bf7d6b8bf600 100644 --- a/arch/loongarch/kernel/fpu.S +++ b/arch/loongarch/kernel/fpu.S @@ -97,7 +97,7 @@ .endm #ifdef CONFIG_32BIT - .macro sc_save_fcc thread tmp0 tmp1 + .macro sc_save_fcc base tmp0 tmp1 movcf2gr \tmp0, $fcc0 move \tmp1, \tmp0 movcf2gr \tmp0, $fcc1 @@ -106,7 +106,7 @@ bstrins.w \tmp1, \tmp0, 23, 16 movcf2gr \tmp0, $fcc3 bstrins.w \tmp1, \tmp0, 31, 24 - EX st.w \tmp1, \thread, THREAD_FCC + EX st.w \tmp1, \base, 0 movcf2gr \tmp0, $fcc4 move \tmp1, \tmp0 movcf2gr \tmp0, $fcc5 @@ -115,11 +115,11 @@ bstrins.w \tmp1, \tmp0, 23, 16 movcf2gr \tmp0, $fcc7 bstrins.w \tmp1, \tmp0, 31, 24 - EX st.w \tmp1, \thread, (THREAD_FCC + 4) + EX st.w \tmp1, \base, 4 .endm - .macro sc_restore_fcc thread tmp0 tmp1 - EX ld.w \tmp0, \thread, THREAD_FCC + .macro sc_restore_fcc base tmp0 tmp1 + EX ld.w \tmp0, \base, 0 bstrpick.w \tmp1, \tmp0, 7, 0 movgr2cf $fcc0, \tmp1 bstrpick.w \tmp1, \tmp0, 15, 8 @@ -128,7 +128,7 @@ movgr2cf $fcc2, \tmp1 bstrpick.w \tmp1, \tmp0, 31, 24 movgr2cf $fcc3, \tmp1 - EX ld.w \tmp0, \thread, (THREAD_FCC + 4) + EX ld.w \tmp0, \base, 4 bstrpick.w \tmp1, \tmp0, 7, 0 movgr2cf $fcc4, \tmp1 bstrpick.w \tmp1, \tmp0, 15, 8 diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c index 1a728082944c..0b9228b7c13a 100644 --- a/arch/loongarch/kernel/inst.c +++ b/arch/loongarch/kernel/inst.c @@ -209,6 +209,9 @@ int larch_insn_write(void *addr, u32 insn) int ret; unsigned long flags = 0; + if ((unsigned long)addr & 3) + return -EINVAL; + raw_spin_lock_irqsave(&patch_lock, flags); ret = copy_to_kernel_nofault(addr, &insn, LOONGARCH_INSN_SIZE); raw_spin_unlock_irqrestore(&patch_lock, flags); @@ -221,9 +224,6 @@ int larch_insn_patch_text(void *addr, u32 insn) int ret; u32 *tp = addr; - if ((unsigned long)tp & 3) - return -EINVAL; - ret = larch_insn_write(tp, insn); if (!ret) flush_icache_range((unsigned long)tp, diff --git a/arch/loongarch/kernel/jump_label.c b/arch/loongarch/kernel/jump_label.c index 31891214b767..24a3f4d8540c 100644 --- a/arch/loongarch/kernel/jump_label.c +++ b/arch/loongarch/kernel/jump_label.c @@ -6,9 +6,10 @@ */ #include <linux/kernel.h> #include <linux/jump_label.h> +#include <asm/cacheflush.h> #include <asm/inst.h> -void arch_jump_label_transform(struct jump_entry *entry, enum jump_label_type type) +bool arch_jump_label_transform_queue(struct jump_entry *entry, enum jump_label_type type) { u32 insn; void *addr = (void *)jump_entry_code(entry); @@ -18,5 +19,12 @@ void arch_jump_label_transform(struct jump_entry *entry, enum jump_label_type ty else insn = larch_insn_gen_nop(); - larch_insn_patch_text(addr, insn); + larch_insn_write(addr, insn); + + return true; +} + +void arch_jump_label_transform_apply(void) +{ + flush_icache_all(); } diff --git a/arch/loongarch/kernel/proc.c b/arch/loongarch/kernel/proc.c index a8127e83da65..d4ce5b585453 100644 --- a/arch/loongarch/kernel/proc.c +++ b/arch/loongarch/kernel/proc.c @@ -64,6 +64,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_puts(m, " cpucfg"); if (cpu_has_lam) seq_puts(m, " lam"); + if (cpu_has_lam_bh) + seq_puts(m, " lam_bh"); if (cpu_has_scq) seq_puts(m, " scq"); if (cpu_has_ual) diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c index ac3a0baa5d00..5505fc355e1b 100644 --- a/arch/loongarch/kernel/process.c +++ b/arch/loongarch/kernel/process.c @@ -136,6 +136,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) return 0; } + dst->thread.fpu.fcsr = src->thread.fpu.fcsr; + if (!used_math()) memcpy(dst, src, offsetof(struct task_struct, thread.fpu.fpr)); else diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c index 82aa3f035927..16f6a9b39659 100644 --- a/arch/loongarch/kernel/relocate.c +++ b/arch/loongarch/kernel/relocate.c @@ -128,24 +128,28 @@ static inline __init unsigned long get_random_boot(void) static int __init nokaslr(char *p) { - pr_info("KASLR is disabled.\n"); - - return 0; /* Print a notice and silence the boot warning */ + return 0; /* Just silence the boot warning */ } early_param("nokaslr", nokaslr); +#define KASLR_DISABLED_MESSAGE "KASLR is disabled by %s in %s cmdline.\n" + static inline __init bool kaslr_disabled(void) { char *str; const char *builtin_cmdline = CONFIG_CMDLINE; str = strstr(builtin_cmdline, "nokaslr"); - if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' ')) + if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' ')) { + pr_info(KASLR_DISABLED_MESSAGE, "\'nokaslr\'", "built-in"); return true; + } str = strstr(boot_command_line, "nokaslr"); - if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) + if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) { + pr_info(KASLR_DISABLED_MESSAGE, "\'nokaslr\'", "bootloader"); return true; + } #ifdef CONFIG_HIBERNATION str = strstr(builtin_cmdline, "nohibernate"); @@ -165,17 +169,23 @@ static inline __init bool kaslr_disabled(void) return false; str = strstr(builtin_cmdline, "resume="); - if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' ')) + if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' ')) { + pr_info(KASLR_DISABLED_MESSAGE, "\'resume=\'", "built-in"); return true; + } str = strstr(boot_command_line, "resume="); - if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) + if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) { + pr_info(KASLR_DISABLED_MESSAGE, "\'resume=\'", "bootloader"); return true; + } #endif str = strstr(boot_command_line, "kexec_file"); - if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) + if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' ')) { + pr_info(KASLR_DISABLED_MESSAGE, "\'kexec_file\'", "bootloader"); return true; + } return false; } diff --git a/arch/loongarch/kernel/syscall.c b/arch/loongarch/kernel/syscall.c index 85da7e050d97..94c1c3b5b0b5 100644 --- a/arch/loongarch/kernel/syscall.c +++ b/arch/loongarch/kernel/syscall.c @@ -9,6 +9,7 @@ #include <linux/entry-common.h> #include <linux/errno.h> #include <linux/linkage.h> +#include <linux/nospec.h> #include <linux/objtool.h> #include <linux/randomize_kstack.h> #include <linux/syscalls.h> @@ -74,7 +75,7 @@ void noinstr __no_stack_protector do_syscall(struct pt_regs *regs) add_random_kstack_offset(); if (nr < NR_syscalls) { - syscall_fn = sys_call_table[nr]; + syscall_fn = sys_call_table[array_index_nospec(nr, NR_syscalls)]; regs->regs[4] = syscall_fn(regs->orig_a0, regs->regs[5], regs->regs[6], regs->regs[7], regs->regs[8], regs->regs[9]); } diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S index d0e1377a041d..840d944c2f73 100644 --- a/arch/loongarch/kernel/vmlinux.lds.S +++ b/arch/loongarch/kernel/vmlinux.lds.S @@ -6,7 +6,12 @@ #define PAGE_SIZE _PAGE_SIZE #define RO_EXCEPTION_TABLE_ALIGN 4 -#define PHYSADDR_MASK 0xffffffffffff /* 48-bit */ + +#ifdef CONFIG_32BIT +#define PHYSADDR_MASK 0x1fffffff /* 29-bit */ +#else +#define PHYSADDR_MASK 0xffffffffffff /* 48-bit */ +#endif /* * Put .bss..swapper_pg_dir as the first thing in .bss. This will diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig index 8e5213609975..15da2d88c0c1 100644 --- a/arch/loongarch/kvm/Kconfig +++ b/arch/loongarch/kvm/Kconfig @@ -19,7 +19,7 @@ if VIRTUALIZATION config KVM tristate "Kernel-based Virtual Machine (KVM) support" - depends on AS_HAS_LVZ_EXTENSION + depends on AS_HAS_LVZ_EXTENSION && 64BIT select HAVE_KVM_DIRTY_RING_ACQ_REL select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_IRQCHIP diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile index 827a88529a42..aa21b3818ec9 100644 --- a/arch/loongarch/lib/Makefile +++ b/arch/loongarch/lib/Makefile @@ -3,8 +3,10 @@ # Makefile for LoongArch-specific library files. # -lib-y += delay.o memset.o memcpy.o memmove.o \ - clear_user.o copy_user.o csum.o dump_tlb.o unaligned.o +lib-y += delay.o clear_user.o copy_user.o dump_tlb.o unaligned.o + +lib-$(CONFIG_32BIT) += bswapsi.o bswapdi.o +lib-$(CONFIG_64BIT) += memset.o memcpy.o memmove.o csum.o obj-$(CONFIG_ARCH_SUPPORTS_INT128) += tishift.o diff --git a/arch/loongarch/mm/Makefile b/arch/loongarch/mm/Makefile index 278be2c8fc36..2aae3773de77 100644 --- a/arch/loongarch/mm/Makefile +++ b/arch/loongarch/mm/Makefile @@ -7,6 +7,7 @@ obj-y += init.o cache.o tlb.o tlbex.o extable.o \ fault.o ioremap.o maccess.o mmap.o pgtable.o \ page.o pageattr.o +obj-$(CONFIG_HIGHMEM) += highmem.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_KASAN) += kasan_init.o diff --git a/arch/loongarch/mm/cache.c b/arch/loongarch/mm/cache.c index 496916845ff7..06dc570eb429 100644 --- a/arch/loongarch/mm/cache.c +++ b/arch/loongarch/mm/cache.c @@ -31,16 +31,6 @@ void cache_error_setup(void) set_merr_handler(0x0, &except_vec_cex, 0x80); } -/* - * LoongArch maintains ICache/DCache coherency by hardware, - * we just need "ibar" to avoid instruction hazard here. - */ -void local_flush_icache_range(unsigned long start, unsigned long end) -{ - asm volatile ("\tibar 0\n"::); -} -EXPORT_SYMBOL(local_flush_icache_range); - static void flush_cache_leaf(unsigned int leaf) { int i, j, nr_nodes; diff --git a/arch/loongarch/mm/highmem.c b/arch/loongarch/mm/highmem.c new file mode 100644 index 000000000000..8a5789ee6842 --- /dev/null +++ b/arch/loongarch/mm/highmem.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/init.h> +#include <linux/export.h> +#include <linux/highmem.h> +#include <asm/fixmap.h> +#include <asm/tlbflush.h> + +void kmap_flush_tlb(unsigned long addr) +{ + flush_tlb_one(addr); +} +EXPORT_SYMBOL(kmap_flush_tlb); diff --git a/arch/loongarch/mm/init.c b/arch/loongarch/mm/init.c index 00f3822b6e47..3f9ab54114c5 100644 --- a/arch/loongarch/mm/init.c +++ b/arch/loongarch/mm/init.c @@ -36,20 +36,6 @@ #include <asm/pgalloc.h> #include <asm/tlb.h> -void copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr, struct vm_area_struct *vma) -{ - void *vfrom, *vto; - - vfrom = kmap_local_page(from); - vto = kmap_local_page(to); - copy_page(vto, vfrom); - kunmap_local(vfrom); - kunmap_local(vto); - /* Make sure this page is cleared on other CPU's too before using it */ - smp_wmb(); -} - int __ref page_is_ram(unsigned long pfn) { unsigned long addr = PFN_PHYS(pfn); @@ -63,6 +49,9 @@ void __init arch_zone_limits_init(unsigned long *max_zone_pfns) max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; #endif max_zone_pfns[ZONE_NORMAL] = max_low_pfn; +#ifdef CONFIG_HIGHMEM + max_zone_pfns[ZONE_HIGHMEM] = max_pfn; +#endif } void __ref free_initmem(void) @@ -70,6 +59,50 @@ void __ref free_initmem(void) free_initmem_default(POISON_FREE_INITMEM); } +#ifdef CONFIG_HIGHMEM + +void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + int i, j, k; + int ptrs_per_pgd; + unsigned long vaddr; + + vaddr = start; + i = pgd_index(vaddr); + j = pud_index(vaddr); + k = pmd_index(vaddr); + pgd = pgd_base + i; + ptrs_per_pgd = min((1 << (BITS_PER_LONG - PGDIR_SHIFT)), PTRS_PER_PGD); + + for ( ; (i < ptrs_per_pgd) && (vaddr < end); pgd++, i++) { + pud = (pud_t *)pgd; + for ( ; (j < PTRS_PER_PUD) && (vaddr < end); pud++, j++) { + pmd = (pmd_t *)pud; + for (; (k < PTRS_PER_PMD) && (vaddr < end); pmd++, k++) { + if (pmd_none(*pmd)) { + pte = (pte_t *) memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); + if (!pte) + panic("%s: Failed to allocate %lu bytes align=%lx\n", + __func__, PAGE_SIZE, PAGE_SIZE); + + kernel_pte_init(pte); + set_pmd(pmd, __pmd((unsigned long)pte)); + BUG_ON(pte != pte_offset_kernel(pmd, 0)); + } + vaddr += PMD_SIZE; + } + k = 0; + } + j = 0; + } +} + +#endif + #ifdef CONFIG_MEMORY_HOTPLUG int arch_add_memory(int nid, u64 start, u64 size, struct mhp_params *params) { diff --git a/arch/loongarch/mm/pgtable.c b/arch/loongarch/mm/pgtable.c index 352d9b2e02ab..4ee188e38fed 100644 --- a/arch/loongarch/mm/pgtable.c +++ b/arch/loongarch/mm/pgtable.c @@ -5,6 +5,7 @@ #include <linux/init.h> #include <linux/export.h> #include <linux/mm.h> +#include <asm/fixmap.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> @@ -144,6 +145,15 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, void __init pagetable_init(void) { +#ifdef CONFIG_HIGHMEM + unsigned long vaddr; + pgd_t *pgd; + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; +#endif + /* Initialize the entire pgd. */ pgd_init(swapper_pg_dir); pgd_init(invalid_pg_dir); @@ -153,4 +163,21 @@ void __init pagetable_init(void) #ifndef __PAGETABLE_PMD_FOLDED pmd_init(invalid_pmd_table); #endif + +#ifdef CONFIG_HIGHMEM + /* Permanent kmaps */ + vaddr = PKMAP_BASE; + fixrange_init(vaddr & PMD_MASK, vaddr + PAGE_SIZE * LAST_PKMAP, swapper_pg_dir); + + pgd = swapper_pg_dir + pgd_index(vaddr); + p4d = p4d_offset(pgd, vaddr); + pud = pud_offset(p4d, vaddr); + pmd = pmd_offset(pud, vaddr); + pte = pte_offset_kernel(pmd, vaddr); + pkmap_page_table = pte; + + /* Fixed mappings */ + vaddr = __fix_to_virt(__end_of_fixed_addresses - 1); + fixrange_init(vaddr & PMD_MASK, vaddr + FIXADDR_SIZE, swapper_pg_dir); +#endif } diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 5149ce4cef7e..24913dc7f4e8 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -344,7 +344,13 @@ toofar: #undef jmp_offset } -static void emit_atomic(const struct bpf_insn *insn, struct jit_ctx *ctx) +static void emit_store_stack_imm64(struct jit_ctx *ctx, int reg, int stack_off, u64 imm64) +{ + move_imm(ctx, reg, imm64, false); + emit_insn(ctx, std, reg, LOONGARCH_GPR_FP, stack_off); +} + +static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) { const u8 t1 = LOONGARCH_GPR_T1; const u8 t2 = LOONGARCH_GPR_T2; @@ -363,10 +369,28 @@ static void emit_atomic(const struct bpf_insn *insn, struct jit_ctx *ctx) switch (imm) { /* lock *(size *)(dst + off) <op>= src */ case BPF_ADD: - if (isdw) - emit_insn(ctx, amaddd, t2, t1, src); - else + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amadd.b instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amaddb, t2, t1, src); + break; + case BPF_H: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amadd.h instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amaddh, t2, t1, src); + break; + case BPF_W: emit_insn(ctx, amaddw, t2, t1, src); + break; + case BPF_DW: + emit_insn(ctx, amaddd, t2, t1, src); + break; + } break; case BPF_AND: if (isdw) @@ -388,11 +412,30 @@ static void emit_atomic(const struct bpf_insn *insn, struct jit_ctx *ctx) break; /* src = atomic_fetch_<op>(dst + off, src) */ case BPF_ADD | BPF_FETCH: - if (isdw) { - emit_insn(ctx, amaddd, src, t1, t3); - } else { + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amadd.b instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amaddb, src, t1, t3); + emit_zext_32(ctx, src, true); + break; + case BPF_H: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amadd.h instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amaddh, src, t1, t3); + emit_zext_32(ctx, src, true); + break; + case BPF_W: emit_insn(ctx, amaddw, src, t1, t3); emit_zext_32(ctx, src, true); + break; + case BPF_DW: + emit_insn(ctx, amaddd, src, t1, t3); + break; } break; case BPF_AND | BPF_FETCH: @@ -421,11 +464,30 @@ static void emit_atomic(const struct bpf_insn *insn, struct jit_ctx *ctx) break; /* src = atomic_xchg(dst + off, src); */ case BPF_XCHG: - if (isdw) { - emit_insn(ctx, amswapd, src, t1, t3); - } else { + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amswap.b instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amswapb, src, t1, t3); + emit_zext_32(ctx, src, true); + break; + case BPF_H: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amswap.h instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amswaph, src, t1, t3); + emit_zext_32(ctx, src, true); + break; + case BPF_W: emit_insn(ctx, amswapw, src, t1, t3); emit_zext_32(ctx, src, true); + break; + case BPF_DW: + emit_insn(ctx, amswapd, src, t1, t3); + break; } break; /* r0 = atomic_cmpxchg(dst + off, r0, src); */ @@ -448,7 +510,105 @@ static void emit_atomic(const struct bpf_insn *insn, struct jit_ctx *ctx) emit_zext_32(ctx, r0, true); } break; + default: + pr_err_once("bpf-jit: invalid atomic read-modify-write opcode %02x\n", imm); + return -EINVAL; } + + return 0; +} + +static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx) +{ + const u8 t1 = LOONGARCH_GPR_T1; + const u8 src = regmap[insn->src_reg]; + const u8 dst = regmap[insn->dst_reg]; + const s16 off = insn->off; + const s32 imm = insn->imm; + + switch (imm) { + /* dst_reg = load_acquire(src_reg + off16) */ + case BPF_LOAD_ACQ: + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (is_signed_imm12(off)) { + emit_insn(ctx, ldbu, dst, src, off); + } else { + move_imm(ctx, t1, off, false); + emit_insn(ctx, ldxbu, dst, src, t1); + } + break; + case BPF_H: + if (is_signed_imm12(off)) { + emit_insn(ctx, ldhu, dst, src, off); + } else { + move_imm(ctx, t1, off, false); + emit_insn(ctx, ldxhu, dst, src, t1); + } + break; + case BPF_W: + if (is_signed_imm12(off)) { + emit_insn(ctx, ldwu, dst, src, off); + } else { + move_imm(ctx, t1, off, false); + emit_insn(ctx, ldxwu, dst, src, t1); + } + break; + case BPF_DW: + if (is_signed_imm12(off)) { + emit_insn(ctx, ldd, dst, src, off); + } else { + move_imm(ctx, t1, off, false); + emit_insn(ctx, ldxd, dst, src, t1); + } + break; + } + emit_insn(ctx, dbar, 0b10100); + break; + /* store_release(dst_reg + off16, src_reg) */ + case BPF_STORE_REL: + emit_insn(ctx, dbar, 0b10010); + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (is_signed_imm12(off)) { + emit_insn(ctx, stb, src, dst, off); + } else { + move_imm(ctx, t1, off, false); + emit_insn(ctx, stxb, src, dst, t1); + } + break; + case BPF_H: + if (is_signed_imm12(off)) { + emit_insn(ctx, sth, src, dst, off); + } else { + move_imm(ctx, t1, off, false); + emit_insn(ctx, stxh, src, dst, t1); + } + break; + case BPF_W: + if (is_signed_imm12(off)) { + emit_insn(ctx, stw, src, dst, off); + } else { + move_imm(ctx, t1, off, false); + emit_insn(ctx, stxw, src, dst, t1); + } + break; + case BPF_DW: + if (is_signed_imm12(off)) { + emit_insn(ctx, std, src, dst, off); + } else { + move_imm(ctx, t1, off, false); + emit_insn(ctx, stxd, src, dst, t1); + } + break; + } + break; + default: + pr_err_once("bpf-jit: invalid atomic load/store opcode %02x\n", imm); + return -EINVAL; + } + + return 0; } static bool is_signed_bpf_cond(u8 cond) @@ -1254,9 +1414,17 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext return ret; break; + /* Atomics */ + case BPF_STX | BPF_ATOMIC | BPF_B: + case BPF_STX | BPF_ATOMIC | BPF_H: case BPF_STX | BPF_ATOMIC | BPF_W: case BPF_STX | BPF_ATOMIC | BPF_DW: - emit_atomic(insn, ctx); + if (!bpf_atomic_is_load_store(insn)) + ret = emit_atomic_rmw(insn, ctx); + else + ret = emit_atomic_ld_st(insn, ctx); + if (ret) + return ret; break; /* Speculation barrier */ @@ -1466,26 +1634,46 @@ int bpf_arch_text_invalidate(void *dst, size_t len) return ret; } -static void store_args(struct jit_ctx *ctx, int nargs, int args_off) +static void store_args(struct jit_ctx *ctx, int nr_arg_slots, int args_off) { int i; - for (i = 0; i < nargs; i++) { - emit_insn(ctx, std, LOONGARCH_GPR_A0 + i, LOONGARCH_GPR_FP, -args_off); + for (i = 0; i < nr_arg_slots; i++) { + if (i < LOONGARCH_MAX_REG_ARGS) + emit_insn(ctx, std, LOONGARCH_GPR_A0 + i, LOONGARCH_GPR_FP, -args_off); + else { + /* Skip slots for T0 and FP of traced function */ + emit_insn(ctx, ldd, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, + 16 + (i - LOONGARCH_MAX_REG_ARGS) * 8); + emit_insn(ctx, std, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -args_off); + } args_off -= 8; } } -static void restore_args(struct jit_ctx *ctx, int nargs, int args_off) +static void restore_args(struct jit_ctx *ctx, int nr_reg_args, int args_off) { int i; - for (i = 0; i < nargs; i++) { + for (i = 0; i < nr_reg_args; i++) { emit_insn(ctx, ldd, LOONGARCH_GPR_A0 + i, LOONGARCH_GPR_FP, -args_off); args_off -= 8; } } +static void restore_stk_args(struct jit_ctx *ctx, int nr_stk_args, int args_off, int stk_args_off) +{ + int i; + + for (i = 0; i < nr_stk_args; i++) { + emit_insn(ctx, ldd, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, + -(args_off - LOONGARCH_MAX_REG_ARGS * 8)); + emit_insn(ctx, std, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -stk_args_off); + args_off -= 8; + stk_args_off -= 8; + } +} + static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_link *l, int args_off, int retval_off, int run_ctx_off, bool save_ret) { @@ -1494,12 +1682,11 @@ static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_link *l, struct bpf_prog *p = l->link.prog; int cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie); - if (l->cookie) { - move_imm(ctx, LOONGARCH_GPR_T1, l->cookie, false); - emit_insn(ctx, std, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -run_ctx_off + cookie_off); - } else { + if (l->cookie) + emit_store_stack_imm64(ctx, LOONGARCH_GPR_T1, + -run_ctx_off + cookie_off, l->cookie); + else emit_insn(ctx, std, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_FP, -run_ctx_off + cookie_off); - } /* arg1: prog */ move_imm(ctx, LOONGARCH_GPR_A0, (const s64)p, false); @@ -1550,18 +1737,27 @@ static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_link *l, return ret; } -static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_links *tl, - int args_off, int retval_off, int run_ctx_off, u32 **branches) +static int invoke_bpf(struct jit_ctx *ctx, struct bpf_tramp_links *tl, + int args_off, int retval_off, int run_ctx_off, + int func_meta_off, bool save_ret, u64 func_meta, int cookie_off) { - int i; + int i, cur_cookie = (cookie_off - args_off) / 8; - emit_insn(ctx, std, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_FP, -retval_off); for (i = 0; i < tl->nr_links; i++) { - invoke_bpf_prog(ctx, tl->links[i], args_off, retval_off, run_ctx_off, true); - emit_insn(ctx, ldd, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -retval_off); - branches[i] = (u32 *)ctx->image + ctx->idx; - emit_insn(ctx, nop); + int err; + + if (bpf_prog_calls_session_cookie(tl->links[i])) { + u64 meta = func_meta | ((u64)cur_cookie << BPF_TRAMP_COOKIE_INDEX_SHIFT); + + emit_store_stack_imm64(ctx, LOONGARCH_GPR_T1, -func_meta_off, meta); + cur_cookie--; + } + err = invoke_bpf_prog(ctx, tl->links[i], args_off, retval_off, run_ctx_off, save_ret); + if (err) + return err; } + + return 0; } void *arch_alloc_bpf_trampoline(unsigned int size) @@ -1615,8 +1811,10 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i void *func_addr, u32 flags) { int i, ret, save_ret; - int stack_size, nargs; - int retval_off, args_off, nargs_off, ip_off, run_ctx_off, sreg_off, tcc_ptr_off; + int cookie_cnt, cookie_off; + int stack_size, args_off, stk_args_off, nr_arg_slots = 0; + int retval_off, func_meta_off, ip_off, run_ctx_off, sreg_off, tcc_ptr_off; + unsigned long long func_meta; bool is_struct_ops = flags & BPF_TRAMP_F_INDIRECT; void *orig_call = func_addr; struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; @@ -1634,30 +1832,44 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i * FP - 16 [ FP of traced func ] frame pointer of traced * function * - * FP - retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or - * BPF_TRAMP_F_RET_FENTRY_RET - * [ argN ] - * [ ... ] - * FP - args_off [ arg1 ] + * FP - retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or + * BPF_TRAMP_F_RET_FENTRY_RET + * [ arg regN ] + * [ ... ] + * FP - args_off [ arg reg1 ] * - * FP - nargs_off [ regs count ] + * FP - func_meta_off [ regs count, etc ] * - * FP - ip_off [ traced func ] BPF_TRAMP_F_IP_ARG + * FP - ip_off [ traced func ] BPF_TRAMP_F_IP_ARG * - * FP - run_ctx_off [ bpf_tramp_run_ctx ] + * [ stack cookie N ] + * [ ... ] + * FP - cookie_off [ stack cookie 1 ] * - * FP - sreg_off [ callee saved reg ] + * FP - run_ctx_off [ bpf_tramp_run_ctx ] * - * FP - tcc_ptr_off [ tail_call_cnt_ptr ] + * FP - sreg_off [ callee saved reg ] + * + * FP - tcc_ptr_off [ tail_call_cnt_ptr ] + * + * [ stack_argN ] + * [ ... ] + * FP - stk_args_off [ stack_arg1 ] BPF_TRAMP_F_CALL_ORIG */ - if (m->nr_args > LOONGARCH_MAX_REG_ARGS) + if (m->nr_args > MAX_BPF_FUNC_ARGS) return -ENOTSUPP; - /* FIXME: No support of struct argument */ + /* Extra registers for struct arguments */ for (i = 0; i < m->nr_args; i++) { - if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG) - return -ENOTSUPP; + /* + * The struct argument size is at most 16 bytes, + * enforced by the verifier. The struct argument + * may be passed in a pair of registers if its + * size is more than 8 bytes and no more than 16 + * bytes. + */ + nr_arg_slots += round_up(m->arg_size[i], 8) / 8; } if (flags & (BPF_TRAMP_F_ORIG_STACK | BPF_TRAMP_F_SHARE_IPMODIFY)) @@ -1673,13 +1885,12 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i retval_off = stack_size; /* Room of trampoline frame to store args */ - nargs = m->nr_args; - stack_size += nargs * 8; + stack_size += nr_arg_slots * 8; args_off = stack_size; - /* Room of trampoline frame to store args number */ + /* Room of function metadata, such as regs count */ stack_size += 8; - nargs_off = stack_size; + func_meta_off = stack_size; /* Room of trampoline frame to store ip address */ if (flags & BPF_TRAMP_F_IP_ARG) { @@ -1687,6 +1898,12 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i ip_off = stack_size; } + cookie_cnt = bpf_fsession_cookie_cnt(tlinks); + + /* Room for session cookies */ + stack_size += cookie_cnt * 8; + cookie_off = stack_size; + /* Room of trampoline frame to store struct bpf_tramp_run_ctx */ stack_size += round_up(sizeof(struct bpf_tramp_run_ctx), 8); run_ctx_off = stack_size; @@ -1700,8 +1917,14 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i tcc_ptr_off = stack_size; } + if ((flags & BPF_TRAMP_F_CALL_ORIG) && (nr_arg_slots - LOONGARCH_MAX_REG_ARGS > 0)) + stack_size += (nr_arg_slots - LOONGARCH_MAX_REG_ARGS) * 8; + stack_size = round_up(stack_size, 16); + /* Room for args on stack must be at the top of stack */ + stk_args_off = stack_size; + if (is_struct_ops) { /* * For the trampoline called directly, just handle @@ -1737,16 +1960,23 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i emit_insn(ctx, std, LOONGARCH_GPR_S1, LOONGARCH_GPR_FP, -sreg_off); /* store ip address of the traced function */ - if (flags & BPF_TRAMP_F_IP_ARG) { - move_imm(ctx, LOONGARCH_GPR_T1, (const s64)func_addr, false); - emit_insn(ctx, std, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -ip_off); - } + if (flags & BPF_TRAMP_F_IP_ARG) + emit_store_stack_imm64(ctx, LOONGARCH_GPR_T1, -ip_off, (u64)func_addr); - /* store nargs number */ - move_imm(ctx, LOONGARCH_GPR_T1, nargs, false); - emit_insn(ctx, std, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -nargs_off); + /* store arg regs count */ + func_meta = nr_arg_slots; + emit_store_stack_imm64(ctx, LOONGARCH_GPR_T1, -func_meta_off, func_meta); - store_args(ctx, nargs, args_off); + store_args(ctx, nr_arg_slots, args_off); + + if (bpf_fsession_cnt(tlinks)) { + /* clear all session cookies' value */ + for (i = 0; i < cookie_cnt; i++) + emit_insn(ctx, std, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_FP, -cookie_off + 8 * i); + + /* clear return value to make sure fentry always get 0 */ + emit_insn(ctx, std, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_FP, -retval_off); + } /* To traced function */ /* Ftrace jump skips 2 NOP instructions */ @@ -1764,9 +1994,9 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i return ret; } - for (i = 0; i < fentry->nr_links; i++) { - ret = invoke_bpf_prog(ctx, fentry->links[i], args_off, retval_off, - run_ctx_off, flags & BPF_TRAMP_F_RET_FENTRY_RET); + if (fentry->nr_links) { + ret = invoke_bpf(ctx, fentry, args_off, retval_off, run_ctx_off, func_meta_off, + flags & BPF_TRAMP_F_RET_FENTRY_RET, func_meta, cookie_off); if (ret) return ret; } @@ -1775,11 +2005,21 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i if (!branches) return -ENOMEM; - invoke_bpf_mod_ret(ctx, fmod_ret, args_off, retval_off, run_ctx_off, branches); + emit_insn(ctx, std, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_FP, -retval_off); + for (i = 0; i < fmod_ret->nr_links; i++) { + ret = invoke_bpf_prog(ctx, fmod_ret->links[i], + args_off, retval_off, run_ctx_off, true); + if (ret) + goto out; + emit_insn(ctx, ldd, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -retval_off); + branches[i] = (u32 *)ctx->image + ctx->idx; + emit_insn(ctx, nop); + } } if (flags & BPF_TRAMP_F_CALL_ORIG) { - restore_args(ctx, m->nr_args, args_off); + restore_args(ctx, min_t(int, nr_arg_slots, LOONGARCH_MAX_REG_ARGS), args_off); + restore_stk_args(ctx, nr_arg_slots - LOONGARCH_MAX_REG_ARGS, args_off, stk_args_off); if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_FP, -tcc_ptr_off); @@ -1800,8 +2040,14 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i *branches[i] = larch_insn_gen_bne(LOONGARCH_GPR_T1, LOONGARCH_GPR_ZERO, offset); } - for (i = 0; i < fexit->nr_links; i++) { - ret = invoke_bpf_prog(ctx, fexit->links[i], args_off, retval_off, run_ctx_off, false); + /* Set "is_return" flag for fsession */ + func_meta |= (1ULL << BPF_TRAMP_IS_RETURN_SHIFT); + if (bpf_fsession_cnt(tlinks)) + emit_store_stack_imm64(ctx, LOONGARCH_GPR_T1, -func_meta_off, func_meta); + + if (fexit->nr_links) { + ret = invoke_bpf(ctx, fexit, args_off, retval_off, run_ctx_off, + func_meta_off, false, func_meta, cookie_off); if (ret) goto out; } @@ -1815,7 +2061,7 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i } if (flags & BPF_TRAMP_F_RESTORE_REGS) - restore_args(ctx, m->nr_args, args_off); + restore_args(ctx, min_t(int, nr_arg_slots, LOONGARCH_MAX_REG_ARGS), args_off); if (save_ret) { emit_insn(ctx, ldd, regmap[BPF_REG_0], LOONGARCH_GPR_FP, -(retval_off - 8)); @@ -2111,6 +2357,11 @@ bool bpf_jit_supports_arena(void) return true; } +bool bpf_jit_supports_fsession(void) +{ + return true; +} + /* Indicate the JIT backend supports mixing bpf2bpf and tailcalls. */ bool bpf_jit_supports_subprog_tailcalls(void) { diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index fbb8d4e33256..983a438e35f3 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -96,6 +96,7 @@ zboot-obj-$(CONFIG_KERNEL_ZSTD) := zboot-decompress-zstd.o lib-xxhash.o CFLAGS_zboot-decompress-zstd.o += -I$(srctree)/lib/zstd zboot-obj-$(CONFIG_RISCV) += lib-clz_ctz.o lib-ashldi3.o +zboot-obj-$(CONFIG_LOONGARCH) += lib-clz_ctz.o lib-ashldi3.o lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y) lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 686349e09cd3..2247709ef6d6 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -187,7 +187,7 @@ config VMD config PCI_LOONGSON bool "LOONGSON PCIe controller" - depends on MACH_LOONGSON64 || COMPILE_TEST + depends on MACH_LOONGSON32 || MACH_LOONGSON64 || COMPILE_TEST depends on OF || ACPI depends on PCI_QUIRKS default MACH_LOONGSON64 diff --git a/lib/crc/Kconfig b/lib/crc/Kconfig index 31038c8d111a..f47bb4c706fb 100644 --- a/lib/crc/Kconfig +++ b/lib/crc/Kconfig @@ -65,7 +65,7 @@ config CRC32_ARCH depends on CRC32 && CRC_OPTIMIZATIONS default y if ARM && KERNEL_MODE_NEON default y if ARM64 - default y if LOONGARCH + default y if LOONGARCH && 64BIT default y if MIPS && CPU_MIPSR6 default y if PPC64 && ALTIVEC default y if RISCV && RISCV_ISA_ZBC diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h index dcd78a3a9052..a0d7b15a24b1 100644 --- a/tools/testing/selftests/bpf/progs/bpf_misc.h +++ b/tools/testing/selftests/bpf/progs/bpf_misc.h @@ -263,8 +263,8 @@ #if __clang_major__ >= 18 && defined(ENABLE_ATOMICS_TESTS) && \ (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \ - (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) || \ - (defined(__TARGET_ARCH_powerpc)) + (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64) || \ + defined(__TARGET_ARCH_powerpc) || defined(__TARGET_ARCH_loongarch)) #define CAN_USE_LOAD_ACQ_STORE_REL #endif diff --git a/tools/testing/selftests/bpf/progs/verifier_precision.c b/tools/testing/selftests/bpf/progs/verifier_precision.c index 4794903aec8e..6f325876efdd 100644 --- a/tools/testing/selftests/bpf/progs/verifier_precision.c +++ b/tools/testing/selftests/bpf/progs/verifier_precision.c @@ -75,8 +75,8 @@ __naked int bpf_end_to_be(void) #if (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \ (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64) || \ - defined(__TARGET_ARCH_arm) || defined(__TARGET_ARCH_s390)) && \ - __clang_major__ >= 18 + defined(__TARGET_ARCH_arm) || defined(__TARGET_ARCH_s390) || \ + defined(__TARGET_ARCH_loongarch)) && __clang_major__ >= 18 SEC("?raw_tp") __success __log_level(2) |
