mirror of
https://github.com/torvalds/linux.git
synced 2026-05-29 17:43:52 +02:00
LoongArch changes for v6.18
1, Init acpi_gbl_use_global_lock to false; 2, Allow specify SIMD width via kernel parameters; 3, Add kexec_file (both EFI & ELF format) support; 4, Add PER_VMA_LOCK for page fault handling support; 5, Improve BPF trampoline support; 6, Update the default config file; 7, Some bug fixes and other small changes. -----BEGIN PGP SIGNATURE----- iQJKBAABCAA0FiEEzOlt8mkP+tbeiYy5AoYrw/LiJnoFAmjiOxsWHGNoZW5odWFj YWlAa2VybmVsLm9yZwAKCRAChivD8uImevP0D/95aVCoh0RPHZr8XRZgQI8yvWUF kn5qS6k0quVtx+tU3hjGCfOYw4GRtBXbguYgdeSZrYuBP+rQoy0U66K10Tw5dARO yoyliTa07ZNvhxxci02qCWZOmOTGhJHOCKk+pe6pktadFgVKPtxx6B6lcsJLAZki e0DrcmlQXH+hUbi4rkVTr5s7Smi8DxS8AIcTdoSyZAuGVB827qBl6fSEb5WTiExx IQfhB2S94psJ6oY9xcEQmoP52VVP+n7l9KYW0czKZ19O+vmU91r6zOJ/JH8nK+CM 1Ooz6/3RSE5Lz2Rk9cFJJCBjAgrQwJIb1Dkr//MQAfinIe4c+8/56Rw/J/wKVi6c UCq4YjV/O5m6J82tSP2ZS4XiideTJFmYDGJSyqIpppOrSZMCyYm4KyCVrw4RgmkH BD1jtWa7fYbCzLduwx4j2sV3NSBZHPKuArpTM/rcQOjnJ7SuiagTDf244Ggp1wlB y7f6le5wgUIlkB3xMRvldAQ7FGvTk9jOYPDGPyGc/lrzca8Db7iX4gx5ykC3VcYe RkMko7EGP2+Bc/cLusDPrLDsXGmRTnGer5fRbv/s7rmUSC3kkmzD548GeLm5Zb5F 32kTkknraruCAMFZcho8sPGu5pTjE6tKIBBGvr9DhTJQxFMeF1TMHgcv6C8Ekryt Nw1NyDWLTX3aGruWjQ== =hrpy -----END PGP SIGNATURE----- Merge tag 'loongarch-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson Pull LoongArch updates from Huacai Chen: - Initialize acpi_gbl_use_global_lock to false - Allow specify SIMD width via kernel parameters - Add kexec_file (both EFI & ELF format) support - Add PER_VMA_LOCK for page fault handling support - Improve BPF trampoline support - Update the default config file - Some bug fixes and other small changes * tag 'loongarch-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson: (23 commits) LoongArch: Update Loongson-3 default config file LoongArch: BPF: Sign-extend struct ops return values properly LoongArch: BPF: Make error handling robust in arch_prepare_bpf_trampoline() LoongArch: BPF: Make trampoline size stable LoongArch: BPF: Don't align trampoline size LoongArch: BPF: No support of struct argument in trampoline programs LoongArch: BPF: No text_poke() for kernel text LoongArch: BPF: Remove duplicated bpf_flush_icache() LoongArch: BPF: Remove duplicated flags check LoongArch: BPF: Fix uninitialized symbol 'retval_off' LoongArch: BPF: Optimize sign-extention mov instructions LoongArch: Handle new atomic instructions for probes LoongArch: Try VMA lock-based page fault handling first LoongArch: Automatically disable kaslr if boot from kexec_file LoongArch: Add crash dump support for kexec_file LoongArch: Add ELF binary support for kexec_file LoongArch: Add EFI binary support for kexec_file LoongArch: Add preparatory infrastructure for kexec_file LoongArch: Add struct loongarch_image_header for kernel LoongArch: Allow specify SIMD width via kernel parameters ...
This commit is contained in:
commit
fb5bc34731
|
|
@ -70,6 +70,7 @@ config LOONGARCH
|
|||
select ARCH_SUPPORTS_LTO_CLANG_THIN
|
||||
select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS
|
||||
select ARCH_SUPPORTS_NUMA_BALANCING
|
||||
select ARCH_SUPPORTS_PER_VMA_LOCK
|
||||
select ARCH_SUPPORTS_RT
|
||||
select ARCH_SUPPORTS_SCHED_SMT if SMP
|
||||
select ARCH_SUPPORTS_SCHED_MC if SMP
|
||||
|
|
@ -618,6 +619,16 @@ config CPU_HAS_PREFETCH
|
|||
config ARCH_SUPPORTS_KEXEC
|
||||
def_bool y
|
||||
|
||||
config ARCH_SUPPORTS_KEXEC_FILE
|
||||
def_bool 64BIT
|
||||
|
||||
config ARCH_SELECTS_KEXEC_FILE
|
||||
def_bool 64BIT
|
||||
depends on KEXEC_FILE
|
||||
select KEXEC_ELF
|
||||
select RELOCATABLE
|
||||
select HAVE_IMA_KEXEC if IMA
|
||||
|
||||
config ARCH_SUPPORTS_CRASH_DUMP
|
||||
def_bool y
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ ifdef CONFIG_LTO_CLANG
|
|||
# The annotate-tablejump option can not be passed to LLVM backend when LTO is enabled.
|
||||
# Ensure it is aware of linker with LTO, '--loongarch-annotate-tablejump' also needs to
|
||||
# be passed via '-mllvm' to ld.lld.
|
||||
KBUILD_LDFLAGS += -mllvm --loongarch-annotate-tablejump
|
||||
KBUILD_LDFLAGS += $(call ld-option,-mllvm --loongarch-annotate-tablejump)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ KBUILD_RUSTFLAGS_KERNEL += -Crelocation-model=pie
|
|||
LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext $(call ld-option, --apply-dynamic-relocs)
|
||||
endif
|
||||
|
||||
cflags-y += $(call cc-option, -mno-check-zero-division)
|
||||
cflags-y += $(call cc-option, -mno-check-zero-division -fno-isolate-erroneous-paths-dereference)
|
||||
|
||||
ifndef CONFIG_KASAN
|
||||
cflags-y += -fno-builtin-memcpy -fno-builtin-memmove -fno-builtin-memset
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ CONFIG_EXPERT=y
|
|||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_PERF_EVENTS=y
|
||||
CONFIG_KEXEC=y
|
||||
CONFIG_KEXEC_FILE=y
|
||||
CONFIG_CRASH_DUMP=y
|
||||
CONFIG_LOONGARCH=y
|
||||
CONFIG_64BIT=y
|
||||
|
|
@ -55,7 +56,7 @@ CONFIG_DMI=y
|
|||
CONFIG_EFI=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
CONFIG_NR_CPUS=256
|
||||
CONFIG_NR_CPUS=2048
|
||||
CONFIG_NUMA=y
|
||||
CONFIG_CPU_HAS_FPU=y
|
||||
CONFIG_CPU_HAS_LSX=y
|
||||
|
|
@ -154,7 +155,16 @@ CONFIG_INET_ESPINTCP=y
|
|||
CONFIG_INET_IPCOMP=m
|
||||
CONFIG_INET_UDP_DIAG=y
|
||||
CONFIG_TCP_CONG_ADVANCED=y
|
||||
CONFIG_TCP_CONG_BBR=m
|
||||
CONFIG_TCP_CONG_BIC=y
|
||||
CONFIG_TCP_CONG_HSTCP=m
|
||||
CONFIG_TCP_CONG_HYBLA=m
|
||||
CONFIG_TCP_CONG_VEGAS=m
|
||||
CONFIG_TCP_CONG_NV=m
|
||||
CONFIG_TCP_CONG_SCALABLE=m
|
||||
CONFIG_TCP_CONG_VENO=m
|
||||
CONFIG_TCP_CONG_DCTCP=m
|
||||
CONFIG_TCP_CONG_CDG=m
|
||||
CONFIG_TCP_CONG_BBR=y
|
||||
CONFIG_IPV6_ROUTER_PREF=y
|
||||
CONFIG_IPV6_ROUTE_INFO=y
|
||||
CONFIG_INET6_AH=m
|
||||
|
|
@ -331,15 +341,33 @@ CONFIG_LLC2=m
|
|||
CONFIG_NET_SCHED=y
|
||||
CONFIG_NET_SCH_HTB=m
|
||||
CONFIG_NET_SCH_PRIO=m
|
||||
CONFIG_NET_SCH_MULTIQ=m
|
||||
CONFIG_NET_SCH_RED=m
|
||||
CONFIG_NET_SCH_SFB=m
|
||||
CONFIG_NET_SCH_SFQ=m
|
||||
CONFIG_NET_SCH_TBF=m
|
||||
CONFIG_NET_SCH_CBS=m
|
||||
CONFIG_NET_SCH_GRED=m
|
||||
CONFIG_NET_SCH_NETEM=m
|
||||
CONFIG_NET_SCH_MQPRIO=m
|
||||
CONFIG_NET_SCH_SKBPRIO=m
|
||||
CONFIG_NET_SCH_QFQ=m
|
||||
CONFIG_NET_SCH_CODEL=m
|
||||
CONFIG_NET_SCH_FQ_CODEL=m
|
||||
CONFIG_NET_SCH_CAKE=m
|
||||
CONFIG_NET_SCH_FQ=m
|
||||
CONFIG_NET_SCH_PIE=m
|
||||
CONFIG_NET_SCH_FQ_PIE=m
|
||||
CONFIG_NET_SCH_INGRESS=m
|
||||
CONFIG_NET_SCH_DEFAULT=y
|
||||
CONFIG_NET_CLS_BASIC=m
|
||||
CONFIG_NET_CLS_FW=m
|
||||
CONFIG_NET_CLS_U32=m
|
||||
CONFIG_NET_CLS_FLOW=m
|
||||
CONFIG_NET_CLS_CGROUP=m
|
||||
CONFIG_NET_CLS_BPF=m
|
||||
CONFIG_NET_CLS_FLOWER=m
|
||||
CONFIG_NET_CLS_MATCHALL=m
|
||||
CONFIG_NET_CLS_ACT=y
|
||||
CONFIG_NET_ACT_POLICE=m
|
||||
CONFIG_NET_ACT_GACT=m
|
||||
|
|
@ -407,6 +435,7 @@ CONFIG_DEVTMPFS=y
|
|||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
CONFIG_FW_LOADER_COMPRESS=y
|
||||
CONFIG_FW_LOADER_COMPRESS_ZSTD=y
|
||||
CONFIG_SYSFB_SIMPLEFB=y
|
||||
CONFIG_EFI_ZBOOT=y
|
||||
CONFIG_EFI_BOOTLOADER_CONTROL=m
|
||||
CONFIG_EFI_CAPSULE_LOADER=m
|
||||
|
|
@ -420,6 +449,11 @@ CONFIG_MTD_CFI_AMDSTD=m
|
|||
CONFIG_MTD_CFI_STAA=m
|
||||
CONFIG_MTD_RAM=m
|
||||
CONFIG_MTD_ROM=m
|
||||
CONFIG_MTD_RAW_NAND=m
|
||||
CONFIG_MTD_NAND_PLATFORM=m
|
||||
CONFIG_MTD_NAND_LOONGSON=m
|
||||
CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC=y
|
||||
CONFIG_MTD_NAND_ECC_SW_BCH=y
|
||||
CONFIG_MTD_UBI=m
|
||||
CONFIG_MTD_UBI_BLOCK=y
|
||||
CONFIG_PARPORT=y
|
||||
|
|
@ -575,6 +609,11 @@ CONFIG_E1000=y
|
|||
CONFIG_E1000E=y
|
||||
CONFIG_IGB=y
|
||||
CONFIG_IXGBE=y
|
||||
CONFIG_I40E=y
|
||||
CONFIG_ICE=y
|
||||
CONFIG_FM10K=y
|
||||
CONFIG_IGC=y
|
||||
CONFIG_IDPF=y
|
||||
# CONFIG_NET_VENDOR_MARVELL is not set
|
||||
# CONFIG_NET_VENDOR_MELLANOX is not set
|
||||
# CONFIG_NET_VENDOR_MICREL is not set
|
||||
|
|
@ -679,6 +718,9 @@ CONFIG_USB4_NET=m
|
|||
CONFIG_INPUT_MOUSEDEV=y
|
||||
CONFIG_INPUT_MOUSEDEV_PSAUX=y
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
CONFIG_KEYBOARD_GPIO=m
|
||||
CONFIG_KEYBOARD_GPIO_POLLED=m
|
||||
CONFIG_KEYBOARD_MATRIX=m
|
||||
CONFIG_KEYBOARD_XTKBD=m
|
||||
CONFIG_MOUSE_PS2_ELANTECH=y
|
||||
CONFIG_MOUSE_PS2_SENTELIC=y
|
||||
|
|
@ -703,8 +745,11 @@ CONFIG_VIRTIO_CONSOLE=y
|
|||
CONFIG_IPMI_HANDLER=m
|
||||
CONFIG_IPMI_DEVICE_INTERFACE=m
|
||||
CONFIG_IPMI_SI=m
|
||||
CONFIG_IPMI_LS2K=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_VIRTIO=m
|
||||
CONFIG_TCG_TPM=m
|
||||
CONFIG_TCG_LOONGSON=m
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
CONFIG_I2C_PIIX4=y
|
||||
CONFIG_I2C_DESIGNWARE_CORE=y
|
||||
|
|
@ -720,6 +765,10 @@ CONFIG_PINCTRL_LOONGSON2=y
|
|||
CONFIG_GPIO_SYSFS=y
|
||||
CONFIG_GPIO_LOONGSON=y
|
||||
CONFIG_GPIO_LOONGSON_64BIT=y
|
||||
CONFIG_GPIO_PCA953X=m
|
||||
CONFIG_GPIO_PCA953X_IRQ=y
|
||||
CONFIG_GPIO_PCA9570=m
|
||||
CONFIG_GPIO_PCF857X=m
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_RESET_RESTART=y
|
||||
CONFIG_POWER_RESET_SYSCON=y
|
||||
|
|
@ -730,6 +779,7 @@ CONFIG_SENSORS_LM93=m
|
|||
CONFIG_SENSORS_W83795=m
|
||||
CONFIG_SENSORS_W83627HF=m
|
||||
CONFIG_LOONGSON2_THERMAL=m
|
||||
CONFIG_MFD_LOONGSON_SE=m
|
||||
CONFIG_RC_CORE=m
|
||||
CONFIG_LIRC=y
|
||||
CONFIG_RC_DECODERS=y
|
||||
|
|
@ -761,6 +811,7 @@ CONFIG_DRM_AST=y
|
|||
CONFIG_DRM_QXL=m
|
||||
CONFIG_DRM_VIRTIO_GPU=m
|
||||
CONFIG_DRM_LOONGSON=y
|
||||
CONFIG_DRM_SIMPLEDRM=y
|
||||
CONFIG_FB=y
|
||||
CONFIG_FB_EFI=y
|
||||
CONFIG_FB_RADEON=y
|
||||
|
|
@ -801,6 +852,7 @@ CONFIG_SND_HDA_CODEC_HDMI_ATI=y
|
|||
CONFIG_SND_HDA_CODEC_HDMI_NVIDIA=y
|
||||
CONFIG_SND_HDA_CODEC_CONEXANT=y
|
||||
CONFIG_SND_USB_AUDIO=m
|
||||
CONFIG_SND_USB_AUDIO_MIDI_V2=y
|
||||
CONFIG_SND_SOC=m
|
||||
CONFIG_SND_SOC_LOONGSON_CARD=m
|
||||
CONFIG_SND_SOC_ES7134=m
|
||||
|
|
@ -861,6 +913,8 @@ CONFIG_TYPEC_TCPM=m
|
|||
CONFIG_TYPEC_TCPCI=m
|
||||
CONFIG_TYPEC_UCSI=m
|
||||
CONFIG_UCSI_ACPI=m
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_LOONGSON2=m
|
||||
CONFIG_INFINIBAND=m
|
||||
CONFIG_EDAC=y
|
||||
# CONFIG_EDAC_LEGACY_SYSFS is not set
|
||||
|
|
@ -922,19 +976,22 @@ CONFIG_NTB_SWITCHTEC=m
|
|||
CONFIG_NTB_PERF=m
|
||||
CONFIG_NTB_TRANSPORT=m
|
||||
CONFIG_PWM=y
|
||||
CONFIG_PWM_LOONGSON=y
|
||||
CONFIG_GENERIC_PHY=y
|
||||
CONFIG_USB4=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT2_FS_XATTR=y
|
||||
CONFIG_EXT2_FS_POSIX_ACL=y
|
||||
CONFIG_EXT2_FS_SECURITY=y
|
||||
CONFIG_EXT3_FS=y
|
||||
CONFIG_EXT3_FS_POSIX_ACL=y
|
||||
CONFIG_EXT3_FS_SECURITY=y
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_POSIX_ACL=y
|
||||
CONFIG_EXT4_FS_SECURITY=y
|
||||
CONFIG_JFS_FS=m
|
||||
CONFIG_JFS_POSIX_ACL=y
|
||||
CONFIG_JFS_SECURITY=y
|
||||
CONFIG_XFS_FS=y
|
||||
CONFIG_XFS_SUPPORT_V4=y
|
||||
CONFIG_XFS_SUPPORT_ASCII_CI=y
|
||||
CONFIG_XFS_QUOTA=y
|
||||
CONFIG_XFS_POSIX_ACL=y
|
||||
CONFIG_GFS2_FS=m
|
||||
|
|
@ -1026,9 +1083,12 @@ CONFIG_CEPH_FS_SECURITY_LABEL=y
|
|||
CONFIG_CIFS=m
|
||||
# CONFIG_CIFS_DEBUG is not set
|
||||
CONFIG_9P_FS=y
|
||||
CONFIG_NLS_DEFAULT="utf8"
|
||||
CONFIG_NLS_CODEPAGE_437=y
|
||||
CONFIG_NLS_CODEPAGE_936=y
|
||||
CONFIG_NLS_CODEPAGE_950=y
|
||||
CONFIG_NLS_ASCII=y
|
||||
CONFIG_NLS_ISO8859_1=y
|
||||
CONFIG_NLS_UTF8=y
|
||||
CONFIG_DLM=m
|
||||
CONFIG_KEY_DH_OPERATIONS=y
|
||||
|
|
@ -1049,9 +1109,11 @@ CONFIG_CRYPTO_CAST6=m
|
|||
CONFIG_CRYPTO_KHAZAD=m
|
||||
CONFIG_CRYPTO_SEED=m
|
||||
CONFIG_CRYPTO_SERPENT=m
|
||||
CONFIG_CRYPTO_SM4_GENERIC=m
|
||||
CONFIG_CRYPTO_TEA=m
|
||||
CONFIG_CRYPTO_TWOFISH=m
|
||||
CONFIG_CRYPTO_CHACHA20POLY1305=m
|
||||
CONFIG_CRYPTO_SM3_GENERIC=m
|
||||
CONFIG_CRYPTO_WP512=m
|
||||
CONFIG_CRYPTO_DEFLATE=m
|
||||
CONFIG_CRYPTO_LZO=m
|
||||
|
|
@ -1063,6 +1125,7 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m
|
|||
CONFIG_CRYPTO_USER_API_RNG=m
|
||||
CONFIG_CRYPTO_USER_API_AEAD=m
|
||||
CONFIG_CRYPTO_DEV_VIRTIO=m
|
||||
CONFIG_CRYPTO_DEV_LOONGSON_RNG=m
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_DMA_NUMA_CMA=y
|
||||
CONFIG_CMA_SIZE_MBYTES=0
|
||||
|
|
|
|||
52
arch/loongarch/include/asm/image.h
Normal file
52
arch/loongarch/include/asm/image.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* LoongArch binary image header for EFI(PE/COFF) format.
|
||||
*
|
||||
* Author: Youling Tang <tangyouling@kylinos.cn>
|
||||
* Copyright (C) 2025 KylinSoft Corporation.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_IMAGE_H
|
||||
#define __ASM_IMAGE_H
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/**
|
||||
* struct loongarch_image_header
|
||||
*
|
||||
* @dos_sig: Optional PE format 'MZ' signature.
|
||||
* @padding_1: Reserved.
|
||||
* @kernel_entry: Kernel image entry pointer.
|
||||
* @kernel_asize: An estimated size of the memory image size in LSB byte order.
|
||||
* @text_offset: The image load offset in LSB byte order.
|
||||
* @padding_2: Reserved.
|
||||
* @pe_header: Optional offset to a PE format header.
|
||||
**/
|
||||
|
||||
struct loongarch_image_header {
|
||||
uint8_t dos_sig[2];
|
||||
uint16_t padding_1[3];
|
||||
uint64_t kernel_entry;
|
||||
uint64_t kernel_asize;
|
||||
uint64_t text_offset;
|
||||
uint32_t padding_2[7];
|
||||
uint32_t pe_header;
|
||||
};
|
||||
|
||||
/*
|
||||
* loongarch_header_check_dos_sig - Helper to check the header
|
||||
*
|
||||
* Returns true (non-zero) if 'MZ' signature is found.
|
||||
*/
|
||||
|
||||
static inline int loongarch_header_check_dos_sig(const struct loongarch_image_header *h)
|
||||
{
|
||||
if (!h)
|
||||
return 0;
|
||||
|
||||
return (h->dos_sig[0] == 'M' && h->dos_sig[1] == 'Z');
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif /* __ASM_IMAGE_H */
|
||||
|
|
@ -77,6 +77,10 @@ enum reg2_op {
|
|||
iocsrwrh_op = 0x19205,
|
||||
iocsrwrw_op = 0x19206,
|
||||
iocsrwrd_op = 0x19207,
|
||||
llacqw_op = 0xe15e0,
|
||||
screlw_op = 0xe15e1,
|
||||
llacqd_op = 0xe15e2,
|
||||
screld_op = 0xe15e3,
|
||||
};
|
||||
|
||||
enum reg2i5_op {
|
||||
|
|
@ -189,6 +193,7 @@ enum reg3_op {
|
|||
fldxd_op = 0x7068,
|
||||
fstxs_op = 0x7070,
|
||||
fstxd_op = 0x7078,
|
||||
scq_op = 0x70ae,
|
||||
amswapw_op = 0x70c0,
|
||||
amswapd_op = 0x70c1,
|
||||
amaddw_op = 0x70c2,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,18 @@ struct kimage_arch {
|
|||
unsigned long systable_ptr;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_KEXEC_FILE
|
||||
extern const struct kexec_file_ops kexec_efi_ops;
|
||||
extern const struct kexec_file_ops kexec_elf_ops;
|
||||
|
||||
int arch_kimage_file_post_load_cleanup(struct kimage *image);
|
||||
#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
|
||||
|
||||
extern int load_other_segments(struct kimage *image,
|
||||
unsigned long kernel_load_addr, unsigned long kernel_size,
|
||||
char *initrd, unsigned long initrd_len, char *cmdline, unsigned long cmdline_len);
|
||||
#endif
|
||||
|
||||
typedef void (*do_kexec_t)(unsigned long efi_boot,
|
||||
unsigned long cmdline_ptr,
|
||||
unsigned long systable_ptr,
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
|
|||
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_UNWINDER_GUESS) += unwind_guess.o
|
||||
|
|
|
|||
|
|
@ -52,6 +52,48 @@ static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_loongarch *c)
|
|||
c->fpu_mask = ~(fcsr0 ^ fcsr1) & ~mask;
|
||||
}
|
||||
|
||||
/* simd = -1/0/128/256 */
|
||||
static unsigned int simd = -1U;
|
||||
|
||||
static int __init cpu_setup_simd(char *str)
|
||||
{
|
||||
get_option(&str, &simd);
|
||||
pr_info("Set SIMD width = %u\n", simd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_param("simd", cpu_setup_simd);
|
||||
|
||||
static int __init cpu_final_simd(void)
|
||||
{
|
||||
struct cpuinfo_loongarch *c = &cpu_data[0];
|
||||
|
||||
if (simd < 128) {
|
||||
c->options &= ~LOONGARCH_CPU_LSX;
|
||||
elf_hwcap &= ~HWCAP_LOONGARCH_LSX;
|
||||
}
|
||||
|
||||
if (simd < 256) {
|
||||
c->options &= ~LOONGARCH_CPU_LASX;
|
||||
elf_hwcap &= ~HWCAP_LOONGARCH_LASX;
|
||||
}
|
||||
|
||||
simd = 0;
|
||||
|
||||
if (c->options & LOONGARCH_CPU_LSX)
|
||||
simd = 128;
|
||||
|
||||
if (c->options & LOONGARCH_CPU_LASX)
|
||||
simd = 256;
|
||||
|
||||
pr_info("Final SIMD width = %u\n", simd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(cpu_final_simd);
|
||||
|
||||
static inline void set_elf_platform(int cpu, const char *plat)
|
||||
{
|
||||
if (cpu == 0)
|
||||
|
|
@ -134,13 +176,13 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
|
|||
elf_hwcap |= HWCAP_LOONGARCH_FPU;
|
||||
}
|
||||
#ifdef CONFIG_CPU_HAS_LSX
|
||||
if (config & CPUCFG2_LSX) {
|
||||
if ((config & CPUCFG2_LSX) && (simd >= 128)) {
|
||||
c->options |= LOONGARCH_CPU_LSX;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_LSX;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_CPU_HAS_LASX
|
||||
if (config & CPUCFG2_LASX) {
|
||||
if ((config & CPUCFG2_LASX) && (simd >= 256)) {
|
||||
c->options |= LOONGARCH_CPU_LASX;
|
||||
elf_hwcap |= HWCAP_LOONGARCH_LASX;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,9 @@ bool insns_not_supported(union loongarch_instruction insn)
|
|||
case amswapw_op ... ammindbdu_op:
|
||||
pr_notice("atomic memory access instructions are not supported\n");
|
||||
return true;
|
||||
case scq_op:
|
||||
pr_notice("sc.q instruction is not supported\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (insn.reg2i14_format.opcode) {
|
||||
|
|
@ -152,6 +155,15 @@ bool insns_not_supported(union loongarch_instruction insn)
|
|||
return true;
|
||||
}
|
||||
|
||||
switch (insn.reg2_format.opcode) {
|
||||
case llacqw_op:
|
||||
case llacqd_op:
|
||||
case screlw_op:
|
||||
case screld_op:
|
||||
pr_notice("llacq and screl instructions are not supported\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (insn.reg1i21_format.opcode) {
|
||||
case bceqz_op:
|
||||
pr_notice("bceqz and bcnez instructions are not supported\n");
|
||||
|
|
|
|||
113
arch/loongarch/kernel/kexec_efi.c
Normal file
113
arch/loongarch/kernel/kexec_efi.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Load EFI vmlinux file for the kexec_file_load syscall.
|
||||
*
|
||||
* Author: Youling Tang <tangyouling@kylinos.cn>
|
||||
* Copyright (C) 2025 KylinSoft Corporation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "kexec_file(EFI): " fmt
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/pe.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/image.h>
|
||||
|
||||
static int efi_kexec_probe(const char *kernel_buf, unsigned long kernel_len)
|
||||
{
|
||||
const struct loongarch_image_header *h = (const struct loongarch_image_header *)kernel_buf;
|
||||
|
||||
if (!h || (kernel_len < sizeof(*h))) {
|
||||
kexec_dprintk("No LoongArch image header.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!loongarch_header_check_dos_sig(h)) {
|
||||
kexec_dprintk("No LoongArch PE image header.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *efi_kexec_load(struct kimage *image,
|
||||
char *kernel, unsigned long kernel_len,
|
||||
char *initrd, unsigned long initrd_len,
|
||||
char *cmdline, unsigned long cmdline_len)
|
||||
{
|
||||
int ret;
|
||||
unsigned long text_offset, kernel_segment_number;
|
||||
struct kexec_buf kbuf;
|
||||
struct kexec_segment *kernel_segment;
|
||||
struct loongarch_image_header *h;
|
||||
|
||||
h = (struct loongarch_image_header *)kernel;
|
||||
if (!h->kernel_asize)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/*
|
||||
* Load the kernel
|
||||
* FIXME: Non-relocatable kernel rejected for kexec_file (require CONFIG_RELOCATABLE)
|
||||
*/
|
||||
kbuf.image = image;
|
||||
kbuf.buf_max = ULONG_MAX;
|
||||
kbuf.top_down = false;
|
||||
|
||||
kbuf.buffer = kernel;
|
||||
kbuf.bufsz = kernel_len;
|
||||
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
|
||||
kbuf.memsz = le64_to_cpu(h->kernel_asize);
|
||||
text_offset = le64_to_cpu(h->text_offset);
|
||||
kbuf.buf_min = text_offset;
|
||||
kbuf.buf_align = SZ_2M;
|
||||
|
||||
kernel_segment_number = image->nr_segments;
|
||||
|
||||
/*
|
||||
* The location of the kernel segment may make it impossible to
|
||||
* satisfy the other segment requirements, so we try repeatedly
|
||||
* to find a location that will work.
|
||||
*/
|
||||
while ((ret = kexec_add_buffer(&kbuf)) == 0) {
|
||||
/* Try to load additional data */
|
||||
kernel_segment = &image->segment[kernel_segment_number];
|
||||
ret = load_other_segments(image, kernel_segment->mem,
|
||||
kernel_segment->memsz, initrd,
|
||||
initrd_len, cmdline, cmdline_len);
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
/*
|
||||
* We couldn't find space for the other segments; erase the
|
||||
* kernel segment and try the next available hole.
|
||||
*/
|
||||
image->nr_segments -= 1;
|
||||
kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
|
||||
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("Could not find any suitable kernel location!");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
kernel_segment = &image->segment[kernel_segment_number];
|
||||
|
||||
/* Make sure the second kernel jumps to the correct "kernel_entry" */
|
||||
image->start = kernel_segment->mem + h->kernel_entry - text_offset;
|
||||
|
||||
kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
|
||||
kernel_segment->mem, kbuf.bufsz, kernel_segment->memsz);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct kexec_file_ops kexec_efi_ops = {
|
||||
.probe = efi_kexec_probe,
|
||||
.load = efi_kexec_load,
|
||||
};
|
||||
105
arch/loongarch/kernel/kexec_elf.c
Normal file
105
arch/loongarch/kernel/kexec_elf.c
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Load ELF vmlinux file for the kexec_file_load syscall.
|
||||
*
|
||||
* Author: Youling Tang <tangyouling@kylinos.cn>
|
||||
* Copyright (C) 2025 KylinSoft Corporation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "kexec_file(ELF): " fmt
|
||||
|
||||
#include <linux/elf.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#define elf_kexec_probe kexec_elf_probe
|
||||
|
||||
static int _elf_kexec_load(struct kimage *image,
|
||||
struct elfhdr *ehdr, struct kexec_elf_info *elf_info,
|
||||
struct kexec_buf *kbuf, unsigned long *text_offset)
|
||||
{
|
||||
int i, ret = -1;
|
||||
|
||||
/* Read in the PT_LOAD segments. */
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
size_t size;
|
||||
const struct elf_phdr *phdr;
|
||||
|
||||
phdr = &elf_info->proghdrs[i];
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
size = phdr->p_filesz;
|
||||
if (size > phdr->p_memsz)
|
||||
size = phdr->p_memsz;
|
||||
|
||||
kbuf->buffer = (void *)elf_info->buffer + phdr->p_offset;
|
||||
kbuf->bufsz = size;
|
||||
kbuf->buf_align = phdr->p_align;
|
||||
*text_offset = __pa(phdr->p_paddr);
|
||||
kbuf->buf_min = *text_offset;
|
||||
kbuf->memsz = ALIGN(phdr->p_memsz, SZ_64K);
|
||||
kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;
|
||||
ret = kexec_add_buffer(kbuf);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *elf_kexec_load(struct kimage *image,
|
||||
char *kernel, unsigned long kernel_len,
|
||||
char *initrd, unsigned long initrd_len,
|
||||
char *cmdline, unsigned long cmdline_len)
|
||||
{
|
||||
int ret;
|
||||
unsigned long text_offset, kernel_segment_number;
|
||||
struct elfhdr ehdr;
|
||||
struct kexec_buf kbuf;
|
||||
struct kexec_elf_info elf_info;
|
||||
struct kexec_segment *kernel_segment;
|
||||
|
||||
ret = kexec_build_elf_info(kernel, kernel_len, &ehdr, &elf_info);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/*
|
||||
* Load the kernel
|
||||
* FIXME: Non-relocatable kernel rejected for kexec_file (require CONFIG_RELOCATABLE)
|
||||
*/
|
||||
kbuf.image = image;
|
||||
kbuf.buf_max = ULONG_MAX;
|
||||
kbuf.top_down = false;
|
||||
|
||||
kernel_segment_number = image->nr_segments;
|
||||
|
||||
ret = _elf_kexec_load(image, &ehdr, &elf_info, &kbuf, &text_offset);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* Load additional data */
|
||||
kernel_segment = &image->segment[kernel_segment_number];
|
||||
ret = load_other_segments(image, kernel_segment->mem, kernel_segment->memsz,
|
||||
initrd, initrd_len, cmdline, cmdline_len);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* Make sure the second kernel jumps to the correct "kernel_entry". */
|
||||
image->start = kernel_segment->mem + __pa(ehdr.e_entry) - text_offset;
|
||||
|
||||
kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
|
||||
kernel_segment->mem, kbuf.bufsz, kernel_segment->memsz);
|
||||
|
||||
out:
|
||||
kexec_free_elf_info(&elf_info);
|
||||
return ret ? ERR_PTR(ret) : NULL;
|
||||
}
|
||||
|
||||
const struct kexec_file_ops kexec_elf_ops = {
|
||||
.probe = elf_kexec_probe,
|
||||
.load = elf_kexec_load,
|
||||
};
|
||||
|
|
@ -70,18 +70,28 @@ int machine_kexec_prepare(struct kimage *kimage)
|
|||
kimage->arch.efi_boot = fw_arg0;
|
||||
kimage->arch.systable_ptr = fw_arg2;
|
||||
|
||||
/* Find the command line */
|
||||
for (i = 0; i < kimage->nr_segments; i++) {
|
||||
if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
|
||||
if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
|
||||
kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
|
||||
break;
|
||||
if (kimage->file_mode == 1) {
|
||||
/*
|
||||
* kimage->cmdline_buf will be released in kexec_file_load, so copy
|
||||
* to the KEXEC_CMDLINE_ADDR safe area.
|
||||
*/
|
||||
memcpy((void *)KEXEC_CMDLINE_ADDR, (void *)kimage->arch.cmdline_ptr,
|
||||
strlen((char *)kimage->arch.cmdline_ptr) + 1);
|
||||
kimage->arch.cmdline_ptr = (unsigned long)KEXEC_CMDLINE_ADDR;
|
||||
} else {
|
||||
/* Find the command line */
|
||||
for (i = 0; i < kimage->nr_segments; i++) {
|
||||
if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
|
||||
if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
|
||||
kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!kimage->arch.cmdline_ptr) {
|
||||
pr_err("Command line not included in the provided image\n");
|
||||
return -EINVAL;
|
||||
if (!kimage->arch.cmdline_ptr) {
|
||||
pr_err("Command line not included in the provided image\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* kexec/kdump need a safe page to save reboot_code_buffer */
|
||||
|
|
@ -287,9 +297,10 @@ void machine_kexec(struct kimage *image)
|
|||
/* We do not want to be bothered. */
|
||||
local_irq_disable();
|
||||
|
||||
pr_notice("EFI boot flag 0x%lx\n", efi_boot);
|
||||
pr_notice("Command line at 0x%lx\n", cmdline_ptr);
|
||||
pr_notice("System table at 0x%lx\n", systable_ptr);
|
||||
pr_notice("EFI boot flag: 0x%lx\n", efi_boot);
|
||||
pr_notice("Command line addr: 0x%lx\n", cmdline_ptr);
|
||||
pr_notice("Command line string: %s\n", (char *)cmdline_ptr);
|
||||
pr_notice("System table addr: 0x%lx\n", systable_ptr);
|
||||
pr_notice("We will call new kernel at 0x%lx\n", start_addr);
|
||||
pr_notice("Bye ...\n");
|
||||
|
||||
|
|
|
|||
239
arch/loongarch/kernel/machine_kexec_file.c
Normal file
239
arch/loongarch/kernel/machine_kexec_file.c
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* kexec_file for LoongArch
|
||||
*
|
||||
* Author: Youling Tang <tangyouling@kylinos.cn>
|
||||
* Copyright (C) 2025 KylinSoft Corporation.
|
||||
*
|
||||
* Most code is derived from LoongArch port of kexec-tools
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "kexec_file: " fmt
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
const struct kexec_file_ops * const kexec_file_loaders[] = {
|
||||
&kexec_efi_ops,
|
||||
&kexec_elf_ops,
|
||||
NULL
|
||||
};
|
||||
|
||||
int arch_kimage_file_post_load_cleanup(struct kimage *image)
|
||||
{
|
||||
vfree(image->elf_headers);
|
||||
image->elf_headers = NULL;
|
||||
image->elf_headers_sz = 0;
|
||||
|
||||
return kexec_image_post_load_cleanup_default(image);
|
||||
}
|
||||
|
||||
/* Add the "kexec_file" command line parameter to command line. */
|
||||
static void cmdline_add_loader(unsigned long *cmdline_tmplen, char *modified_cmdline)
|
||||
{
|
||||
int loader_strlen;
|
||||
|
||||
loader_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "kexec_file ");
|
||||
*cmdline_tmplen += loader_strlen;
|
||||
}
|
||||
|
||||
/* Add the "initrd=start,size" command line parameter to command line. */
|
||||
static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmplen,
|
||||
char *modified_cmdline, unsigned long initrd)
|
||||
{
|
||||
int initrd_strlen;
|
||||
|
||||
initrd_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "initrd=0x%lx,0x%lx ",
|
||||
initrd, image->initrd_buf_len);
|
||||
*cmdline_tmplen += initrd_strlen;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
|
||||
static int prepare_elf_headers(void **addr, unsigned long *sz)
|
||||
{
|
||||
int ret, nr_ranges;
|
||||
uint64_t i;
|
||||
phys_addr_t start, end;
|
||||
struct crash_mem *cmem;
|
||||
|
||||
nr_ranges = 2; /* for exclusion of crashkernel region */
|
||||
for_each_mem_range(i, &start, &end)
|
||||
nr_ranges++;
|
||||
|
||||
cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL);
|
||||
if (!cmem)
|
||||
return -ENOMEM;
|
||||
|
||||
cmem->max_nr_ranges = nr_ranges;
|
||||
cmem->nr_ranges = 0;
|
||||
for_each_mem_range(i, &start, &end) {
|
||||
cmem->ranges[cmem->nr_ranges].start = start;
|
||||
cmem->ranges[cmem->nr_ranges].end = end - 1;
|
||||
cmem->nr_ranges++;
|
||||
}
|
||||
|
||||
/* Exclude crashkernel region */
|
||||
ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (crashk_low_res.end) {
|
||||
ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
|
||||
|
||||
out:
|
||||
kfree(cmem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the "mem=size@start" command line parameter to command line, indicating the
|
||||
* memory region the new kernel can use to boot into.
|
||||
*/
|
||||
static void cmdline_add_mem(unsigned long *cmdline_tmplen, char *modified_cmdline)
|
||||
{
|
||||
int mem_strlen = 0;
|
||||
|
||||
mem_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "mem=0x%llx@0x%llx ",
|
||||
crashk_res.end - crashk_res.start + 1, crashk_res.start);
|
||||
*cmdline_tmplen += mem_strlen;
|
||||
|
||||
if (crashk_low_res.end) {
|
||||
mem_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "mem=0x%llx@0x%llx ",
|
||||
crashk_low_res.end - crashk_low_res.start + 1, crashk_low_res.start);
|
||||
*cmdline_tmplen += mem_strlen;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the "elfcorehdr=size@start" command line parameter to command line. */
|
||||
static void cmdline_add_elfcorehdr(struct kimage *image, unsigned long *cmdline_tmplen,
|
||||
char *modified_cmdline, unsigned long elfcorehdr_sz)
|
||||
{
|
||||
int elfcorehdr_strlen = 0;
|
||||
|
||||
elfcorehdr_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "elfcorehdr=0x%lx@0x%lx ",
|
||||
elfcorehdr_sz, image->elf_load_addr);
|
||||
*cmdline_tmplen += elfcorehdr_strlen;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Try to add the initrd to the image. If it is not possible to find valid
|
||||
* locations, this function will undo changes to the image and return non zero.
|
||||
*/
|
||||
int load_other_segments(struct kimage *image,
|
||||
unsigned long kernel_load_addr, unsigned long kernel_size,
|
||||
char *initrd, unsigned long initrd_len, char *cmdline, unsigned long cmdline_len)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long cmdline_tmplen = 0;
|
||||
unsigned long initrd_load_addr = 0;
|
||||
unsigned long orig_segments = image->nr_segments;
|
||||
char *modified_cmdline = NULL;
|
||||
struct kexec_buf kbuf;
|
||||
|
||||
kbuf.image = image;
|
||||
/* Don't allocate anything below the kernel */
|
||||
kbuf.buf_min = kernel_load_addr + kernel_size;
|
||||
|
||||
modified_cmdline = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
|
||||
if (!modified_cmdline)
|
||||
return -EINVAL;
|
||||
|
||||
cmdline_add_loader(&cmdline_tmplen, modified_cmdline);
|
||||
/* Ensure it's null terminated */
|
||||
modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
|
||||
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
/* Load elf core header */
|
||||
if (image->type == KEXEC_TYPE_CRASH) {
|
||||
void *headers;
|
||||
unsigned long headers_sz;
|
||||
|
||||
ret = prepare_elf_headers(&headers, &headers_sz);
|
||||
if (ret < 0) {
|
||||
pr_err("Preparing elf core header failed\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
kbuf.buffer = headers;
|
||||
kbuf.bufsz = headers_sz;
|
||||
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
|
||||
kbuf.memsz = headers_sz;
|
||||
kbuf.buf_align = SZ_64K; /* largest supported page size */
|
||||
kbuf.buf_max = ULONG_MAX;
|
||||
kbuf.top_down = true;
|
||||
|
||||
ret = kexec_add_buffer(&kbuf);
|
||||
if (ret < 0) {
|
||||
vfree(headers);
|
||||
goto out_err;
|
||||
}
|
||||
image->elf_headers = headers;
|
||||
image->elf_load_addr = kbuf.mem;
|
||||
image->elf_headers_sz = headers_sz;
|
||||
|
||||
kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
|
||||
image->elf_load_addr, kbuf.bufsz, kbuf.memsz);
|
||||
|
||||
/* Add the mem=size@start parameter to the command line */
|
||||
cmdline_add_mem(&cmdline_tmplen, modified_cmdline);
|
||||
|
||||
/* Add the elfcorehdr=size@start parameter to the command line */
|
||||
cmdline_add_elfcorehdr(image, &cmdline_tmplen, modified_cmdline, headers_sz);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Load initrd */
|
||||
if (initrd) {
|
||||
kbuf.buffer = initrd;
|
||||
kbuf.bufsz = initrd_len;
|
||||
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
|
||||
kbuf.memsz = initrd_len;
|
||||
kbuf.buf_align = 0;
|
||||
/* within 1GB-aligned window of up to 32GB in size */
|
||||
kbuf.buf_max = round_down(kernel_load_addr, SZ_1G) + (unsigned long)SZ_1G * 32;
|
||||
kbuf.top_down = false;
|
||||
|
||||
ret = kexec_add_buffer(&kbuf);
|
||||
if (ret < 0)
|
||||
goto out_err;
|
||||
initrd_load_addr = kbuf.mem;
|
||||
|
||||
kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
|
||||
initrd_load_addr, kbuf.bufsz, kbuf.memsz);
|
||||
|
||||
/* Add the initrd=start,size parameter to the command line */
|
||||
cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr);
|
||||
}
|
||||
|
||||
if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) {
|
||||
pr_err("Appending command line exceeds COMMAND_LINE_SIZE\n");
|
||||
ret = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
memcpy(modified_cmdline + cmdline_tmplen, cmdline, cmdline_len);
|
||||
cmdline = modified_cmdline;
|
||||
image->arch.cmdline_ptr = (unsigned long)cmdline;
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
image->nr_segments = orig_segments;
|
||||
kfree(modified_cmdline);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -166,6 +166,10 @@ static inline __init bool kaslr_disabled(void)
|
|||
return true;
|
||||
#endif
|
||||
|
||||
str = strstr(boot_command_line, "kexec_file");
|
||||
if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ void __init platform_init(void)
|
|||
|
||||
#ifdef CONFIG_ACPI
|
||||
acpi_table_upgrade();
|
||||
acpi_gbl_use_global_lock = false;
|
||||
acpi_gbl_use_default_register_widths = false;
|
||||
acpi_boot_table_init();
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -215,6 +215,58 @@ static void __kprobes __do_page_fault(struct pt_regs *regs,
|
|||
flags |= FAULT_FLAG_USER;
|
||||
|
||||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
|
||||
|
||||
if (!(flags & FAULT_FLAG_USER))
|
||||
goto lock_mmap;
|
||||
|
||||
vma = lock_vma_under_rcu(mm, address);
|
||||
if (!vma)
|
||||
goto lock_mmap;
|
||||
|
||||
if (write) {
|
||||
flags |= FAULT_FLAG_WRITE;
|
||||
if (!(vma->vm_flags & VM_WRITE)) {
|
||||
vma_end_read(vma);
|
||||
si_code = SEGV_ACCERR;
|
||||
count_vm_vma_lock_event(VMA_LOCK_SUCCESS);
|
||||
goto bad_area_nosemaphore;
|
||||
}
|
||||
} else {
|
||||
if (!(vma->vm_flags & VM_EXEC) && address == exception_era(regs)) {
|
||||
vma_end_read(vma);
|
||||
si_code = SEGV_ACCERR;
|
||||
count_vm_vma_lock_event(VMA_LOCK_SUCCESS);
|
||||
goto bad_area_nosemaphore;
|
||||
}
|
||||
if (!(vma->vm_flags & (VM_READ | VM_WRITE)) && address != exception_era(regs)) {
|
||||
vma_end_read(vma);
|
||||
si_code = SEGV_ACCERR;
|
||||
count_vm_vma_lock_event(VMA_LOCK_SUCCESS);
|
||||
goto bad_area_nosemaphore;
|
||||
}
|
||||
}
|
||||
|
||||
fault = handle_mm_fault(vma, address, flags | FAULT_FLAG_VMA_LOCK, regs);
|
||||
if (!(fault & (VM_FAULT_RETRY | VM_FAULT_COMPLETED)))
|
||||
vma_end_read(vma);
|
||||
|
||||
if (!(fault & VM_FAULT_RETRY)) {
|
||||
count_vm_vma_lock_event(VMA_LOCK_SUCCESS);
|
||||
goto done;
|
||||
}
|
||||
|
||||
count_vm_vma_lock_event(VMA_LOCK_RETRY);
|
||||
if (fault & VM_FAULT_MAJOR)
|
||||
flags |= FAULT_FLAG_TRIED;
|
||||
|
||||
/* Quick path to respond to signals */
|
||||
if (fault_signal_pending(fault, regs)) {
|
||||
if (!user_mode(regs))
|
||||
no_context(regs, write, address);
|
||||
return;
|
||||
}
|
||||
lock_mmap:
|
||||
|
||||
retry:
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (unlikely(!vma))
|
||||
|
|
@ -276,8 +328,10 @@ static void __kprobes __do_page_fault(struct pt_regs *regs,
|
|||
*/
|
||||
goto retry;
|
||||
}
|
||||
mmap_read_unlock(mm);
|
||||
|
||||
done:
|
||||
if (unlikely(fault & VM_FAULT_ERROR)) {
|
||||
mmap_read_unlock(mm);
|
||||
if (fault & VM_FAULT_OOM) {
|
||||
do_out_of_memory(regs, write, address);
|
||||
return;
|
||||
|
|
@ -290,8 +344,6 @@ static void __kprobes __do_page_fault(struct pt_regs *regs,
|
|||
}
|
||||
BUG();
|
||||
}
|
||||
|
||||
mmap_read_unlock(mm);
|
||||
}
|
||||
|
||||
asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
|
||||
|
|
|
|||
|
|
@ -527,13 +527,11 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
case 8:
|
||||
move_reg(ctx, t1, src);
|
||||
emit_insn(ctx, extwb, dst, t1);
|
||||
emit_insn(ctx, extwb, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
case 16:
|
||||
move_reg(ctx, t1, src);
|
||||
emit_insn(ctx, extwh, dst, t1);
|
||||
emit_insn(ctx, extwh, dst, src);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
break;
|
||||
case 32:
|
||||
|
|
@ -1294,8 +1292,10 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
|
|||
u32 old_insns[LOONGARCH_LONG_JUMP_NINSNS] = {[0 ... 4] = INSN_NOP};
|
||||
u32 new_insns[LOONGARCH_LONG_JUMP_NINSNS] = {[0 ... 4] = INSN_NOP};
|
||||
|
||||
if (!is_kernel_text((unsigned long)ip) &&
|
||||
!is_bpf_text_address((unsigned long)ip))
|
||||
/* Only poking bpf text is supported. Since kernel function entry
|
||||
* is set up by ftrace, we rely on ftrace to poke kernel functions.
|
||||
*/
|
||||
if (!is_bpf_text_address((unsigned long)ip))
|
||||
return -ENOTSUPP;
|
||||
|
||||
ret = emit_jump_or_nops(old_addr, ip, old_insns, is_call);
|
||||
|
|
@ -1448,12 +1448,43 @@ void arch_free_bpf_trampoline(void *image, unsigned int size)
|
|||
bpf_prog_pack_free(image, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sign-extend the register if necessary
|
||||
*/
|
||||
static void sign_extend(struct jit_ctx *ctx, int rd, int rj, u8 size, bool sign)
|
||||
{
|
||||
/* ABI requires unsigned char/short to be zero-extended */
|
||||
if (!sign && (size == 1 || size == 2)) {
|
||||
if (rd != rj)
|
||||
move_reg(ctx, rd, rj);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
emit_insn(ctx, extwb, rd, rj);
|
||||
break;
|
||||
case 2:
|
||||
emit_insn(ctx, extwh, rd, rj);
|
||||
break;
|
||||
case 4:
|
||||
emit_insn(ctx, addiw, rd, rj, 0);
|
||||
break;
|
||||
case 8:
|
||||
if (rd != rj)
|
||||
move_reg(ctx, rd, rj);
|
||||
break;
|
||||
default:
|
||||
pr_warn("bpf_jit: invalid size %d for sign_extend\n", size);
|
||||
}
|
||||
}
|
||||
|
||||
static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
||||
const struct btf_func_model *m, struct bpf_tramp_links *tlinks,
|
||||
void *func_addr, u32 flags)
|
||||
{
|
||||
int i, ret, save_ret;
|
||||
int stack_size = 0, nargs = 0;
|
||||
int stack_size, nargs;
|
||||
int retval_off, args_off, nargs_off, ip_off, run_ctx_off, sreg_off, tcc_ptr_off;
|
||||
bool is_struct_ops = flags & BPF_TRAMP_F_INDIRECT;
|
||||
void *orig_call = func_addr;
|
||||
|
|
@ -1462,9 +1493,6 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i
|
|||
struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN];
|
||||
u32 **branches = NULL;
|
||||
|
||||
if (flags & (BPF_TRAMP_F_ORIG_STACK | BPF_TRAMP_F_SHARE_IPMODIFY))
|
||||
return -ENOTSUPP;
|
||||
|
||||
/*
|
||||
* FP + 8 [ RA to parent func ] return address to parent
|
||||
* function
|
||||
|
|
@ -1495,20 +1523,23 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i
|
|||
if (m->nr_args > LOONGARCH_MAX_REG_ARGS)
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* FIXME: No support of struct argument */
|
||||
for (i = 0; i < m->nr_args; i++) {
|
||||
if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG)
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (flags & (BPF_TRAMP_F_ORIG_STACK | BPF_TRAMP_F_SHARE_IPMODIFY))
|
||||
return -ENOTSUPP;
|
||||
|
||||
stack_size = 0;
|
||||
|
||||
/* Room of trampoline frame to store return address and frame pointer */
|
||||
stack_size += 16;
|
||||
stack_size = 16;
|
||||
|
||||
save_ret = flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET);
|
||||
if (save_ret) {
|
||||
/* Save BPF R0 and A0 */
|
||||
stack_size += 16;
|
||||
retval_off = stack_size;
|
||||
}
|
||||
if (save_ret)
|
||||
stack_size += 16; /* Save BPF R0 and A0 */
|
||||
|
||||
retval_off = stack_size;
|
||||
|
||||
/* Room of trampoline frame to store args */
|
||||
nargs = m->nr_args;
|
||||
|
|
@ -1595,7 +1626,7 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i
|
|||
orig_call += LOONGARCH_BPF_FENTRY_NBYTES;
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
move_imm(ctx, LOONGARCH_GPR_A0, (const s64)im, false);
|
||||
move_addr(ctx, LOONGARCH_GPR_A0, (const u64)im);
|
||||
ret = emit_call(ctx, (const u64)__bpf_tramp_enter);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -1645,7 +1676,7 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i
|
|||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
im->ip_epilogue = ctx->ro_image + ctx->idx;
|
||||
move_imm(ctx, LOONGARCH_GPR_A0, (const s64)im, false);
|
||||
move_addr(ctx, LOONGARCH_GPR_A0, (const u64)im);
|
||||
ret = emit_call(ctx, (const u64)__bpf_tramp_exit);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
|
@ -1655,8 +1686,12 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i
|
|||
restore_args(ctx, m->nr_args, args_off);
|
||||
|
||||
if (save_ret) {
|
||||
emit_insn(ctx, ldd, LOONGARCH_GPR_A0, LOONGARCH_GPR_FP, -retval_off);
|
||||
emit_insn(ctx, ldd, regmap[BPF_REG_0], LOONGARCH_GPR_FP, -(retval_off - 8));
|
||||
if (is_struct_ops)
|
||||
sign_extend(ctx, LOONGARCH_GPR_A0, regmap[BPF_REG_0],
|
||||
m->ret_size, m->ret_flags & BTF_FMODEL_SIGNED_ARG);
|
||||
else
|
||||
emit_insn(ctx, ldd, LOONGARCH_GPR_A0, LOONGARCH_GPR_FP, -retval_off);
|
||||
}
|
||||
|
||||
emit_insn(ctx, ldd, LOONGARCH_GPR_S1, LOONGARCH_GPR_FP, -sreg_off);
|
||||
|
|
@ -1715,7 +1750,10 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
|
|||
|
||||
jit_fill_hole(image, (unsigned int)(ro_image_end - ro_image));
|
||||
ret = __arch_prepare_bpf_trampoline(&ctx, im, m, tlinks, func_addr, flags);
|
||||
if (ret > 0 && validate_code(&ctx) < 0) {
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (validate_code(&ctx) < 0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1726,7 +1764,6 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
|
|||
goto out;
|
||||
}
|
||||
|
||||
bpf_flush_icache(ro_image, ro_image_end);
|
||||
out:
|
||||
kvfree(image);
|
||||
return ret < 0 ? ret : size;
|
||||
|
|
@ -1744,8 +1781,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
|
|||
|
||||
ret = __arch_prepare_bpf_trampoline(&ctx, &im, m, tlinks, func_addr, flags);
|
||||
|
||||
/* Page align */
|
||||
return ret < 0 ? ret : round_up(ret * LOONGARCH_INSN_SIZE, PAGE_SIZE);
|
||||
return ret < 0 ? ret : ret * LOONGARCH_INSN_SIZE;
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user