mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
LoongArch changes for v7.4
1, Add LoongArch-specific ACPI initialization;
2, Set NX compat flag in PE/COFF efi header;
3, Use pa_to_nid()/nid_to_addrbase() rather than hard-code;
4, Detect and expose LAMCAS/DIV32 feature existence;
5, Fix and improve perf hardware breakpoints;
6, Fix and improve BPF JIT (trampoline and 32-bit operations);
7, Add arch_crash_save_vmcoreinfo() support;
8, Some bug fixes and other small changes.
-----BEGIN PGP SIGNATURE-----
iQJKBAABCAA0FiEEzOlt8mkP+tbeiYy5AoYrw/LiJnoFAmrh/wMWHGNoZW5odWFj
YWlAa2VybmVsLm9yZwAKCRAChivD8uImeuBhD/0dznfX3XCSm1tqHMRIf3olKUw/
WbXJXg+ZOpOrgrb9O14FBj92KhdaYyf5WZpFHnpuf1YtfX2WR5kMOVyOHabM5nWa
nOMaLRaIqollC9kMX2hOkktGe6WnJBwfe8pNbnmYemcpJPbZEEPxeFycx7EMNKBf
b6sXOcZWu05alLkeVgYlVdMQsJOhUq/dNwcmBLBfP8tWnv8HcCvSjryJAAgZb+1T
UGXxEjOxingXi3JVUbbRaQTfjV2cho1PLIVd76JdKyUpAByMPV7hzkKU+lhMRaVq
WFhVMDghshuNjwTapcRH2BwIT49/pNZXtcpnWo7H0fEjzyqz4HYPGm888WLeRYWN
yFAZ6FgYo0S6CX4qkZnN4aWHK7zraqqsjQK33JzJBXhJUzwgTuKowrgHN9c+/FC9
88VvAS8aGxrrMd74pR5PO5jzP0lMhaCViVxqgrnRNf7TZtqMS40Q6rg+0YhTZWG8
KgkwVJ3pYqFUG2LLepKX9PmEngblNf3ajWn7EyiQ+5djktc/KSxEo5mwYLBEn8hk
gMFTY2QEO1gH5hSHhxbYhRPtpQG0v4fBAZJ+Yo8kxTuQkEILD2200LDrvQiBnYF2
eWcp5TXQMdG3VjVd250S1NCqx06VyKSQOH5RqopTPk7Rh93hV8QCVxvat1/3jyAK
rC9vLYjoxS8H3/wSng==
=k2V9
-----END PGP SIGNATURE-----
Merge tag 'loongarch-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
Pull LoongArch updates from Huacai Chen:
- Add LoongArch-specific ACPI initialization
- Set NX compat flag in PE/COFF efi header
- Use pa_to_nid()/nid_to_addrbase() rather than hard-code
- Detect and expose LAMCAS/DIV32 feature existence
- Fix and improve perf hardware breakpoints
- Fix and improve BPF JIT (trampoline and 32-bit operations)
- Add arch_crash_save_vmcoreinfo() support
- Some bug fixes and other small changes
* tag 'loongarch-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson: (24 commits)
soc: loongson: loongson2_guts: Use of_root instead of own reference
soc: loongson: loongson2_pm: Fix build warnings for 32BIT
LoongArch: dts: loongson-2k0500: Drop unsupported bus_id in DWMAC
LoongArch: BPF: Optimize 32-bit operations using native instructions
LoongArch: BPF: Clean up and decouple is32 parameter from move_imm()
LoongArch: BPF: Fix stack arguments for indirect trampolines
LoongArch: Add arch_crash_save_vmcoreinfo() support
LoongArch: Fix one-shot limitation for perf hardware breakpoints
LoongArch: Fix perf hardware breakpoint failure via installation
LoongArch: Only send SIGTRAP signal if necessary in do_watch()
LoongArch: Fix architectural naming typo for CSR_FWPS_SKIP
LoongArch: Fix bitmask corruption in update_bp_registers()
LoongArch: Remove redundant call in update_bp_registers()
LoongArch: Remove arch-specific __smp_mb__{before,after}_atomic()
LoongArch: Detect and expose DIV32 feature existence
LoongArch: Detect and expose LAMCAS feature existence
LoongArch: Use pa_to_nid()/nid_to_addrbase() rather than hard-code
LoongArch: Don't init & online empty nodes
LoongArch: Call cpu_final_simd() with pure_initcall()
LoongArch: Use assign_bit() API where applicable
...
This commit is contained in:
commit
780cb2a5fd
|
|
@ -594,3 +594,39 @@ va_kernel_pa_offset
|
|||
|
||||
Indicates the offset between the kernel virtual and physical mappings.
|
||||
Used to translate virtual to physical addresses.
|
||||
|
||||
LOONGARCH64
|
||||
===========
|
||||
|
||||
VA_BITS
|
||||
-------
|
||||
|
||||
The maximum number of bits for virtual addresses. Used to compute the
|
||||
virtual memory ranges.
|
||||
|
||||
PHYS_OFFSET
|
||||
-----------
|
||||
|
||||
Indicates the physical address of the start of memory. Used to translate
|
||||
virtual to physical addresses.
|
||||
|
||||
PAGE_OFFSET
|
||||
-----------
|
||||
|
||||
Indicates the virtual kernel start address of the direct-mapped RAM region.
|
||||
Used together with PHYS_OFFSET to translate between virtual and physical
|
||||
addresses.
|
||||
|
||||
KERNELOFFSET
|
||||
------------
|
||||
|
||||
The kernel randomization offset. Used to locate the kernel text in virtual
|
||||
memory. If KASLR is disabled, this value is zero.
|
||||
|
||||
MODULES_VADDR|MODULES_END|VMALLOC_START|VMALLOC_END|VMEMMAP_START|VMEMMAP_END
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Used to get the correct ranges:
|
||||
MODULES_VADDR ~ MODULES_END-1 : Kernel module space.
|
||||
VMALLOC_START ~ VMALLOC_END-1 : vmalloc() / ioremap() space.
|
||||
VMEMMAP_START ~ VMEMMAP_END-1 : vmemmap region, used for struct page array.
|
||||
|
|
|
|||
|
|
@ -350,6 +350,15 @@ S: Maintained
|
|||
F: drivers/acpi/arm64
|
||||
F: include/linux/acpi_iort.h
|
||||
|
||||
ACPI FOR LOONGARCH (ACPI/LoongArch)
|
||||
M: Bibo Mao <maobibo@loongson.cn>
|
||||
M: Huacai Chen <chenhuacai@kernel.org>
|
||||
L: linux-acpi@vger.kernel.org
|
||||
L: loongarch@lists.linux.dev
|
||||
S: Maintained
|
||||
F: drivers/acpi/loongarch/
|
||||
F: include/linux/acpi_iovt.h
|
||||
|
||||
ACPI FOR RISC-V (ACPI/riscv)
|
||||
M: Sunil V L <sunilvl@ventanamicro.com>
|
||||
L: linux-acpi@vger.kernel.org
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ config LOONGARCH
|
|||
select ACPI_GENERIC_GSI if ACPI
|
||||
select ACPI_MCFG if ACPI
|
||||
select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU
|
||||
select ACPI_IOVT if ACPI
|
||||
select ACPI_PPTT if ACPI
|
||||
select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
|
||||
select ARCH_BINFMT_ELF_STATE
|
||||
|
|
|
|||
|
|
@ -73,14 +73,12 @@ &gmac0 {
|
|||
status = "okay";
|
||||
|
||||
phy-mode = "rgmii-id";
|
||||
bus_id = <0x0>;
|
||||
};
|
||||
|
||||
&gmac1 {
|
||||
status = "okay";
|
||||
|
||||
phy-mode = "rgmii-id";
|
||||
bus_id = <0x1>;
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
|
|
|
|||
|
|
@ -57,9 +57,6 @@
|
|||
#define __WEAK_LLSC_MB " \n"
|
||||
#endif
|
||||
|
||||
#define __smp_mb__before_atomic() barrier()
|
||||
#define __smp_mb__after_atomic() barrier()
|
||||
|
||||
/**
|
||||
* array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
|
||||
* @index: array element index
|
||||
|
|
|
|||
|
|
@ -36,6 +36,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_lamcas cpu_opt(LOONGARCH_CPU_LAMCAS)
|
||||
#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)
|
||||
|
|
@ -44,6 +45,7 @@
|
|||
#define cpu_has_crc32 cpu_opt(LOONGARCH_CPU_CRC32)
|
||||
#define cpu_has_complex cpu_opt(LOONGARCH_CPU_COMPLEX)
|
||||
#define cpu_has_crypto cpu_opt(LOONGARCH_CPU_CRYPTO)
|
||||
#define cpu_has_div32 cpu_opt(LOONGARCH_CPU_DIV32)
|
||||
#define cpu_has_lvz cpu_opt(LOONGARCH_CPU_LVZ)
|
||||
#define cpu_has_lbt_x86 cpu_opt(LOONGARCH_CPU_LBT_X86)
|
||||
#define cpu_has_lbt_arm cpu_opt(LOONGARCH_CPU_LBT_ARM)
|
||||
|
|
|
|||
|
|
@ -96,41 +96,44 @@ 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_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 CPU_FEATURE_LAMCAS 3 /* CPU has AMCAS[_DB].{B/H/W/D} instructions */
|
||||
#define CPU_FEATURE_SCQ 4 /* CPU has SC.Q instruction */
|
||||
#define CPU_FEATURE_UAL 5 /* CPU supports unaligned access */
|
||||
#define CPU_FEATURE_FPU 6 /* CPU has FPU */
|
||||
#define CPU_FEATURE_LSX 7 /* CPU has LSX (128-bit SIMD) */
|
||||
#define CPU_FEATURE_LASX 8 /* CPU has LASX (256-bit SIMD) */
|
||||
#define CPU_FEATURE_CRC32 9 /* CPU has CRC32 instructions */
|
||||
#define CPU_FEATURE_COMPLEX 10 /* CPU has Complex instructions */
|
||||
#define CPU_FEATURE_CRYPTO 11 /* CPU has Crypto instructions */
|
||||
#define CPU_FEATURE_DIV32 12 /* CPU has DIV32 feature */
|
||||
#define CPU_FEATURE_LVZ 13 /* CPU has Virtualization extension */
|
||||
#define CPU_FEATURE_LBT_X86 14 /* CPU has X86 Binary Translation */
|
||||
#define CPU_FEATURE_LBT_ARM 15 /* CPU has ARM Binary Translation */
|
||||
#define CPU_FEATURE_LBT_MIPS 16 /* CPU has MIPS Binary Translation */
|
||||
#define CPU_FEATURE_TLB 17 /* CPU has TLB */
|
||||
#define CPU_FEATURE_CSR 18 /* CPU has CSR */
|
||||
#define CPU_FEATURE_IOCSR 19 /* CPU has IOCSR */
|
||||
#define CPU_FEATURE_WATCH 20 /* CPU has watchpoint registers */
|
||||
#define CPU_FEATURE_VINT 21 /* CPU has vectored interrupts */
|
||||
#define CPU_FEATURE_CSRIPI 22 /* CPU has CSR-IPI */
|
||||
#define CPU_FEATURE_EXTIOI 23 /* CPU has EXT-IOI */
|
||||
#define CPU_FEATURE_PREFETCH 24 /* CPU has prefetch instructions */
|
||||
#define CPU_FEATURE_PMP 25 /* CPU has perfermance counter */
|
||||
#define CPU_FEATURE_SCALEFREQ 26 /* CPU supports cpufreq scaling */
|
||||
#define CPU_FEATURE_FLATMODE 27 /* CPU has flat mode */
|
||||
#define CPU_FEATURE_EIODECODE 28 /* CPU has EXTIOI interrupt pin decode mode */
|
||||
#define CPU_FEATURE_GUESTID 29 /* CPU has GuestID feature */
|
||||
#define CPU_FEATURE_HYPERVISOR 30 /* CPU has hypervisor (running in VM) */
|
||||
#define CPU_FEATURE_PTW 31 /* CPU has hardware page table walker */
|
||||
#define CPU_FEATURE_LSPW 32 /* CPU has LSPW (lddir/ldpte instructions) */
|
||||
#define CPU_FEATURE_MSGINT 33 /* CPU has MSG interrupt */
|
||||
#define CPU_FEATURE_AVECINT 34 /* CPU has AVEC interrupt */
|
||||
#define CPU_FEATURE_REDIRECTINT 35 /* 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_LAMCAS BIT_ULL(CPU_FEATURE_LAMCAS)
|
||||
#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)
|
||||
|
|
@ -139,6 +142,7 @@ static inline char *id_to_core_name(unsigned int id)
|
|||
#define LOONGARCH_CPU_CRC32 BIT_ULL(CPU_FEATURE_CRC32)
|
||||
#define LOONGARCH_CPU_COMPLEX BIT_ULL(CPU_FEATURE_COMPLEX)
|
||||
#define LOONGARCH_CPU_CRYPTO BIT_ULL(CPU_FEATURE_CRYPTO)
|
||||
#define LOONGARCH_CPU_DIV32 BIT_ULL(CPU_FEATURE_DIV32)
|
||||
#define LOONGARCH_CPU_LVZ BIT_ULL(CPU_FEATURE_LVZ)
|
||||
#define LOONGARCH_CPU_LBT_X86 BIT_ULL(CPU_FEATURE_LBT_X86)
|
||||
#define LOONGARCH_CPU_LBT_ARM BIT_ULL(CPU_FEATURE_LBT_ARM)
|
||||
|
|
|
|||
|
|
@ -116,17 +116,17 @@ extern void arch_uninstall_hw_breakpoint(struct perf_event *bp);
|
|||
extern int hw_breakpoint_slots(int type);
|
||||
extern void hw_breakpoint_pmu_read(struct perf_event *bp);
|
||||
|
||||
void breakpoint_handler(struct pt_regs *regs);
|
||||
void watchpoint_handler(struct pt_regs *regs);
|
||||
bool breakpoint_handler(struct pt_regs *regs);
|
||||
bool watchpoint_handler(struct pt_regs *regs);
|
||||
|
||||
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||
extern void ptrace_hw_copy_thread(struct task_struct *task);
|
||||
extern void hw_breakpoint_thread_switch(struct task_struct *next);
|
||||
extern void hw_breakpoint_thread_switch(struct task_struct *prev, struct task_struct *next);
|
||||
#else
|
||||
static inline void ptrace_hw_copy_thread(struct task_struct *task)
|
||||
{
|
||||
}
|
||||
static inline void hw_breakpoint_thread_switch(struct task_struct *next)
|
||||
static inline void hw_breakpoint_thread_switch(struct task_struct *prev, struct task_struct *next)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -752,11 +752,17 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \
|
|||
|
||||
DEF_EMIT_REG3_FORMAT(addw, addw_op)
|
||||
DEF_EMIT_REG3_FORMAT(addd, addd_op)
|
||||
DEF_EMIT_REG3_FORMAT(subw, subw_op)
|
||||
DEF_EMIT_REG3_FORMAT(subd, subd_op)
|
||||
DEF_EMIT_REG3_FORMAT(mulw, mulw_op)
|
||||
DEF_EMIT_REG3_FORMAT(muld, muld_op)
|
||||
DEF_EMIT_REG3_FORMAT(divw, divw_op)
|
||||
DEF_EMIT_REG3_FORMAT(divd, divd_op)
|
||||
DEF_EMIT_REG3_FORMAT(modw, modw_op)
|
||||
DEF_EMIT_REG3_FORMAT(modd, modd_op)
|
||||
DEF_EMIT_REG3_FORMAT(divwu, divwu_op)
|
||||
DEF_EMIT_REG3_FORMAT(divdu, divdu_op)
|
||||
DEF_EMIT_REG3_FORMAT(modwu, modwu_op)
|
||||
DEF_EMIT_REG3_FORMAT(moddu, moddu_op)
|
||||
DEF_EMIT_REG3_FORMAT(maskeqz, maskeqz_op)
|
||||
DEF_EMIT_REG3_FORMAT(masknez, masknez_op)
|
||||
|
|
|
|||
|
|
@ -1135,8 +1135,11 @@
|
|||
#define LOONGARCH_CSR_DERA 0x501 /* debug era */
|
||||
#define LOONGARCH_CSR_DESAVE 0x502 /* debug save */
|
||||
|
||||
#define CSR_FWPC_SKIP_SHIFT 16
|
||||
#define CSR_FWPC_SKIP (_ULCAST_(1) << CSR_FWPC_SKIP_SHIFT)
|
||||
#define CSR_FWPS_SKIP_SHIFT 16
|
||||
#define CSR_FWPS_SKIP (_ULCAST_(1) << CSR_FWPS_SKIP_SHIFT)
|
||||
|
||||
#define CSR_MWPS_SKIP_SHIFT 16
|
||||
#define CSR_MWPS_SKIP (_ULCAST_(1) << CSR_MWPS_SKIP_SHIFT)
|
||||
|
||||
/*
|
||||
* CSR_ECFG IM
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#define NODE_ADDRSPACE_SHIFT 44
|
||||
|
||||
#define pa_to_nid(addr) (((addr) & 0xf00000000000) >> NODE_ADDRSPACE_SHIFT)
|
||||
#define nid_to_addrbase(nid) (_ULCAST_(nid) << NODE_ADDRSPACE_SHIFT)
|
||||
#define nid_to_addrbase(nid) (_U64CAST_(nid) << NODE_ADDRSPACE_SHIFT)
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ struct thread_struct {
|
|||
struct loongarch_lbt lbt; /* Also conditionally copied */
|
||||
|
||||
/* Hardware breakpoints pinned to this task. */
|
||||
bool hbp_break_skip, hbp_watch_skip;
|
||||
struct perf_event *hbp_break[LOONGARCH_MAX_BRP];
|
||||
struct perf_event *hbp_watch[LOONGARCH_MAX_WRP];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev,
|
|||
do { \
|
||||
lose_fpu_inatomic(1, prev); \
|
||||
lose_lbt_inatomic(1, prev); \
|
||||
hw_breakpoint_thread_switch(next); \
|
||||
hw_breakpoint_thread_switch(prev, next); \
|
||||
set_current(next); \
|
||||
(last) = __switch_to(prev, next, \
|
||||
__builtin_return_address(0), __builtin_frame_address(0)); \
|
||||
|
|
|
|||
|
|
@ -20,5 +20,7 @@
|
|||
#define HWCAP_LOONGARCH_LSPW (1 << 14)
|
||||
#define HWCAP_LOONGARCH_SCQ (1 << 15)
|
||||
#define HWCAP_LOONGARCH_LAM_BH (1 << 16)
|
||||
#define HWCAP_LOONGARCH_LAMCAS (1 << 17)
|
||||
#define HWCAP_LOONGARCH_DIV32 (1 << 18)
|
||||
|
||||
#endif /* _UAPI_ASM_HWCAP_H */
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ obj-$(CONFIG_RELOCATABLE) += relocate.o
|
|||
obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o
|
||||
obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_efi.o kexec_elf.o
|
||||
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
||||
obj-$(CONFIG_VMCORE_INFO) += vmcore_info.o
|
||||
|
||||
obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o
|
||||
obj-$(CONFIG_UNWINDER_PROLOGUE) += unwind_prologue.o
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ static int __init cpu_final_simd(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(cpu_final_simd);
|
||||
pure_initcall(cpu_final_simd);
|
||||
|
||||
static inline void set_elf_platform(int cpu, const char *plat)
|
||||
{
|
||||
|
|
@ -182,6 +182,10 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
|
|||
c->options |= LOONGARCH_CPU_LAM_BH;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_LAM_BH;
|
||||
}
|
||||
if (config & CPUCFG2_LAMCAS) {
|
||||
c->options |= LOONGARCH_CPU_LAMCAS;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_LAMCAS;
|
||||
}
|
||||
if (config & CPUCFG2_SCQ) {
|
||||
c->options |= LOONGARCH_CPU_SCQ;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_SCQ;
|
||||
|
|
@ -210,6 +214,10 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
|
|||
c->options |= LOONGARCH_CPU_CRYPTO;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_CRYPTO;
|
||||
}
|
||||
if (config & CPUCFG2_DIV32) {
|
||||
c->options |= LOONGARCH_CPU_DIV32;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_DIV32;
|
||||
}
|
||||
if (config & CPUCFG2_PTW) {
|
||||
c->options |= LOONGARCH_CPU_PTW;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_PTW;
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
.long .Lefi_header_end - _head /* SizeOfHeaders */
|
||||
.long 0 /* CheckSum */
|
||||
.short IMAGE_SUBSYSTEM_EFI_APPLICATION /* Subsystem */
|
||||
.short 0 /* DllCharacteristics */
|
||||
.short IMAGE_DLLCHARACTERISTICS_NX_COMPAT /* DllCharacteristics */
|
||||
.quad 0 /* SizeOfStackReserve */
|
||||
.quad 0 /* SizeOfStackCommit */
|
||||
.quad 0 /* SizeOfHeapReserve */
|
||||
|
|
|
|||
|
|
@ -25,10 +25,7 @@ void __init init_environ(void)
|
|||
int efi_boot = fw_arg0;
|
||||
char *cmdline = early_memremap_ro(fw_arg1, COMMAND_LINE_SIZE);
|
||||
|
||||
if (efi_boot)
|
||||
set_bit(EFI_BOOT, &efi.flags);
|
||||
else
|
||||
clear_bit(EFI_BOOT, &efi.flags);
|
||||
assign_bit(EFI_BOOT, &efi.flags, efi_boot);
|
||||
|
||||
strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE);
|
||||
strscpy(init_command_line, cmdline, COMMAND_LINE_SIZE);
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots,
|
|||
|
||||
void ptrace_hw_copy_thread(struct task_struct *tsk)
|
||||
{
|
||||
tsk->thread.hbp_break_skip = 0;
|
||||
tsk->thread.hbp_watch_skip = 0;
|
||||
|
||||
memset(tsk->thread.hbp_break, 0, sizeof(tsk->thread.hbp_break));
|
||||
memset(tsk->thread.hbp_watch, 0, sizeof(tsk->thread.hbp_watch));
|
||||
}
|
||||
|
|
@ -233,7 +236,7 @@ static int hw_breakpoint_control(struct perf_event *bp,
|
|||
}
|
||||
enable = csr_read64(LOONGARCH_CSR_CRMD);
|
||||
csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD);
|
||||
if (bp->hw.target && test_tsk_thread_flag(bp->hw.target, TIF_LOAD_WATCH))
|
||||
if (bp->hw.target)
|
||||
regs->csr_prmd |= CSR_PRMD_PWE;
|
||||
break;
|
||||
case HW_BREAKPOINT_UNINSTALL:
|
||||
|
|
@ -453,7 +456,6 @@ static void update_bp_registers(struct pt_regs *regs, int enable, int type)
|
|||
if (enable) {
|
||||
if ((info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) && (type == 0)) {
|
||||
write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE);
|
||||
write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE);
|
||||
} else {
|
||||
ctrl = read_wb_reg(CSR_CFG_CTRL, i, 1);
|
||||
if (info->ctrl.type == LOONGARCH_BREAKPOINT_LOAD)
|
||||
|
|
@ -469,9 +471,9 @@ static void update_bp_registers(struct pt_regs *regs, int enable, int type)
|
|||
} else {
|
||||
ctrl = read_wb_reg(CSR_CFG_CTRL, i, 1);
|
||||
if (info->ctrl.type == LOONGARCH_BREAKPOINT_LOAD)
|
||||
ctrl &= ~0x1 << MWPnCFG3_LoadEn;
|
||||
ctrl &= ~(0x1 << MWPnCFG3_LoadEn);
|
||||
if (info->ctrl.type == LOONGARCH_BREAKPOINT_STORE)
|
||||
ctrl &= ~0x1 << MWPnCFG3_StoreEn;
|
||||
ctrl &= ~(0x1 << MWPnCFG3_StoreEn);
|
||||
write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl);
|
||||
}
|
||||
regs->csr_prmd &= ~CSR_PRMD_PWE;
|
||||
|
|
@ -483,9 +485,11 @@ NOKPROBE_SYMBOL(update_bp_registers);
|
|||
/*
|
||||
* Debug exception handlers.
|
||||
*/
|
||||
void breakpoint_handler(struct pt_regs *regs)
|
||||
bool breakpoint_handler(struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
unsigned int clear_mask = 0;
|
||||
bool need_sigtrap = false;
|
||||
struct perf_event *bp, **slots;
|
||||
|
||||
slots = this_cpu_ptr(bp_on_reg);
|
||||
|
|
@ -495,17 +499,27 @@ void breakpoint_handler(struct pt_regs *regs)
|
|||
bp = slots[i];
|
||||
if (bp == NULL)
|
||||
continue;
|
||||
|
||||
perf_bp_event(bp, regs);
|
||||
csr_write32(0x1 << i, LOONGARCH_CSR_FWPS);
|
||||
update_bp_registers(regs, 0, 0);
|
||||
if (bp->attr.sigtrap)
|
||||
need_sigtrap = true;
|
||||
|
||||
clear_mask |= (0x1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
if (clear_mask)
|
||||
csr_write32(clear_mask | CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS);
|
||||
|
||||
return need_sigtrap;
|
||||
}
|
||||
NOKPROBE_SYMBOL(breakpoint_handler);
|
||||
|
||||
void watchpoint_handler(struct pt_regs *regs)
|
||||
bool watchpoint_handler(struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
unsigned int clear_mask = 0;
|
||||
bool need_sigtrap = false;
|
||||
struct perf_event *wp, **slots;
|
||||
|
||||
slots = this_cpu_ptr(wp_on_reg);
|
||||
|
|
@ -515,11 +529,19 @@ void watchpoint_handler(struct pt_regs *regs)
|
|||
wp = slots[i];
|
||||
if (wp == NULL)
|
||||
continue;
|
||||
|
||||
perf_bp_event(wp, regs);
|
||||
csr_write32(0x1 << i, LOONGARCH_CSR_MWPS);
|
||||
update_bp_registers(regs, 0, 1);
|
||||
if (wp->attr.sigtrap)
|
||||
need_sigtrap = true;
|
||||
|
||||
clear_mask |= (0x1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
if (clear_mask)
|
||||
csr_write32(clear_mask | CSR_MWPS_SKIP, LOONGARCH_CSR_MWPS);
|
||||
|
||||
return need_sigtrap;
|
||||
}
|
||||
NOKPROBE_SYMBOL(watchpoint_handler);
|
||||
|
||||
|
|
@ -542,7 +564,7 @@ static int __init arch_hw_breakpoint_init(void)
|
|||
}
|
||||
arch_initcall(arch_hw_breakpoint_init);
|
||||
|
||||
void hw_breakpoint_thread_switch(struct task_struct *next)
|
||||
void hw_breakpoint_thread_switch(struct task_struct *prev, struct task_struct *next)
|
||||
{
|
||||
u64 addr, mask;
|
||||
struct pt_regs *regs = task_pt_regs(next);
|
||||
|
|
@ -551,9 +573,29 @@ void hw_breakpoint_thread_switch(struct task_struct *next)
|
|||
addr = read_wb_reg(CSR_CFG_ADDR, 0, 0);
|
||||
mask = read_wb_reg(CSR_CFG_MASK, 0, 0);
|
||||
if (!((regs->csr_era ^ addr) & ~mask))
|
||||
csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS);
|
||||
csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS);
|
||||
regs->csr_prmd |= CSR_PRMD_PWE;
|
||||
} else {
|
||||
unsigned int fwps = csr_read32(LOONGARCH_CSR_FWPS);
|
||||
unsigned int mwps = csr_read32(LOONGARCH_CSR_MWPS);
|
||||
|
||||
prev->thread.hbp_break_skip = !!(fwps & CSR_FWPS_SKIP);
|
||||
prev->thread.hbp_watch_skip = !!(mwps & CSR_MWPS_SKIP);
|
||||
|
||||
if (!next->thread.hbp_break_skip)
|
||||
csr_write32(0, LOONGARCH_CSR_FWPS);
|
||||
else {
|
||||
csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS);
|
||||
next->thread.hbp_break_skip = 0;
|
||||
}
|
||||
|
||||
if (!next->thread.hbp_watch_skip)
|
||||
csr_write32(0, LOONGARCH_CSR_MWPS);
|
||||
else {
|
||||
csr_write32(CSR_MWPS_SKIP, LOONGARCH_CSR_MWPS);
|
||||
next->thread.hbp_watch_skip = 0;
|
||||
}
|
||||
|
||||
/* Update breakpoints */
|
||||
update_bp_registers(regs, 1, 0);
|
||||
/* Update watchpoints */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/loongson.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
DEFINE_PER_CPU(unsigned long, irq_stack);
|
||||
|
|
@ -69,7 +70,7 @@ static int __init early_pci_mcfg_parse(struct acpi_table_header *header)
|
|||
|
||||
for (i = 0; i < n; i++, mptr++) {
|
||||
msi_group[i].pci_segment = mptr->pci_segment;
|
||||
pch_group[i].node = msi_group[i].node = (mptr->address >> 44) & 0xf;
|
||||
pch_group[i].node = msi_group[i].node = pa_to_nid(mptr->address);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -216,6 +216,8 @@ static int __init fake_numa_init(void)
|
|||
phys_addr_t start = memblock_start_of_DRAM();
|
||||
phys_addr_t end = memblock_end_of_DRAM() - 1;
|
||||
|
||||
set_cpuid_to_node(0, 0);
|
||||
early_numa_add_cpu(0, 0);
|
||||
pr_info("Faking a node at [mem %pap-%pap]\n", &start, &end);
|
||||
|
||||
return numa_add_memblk(0, start, end + 1);
|
||||
|
|
@ -244,8 +246,10 @@ int __init init_numa_memory(void)
|
|||
return -EINVAL;
|
||||
|
||||
for_each_node_mask(node, node_possible_map) {
|
||||
node_mem_init(node);
|
||||
node_set_online(node);
|
||||
if (!cpumask_empty(&cpus_on_node[node])) {
|
||||
node_mem_init(node);
|
||||
node_set_online(node);
|
||||
}
|
||||
}
|
||||
max_pfn = PFN_DOWN(memblock_end_of_DRAM());
|
||||
max_low_pfn = min(PFN_DOWN(HIGHMEM_START), max_pfn);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
|||
seq_puts(m, " lam");
|
||||
if (cpu_has_lam_bh)
|
||||
seq_puts(m, " lam_bh");
|
||||
if (cpu_has_lamcas)
|
||||
seq_puts(m, " lamcas");
|
||||
if (cpu_has_scq)
|
||||
seq_puts(m, " scq");
|
||||
if (cpu_has_ual)
|
||||
|
|
@ -82,6 +84,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
|||
seq_puts(m, " complex");
|
||||
if (cpu_has_crypto)
|
||||
seq_puts(m, " crypto");
|
||||
if (cpu_has_div32)
|
||||
seq_puts(m, " div32");
|
||||
if (cpu_has_ptw)
|
||||
seq_puts(m, " ptw");
|
||||
if (cpu_has_lspw)
|
||||
|
|
|
|||
|
|
@ -815,6 +815,8 @@ asmlinkage void noinstr do_watch(struct pt_regs *regs)
|
|||
#ifndef CONFIG_HAVE_HW_BREAKPOINT
|
||||
pr_warn("Hardware watch point handler not implemented!\n");
|
||||
#else
|
||||
bool need_sigtrap = !!current->ptrace;
|
||||
|
||||
if (kgdb_breakpoint_handler(regs))
|
||||
goto out;
|
||||
|
||||
|
|
@ -829,7 +831,7 @@ asmlinkage void noinstr do_watch(struct pt_regs *regs)
|
|||
* instruction. So don't clear llbit and reset CSR.FWPS.Skip until
|
||||
* the llsc execution is completed.
|
||||
*/
|
||||
csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS);
|
||||
csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS);
|
||||
csr_write32(CSR_LLBCTL_KLO, LOONGARCH_CSR_LLBCTL);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -846,16 +848,17 @@ asmlinkage void noinstr do_watch(struct pt_regs *regs)
|
|||
* current pc, If yes, then we should not set the CSR.FWPS.SKIP
|
||||
* bit to break the original instruction stream.
|
||||
*/
|
||||
csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS);
|
||||
csr_write32(CSR_FWPS_SKIP, LOONGARCH_CSR_FWPS);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
breakpoint_handler(regs);
|
||||
watchpoint_handler(regs);
|
||||
need_sigtrap |= breakpoint_handler(regs);
|
||||
need_sigtrap |= watchpoint_handler(regs);
|
||||
}
|
||||
|
||||
force_sig(SIGTRAP);
|
||||
if (need_sigtrap)
|
||||
force_sig(SIGTRAP);
|
||||
out:
|
||||
#endif
|
||||
irqentry_exit(regs, state);
|
||||
|
|
|
|||
22
arch/loongarch/kernel/vmcore_info.c
Normal file
22
arch/loongarch/kernel/vmcore_info.c
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/vmcore_info.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
void arch_crash_save_vmcoreinfo(void)
|
||||
{
|
||||
VMCOREINFO_NUMBER(VA_BITS);
|
||||
/* NUMBER(VMALLOC_START) is exported by the generic code */
|
||||
vmcoreinfo_append_str("NUMBER(VMALLOC_END)=0x%lx\n", VMALLOC_END);
|
||||
#ifdef CONFIG_64BIT
|
||||
vmcoreinfo_append_str("NUMBER(MODULES_VADDR)=0x%lx\n", MODULES_VADDR);
|
||||
vmcoreinfo_append_str("NUMBER(MODULES_END)=0x%lx\n", MODULES_END);
|
||||
vmcoreinfo_append_str("NUMBER(VMEMMAP_START)=0x%lx\n", (unsigned long)vmemmap);
|
||||
vmcoreinfo_append_str("NUMBER(VMEMMAP_END)=0x%lx\n", VMEMMAP_END + 1);
|
||||
#endif
|
||||
vmcoreinfo_append_str("NUMBER(PHYS_OFFSET)=0x%lx\n", PHYS_OFFSET);
|
||||
vmcoreinfo_append_str("NUMBER(PAGE_OFFSET)=0x%lx\n", PAGE_OFFSET);
|
||||
vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset());
|
||||
}
|
||||
|
|
@ -194,7 +194,7 @@ static void build_prologue(struct jit_ctx *ctx)
|
|||
ctx->stack_size = stack_adjust;
|
||||
|
||||
if (ctx->arena_vm_start)
|
||||
move_imm(ctx, REG_ARENA, ctx->arena_vm_start, false);
|
||||
move_imm(ctx, REG_ARENA, ctx->arena_vm_start);
|
||||
}
|
||||
|
||||
static void __build_epilogue(struct jit_ctx *ctx, bool is_tail_call)
|
||||
|
|
@ -288,7 +288,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn)
|
|||
* if (index >= array->map.max_entries)
|
||||
* goto out;
|
||||
*/
|
||||
emit_zext_32(ctx, a2, true);
|
||||
emit_insn(ctx, bstrpickd, a2, a2, 31, 0);
|
||||
|
||||
off = offsetof(struct bpf_array, map.max_entries);
|
||||
emit_insn(ctx, ldwu, t1, a1, off);
|
||||
|
|
@ -339,7 +339,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn)
|
|||
|
||||
static void emit_store_stack_imm64(struct jit_ctx *ctx, int reg, int stack_off, u64 imm64)
|
||||
{
|
||||
move_imm(ctx, reg, imm64, false);
|
||||
move_imm(ctx, reg, imm64);
|
||||
emit_insn(ctx, std, reg, LOONGARCH_GPR_FP, stack_off);
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +355,7 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
const s32 imm = insn->imm;
|
||||
const bool isdw = BPF_SIZE(insn->code) == BPF_DW;
|
||||
|
||||
move_imm(ctx, t1, off, false);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, addd, t1, dst, t1);
|
||||
move_reg(ctx, t3, src);
|
||||
|
||||
|
|
@ -412,7 +412,6 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
return -EINVAL;
|
||||
}
|
||||
emit_insn(ctx, amadddbb, src, t1, t3);
|
||||
emit_zext_32(ctx, src, true);
|
||||
break;
|
||||
case BPF_H:
|
||||
if (!cpu_has_lam_bh) {
|
||||
|
|
@ -420,23 +419,23 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
return -EINVAL;
|
||||
}
|
||||
emit_insn(ctx, amadddbh, src, t1, t3);
|
||||
emit_zext_32(ctx, src, true);
|
||||
break;
|
||||
case BPF_W:
|
||||
emit_insn(ctx, amadddbw, src, t1, t3);
|
||||
emit_zext_32(ctx, src, true);
|
||||
break;
|
||||
case BPF_DW:
|
||||
emit_insn(ctx, amadddbd, src, t1, t3);
|
||||
break;
|
||||
}
|
||||
if (!isdw)
|
||||
emit_insn(ctx, bstrpickd, src, src, 31, 0);
|
||||
break;
|
||||
case BPF_AND | BPF_FETCH:
|
||||
if (isdw) {
|
||||
emit_insn(ctx, amanddbd, src, t1, t3);
|
||||
} else {
|
||||
emit_insn(ctx, amanddbw, src, t1, t3);
|
||||
emit_zext_32(ctx, src, true);
|
||||
emit_insn(ctx, bstrpickd, src, src, 31, 0);
|
||||
}
|
||||
break;
|
||||
case BPF_OR | BPF_FETCH:
|
||||
|
|
@ -444,7 +443,7 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
emit_insn(ctx, amordbd, src, t1, t3);
|
||||
} else {
|
||||
emit_insn(ctx, amordbw, src, t1, t3);
|
||||
emit_zext_32(ctx, src, true);
|
||||
emit_insn(ctx, bstrpickd, src, src, 31, 0);
|
||||
}
|
||||
break;
|
||||
case BPF_XOR | BPF_FETCH:
|
||||
|
|
@ -452,7 +451,7 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
emit_insn(ctx, amxordbd, src, t1, t3);
|
||||
} else {
|
||||
emit_insn(ctx, amxordbw, src, t1, t3);
|
||||
emit_zext_32(ctx, src, true);
|
||||
emit_insn(ctx, bstrpickd, src, src, 31, 0);
|
||||
}
|
||||
break;
|
||||
/* src = atomic_xchg(dst + off, src); */
|
||||
|
|
@ -464,7 +463,6 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
return -EINVAL;
|
||||
}
|
||||
emit_insn(ctx, amswapdbb, src, t1, t3);
|
||||
emit_zext_32(ctx, src, true);
|
||||
break;
|
||||
case BPF_H:
|
||||
if (!cpu_has_lam_bh) {
|
||||
|
|
@ -472,16 +470,16 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
return -EINVAL;
|
||||
}
|
||||
emit_insn(ctx, amswapdbh, src, t1, t3);
|
||||
emit_zext_32(ctx, src, true);
|
||||
break;
|
||||
case BPF_W:
|
||||
emit_insn(ctx, amswapdbw, src, t1, t3);
|
||||
emit_zext_32(ctx, src, true);
|
||||
break;
|
||||
case BPF_DW:
|
||||
emit_insn(ctx, amswapdbd, src, t1, t3);
|
||||
break;
|
||||
}
|
||||
if (!isdw)
|
||||
emit_insn(ctx, bstrpickd, src, src, 31, 0);
|
||||
break;
|
||||
/* r0 = atomic_cmpxchg(dst + off, r0, src); */
|
||||
case BPF_CMPXCHG:
|
||||
|
|
@ -494,13 +492,13 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
emit_insn(ctx, beq, t3, LOONGARCH_GPR_ZERO, -4);
|
||||
} else {
|
||||
emit_insn(ctx, llw, r0, t1, 0);
|
||||
emit_zext_32(ctx, t2, true);
|
||||
emit_zext_32(ctx, r0, true);
|
||||
emit_insn(ctx, bstrpickd, t2, t2, 31, 0);
|
||||
emit_insn(ctx, bstrpickd, r0, r0, 31, 0);
|
||||
emit_insn(ctx, bne, t2, r0, 4);
|
||||
move_reg(ctx, t3, src);
|
||||
emit_insn(ctx, scw, t3, t1, 0);
|
||||
emit_insn(ctx, beq, t3, LOONGARCH_GPR_ZERO, -6);
|
||||
emit_zext_32(ctx, r0, true);
|
||||
emit_insn(ctx, bstrpickd, r0, r0, 31, 0);
|
||||
}
|
||||
emit_insn(ctx, dbar, DBAR_LLSC_MB);
|
||||
break;
|
||||
|
|
@ -528,7 +526,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, ldbu, dst, src, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, false);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, ldxbu, dst, src, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -536,7 +534,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, ldhu, dst, src, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, false);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, ldxhu, dst, src, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -544,7 +542,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, ldwu, dst, src, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, false);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, ldxwu, dst, src, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -552,7 +550,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, ldd, dst, src, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, false);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, ldxd, dst, src, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -567,7 +565,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, stb, src, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, false);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, stxb, src, dst, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -575,7 +573,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, sth, src, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, false);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, stxh, src, dst, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -583,7 +581,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, stw, src, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, false);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, stxw, src, dst, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -591,7 +589,7 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, std, src, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, false);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, stxd, src, dst, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -605,12 +603,6 @@ static int emit_atomic_ld_st(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool is_signed_bpf_cond(u8 cond)
|
||||
{
|
||||
return cond == BPF_JSGT || cond == BPF_JSLT ||
|
||||
cond == BPF_JSGE || cond == BPF_JSLE;
|
||||
}
|
||||
|
||||
#define BPF_FIXUP_REG_MASK GENMASK(31, 27)
|
||||
#define BPF_FIXUP_OFFSET_MASK GENMASK(26, 0)
|
||||
#define REG_DONT_CLEAR_MARKER 0
|
||||
|
|
@ -707,7 +699,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
u8 dst = regmap[insn->dst_reg];
|
||||
const s16 off = insn->off;
|
||||
const s32 imm = insn->imm;
|
||||
const bool is32 = BPF_CLASS(insn->code) == BPF_ALU || BPF_CLASS(insn->code) == BPF_JMP32;
|
||||
const bool is32 = BPF_CLASS(insn->code) == BPF_ALU && BPF_OP(insn->code) != BPF_END;
|
||||
|
||||
switch (code) {
|
||||
/* dst = src */
|
||||
|
|
@ -715,8 +707,8 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
case BPF_ALU64 | BPF_MOV | BPF_X:
|
||||
if (insn_is_cast_user(insn)) {
|
||||
move_reg(ctx, t1, src);
|
||||
emit_zext_32(ctx, t1, true);
|
||||
move_imm(ctx, dst, (ctx->user_vm_start >> 32) << 32, false);
|
||||
emit_insn(ctx, bstrpickd, t1, t1, 31, 0);
|
||||
move_imm(ctx, dst, (ctx->user_vm_start >> 32) << 32);
|
||||
emit_insn(ctx, beq, t1, LOONGARCH_GPR_ZERO, 2);
|
||||
emit_insn(ctx, or, t1, dst, t1);
|
||||
move_reg(ctx, dst, t1);
|
||||
|
|
@ -734,15 +726,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
switch (off) {
|
||||
case 0:
|
||||
move_reg(ctx, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
case 8:
|
||||
emit_insn(ctx, extwb, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
case 16:
|
||||
emit_insn(ctx, extwh, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
case 32:
|
||||
emit_insn(ctx, addw, dst, src, LOONGARCH_GPR_ZERO);
|
||||
|
|
@ -752,145 +741,188 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
|
||||
/* dst = imm */
|
||||
case BPF_ALU | BPF_MOV | BPF_K:
|
||||
move_imm(ctx, dst, (u32)imm);
|
||||
return 0;
|
||||
case BPF_ALU64 | BPF_MOV | BPF_K:
|
||||
move_imm(ctx, dst, imm, is32);
|
||||
break;
|
||||
move_imm(ctx, dst, imm);
|
||||
return 0;
|
||||
|
||||
/* dst = dst + src */
|
||||
case BPF_ALU | BPF_ADD | BPF_X:
|
||||
emit_insn(ctx, addw, dst, dst, src);
|
||||
break;
|
||||
case BPF_ALU64 | BPF_ADD | BPF_X:
|
||||
emit_insn(ctx, addd, dst, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst + imm */
|
||||
case BPF_ALU | BPF_ADD | BPF_K:
|
||||
if (is_signed_imm12(imm)) {
|
||||
emit_insn(ctx, addiw, dst, dst, imm);
|
||||
} else {
|
||||
move_imm(ctx, t1, (u32)imm);
|
||||
emit_insn(ctx, addw, dst, dst, t1);
|
||||
}
|
||||
break;
|
||||
case BPF_ALU64 | BPF_ADD | BPF_K:
|
||||
if (is_signed_imm12(imm)) {
|
||||
emit_insn(ctx, addid, dst, dst, imm);
|
||||
} else {
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
move_imm(ctx, t1, imm);
|
||||
emit_insn(ctx, addd, dst, dst, t1);
|
||||
}
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst - src */
|
||||
case BPF_ALU | BPF_SUB | BPF_X:
|
||||
emit_insn(ctx, subw, dst, dst, src);
|
||||
break;
|
||||
case BPF_ALU64 | BPF_SUB | BPF_X:
|
||||
emit_insn(ctx, subd, dst, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst - imm */
|
||||
case BPF_ALU | BPF_SUB | BPF_K:
|
||||
if (is_signed_imm12(-imm)) {
|
||||
emit_insn(ctx, addiw, dst, dst, -imm);
|
||||
} else {
|
||||
move_imm(ctx, t1, (u32)imm);
|
||||
emit_insn(ctx, subw, dst, dst, t1);
|
||||
}
|
||||
break;
|
||||
case BPF_ALU64 | BPF_SUB | BPF_K:
|
||||
if (is_signed_imm12(-imm)) {
|
||||
emit_insn(ctx, addid, dst, dst, -imm);
|
||||
} else {
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
move_imm(ctx, t1, imm);
|
||||
emit_insn(ctx, subd, dst, dst, t1);
|
||||
}
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst * src */
|
||||
case BPF_ALU | BPF_MUL | BPF_X:
|
||||
emit_insn(ctx, mulw, dst, dst, src);
|
||||
break;
|
||||
case BPF_ALU64 | BPF_MUL | BPF_X:
|
||||
emit_insn(ctx, muld, dst, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst * imm */
|
||||
case BPF_ALU | BPF_MUL | BPF_K:
|
||||
move_imm(ctx, t1, (u32)imm);
|
||||
emit_insn(ctx, mulw, dst, dst, t1);
|
||||
break;
|
||||
case BPF_ALU64 | BPF_MUL | BPF_K:
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
move_imm(ctx, t1, imm);
|
||||
emit_insn(ctx, muld, dst, dst, t1);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst / src */
|
||||
case BPF_ALU | BPF_DIV | BPF_X:
|
||||
case BPF_ALU64 | BPF_DIV | BPF_X:
|
||||
if (!off) {
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
move_reg(ctx, t1, src);
|
||||
emit_zext_32(ctx, t1, is32);
|
||||
emit_insn(ctx, divdu, dst, dst, t1);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
} else {
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
move_reg(ctx, t1, src);
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_insn(ctx, divd, dst, dst, t1);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
if (cpu_has_div32) {
|
||||
if (!off)
|
||||
emit_insn(ctx, divwu, dst, dst, src);
|
||||
else
|
||||
emit_insn(ctx, divw, dst, dst, src);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Legacy fallback for !div32: src must be extended into a
|
||||
* temporary register to keep the original src register intact.
|
||||
*/
|
||||
emit_insn(ctx, addw, dst, dst, LOONGARCH_GPR_ZERO);
|
||||
emit_insn(ctx, addw, t1, src, LOONGARCH_GPR_ZERO);
|
||||
if (!off)
|
||||
emit_insn(ctx, divwu, dst, dst, t1);
|
||||
else
|
||||
emit_insn(ctx, divw, dst, dst, t1);
|
||||
break;
|
||||
case BPF_ALU64 | BPF_DIV | BPF_X:
|
||||
if (!off)
|
||||
emit_insn(ctx, divdu, dst, dst, src);
|
||||
else
|
||||
emit_insn(ctx, divd, dst, dst, src);
|
||||
break;
|
||||
|
||||
/* dst = dst / imm */
|
||||
case BPF_ALU | BPF_DIV | BPF_K:
|
||||
case BPF_ALU64 | BPF_DIV | BPF_K:
|
||||
if (!off) {
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
emit_insn(ctx, divdu, dst, dst, t1);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
} else {
|
||||
move_imm(ctx, t1, imm, false);
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_insn(ctx, divd, dst, dst, t1);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
move_imm(ctx, t1, (u32)imm);
|
||||
if (!cpu_has_div32) {
|
||||
emit_insn(ctx, addw, dst, dst, LOONGARCH_GPR_ZERO);
|
||||
emit_insn(ctx, addw, t1, t1, LOONGARCH_GPR_ZERO);
|
||||
}
|
||||
if (!off)
|
||||
emit_insn(ctx, divwu, dst, dst, t1);
|
||||
else
|
||||
emit_insn(ctx, divw, dst, dst, t1);
|
||||
break;
|
||||
case BPF_ALU64 | BPF_DIV | BPF_K:
|
||||
move_imm(ctx, t1, imm);
|
||||
if (!off)
|
||||
emit_insn(ctx, divdu, dst, dst, t1);
|
||||
else
|
||||
emit_insn(ctx, divd, dst, dst, t1);
|
||||
break;
|
||||
|
||||
/* dst = dst % src */
|
||||
case BPF_ALU | BPF_MOD | BPF_X:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_X:
|
||||
if (!off) {
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
move_reg(ctx, t1, src);
|
||||
emit_zext_32(ctx, t1, is32);
|
||||
emit_insn(ctx, moddu, dst, dst, t1);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
} else {
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
move_reg(ctx, t1, src);
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_insn(ctx, modd, dst, dst, t1);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
if (cpu_has_div32) {
|
||||
if (!off)
|
||||
emit_insn(ctx, modwu, dst, dst, src);
|
||||
else
|
||||
emit_insn(ctx, modw, dst, dst, src);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Legacy fallback for !div32: src must be extended into a
|
||||
* temporary register to keep the original src register intact.
|
||||
*/
|
||||
emit_insn(ctx, addw, dst, dst, LOONGARCH_GPR_ZERO);
|
||||
emit_insn(ctx, addw, t1, src, LOONGARCH_GPR_ZERO);
|
||||
if (!off)
|
||||
emit_insn(ctx, modwu, dst, dst, t1);
|
||||
else
|
||||
emit_insn(ctx, modw, dst, dst, t1);
|
||||
break;
|
||||
case BPF_ALU64 | BPF_MOD | BPF_X:
|
||||
if (!off)
|
||||
emit_insn(ctx, moddu, dst, dst, src);
|
||||
else
|
||||
emit_insn(ctx, modd, dst, dst, src);
|
||||
break;
|
||||
|
||||
/* dst = dst % imm */
|
||||
case BPF_ALU | BPF_MOD | BPF_K:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_K:
|
||||
if (!off) {
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
emit_insn(ctx, moddu, dst, dst, t1);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
} else {
|
||||
move_imm(ctx, t1, imm, false);
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_insn(ctx, modd, dst, dst, t1);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
move_imm(ctx, t1, (u32)imm);
|
||||
if (!cpu_has_div32) {
|
||||
emit_insn(ctx, addw, dst, dst, LOONGARCH_GPR_ZERO);
|
||||
emit_insn(ctx, addw, t1, t1, LOONGARCH_GPR_ZERO);
|
||||
}
|
||||
if (!off)
|
||||
emit_insn(ctx, modwu, dst, dst, t1);
|
||||
else
|
||||
emit_insn(ctx, modw, dst, dst, t1);
|
||||
break;
|
||||
case BPF_ALU64 | BPF_MOD | BPF_K:
|
||||
move_imm(ctx, t1, imm);
|
||||
if (!off)
|
||||
emit_insn(ctx, moddu, dst, dst, t1);
|
||||
else
|
||||
emit_insn(ctx, modd, dst, dst, t1);
|
||||
break;
|
||||
|
||||
/* dst = -dst */
|
||||
case BPF_ALU | BPF_NEG:
|
||||
emit_insn(ctx, subw, dst, LOONGARCH_GPR_ZERO, dst);
|
||||
break;
|
||||
case BPF_ALU64 | BPF_NEG:
|
||||
emit_insn(ctx, subd, dst, LOONGARCH_GPR_ZERO, dst);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst & src */
|
||||
case BPF_ALU | BPF_AND | BPF_X:
|
||||
case BPF_ALU64 | BPF_AND | BPF_X:
|
||||
emit_insn(ctx, and, dst, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst & imm */
|
||||
|
|
@ -899,17 +931,18 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
if (is_unsigned_imm12(imm)) {
|
||||
emit_insn(ctx, andi, dst, dst, imm);
|
||||
} else {
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
if (is32)
|
||||
move_imm(ctx, t1, (u32)imm);
|
||||
else
|
||||
move_imm(ctx, t1, imm);
|
||||
emit_insn(ctx, and, dst, dst, t1);
|
||||
}
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst | src */
|
||||
case BPF_ALU | BPF_OR | BPF_X:
|
||||
case BPF_ALU64 | BPF_OR | BPF_X:
|
||||
emit_insn(ctx, or, dst, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst | imm */
|
||||
|
|
@ -918,17 +951,18 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
if (is_unsigned_imm12(imm)) {
|
||||
emit_insn(ctx, ori, dst, dst, imm);
|
||||
} else {
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
if (is32)
|
||||
move_imm(ctx, t1, (u32)imm);
|
||||
else
|
||||
move_imm(ctx, t1, imm);
|
||||
emit_insn(ctx, or, dst, dst, t1);
|
||||
}
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst ^ src */
|
||||
case BPF_ALU | BPF_XOR | BPF_X:
|
||||
case BPF_ALU64 | BPF_XOR | BPF_X:
|
||||
emit_insn(ctx, xor, dst, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst ^ imm */
|
||||
|
|
@ -937,18 +971,18 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
if (is_unsigned_imm12(imm)) {
|
||||
emit_insn(ctx, xori, dst, dst, imm);
|
||||
} else {
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
if (is32)
|
||||
move_imm(ctx, t1, (u32)imm);
|
||||
else
|
||||
move_imm(ctx, t1, imm);
|
||||
emit_insn(ctx, xor, dst, dst, t1);
|
||||
}
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
/* dst = dst << src (logical) */
|
||||
case BPF_ALU | BPF_LSH | BPF_X:
|
||||
emit_insn(ctx, sllw, dst, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
case BPF_ALU64 | BPF_LSH | BPF_X:
|
||||
emit_insn(ctx, slld, dst, dst, src);
|
||||
break;
|
||||
|
|
@ -956,9 +990,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
/* dst = dst << imm (logical) */
|
||||
case BPF_ALU | BPF_LSH | BPF_K:
|
||||
emit_insn(ctx, slliw, dst, dst, imm);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
case BPF_ALU64 | BPF_LSH | BPF_K:
|
||||
emit_insn(ctx, sllid, dst, dst, imm);
|
||||
break;
|
||||
|
|
@ -966,9 +998,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
/* dst = dst >> src (logical) */
|
||||
case BPF_ALU | BPF_RSH | BPF_X:
|
||||
emit_insn(ctx, srlw, dst, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
case BPF_ALU64 | BPF_RSH | BPF_X:
|
||||
emit_insn(ctx, srld, dst, dst, src);
|
||||
break;
|
||||
|
|
@ -976,9 +1006,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
/* dst = dst >> imm (logical) */
|
||||
case BPF_ALU | BPF_RSH | BPF_K:
|
||||
emit_insn(ctx, srliw, dst, dst, imm);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
case BPF_ALU64 | BPF_RSH | BPF_K:
|
||||
emit_insn(ctx, srlid, dst, dst, imm);
|
||||
break;
|
||||
|
|
@ -986,9 +1014,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
/* dst = dst >> src (arithmetic) */
|
||||
case BPF_ALU | BPF_ARSH | BPF_X:
|
||||
emit_insn(ctx, sraw, dst, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
case BPF_ALU64 | BPF_ARSH | BPF_X:
|
||||
emit_insn(ctx, srad, dst, dst, src);
|
||||
break;
|
||||
|
|
@ -996,9 +1022,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
/* dst = dst >> imm (arithmetic) */
|
||||
case BPF_ALU | BPF_ARSH | BPF_K:
|
||||
emit_insn(ctx, sraiw, dst, dst, imm);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
|
||||
case BPF_ALU64 | BPF_ARSH | BPF_K:
|
||||
emit_insn(ctx, sraid, dst, dst, imm);
|
||||
break;
|
||||
|
|
@ -1007,12 +1031,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
case BPF_ALU | BPF_END | BPF_FROM_LE:
|
||||
switch (imm) {
|
||||
case 16:
|
||||
/* zero-extend 16 bits into 64 bits */
|
||||
emit_insn(ctx, bstrpickd, dst, dst, 15, 0);
|
||||
break;
|
||||
case 32:
|
||||
/* zero-extend 32 bits into 64 bits */
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
emit_insn(ctx, bstrpickd, dst, dst, 31, 0);
|
||||
break;
|
||||
case 64:
|
||||
/* do nothing */
|
||||
|
|
@ -1025,13 +1047,11 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
switch (imm) {
|
||||
case 16:
|
||||
emit_insn(ctx, revb2h, dst, dst);
|
||||
/* zero-extend 16 bits into 64 bits */
|
||||
emit_insn(ctx, bstrpickd, dst, dst, 15, 0);
|
||||
break;
|
||||
case 32:
|
||||
emit_insn(ctx, revb2w, dst, dst);
|
||||
/* clear the upper 32 bits */
|
||||
emit_zext_32(ctx, dst, true);
|
||||
emit_insn(ctx, bstrpickd, dst, dst, 31, 0);
|
||||
break;
|
||||
case 64:
|
||||
emit_insn(ctx, revbd, dst, dst);
|
||||
|
|
@ -1039,7 +1059,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
}
|
||||
break;
|
||||
|
||||
/* PC += off if dst cond src */
|
||||
/* PC += off if dst cond src (64-bit) */
|
||||
case BPF_JMP | BPF_JEQ | BPF_X:
|
||||
case BPF_JMP | BPF_JNE | BPF_X:
|
||||
case BPF_JMP | BPF_JGT | BPF_X:
|
||||
|
|
@ -1050,31 +1070,38 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
case BPF_JMP | BPF_JSGE | BPF_X:
|
||||
case BPF_JMP | BPF_JSLT | BPF_X:
|
||||
case BPF_JMP | BPF_JSLE | BPF_X:
|
||||
jmp_offset = bpf2la_offset(i, off, ctx);
|
||||
if (emit_cond_jmp(ctx, cond, dst, src, jmp_offset) < 0)
|
||||
goto toofar;
|
||||
break;
|
||||
|
||||
/* PC += off if dst cond src (32-bit unsigned) */
|
||||
case BPF_JMP32 | BPF_JEQ | BPF_X:
|
||||
case BPF_JMP32 | BPF_JNE | BPF_X:
|
||||
case BPF_JMP32 | BPF_JGT | BPF_X:
|
||||
case BPF_JMP32 | BPF_JGE | BPF_X:
|
||||
case BPF_JMP32 | BPF_JLT | BPF_X:
|
||||
case BPF_JMP32 | BPF_JLE | BPF_X:
|
||||
jmp_offset = bpf2la_offset(i, off, ctx);
|
||||
emit_insn(ctx, bstrpickd, t1, dst, 31, 0);
|
||||
emit_insn(ctx, bstrpickd, t2, src, 31, 0);
|
||||
if (emit_cond_jmp(ctx, cond, t1, t2, jmp_offset) < 0)
|
||||
goto toofar;
|
||||
break;
|
||||
|
||||
/* PC += off if dst cond src (32-bit signed) */
|
||||
case BPF_JMP32 | BPF_JSGT | BPF_X:
|
||||
case BPF_JMP32 | BPF_JSGE | BPF_X:
|
||||
case BPF_JMP32 | BPF_JSLT | BPF_X:
|
||||
case BPF_JMP32 | BPF_JSLE | BPF_X:
|
||||
jmp_offset = bpf2la_offset(i, off, ctx);
|
||||
move_reg(ctx, t1, dst);
|
||||
move_reg(ctx, t2, src);
|
||||
if (is_signed_bpf_cond(BPF_OP(code))) {
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_sext_32(ctx, t2, is32);
|
||||
} else {
|
||||
emit_zext_32(ctx, t1, is32);
|
||||
emit_zext_32(ctx, t2, is32);
|
||||
}
|
||||
emit_insn(ctx, addw, t1, dst, LOONGARCH_GPR_ZERO);
|
||||
emit_insn(ctx, addw, t2, src, LOONGARCH_GPR_ZERO);
|
||||
if (emit_cond_jmp(ctx, cond, t1, t2, jmp_offset) < 0)
|
||||
goto toofar;
|
||||
break;
|
||||
|
||||
/* PC += off if dst cond imm */
|
||||
/* PC += off if dst cond imm (64-bit) */
|
||||
case BPF_JMP | BPF_JEQ | BPF_K:
|
||||
case BPF_JMP | BPF_JNE | BPF_K:
|
||||
case BPF_JMP | BPF_JGT | BPF_K:
|
||||
|
|
@ -1085,32 +1112,51 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
case BPF_JMP | BPF_JSGE | BPF_K:
|
||||
case BPF_JMP | BPF_JSLT | BPF_K:
|
||||
case BPF_JMP | BPF_JSLE | BPF_K:
|
||||
jmp_offset = bpf2la_offset(i, off, ctx);
|
||||
if (imm) {
|
||||
move_imm(ctx, t1, imm);
|
||||
tm = t1;
|
||||
} else {
|
||||
tm = LOONGARCH_GPR_ZERO;
|
||||
}
|
||||
if (emit_cond_jmp(ctx, cond, dst, tm, jmp_offset) < 0)
|
||||
goto toofar;
|
||||
break;
|
||||
|
||||
/* PC += off if dst cond imm (32-bit unsigned) */
|
||||
case BPF_JMP32 | BPF_JEQ | BPF_K:
|
||||
case BPF_JMP32 | BPF_JNE | BPF_K:
|
||||
case BPF_JMP32 | BPF_JGT | BPF_K:
|
||||
case BPF_JMP32 | BPF_JGE | BPF_K:
|
||||
case BPF_JMP32 | BPF_JLT | BPF_K:
|
||||
case BPF_JMP32 | BPF_JLE | BPF_K:
|
||||
jmp_offset = bpf2la_offset(i, off, ctx);
|
||||
if (imm) {
|
||||
move_imm(ctx, t1, imm);
|
||||
emit_insn(ctx, bstrpickd, t1, t1, 31, 0);
|
||||
tm = t1;
|
||||
} else {
|
||||
tm = LOONGARCH_GPR_ZERO;
|
||||
}
|
||||
emit_insn(ctx, bstrpickd, t2, dst, 31, 0);
|
||||
if (emit_cond_jmp(ctx, cond, t2, tm, jmp_offset) < 0)
|
||||
goto toofar;
|
||||
break;
|
||||
|
||||
/* PC += off if dst cond imm (32-bit signed) */
|
||||
case BPF_JMP32 | BPF_JSGT | BPF_K:
|
||||
case BPF_JMP32 | BPF_JSGE | BPF_K:
|
||||
case BPF_JMP32 | BPF_JSLT | BPF_K:
|
||||
case BPF_JMP32 | BPF_JSLE | BPF_K:
|
||||
jmp_offset = bpf2la_offset(i, off, ctx);
|
||||
if (imm) {
|
||||
move_imm(ctx, t1, imm, false);
|
||||
move_imm(ctx, t1, imm);
|
||||
emit_insn(ctx, addw, t1, t1, LOONGARCH_GPR_ZERO);
|
||||
tm = t1;
|
||||
} else {
|
||||
/* If imm is 0, simply use zero register. */
|
||||
tm = LOONGARCH_GPR_ZERO;
|
||||
}
|
||||
move_reg(ctx, t2, dst);
|
||||
if (is_signed_bpf_cond(BPF_OP(code))) {
|
||||
emit_sext_32(ctx, tm, is32);
|
||||
emit_sext_32(ctx, t2, is32);
|
||||
} else {
|
||||
emit_zext_32(ctx, tm, is32);
|
||||
emit_zext_32(ctx, t2, is32);
|
||||
}
|
||||
emit_insn(ctx, addw, t2, dst, LOONGARCH_GPR_ZERO);
|
||||
if (emit_cond_jmp(ctx, cond, t2, tm, jmp_offset) < 0)
|
||||
goto toofar;
|
||||
break;
|
||||
|
|
@ -1120,7 +1166,8 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
case BPF_JMP32 | BPF_JSET | BPF_X:
|
||||
jmp_offset = bpf2la_offset(i, off, ctx);
|
||||
emit_insn(ctx, and, t1, dst, src);
|
||||
emit_zext_32(ctx, t1, is32);
|
||||
if (BPF_CLASS(code) == BPF_JMP32)
|
||||
emit_insn(ctx, bstrpickd, t1, t1, 31, 0);
|
||||
if (emit_cond_jmp(ctx, cond, t1, LOONGARCH_GPR_ZERO, jmp_offset) < 0)
|
||||
goto toofar;
|
||||
break;
|
||||
|
|
@ -1129,9 +1176,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
case BPF_JMP | BPF_JSET | BPF_K:
|
||||
case BPF_JMP32 | BPF_JSET | BPF_K:
|
||||
jmp_offset = bpf2la_offset(i, off, ctx);
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
move_imm(ctx, t1, imm);
|
||||
emit_insn(ctx, and, t1, dst, t1);
|
||||
emit_zext_32(ctx, t1, is32);
|
||||
if (BPF_CLASS(code) == BPF_JMP32)
|
||||
emit_insn(ctx, bstrpickd, t1, t1, 31, 0);
|
||||
if (emit_cond_jmp(ctx, cond, t1, LOONGARCH_GPR_ZERO, jmp_offset) < 0)
|
||||
goto toofar;
|
||||
break;
|
||||
|
|
@ -1227,7 +1275,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
if (bpf_pseudo_func(insn))
|
||||
move_addr(ctx, dst, imm64);
|
||||
else
|
||||
move_imm(ctx, dst, imm64, is32);
|
||||
move_imm(ctx, dst, imm64);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -1268,7 +1316,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
else
|
||||
emit_insn(ctx, ldbu, dst, src, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, is32);
|
||||
move_imm(ctx, t1, off);
|
||||
if (sign_extend)
|
||||
emit_insn(ctx, ldxb, dst, src, t1);
|
||||
else
|
||||
|
|
@ -1282,7 +1330,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
else
|
||||
emit_insn(ctx, ldhu, dst, src, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, is32);
|
||||
move_imm(ctx, t1, off);
|
||||
if (sign_extend)
|
||||
emit_insn(ctx, ldxh, dst, src, t1);
|
||||
else
|
||||
|
|
@ -1296,7 +1344,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
else
|
||||
emit_insn(ctx, ldwu, dst, src, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, is32);
|
||||
move_imm(ctx, t1, off);
|
||||
if (sign_extend)
|
||||
emit_insn(ctx, ldxw, dst, src, t1);
|
||||
else
|
||||
|
|
@ -1304,7 +1352,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
}
|
||||
break;
|
||||
case BPF_DW:
|
||||
move_imm(ctx, t1, off, is32);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, ldxd, dst, src, t1);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1331,42 +1379,42 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
|
||||
switch (BPF_SIZE(code)) {
|
||||
case BPF_B:
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
move_imm(ctx, t1, imm);
|
||||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, stb, t1, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t2, off, is32);
|
||||
move_imm(ctx, t2, off);
|
||||
emit_insn(ctx, stxb, t1, dst, t2);
|
||||
}
|
||||
break;
|
||||
case BPF_H:
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
move_imm(ctx, t1, imm);
|
||||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, sth, t1, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t2, off, is32);
|
||||
move_imm(ctx, t2, off);
|
||||
emit_insn(ctx, stxh, t1, dst, t2);
|
||||
}
|
||||
break;
|
||||
case BPF_W:
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
move_imm(ctx, t1, imm);
|
||||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, stw, t1, dst, off);
|
||||
} else if (is_signed_imm14(off)) {
|
||||
emit_insn(ctx, stptrw, t1, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t2, off, is32);
|
||||
move_imm(ctx, t2, off);
|
||||
emit_insn(ctx, stxw, t1, dst, t2);
|
||||
}
|
||||
break;
|
||||
case BPF_DW:
|
||||
move_imm(ctx, t1, imm, is32);
|
||||
move_imm(ctx, t1, imm);
|
||||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, std, t1, dst, off);
|
||||
} else if (is_signed_imm14(off)) {
|
||||
emit_insn(ctx, stptrd, t1, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t2, off, is32);
|
||||
move_imm(ctx, t2, off);
|
||||
emit_insn(ctx, stxd, t1, dst, t2);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1397,7 +1445,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, stb, src, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, is32);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, stxb, src, dst, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1405,7 +1453,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
if (is_signed_imm12(off)) {
|
||||
emit_insn(ctx, sth, src, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, is32);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, stxh, src, dst, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1415,7 +1463,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
} else if (is_signed_imm14(off)) {
|
||||
emit_insn(ctx, stptrw, src, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, is32);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, stxw, src, dst, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1425,7 +1473,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
} else if (is_signed_imm14(off)) {
|
||||
emit_insn(ctx, stptrd, src, dst, off);
|
||||
} else {
|
||||
move_imm(ctx, t1, off, is32);
|
||||
move_imm(ctx, t1, off);
|
||||
emit_insn(ctx, stxd, src, dst, t1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1458,6 +1506,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (is32)
|
||||
emit_insn(ctx, bstrpickd, dst, dst, 31, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
toofar:
|
||||
|
|
@ -1537,7 +1588,7 @@ static int emit_jump_and_link(struct jit_ctx *ctx, u8 rd, u64 target)
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
move_imm(ctx, LOONGARCH_GPR_T1, target, false);
|
||||
move_imm(ctx, LOONGARCH_GPR_T1, target);
|
||||
emit_insn(ctx, jirl, rd, LOONGARCH_GPR_T1, 0);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1674,17 +1725,17 @@ int bpf_arch_text_invalidate(void *dst, size_t len)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void store_args(struct jit_ctx *ctx, int nr_arg_slots, int args_off)
|
||||
static void store_args(struct jit_ctx *ctx, int nr_arg_slots, int args_off, bool is_struct_ops)
|
||||
{
|
||||
int i;
|
||||
int stack_args_off = is_struct_ops ? 0 : 16;
|
||||
|
||||
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);
|
||||
stack_args_off + (i - LOONGARCH_MAX_REG_ARGS) * 8);
|
||||
emit_insn(ctx, std, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -args_off);
|
||||
}
|
||||
args_off -= 8;
|
||||
|
|
@ -1734,7 +1785,7 @@ static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
|||
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);
|
||||
move_imm(ctx, LOONGARCH_GPR_A0, (const s64)p);
|
||||
/* arg2: &run_ctx */
|
||||
emit_insn(ctx, addid, LOONGARCH_GPR_A1, LOONGARCH_GPR_FP, -run_ctx_off);
|
||||
ret = emit_call(ctx, (const u64)bpf_trampoline_enter(p));
|
||||
|
|
@ -1755,7 +1806,7 @@ static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
|||
/* arg1: &args_off */
|
||||
emit_insn(ctx, addid, LOONGARCH_GPR_A0, LOONGARCH_GPR_FP, -args_off);
|
||||
if (!p->jited)
|
||||
move_imm(ctx, LOONGARCH_GPR_A1, (const s64)p->insnsi, false);
|
||||
move_imm(ctx, LOONGARCH_GPR_A1, (const s64)p->insnsi);
|
||||
ret = emit_call(ctx, (const u64)p->bpf_func);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -1772,7 +1823,7 @@ static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
|||
}
|
||||
|
||||
/* arg1: prog */
|
||||
move_imm(ctx, LOONGARCH_GPR_A0, (const s64)p, false);
|
||||
move_imm(ctx, LOONGARCH_GPR_A0, (const s64)p);
|
||||
/* arg2: prog start time */
|
||||
move_reg(ctx, LOONGARCH_GPR_A1, LOONGARCH_GPR_S1);
|
||||
/* arg3: &run_ctx */
|
||||
|
|
@ -2017,7 +2068,7 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i
|
|||
func_meta = nr_arg_slots;
|
||||
emit_store_stack_imm64(ctx, LOONGARCH_GPR_T1, -func_meta_off, func_meta);
|
||||
|
||||
store_args(ctx, nr_arg_slots, args_off);
|
||||
store_args(ctx, nr_arg_slots, args_off, is_struct_ops);
|
||||
|
||||
if (bpf_fsession_cnt(tnodes)) {
|
||||
/* clear all session cookies' value */
|
||||
|
|
|
|||
|
|
@ -72,24 +72,6 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
|
|||
return (to - from);
|
||||
}
|
||||
|
||||
/* Zero-extend 32 bits into 64 bits */
|
||||
static inline void emit_zext_32(struct jit_ctx *ctx, enum loongarch_gpr reg, bool is32)
|
||||
{
|
||||
if (!is32)
|
||||
return;
|
||||
|
||||
emit_insn(ctx, lu32id, reg, 0);
|
||||
}
|
||||
|
||||
/* Signed-extend 32 bits into 64 bits */
|
||||
static inline void emit_sext_32(struct jit_ctx *ctx, enum loongarch_gpr reg, bool is32)
|
||||
{
|
||||
if (!is32)
|
||||
return;
|
||||
|
||||
emit_insn(ctx, addiw, reg, reg, 0);
|
||||
}
|
||||
|
||||
/* Emit proper extension according to ABI requirements.
|
||||
* Note that it requires a value of size `size` already resides in register `reg`.
|
||||
*/
|
||||
|
|
@ -137,7 +119,7 @@ static inline void move_addr(struct jit_ctx *ctx, enum loongarch_gpr rd, u64 add
|
|||
emit_insn(ctx, lu52id, rd, rd, imm_63_52);
|
||||
}
|
||||
|
||||
static inline void move_imm(struct jit_ctx *ctx, enum loongarch_gpr rd, long imm, bool is32)
|
||||
static inline void move_imm(struct jit_ctx *ctx, enum loongarch_gpr rd, long imm)
|
||||
{
|
||||
long imm_11_0, imm_31_12, imm_51_32, imm_63_52, imm_51_0, imm_51_31;
|
||||
|
||||
|
|
@ -150,7 +132,7 @@ static inline void move_imm(struct jit_ctx *ctx, enum loongarch_gpr rd, long imm
|
|||
/* addiw rd, $zero, imm_11_0 */
|
||||
if (is_signed_imm12(imm)) {
|
||||
emit_insn(ctx, addiw, rd, LOONGARCH_GPR_ZERO, imm);
|
||||
goto zext;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ori rd, $zero, imm_11_0 */
|
||||
|
|
@ -195,9 +177,6 @@ static inline void move_imm(struct jit_ctx *ctx, enum loongarch_gpr rd, long imm
|
|||
if (!is_signed_imm52(imm))
|
||||
emit_insn(ctx, lu52id, rd, rd, imm_63_52);
|
||||
}
|
||||
|
||||
zext:
|
||||
emit_zext_32(ctx, rd, is32);
|
||||
}
|
||||
|
||||
static inline void move_reg(struct jit_ctx *ctx, enum loongarch_gpr rd,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/loongson.h>
|
||||
#include <asm/numa.h>
|
||||
|
||||
#define PCI_DEVICE_ID_LOONGSON_HOST 0x7a00
|
||||
#define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06
|
||||
|
|
@ -43,7 +44,7 @@ int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
|
|||
|
||||
phys_addr_t mcfg_addr_init(int node)
|
||||
{
|
||||
return (((u64)node << 44) | MCFG_EXT_PCICFG_BASE);
|
||||
return (nid_to_addrbase(node) | MCFG_EXT_PCICFG_BASE);
|
||||
}
|
||||
|
||||
static int __init pcibios_init(void)
|
||||
|
|
|
|||
|
|
@ -550,6 +550,10 @@ if ARM64
|
|||
source "drivers/acpi/arm64/Kconfig"
|
||||
endif
|
||||
|
||||
if LOONGARCH
|
||||
source "drivers/acpi/loongarch/Kconfig"
|
||||
endif
|
||||
|
||||
if RISCV
|
||||
source "drivers/acpi/riscv/Kconfig"
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -131,6 +131,6 @@ obj-y += dptf/
|
|||
obj-$(CONFIG_ARM64) += arm64/
|
||||
|
||||
obj-$(CONFIG_ACPI_VIOT) += viot.o
|
||||
|
||||
obj-$(CONFIG_LOONGARCH) += loongarch/
|
||||
obj-$(CONFIG_RISCV) += riscv/
|
||||
obj-$(CONFIG_X86) += x86/
|
||||
|
|
|
|||
|
|
@ -1449,6 +1449,7 @@ struct kobject *acpi_kobj;
|
|||
EXPORT_SYMBOL_GPL(acpi_kobj);
|
||||
|
||||
void __weak __init acpi_arch_init(void) { }
|
||||
void __weak __init acpi_arch_late_init(void) { }
|
||||
|
||||
static int __init acpi_init(void)
|
||||
{
|
||||
|
|
@ -1487,6 +1488,7 @@ static int __init acpi_init(void)
|
|||
acpi_wakeup_device_init();
|
||||
acpi_debugger_init();
|
||||
acpi_setup_sb_notify_handler();
|
||||
acpi_arch_late_init();
|
||||
acpi_viot_init();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
7
drivers/acpi/loongarch/Kconfig
Normal file
7
drivers/acpi/loongarch/Kconfig
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# ACPI Configuration for LOONGARCH
|
||||
#
|
||||
|
||||
config ACPI_IOVT
|
||||
bool
|
||||
3
drivers/acpi/loongarch/Makefile
Normal file
3
drivers/acpi/loongarch/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-y += init.o
|
||||
obj-$(CONFIG_ACPI_IOVT) += iovt.o
|
||||
16
drivers/acpi/loongarch/init.c
Normal file
16
drivers/acpi/loongarch/init.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include "init.h"
|
||||
|
||||
void __init acpi_arch_init(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ACPI_IOVT))
|
||||
acpi_iovt_init();
|
||||
}
|
||||
|
||||
void __init acpi_arch_late_init(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ACPI_IOVT))
|
||||
acpi_iovt_late_init();
|
||||
}
|
||||
5
drivers/acpi/loongarch/init.h
Normal file
5
drivers/acpi/loongarch/init.h
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#include <linux/init.h>
|
||||
|
||||
void __init acpi_iovt_init(void);
|
||||
void __init acpi_iovt_late_init(void);
|
||||
258
drivers/acpi/loongarch/iovt.c
Normal file
258
drivers/acpi/loongarch/iovt.c
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/acpi_iovt.h>
|
||||
#include <linux/pci.h>
|
||||
#include "init.h"
|
||||
|
||||
struct iovt_device_entry {
|
||||
struct list_head list;
|
||||
int start_devid, end_devid;
|
||||
};
|
||||
|
||||
struct iovt_fwnode {
|
||||
struct list_head list;
|
||||
struct fwnode_handle *fwnode;
|
||||
int flag;
|
||||
int nid, segment, devid;
|
||||
struct list_head ep_list;
|
||||
};
|
||||
|
||||
static LIST_HEAD(iovt_fwnode_list);
|
||||
static DEFINE_SPINLOCK(iovt_fwnode_lock);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static void __init iovt_enable_acs(struct acpi_iovt_iommu *iommu)
|
||||
{
|
||||
static bool acs_enabled __initdata;
|
||||
|
||||
if (acs_enabled)
|
||||
return;
|
||||
|
||||
/* IOMMU V1 only supports PCI device management */
|
||||
if ((iommu->header.type == ACPI_IOVT_IOMMU_V1) ||
|
||||
(iommu->flags & (ACPI_IOVT_IOMMU_PCI_DEVICE | ACPI_IOVT_IOMMU_MAGAGE_BY_SEGMENT))) {
|
||||
pci_request_acs();
|
||||
acs_enabled = true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void iovt_enable_acs(struct acpi_iovt_iommu *iommu) { }
|
||||
#endif
|
||||
|
||||
static int __init iovt_get_pci_iommu_fwnode(struct iovt_fwnode *np, u16 segment, u16 bdf)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
struct fwnode_handle *fwnode;
|
||||
|
||||
pdev = pci_get_domain_bus_and_slot(segment, PCI_BUS_NUM(bdf), bdf & 0xff);
|
||||
if (!pdev) {
|
||||
pr_err("No PCI IOMMU found for segment 0x%x bdf 0x%x\n", segment, bdf);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
fwnode = dev_fwnode(&pdev->dev);
|
||||
if (!fwnode) {
|
||||
/*
|
||||
* PCI devices aren't necessarily described by ACPI. Create
|
||||
* a fwnode so the IOMMU subsystem can identify this device.
|
||||
*/
|
||||
fwnode = acpi_alloc_fwnode_static();
|
||||
if (!fwnode) {
|
||||
pci_dev_put(pdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
set_primary_fwnode(&pdev->dev, fwnode);
|
||||
}
|
||||
|
||||
np->fwnode = dev_fwnode(&pdev->dev);
|
||||
if (np->flag & ACPI_IOVT_IOMMU_PXM_VALID)
|
||||
set_dev_node(&pdev->dev, np->nid);
|
||||
pci_dev_put(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init iovt_add_iommu(struct acpi_iovt_iommu *iommu)
|
||||
{
|
||||
int i, ret;
|
||||
bool is_start = false;
|
||||
struct iovt_fwnode *np;
|
||||
struct iovt_device_entry *entry;
|
||||
struct acpi_iovt_device_entry *ep;
|
||||
|
||||
np = kzalloc_obj(struct iovt_fwnode, GFP_ATOMIC);
|
||||
if (WARN_ON(!np))
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&np->list);
|
||||
np->flag = iommu->flags;
|
||||
np->segment = iommu->segment;
|
||||
if (np->flag & ACPI_IOVT_IOMMU_PXM_VALID)
|
||||
np->nid = pxm_to_node(iommu->proximity_domain);
|
||||
|
||||
if (np->flag & ACPI_IOVT_IOMMU_PCI_DEVICE) {
|
||||
np->devid = iommu->device_id;
|
||||
ret = iovt_get_pci_iommu_fwnode(np, np->segment, np->devid);
|
||||
if (ret < 0) {
|
||||
kfree(np);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
np->fwnode = acpi_alloc_fwnode_static();
|
||||
if (!np->fwnode) {
|
||||
kfree(np);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* All devices in the segment are managed by this IOMMU */
|
||||
if (np->flag & ACPI_IOVT_IOMMU_MAGAGE_BY_SEGMENT)
|
||||
goto skip;
|
||||
|
||||
INIT_LIST_HEAD(&np->ep_list);
|
||||
ep = ACPI_ADD_PTR(struct acpi_iovt_device_entry, iommu, iommu->device_entry_offset);
|
||||
for (i = 0; i < iommu->device_entry_num; i++) {
|
||||
switch (ep->type) {
|
||||
case ACPI_IOVT_DEVICE_ENTRY_START:
|
||||
is_start = true;
|
||||
entry->start_devid = ep->device_id;
|
||||
break;
|
||||
case ACPI_IOVT_DEVICE_ENTRY_END:
|
||||
if (!is_start)
|
||||
break;
|
||||
|
||||
entry = kzalloc_obj(struct iovt_device_entry, GFP_ATOMIC);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
is_start = false;
|
||||
entry->end_devid = ep->device_id;
|
||||
list_add_tail(&entry->list, &np->ep_list);
|
||||
break;
|
||||
case ACPI_IOVT_DEVICE_ENTRY_SINGLE:
|
||||
entry = kzalloc_obj(struct iovt_device_entry, GFP_ATOMIC);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
is_start = false;
|
||||
entry->start_devid = ep->device_id;
|
||||
entry->end_devid = ep->device_id;
|
||||
list_add_tail(&entry->list, &np->ep_list);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ep = ACPI_ADD_PTR(struct acpi_iovt_device_entry, ep, ep->length);
|
||||
}
|
||||
|
||||
skip:
|
||||
spin_lock(&iovt_fwnode_lock);
|
||||
list_add_tail(&np->list, &iovt_fwnode_list);
|
||||
spin_unlock(&iovt_fwnode_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init iovt_init_devices(struct acpi_table_header *header)
|
||||
{
|
||||
int i;
|
||||
struct acpi_table_iovt *iovt;
|
||||
struct acpi_iovt_iommu *iommu;
|
||||
|
||||
/* Get the first IOVT node */
|
||||
iovt = (struct acpi_table_iovt *)header;
|
||||
iommu = ACPI_ADD_PTR(struct acpi_iovt_iommu, iovt, iovt->iommu_offset);
|
||||
for (i = 0; i < iovt->iommu_count; i++) {
|
||||
iovt_add_iommu(iommu);
|
||||
iommu = ACPI_ADD_PTR(struct acpi_iovt_iommu, iommu, iommu->header.length);
|
||||
}
|
||||
}
|
||||
|
||||
void __init acpi_iovt_init(void)
|
||||
{
|
||||
int i;
|
||||
acpi_status status;
|
||||
struct acpi_table_header *hdr;
|
||||
struct acpi_table_iovt *iovt;
|
||||
struct acpi_iovt_iommu *iommu;
|
||||
|
||||
status = acpi_get_table(ACPI_SIG_IOVT, 0, &hdr);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (status != AE_NOT_FOUND)
|
||||
pr_err("Failed to get table, %s\n", acpi_format_exception(status));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
iovt = (struct acpi_table_iovt *)&hdr;
|
||||
iommu = ACPI_ADD_PTR(struct acpi_iovt_iommu, iovt, iovt->iommu_offset);
|
||||
for (i = 0; i < iovt->iommu_count; i++) {
|
||||
iovt_enable_acs(iommu);
|
||||
iommu = ACPI_ADD_PTR(struct acpi_iovt_iommu, iommu, iommu->header.length);
|
||||
}
|
||||
|
||||
acpi_put_table(hdr);
|
||||
}
|
||||
|
||||
void __init acpi_iovt_late_init(void)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_table_header *hdr;
|
||||
|
||||
status = acpi_get_table(ACPI_SIG_IOVT, 0, &hdr);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (status != AE_NOT_FOUND)
|
||||
pr_err("Failed to get table, %s\n", acpi_format_exception(status));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
iovt_init_devices(hdr);
|
||||
acpi_put_table(hdr);
|
||||
}
|
||||
|
||||
static int iovt_pci_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data)
|
||||
{
|
||||
struct iovt_fwnode *np;
|
||||
struct iovt_device_entry *entry;
|
||||
struct device *aliased_dev = data;
|
||||
u32 domain = pci_domain_nr(pdev->bus);
|
||||
|
||||
list_for_each_entry(np, &iovt_fwnode_list, list) {
|
||||
if (domain != np->segment)
|
||||
continue;
|
||||
|
||||
/* We're not translating ourself */
|
||||
if (dev_id == np->devid)
|
||||
return -EINVAL;
|
||||
|
||||
if (np->flag & ACPI_IOVT_IOMMU_MAGAGE_BY_SEGMENT)
|
||||
goto found;
|
||||
|
||||
list_for_each_entry(entry, &np->ep_list, list) {
|
||||
if (dev_id >= entry->start_devid && dev_id <= entry->end_devid)
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
|
||||
found:
|
||||
return acpi_iommu_fwspec_init(aliased_dev, (domain << 16) + dev_id, np->fwnode);
|
||||
}
|
||||
|
||||
/*
|
||||
* iovt_iommu_configure_id - Set-up IOMMU configuration for a device.
|
||||
*
|
||||
* @dev: device to configure
|
||||
* @id_in: optional input id const value pointer
|
||||
*
|
||||
* Returns: 0 on success, <0 on failure
|
||||
*/
|
||||
int iovt_iommu_configure_id(struct device *dev, const u32 *id_in)
|
||||
{
|
||||
if (!dev_is_pci(dev))
|
||||
return -ENODEV;
|
||||
|
||||
return pci_for_each_dma_alias(to_pci_dev(dev), iovt_pci_iommu_init, dev);
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/acpi_iort.h>
|
||||
#include <linux/acpi_iovt.h>
|
||||
#include <linux/acpi_rimt.h>
|
||||
#include <linux/acpi_viot.h>
|
||||
#include <linux/iommu.h>
|
||||
|
|
@ -1625,6 +1626,8 @@ static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in)
|
|||
err = iort_iommu_configure_id(dev, id_in);
|
||||
if (err && err != -EPROBE_DEFER)
|
||||
err = rimt_iommu_configure_id(dev, id_in);
|
||||
if (err && err != -EPROBE_DEFER)
|
||||
err = iovt_iommu_configure_id(dev, id_in);
|
||||
if (err && err != -EPROBE_DEFER)
|
||||
err = viot_iommu_configure(dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ static u32 loongson2_guts_get_svr(void)
|
|||
|
||||
static int loongson2_guts_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *root, *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct loongson2_soc_die_attr *soc_die;
|
||||
const char *machine;
|
||||
u32 svr;
|
||||
|
|
@ -109,11 +109,8 @@ static int loongson2_guts_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(guts->regs))
|
||||
return PTR_ERR(guts->regs);
|
||||
|
||||
/* Register soc device */
|
||||
root = of_find_node_by_path("/");
|
||||
if (of_property_read_string(root, "model", &machine))
|
||||
of_property_read_string_index(root, "compatible", 0, &machine);
|
||||
of_node_put(root);
|
||||
if (of_property_read_string(of_root, "model", &machine))
|
||||
of_property_read_string_index(of_root, "compatible", 0, &machine);
|
||||
if (machine) {
|
||||
soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
|
||||
if (!soc_dev_attr.machine)
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ static int loongson2_pm_probe(struct platform_device *pdev)
|
|||
return irq;
|
||||
|
||||
if (!device_property_read_u64(dev, "loongson,suspend-address", &suspend_addr))
|
||||
loongson_sysconf.suspend_addr = (u64)phys_to_virt(suspend_addr);
|
||||
loongson_sysconf.suspend_addr = (unsigned long)phys_to_virt(suspend_addr);
|
||||
else
|
||||
dev_err(dev, "No loongson,suspend-address, could not support S3!\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -1637,6 +1637,7 @@ static inline int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id,
|
|||
#endif
|
||||
|
||||
void acpi_arch_init(void);
|
||||
void acpi_arch_late_init(void);
|
||||
|
||||
#ifdef CONFIG_ACPI_PCC
|
||||
void acpi_init_pcc(void);
|
||||
|
|
|
|||
13
include/linux/acpi_iovt.h
Normal file
13
include/linux/acpi_iovt.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef __ACPI_IOVT_H__
|
||||
#define __ACPI_IOVT_H__
|
||||
|
||||
#ifdef CONFIG_ACPI_IOVT
|
||||
int iovt_iommu_configure_id(struct device *dev, const u32 *id_in);
|
||||
#else
|
||||
static inline int iovt_iommu_configure_id(struct device *dev, const u32 *id_in)
|
||||
{ return -ENODEV; }
|
||||
#endif
|
||||
|
||||
#endif /* __ACPI_IOVT_H__ */
|
||||
Loading…
Reference in New Issue
Block a user