Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'loongarch-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson

Pull LoongArch updates from Huacai Chen:

- Switch to relative exception tables

- Add unaligned access support

- Add alternative runtime patching mechanism

- Add FDT booting support from efi system table

- Add suspend/hibernation (ACPI S3/S4) support

- Add basic STACKPROTECTOR support

- Add ftrace (function tracer) support

- Update the default config file

* tag 'loongarch-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson: (24 commits)
LoongArch: Update Loongson-3 default config file
LoongArch: modules/ftrace: Initialize PLT at load time
LoongArch/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support
LoongArch/ftrace: Add HAVE_DYNAMIC_FTRACE_WITH_ARGS support
LoongArch/ftrace: Add HAVE_DYNAMIC_FTRACE_WITH_REGS support
LoongArch/ftrace: Add dynamic function graph tracer support
LoongArch/ftrace: Add dynamic function tracer support
LoongArch/ftrace: Add recordmcount support
LoongArch/ftrace: Add basic support
LoongArch: module: Use got/plt section indices for relocations
LoongArch: Add basic STACKPROTECTOR support
LoongArch: Add hibernation (ACPI S4) support
LoongArch: Add suspend (ACPI S3) support
LoongArch: Add processing ISA Node in DeviceTree
LoongArch: Add FDT booting support from efi system table
LoongArch: Use alternative to optimize libraries
LoongArch: Add alternative runtime patching mechanism
LoongArch: Add unaligned access support
LoongArch: BPF: Add BPF exception tables
LoongArch: Remove the .fixup section usage
...

+3645 -187
+4 -4
Documentation/admin-guide/sysctl/kernel.rst
··· 436 436 437 437 On architectures where unaligned accesses cause traps, and where this 438 438 feature is supported (``CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN``; 439 - currently, ``arc`` and ``ia64``), controls whether all unaligned traps 440 - are logged. 439 + currently, ``arc``, ``ia64`` and ``loongarch``), controls whether all 440 + unaligned traps are logged. 441 441 442 442 = ============================================================= 443 443 0 Log all unaligned accesses. ··· 1492 1492 1493 1493 On architectures where unaligned accesses cause traps, and where this 1494 1494 feature is supported (``CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW``; currently, 1495 - ``arc`` and ``parisc``), controls whether unaligned traps are caught 1496 - and emulated (instead of failing). 1495 + ``arc``, ``parisc`` and ``loongarch``), controls whether unaligned traps 1496 + are caught and emulated (instead of failing). 1497 1497 1498 1498 = ======================================================== 1499 1499 0 Do not emulate unaligned accesses.
+20
arch/loongarch/Kconfig
··· 58 58 select ARCH_WANTS_NO_INSTR 59 59 select BUILDTIME_TABLE_SORT 60 60 select COMMON_CLK 61 + select CPU_PM 61 62 select EFI 62 63 select GENERIC_CLOCKEVENTS 63 64 select GENERIC_CMOS_UPDATE ··· 87 86 select HAVE_ARCH_TRANSPARENT_HUGEPAGE 88 87 select HAVE_ASM_MODVERSIONS 89 88 select HAVE_CONTEXT_TRACKING_USER 89 + select HAVE_C_RECORDMCOUNT 90 90 select HAVE_DEBUG_STACKOVERFLOW 91 91 select HAVE_DMA_CONTIGUOUS 92 + select HAVE_DYNAMIC_FTRACE 93 + select HAVE_DYNAMIC_FTRACE_WITH_ARGS 94 + select HAVE_DYNAMIC_FTRACE_WITH_REGS 92 95 select HAVE_EBPF_JIT 93 96 select HAVE_EXIT_THREAD 94 97 select HAVE_FAST_GUP 98 + select HAVE_FTRACE_MCOUNT_RECORD 99 + select HAVE_FUNCTION_GRAPH_TRACER 100 + select HAVE_FUNCTION_TRACER 95 101 select HAVE_GENERIC_VDSO 96 102 select HAVE_IOREMAP_PROT 97 103 select HAVE_IRQ_EXIT_ON_IRQ_STACK ··· 112 104 select HAVE_REGS_AND_STACK_ACCESS_API 113 105 select HAVE_RSEQ 114 106 select HAVE_SETUP_PER_CPU_AREA if NUMA 107 + select HAVE_STACKPROTECTOR 115 108 select HAVE_SYSCALL_TRACEPOINTS 116 109 select HAVE_TIF_NOHZ 117 110 select HAVE_VIRT_CPU_ACCOUNTING_GEN if !SMP ··· 122 113 select MODULES_USE_ELF_RELA if MODULES 123 114 select NEED_PER_CPU_EMBED_FIRST_CHUNK 124 115 select NEED_PER_CPU_PAGE_FIRST_CHUNK 116 + select OF 117 + select OF_EARLY_FLATTREE 125 118 select PCI 126 119 select PCI_DOMAINS_GENERIC 127 120 select PCI_ECAM if ACPI ··· 134 123 select RTC_LIB 135 124 select SMP 136 125 select SPARSE_IRQ 126 + select SYSCTL_ARCH_UNALIGN_ALLOW 127 + select SYSCTL_ARCH_UNALIGN_NO_WARN 137 128 select SYSCTL_EXCEPTION_TRACE 138 129 select SWIOTLB 139 130 select TRACE_IRQFLAGS_SUPPORT ··· 529 516 530 517 menu "Power management options" 531 518 519 + config ARCH_SUSPEND_POSSIBLE 520 + def_bool y 521 + 522 + config ARCH_HIBERNATION_POSSIBLE 523 + def_bool y 524 + 525 + source "kernel/power/Kconfig" 532 526 source "drivers/acpi/Kconfig" 533 527 534 528 endmenu
+8
arch/loongarch/Makefile
··· 25 25 32bit-emul = elf32loongarch 26 26 64bit-emul = elf64loongarch 27 27 28 + ifdef CONFIG_DYNAMIC_FTRACE 29 + KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY 30 + CC_FLAGS_FTRACE := -fpatchable-function-entry=2 31 + endif 32 + 28 33 ifdef CONFIG_64BIT 29 34 tool-archpref = $(64bit-tool-archpref) 30 35 UTS_MACHINE := loongarch64 ··· 108 103 109 104 libs-y += arch/loongarch/lib/ 110 105 libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a 106 + 107 + # suspend and hibernation support 108 + drivers-$(CONFIG_PM) += arch/loongarch/power/ 111 109 112 110 ifeq ($(KBUILD_EXTMOD),) 113 111 prepare: vdso_prepare
+32 -24
arch/loongarch/configs/loongson3_defconfig
··· 34 34 CONFIG_RELAY=y 35 35 CONFIG_BLK_DEV_INITRD=y 36 36 CONFIG_EXPERT=y 37 - CONFIG_USERFAULTFD=y 37 + CONFIG_KALLSYMS_ALL=y 38 38 CONFIG_PERF_EVENTS=y 39 - # CONFIG_COMPAT_BRK is not set 40 39 CONFIG_LOONGARCH=y 41 40 CONFIG_64BIT=y 42 41 CONFIG_MACH_LOONGSON64=y 42 + CONFIG_PAGE_SIZE_16KB=y 43 + CONFIG_HZ_250=y 43 44 CONFIG_DMI=y 44 45 CONFIG_EFI=y 45 46 CONFIG_SMP=y ··· 48 47 CONFIG_NR_CPUS=64 49 48 CONFIG_NUMA=y 50 49 CONFIG_KEXEC=y 51 - CONFIG_PAGE_SIZE_16KB=y 52 - CONFIG_HZ_250=y 50 + CONFIG_SUSPEND=y 51 + CONFIG_HIBERNATION=y 53 52 CONFIG_ACPI=y 54 53 CONFIG_ACPI_SPCR_TABLE=y 55 - CONFIG_ACPI_HOTPLUG_CPU=y 56 54 CONFIG_ACPI_TAD=y 57 55 CONFIG_ACPI_DOCK=y 58 56 CONFIG_ACPI_IPMI=m 57 + CONFIG_ACPI_HOTPLUG_CPU=y 59 58 CONFIG_ACPI_PCI_SLOT=y 60 59 CONFIG_ACPI_HOTPLUG_MEMORY=y 61 60 CONFIG_EFI_ZBOOT=y ··· 74 73 CONFIG_IOSCHED_BFQ=y 75 74 CONFIG_BFQ_GROUP_IOSCHED=y 76 75 CONFIG_BINFMT_MISC=m 76 + CONFIG_ZPOOL=y 77 + CONFIG_ZSWAP=y 78 + CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y 79 + CONFIG_ZBUD=y 80 + CONFIG_Z3FOLD=y 81 + CONFIG_ZSMALLOC=m 82 + # CONFIG_COMPAT_BRK is not set 77 83 CONFIG_MEMORY_HOTPLUG=y 78 84 CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y 79 85 CONFIG_MEMORY_HOTREMOVE=y 80 86 CONFIG_KSM=y 81 87 CONFIG_TRANSPARENT_HUGEPAGE=y 82 - CONFIG_ZSWAP=y 83 - CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y 84 - CONFIG_ZPOOL=y 85 - CONFIG_ZBUD=y 86 - CONFIG_Z3FOLD=y 87 - CONFIG_ZSMALLOC=m 88 + CONFIG_USERFAULTFD=y 88 89 CONFIG_NET=y 89 90 CONFIG_PACKET=y 90 91 CONFIG_UNIX=y ··· 121 118 CONFIG_BRIDGE_NETFILTER=m 122 119 CONFIG_NETFILTER_NETLINK_LOG=m 123 120 CONFIG_NF_CONNTRACK=m 124 - CONFIG_NF_LOG_NETDEV=m 125 121 CONFIG_NF_CONNTRACK_AMANDA=m 126 122 CONFIG_NF_CONNTRACK_FTP=m 127 123 CONFIG_NF_CONNTRACK_NETBIOS_NS=m ··· 418 416 CONFIG_ATA=y 419 417 CONFIG_SATA_AHCI=y 420 418 CONFIG_SATA_AHCI_PLATFORM=y 419 + CONFIG_AHCI_DWC=y 421 420 CONFIG_PATA_ATIIXP=y 422 421 CONFIG_PATA_PCMCIA=m 423 422 CONFIG_MD=y ··· 472 469 # CONFIG_NET_VENDOR_ARC is not set 473 470 # CONFIG_NET_VENDOR_ATHEROS is not set 474 471 CONFIG_BNX2=y 475 - # CONFIG_NET_VENDOR_BROCADE is not set 476 472 # CONFIG_NET_VENDOR_CAVIUM is not set 477 473 CONFIG_CHELSIO_T1=m 478 474 CONFIG_CHELSIO_T1_1G=y 479 475 CONFIG_CHELSIO_T3=m 480 476 CONFIG_CHELSIO_T4=m 481 - # CONFIG_NET_VENDOR_CIRRUS is not set 482 477 # CONFIG_NET_VENDOR_CISCO is not set 483 478 # CONFIG_NET_VENDOR_DEC is not set 484 479 # CONFIG_NET_VENDOR_DLINK is not set ··· 497 496 # CONFIG_NET_VENDOR_NVIDIA is not set 498 497 # CONFIG_NET_VENDOR_OKI is not set 499 498 # CONFIG_NET_VENDOR_QLOGIC is not set 499 + # CONFIG_NET_VENDOR_BROCADE is not set 500 500 # CONFIG_NET_VENDOR_QUALCOMM is not set 501 501 # CONFIG_NET_VENDOR_RDC is not set 502 502 CONFIG_8139CP=m ··· 507 505 # CONFIG_NET_VENDOR_ROCKER is not set 508 506 # CONFIG_NET_VENDOR_SAMSUNG is not set 509 507 # CONFIG_NET_VENDOR_SEEQ is not set 510 - # CONFIG_NET_VENDOR_SOLARFLARE is not set 511 508 # CONFIG_NET_VENDOR_SILAN is not set 512 509 # CONFIG_NET_VENDOR_SIS is not set 510 + # CONFIG_NET_VENDOR_SOLARFLARE is not set 513 511 # CONFIG_NET_VENDOR_SMSC is not set 514 512 CONFIG_STMMAC_ETH=y 515 513 # CONFIG_NET_VENDOR_SUN is not set ··· 590 588 CONFIG_SERIAL_8250_MANY_PORTS=y 591 589 CONFIG_SERIAL_8250_SHARE_IRQ=y 592 590 CONFIG_SERIAL_8250_RSA=y 591 + CONFIG_SERIAL_OF_PLATFORM=y 593 592 CONFIG_SERIAL_NONSTANDARD=y 594 593 CONFIG_PRINTER=m 595 594 CONFIG_VIRTIO_CONSOLE=y ··· 605 602 CONFIG_SPI=y 606 603 CONFIG_GPIO_SYSFS=y 607 604 CONFIG_GPIO_LOONGSON=y 605 + CONFIG_POWER_RESET=y 606 + CONFIG_POWER_RESET_RESTART=y 607 + CONFIG_POWER_RESET_SYSCON=y 608 + CONFIG_POWER_RESET_SYSCON_POWEROFF=y 609 + CONFIG_SYSCON_REBOOT_MODE=y 608 610 CONFIG_SENSORS_LM75=m 609 611 CONFIG_SENSORS_LM93=m 610 612 CONFIG_SENSORS_W83795=m ··· 617 609 CONFIG_RC_CORE=m 618 610 CONFIG_LIRC=y 619 611 CONFIG_RC_DECODERS=y 612 + CONFIG_IR_IMON_DECODER=m 613 + CONFIG_IR_JVC_DECODER=m 614 + CONFIG_IR_MCE_KBD_DECODER=m 620 615 CONFIG_IR_NEC_DECODER=m 621 616 CONFIG_IR_RC5_DECODER=m 622 617 CONFIG_IR_RC6_DECODER=m 623 - CONFIG_IR_JVC_DECODER=m 624 - CONFIG_IR_SONY_DECODER=m 625 618 CONFIG_IR_SANYO_DECODER=m 626 619 CONFIG_IR_SHARP_DECODER=m 627 - CONFIG_IR_MCE_KBD_DECODER=m 620 + CONFIG_IR_SONY_DECODER=m 628 621 CONFIG_IR_XMP_DECODER=m 629 - CONFIG_IR_IMON_DECODER=m 630 622 CONFIG_MEDIA_SUPPORT=m 631 623 CONFIG_MEDIA_USB_SUPPORT=y 632 624 CONFIG_USB_VIDEO_CLASS=m ··· 646 638 CONFIG_FB=y 647 639 CONFIG_FB_EFI=y 648 640 CONFIG_FB_RADEON=y 641 + CONFIG_LCD_CLASS_DEVICE=y 649 642 CONFIG_LCD_PLATFORM=m 650 643 # CONFIG_VGA_CONSOLE is not set 651 644 CONFIG_FRAMEBUFFER_CONSOLE=y ··· 656 647 CONFIG_SND=y 657 648 CONFIG_SND_SEQUENCER=m 658 649 CONFIG_SND_SEQ_DUMMY=m 659 - # CONFIG_SND_ISA is not set 660 650 CONFIG_SND_BT87X=m 661 651 CONFIG_SND_BT87X_OVERCLOCK=y 662 652 CONFIG_SND_HDA_INTEL=y ··· 826 818 # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set 827 819 CONFIG_CRYPTO_PCRYPT=m 828 820 CONFIG_CRYPTO_CRYPTD=m 829 - CONFIG_CRYPTO_CHACHA20POLY1305=m 830 - CONFIG_CRYPTO_HMAC=y 831 - CONFIG_CRYPTO_VMAC=m 832 - CONFIG_CRYPTO_WP512=m 833 821 CONFIG_CRYPTO_ANUBIS=m 834 822 CONFIG_CRYPTO_BLOWFISH=m 835 823 CONFIG_CRYPTO_CAST5=m ··· 835 831 CONFIG_CRYPTO_SERPENT=m 836 832 CONFIG_CRYPTO_TEA=m 837 833 CONFIG_CRYPTO_TWOFISH=m 834 + CONFIG_CRYPTO_CHACHA20POLY1305=m 835 + CONFIG_CRYPTO_VMAC=m 836 + CONFIG_CRYPTO_WP512=m 838 837 CONFIG_CRYPTO_DEFLATE=m 839 838 CONFIG_CRYPTO_LZO=m 840 839 CONFIG_CRYPTO_842=m ··· 851 844 CONFIG_PRINTK_TIME=y 852 845 CONFIG_STRIP_ASM_SYMS=y 853 846 CONFIG_MAGIC_SYSRQ=y 847 + CONFIG_DEBUG_FS=y 854 848 # CONFIG_SCHED_DEBUG is not set 855 849 CONFIG_SCHEDSTATS=y 856 850 # CONFIG_DEBUG_PREEMPT is not set
+10
arch/loongarch/include/asm/acpi.h
··· 35 35 36 36 #define ACPI_TABLE_UPGRADE_MAX_PHYS ARCH_LOW_ADDRESS_LIMIT 37 37 38 + extern int loongarch_acpi_suspend(void); 39 + extern int (*acpi_suspend_lowlevel)(void); 40 + extern void loongarch_suspend_enter(void); 41 + 42 + static inline unsigned long acpi_get_wakeup_address(void) 43 + { 44 + extern void loongarch_wakeup_start(void); 45 + return (unsigned long)loongarch_wakeup_start; 46 + } 47 + 38 48 #endif /* _ASM_LOONGARCH_ACPI_H */
+82
arch/loongarch/include/asm/alternative-asm.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _ASM_ALTERNATIVE_ASM_H 3 + #define _ASM_ALTERNATIVE_ASM_H 4 + 5 + #ifdef __ASSEMBLY__ 6 + 7 + #include <asm/asm.h> 8 + 9 + /* 10 + * Issue one struct alt_instr descriptor entry (need to put it into 11 + * the section .altinstructions, see below). This entry contains 12 + * enough information for the alternatives patching code to patch an 13 + * instruction. See apply_alternatives(). 14 + */ 15 + .macro altinstruction_entry orig alt feature orig_len alt_len 16 + .long \orig - . 17 + .long \alt - . 18 + .short \feature 19 + .byte \orig_len 20 + .byte \alt_len 21 + .endm 22 + 23 + /* 24 + * Define an alternative between two instructions. If @feature is 25 + * present, early code in apply_alternatives() replaces @oldinstr with 26 + * @newinstr. ".fill" directive takes care of proper instruction padding 27 + * in case @newinstr is longer than @oldinstr. 28 + */ 29 + .macro ALTERNATIVE oldinstr, newinstr, feature 30 + 140 : 31 + \oldinstr 32 + 141 : 33 + .fill - (((144f-143f)-(141b-140b)) > 0) * ((144f-143f)-(141b-140b)) / 4, 4, 0x03400000 34 + 142 : 35 + 36 + .pushsection .altinstructions, "a" 37 + altinstruction_entry 140b, 143f, \feature, 142b-140b, 144f-143f 38 + .popsection 39 + 40 + .subsection 1 41 + 143 : 42 + \newinstr 43 + 144 : 44 + .previous 45 + .endm 46 + 47 + #define old_len (141b-140b) 48 + #define new_len1 (144f-143f) 49 + #define new_len2 (145f-144f) 50 + 51 + #define alt_max_short(a, b) ((a) ^ (((a) ^ (b)) & -(-((a) < (b))))) 52 + 53 + /* 54 + * Same as ALTERNATIVE macro above but for two alternatives. If CPU 55 + * has @feature1, it replaces @oldinstr with @newinstr1. If CPU has 56 + * @feature2, it replaces @oldinstr with @feature2. 57 + */ 58 + .macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2 59 + 140 : 60 + \oldinstr 61 + 141 : 62 + .fill - ((alt_max_short(new_len1, new_len2) - (old_len)) > 0) * \ 63 + (alt_max_short(new_len1, new_len2) - (old_len)) / 4, 4, 0x03400000 64 + 142 : 65 + 66 + .pushsection .altinstructions, "a" 67 + altinstruction_entry 140b, 143f, \feature1, 142b-140b, 144f-143f, 142b-141b 68 + altinstruction_entry 140b, 144f, \feature2, 142b-140b, 145f-144f, 142b-141b 69 + .popsection 70 + 71 + .subsection 1 72 + 143 : 73 + \newinstr1 74 + 144 : 75 + \newinstr2 76 + 145 : 77 + .previous 78 + .endm 79 + 80 + #endif /* __ASSEMBLY__ */ 81 + 82 + #endif /* _ASM_ALTERNATIVE_ASM_H */
+111
arch/loongarch/include/asm/alternative.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _ASM_ALTERNATIVE_H 3 + #define _ASM_ALTERNATIVE_H 4 + 5 + #ifndef __ASSEMBLY__ 6 + 7 + #include <linux/types.h> 8 + #include <linux/stddef.h> 9 + #include <linux/stringify.h> 10 + #include <asm/asm.h> 11 + 12 + struct alt_instr { 13 + s32 instr_offset; /* offset to original instruction */ 14 + s32 replace_offset; /* offset to replacement instruction */ 15 + u16 feature; /* feature bit set for replacement */ 16 + u8 instrlen; /* length of original instruction */ 17 + u8 replacementlen; /* length of new instruction */ 18 + } __packed; 19 + 20 + /* 21 + * Debug flag that can be tested to see whether alternative 22 + * instructions were patched in already: 23 + */ 24 + extern int alternatives_patched; 25 + extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; 26 + 27 + extern void alternative_instructions(void); 28 + extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); 29 + 30 + #define b_replacement(num) "664"#num 31 + #define e_replacement(num) "665"#num 32 + 33 + #define alt_end_marker "663" 34 + #define alt_slen "662b-661b" 35 + #define alt_total_slen alt_end_marker"b-661b" 36 + #define alt_rlen(num) e_replacement(num)"f-"b_replacement(num)"f" 37 + 38 + #define __OLDINSTR(oldinstr, num) \ 39 + "661:\n\t" oldinstr "\n662:\n" \ 40 + ".fill -(((" alt_rlen(num) ")-(" alt_slen ")) > 0) * " \ 41 + "((" alt_rlen(num) ")-(" alt_slen ")) / 4, 4, 0x03400000\n" 42 + 43 + #define OLDINSTR(oldinstr, num) \ 44 + __OLDINSTR(oldinstr, num) \ 45 + alt_end_marker ":\n" 46 + 47 + #define alt_max_short(a, b) "((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") < (" b ")))))" 48 + 49 + /* 50 + * Pad the second replacement alternative with additional NOPs if it is 51 + * additionally longer than the first replacement alternative. 52 + */ 53 + #define OLDINSTR_2(oldinstr, num1, num2) \ 54 + "661:\n\t" oldinstr "\n662:\n" \ 55 + ".fill -((" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")) > 0) * " \ 56 + "(" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")) / 4, " \ 57 + "4, 0x03400000\n" \ 58 + alt_end_marker ":\n" 59 + 60 + #define ALTINSTR_ENTRY(feature, num) \ 61 + " .long 661b - .\n" /* label */ \ 62 + " .long " b_replacement(num)"f - .\n" /* new instruction */ \ 63 + " .short " __stringify(feature) "\n" /* feature bit */ \ 64 + " .byte " alt_total_slen "\n" /* source len */ \ 65 + " .byte " alt_rlen(num) "\n" /* replacement len */ 66 + 67 + #define ALTINSTR_REPLACEMENT(newinstr, feature, num) /* replacement */ \ 68 + b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n\t" 69 + 70 + /* alternative assembly primitive: */ 71 + #define ALTERNATIVE(oldinstr, newinstr, feature) \ 72 + OLDINSTR(oldinstr, 1) \ 73 + ".pushsection .altinstructions,\"a\"\n" \ 74 + ALTINSTR_ENTRY(feature, 1) \ 75 + ".popsection\n" \ 76 + ".subsection 1\n" \ 77 + ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ 78 + ".previous\n" 79 + 80 + #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\ 81 + OLDINSTR_2(oldinstr, 1, 2) \ 82 + ".pushsection .altinstructions,\"a\"\n" \ 83 + ALTINSTR_ENTRY(feature1, 1) \ 84 + ALTINSTR_ENTRY(feature2, 2) \ 85 + ".popsection\n" \ 86 + ".subsection 1\n" \ 87 + ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \ 88 + ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \ 89 + ".previous\n" 90 + 91 + /* 92 + * Alternative instructions for different CPU types or capabilities. 93 + * 94 + * This allows to use optimized instructions even on generic binary 95 + * kernels. 96 + * 97 + * length of oldinstr must be longer or equal the length of newinstr 98 + * It can be padded with nops as needed. 99 + * 100 + * For non barrier like inlines please define new variants 101 + * without volatile and memory clobber. 102 + */ 103 + #define alternative(oldinstr, newinstr, feature) \ 104 + (asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")) 105 + 106 + #define alternative_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \ 107 + (asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) ::: "memory")) 108 + 109 + #endif /* __ASSEMBLY__ */ 110 + 111 + #endif /* _ASM_ALTERNATIVE_H */
+65
arch/loongarch/include/asm/asm-extable.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef __ASM_ASM_EXTABLE_H 3 + #define __ASM_ASM_EXTABLE_H 4 + 5 + #define EX_TYPE_NONE 0 6 + #define EX_TYPE_FIXUP 1 7 + #define EX_TYPE_UACCESS_ERR_ZERO 2 8 + #define EX_TYPE_BPF 3 9 + 10 + #ifdef __ASSEMBLY__ 11 + 12 + #define __ASM_EXTABLE_RAW(insn, fixup, type, data) \ 13 + .pushsection __ex_table, "a"; \ 14 + .balign 4; \ 15 + .long ((insn) - .); \ 16 + .long ((fixup) - .); \ 17 + .short (type); \ 18 + .short (data); \ 19 + .popsection; 20 + 21 + .macro _asm_extable, insn, fixup 22 + __ASM_EXTABLE_RAW(\insn, \fixup, EX_TYPE_FIXUP, 0) 23 + .endm 24 + 25 + #else /* __ASSEMBLY__ */ 26 + 27 + #include <linux/bits.h> 28 + #include <linux/stringify.h> 29 + #include <asm/gpr-num.h> 30 + 31 + #define __ASM_EXTABLE_RAW(insn, fixup, type, data) \ 32 + ".pushsection __ex_table, \"a\"\n" \ 33 + ".balign 4\n" \ 34 + ".long ((" insn ") - .)\n" \ 35 + ".long ((" fixup ") - .)\n" \ 36 + ".short (" type ")\n" \ 37 + ".short (" data ")\n" \ 38 + ".popsection\n" 39 + 40 + #define _ASM_EXTABLE(insn, fixup) \ 41 + __ASM_EXTABLE_RAW(#insn, #fixup, __stringify(EX_TYPE_FIXUP), "0") 42 + 43 + #define EX_DATA_REG_ERR_SHIFT 0 44 + #define EX_DATA_REG_ERR GENMASK(4, 0) 45 + #define EX_DATA_REG_ZERO_SHIFT 5 46 + #define EX_DATA_REG_ZERO GENMASK(9, 5) 47 + 48 + #define EX_DATA_REG(reg, gpr) \ 49 + "((.L__gpr_num_" #gpr ") << " __stringify(EX_DATA_REG_##reg##_SHIFT) ")" 50 + 51 + #define _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, zero) \ 52 + __DEFINE_ASM_GPR_NUMS \ 53 + __ASM_EXTABLE_RAW(#insn, #fixup, \ 54 + __stringify(EX_TYPE_UACCESS_ERR_ZERO), \ 55 + "(" \ 56 + EX_DATA_REG(ERR, err) " | " \ 57 + EX_DATA_REG(ZERO, zero) \ 58 + ")") 59 + 60 + #define _ASM_EXTABLE_UACCESS_ERR(insn, fixup, err) \ 61 + _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, zero) 62 + 63 + #endif /* __ASSEMBLY__ */ 64 + 65 + #endif /* __ASM_ASM_EXTABLE_H */
+1
arch/loongarch/include/asm/bootinfo.h
··· 32 32 int cores_per_node; 33 33 int cores_per_package; 34 34 unsigned long cores_io_master; 35 + unsigned long suspend_addr; 35 36 const char *cpuname; 36 37 }; 37 38
+15
arch/loongarch/include/asm/bugs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * This is included by init/main.c to check for architecture-dependent bugs. 4 + * 5 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 6 + */ 7 + #ifndef _ASM_BUGS_H 8 + #define _ASM_BUGS_H 9 + 10 + #include <asm/cpu.h> 11 + #include <asm/cpu-info.h> 12 + 13 + extern void check_bugs(void); 14 + 15 + #endif /* _ASM_BUGS_H */
+1
arch/loongarch/include/asm/efi.h
··· 9 9 10 10 void __init efi_init(void); 11 11 void __init efi_runtime_init(void); 12 + void __init *efi_fdt_pointer(void); 12 13 void efifb_setup_from_dmi(struct screen_info *si, const char *opt); 13 14 14 15 #define ARCH_EFI_IRQ_FLAGS_MASK 0x00000004 /* Bit 2: CSR.CRMD.IE */
+47
arch/loongarch/include/asm/extable.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _ASM_LOONGARCH_EXTABLE_H 3 + #define _ASM_LOONGARCH_EXTABLE_H 4 + 5 + /* 6 + * The exception table consists of pairs of relative offsets: the first 7 + * is the relative offset to an instruction that is allowed to fault, 8 + * and the second is the relative offset at which the program should 9 + * continue. No registers are modified, so it is entirely up to the 10 + * continuation code to figure out what to do. 11 + * 12 + * All the routines below use bits of fixup code that are out of line 13 + * with the main instruction path. This means when everything is well, 14 + * we don't even have to jump over them. Further, they do not intrude 15 + * on our cache or tlb entries. 16 + */ 17 + 18 + struct exception_table_entry { 19 + int insn, fixup; 20 + short type, data; 21 + }; 22 + 23 + #define ARCH_HAS_RELATIVE_EXTABLE 24 + 25 + #define swap_ex_entry_fixup(a, b, tmp, delta) \ 26 + do { \ 27 + (a)->fixup = (b)->fixup + (delta); \ 28 + (b)->fixup = (tmp).fixup - (delta); \ 29 + (a)->type = (b)->type; \ 30 + (b)->type = (tmp).type; \ 31 + (a)->data = (b)->data; \ 32 + (b)->data = (tmp).data; \ 33 + } while (0) 34 + 35 + #ifdef CONFIG_BPF_JIT 36 + bool ex_handler_bpf(const struct exception_table_entry *ex, struct pt_regs *regs); 37 + #else 38 + static inline 39 + bool ex_handler_bpf(const struct exception_table_entry *ex, struct pt_regs *regs) 40 + { 41 + return false; 42 + } 43 + #endif /* !CONFIG_BPF_JIT */ 44 + 45 + bool fixup_exception(struct pt_regs *regs); 46 + 47 + #endif
+68
arch/loongarch/include/asm/ftrace.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2022 Loongson Technology Corporation Limited 4 + */ 5 + 6 + #ifndef _ASM_LOONGARCH_FTRACE_H 7 + #define _ASM_LOONGARCH_FTRACE_H 8 + 9 + #define FTRACE_PLT_IDX 0 10 + #define FTRACE_REGS_PLT_IDX 1 11 + #define NR_FTRACE_PLTS 2 12 + 13 + #define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1])) 14 + 15 + #ifdef CONFIG_FUNCTION_TRACER 16 + 17 + #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ 18 + 19 + #ifndef __ASSEMBLY__ 20 + 21 + #ifndef CONFIG_DYNAMIC_FTRACE 22 + 23 + #define mcount _mcount 24 + extern void _mcount(void); 25 + extern void prepare_ftrace_return(unsigned long self_addr, unsigned long callsite_sp, unsigned long old); 26 + 27 + #else 28 + 29 + struct dyn_ftrace; 30 + struct dyn_arch_ftrace { }; 31 + 32 + #define ARCH_SUPPORTS_FTRACE_OPS 1 33 + #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR 34 + 35 + #define ftrace_init_nop ftrace_init_nop 36 + int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); 37 + 38 + static inline unsigned long ftrace_call_adjust(unsigned long addr) 39 + { 40 + return addr; 41 + } 42 + 43 + void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent); 44 + 45 + #endif /* CONFIG_DYNAMIC_FTRACE */ 46 + 47 + #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS 48 + struct ftrace_ops; 49 + 50 + struct ftrace_regs { 51 + struct pt_regs regs; 52 + }; 53 + 54 + static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) 55 + { 56 + return &fregs->regs; 57 + } 58 + 59 + #define ftrace_graph_func ftrace_graph_func 60 + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, 61 + struct ftrace_ops *op, struct ftrace_regs *fregs); 62 + #endif 63 + 64 + #endif /* __ASSEMBLY__ */ 65 + 66 + #endif /* CONFIG_FUNCTION_TRACER */ 67 + 68 + #endif /* _ASM_LOONGARCH_FTRACE_H */
+7 -20
arch/loongarch/include/asm/futex.h
··· 7 7 8 8 #include <linux/futex.h> 9 9 #include <linux/uaccess.h> 10 + #include <asm/asm-extable.h> 10 11 #include <asm/barrier.h> 11 12 #include <asm/errno.h> 12 13 ··· 19 18 "2: sc.w $t0, %2 \n" \ 20 19 " beqz $t0, 1b \n" \ 21 20 "3: \n" \ 22 - " .section .fixup,\"ax\" \n" \ 23 - "4: li.w %0, %6 \n" \ 24 - " b 3b \n" \ 25 - " .previous \n" \ 26 - " .section __ex_table,\"a\" \n" \ 27 - " "__UA_ADDR "\t1b, 4b \n" \ 28 - " "__UA_ADDR "\t2b, 4b \n" \ 29 - " .previous \n" \ 21 + _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0) \ 22 + _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0) \ 30 23 : "=r" (ret), "=&r" (oldval), \ 31 24 "=ZC" (*uaddr) \ 32 - : "0" (0), "ZC" (*uaddr), "Jr" (oparg), \ 33 - "i" (-EFAULT) \ 25 + : "0" (0), "ZC" (*uaddr), "Jr" (oparg) \ 34 26 : "memory", "t0"); \ 35 27 } 36 28 ··· 80 86 " beqz $t0, 1b \n" 81 87 "3: \n" 82 88 __WEAK_LLSC_MB 83 - " .section .fixup,\"ax\" \n" 84 - "4: li.d %0, %6 \n" 85 - " b 3b \n" 86 - " .previous \n" 87 - " .section __ex_table,\"a\" \n" 88 - " "__UA_ADDR "\t1b, 4b \n" 89 - " "__UA_ADDR "\t2b, 4b \n" 90 - " .previous \n" 89 + _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0) 90 + _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0) 91 91 : "+r" (ret), "=&r" (val), "=ZC" (*uaddr) 92 - : "ZC" (*uaddr), "Jr" (oldval), "Jr" (newval), 93 - "i" (-EFAULT) 92 + : "ZC" (*uaddr), "Jr" (oldval), "Jr" (newval) 94 93 : "memory", "t0"); 95 94 96 95 *uval = val;
+22
arch/loongarch/include/asm/gpr-num.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef __ASM_GPR_NUM_H 3 + #define __ASM_GPR_NUM_H 4 + 5 + #ifdef __ASSEMBLY__ 6 + 7 + .equ .L__gpr_num_zero, 0 8 + .irp num,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 9 + .equ .L__gpr_num_$r\num, \num 10 + .endr 11 + 12 + #else /* __ASSEMBLY__ */ 13 + 14 + #define __DEFINE_ASM_GPR_NUMS \ 15 + " .equ .L__gpr_num_zero, 0\n" \ 16 + " .irp num,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31\n" \ 17 + " .equ .L__gpr_num_$r\\num, \\num\n" \ 18 + " .endr\n" \ 19 + 20 + #endif /* __ASSEMBLY__ */ 21 + 22 + #endif /* __ASM_GPR_NUM_H */
+46
arch/loongarch/include/asm/inst.h
··· 8 8 #include <linux/types.h> 9 9 #include <asm/asm.h> 10 10 11 + #define INSN_NOP 0x03400000 11 12 #define INSN_BREAK 0x002a0000 12 13 13 14 #define ADDR_IMMMASK_LU52ID 0xFFF0000000000000 14 15 #define ADDR_IMMMASK_LU32ID 0x000FFFFF00000000 16 + #define ADDR_IMMMASK_LU12IW 0x00000000FFFFF000 15 17 #define ADDR_IMMMASK_ADDU16ID 0x00000000FFFF0000 16 18 17 19 #define ADDR_IMMSHIFT_LU52ID 52 18 20 #define ADDR_IMMSHIFT_LU32ID 32 21 + #define ADDR_IMMSHIFT_LU12IW 12 19 22 #define ADDR_IMMSHIFT_ADDU16ID 16 20 23 21 24 #define ADDR_IMM(addr, INSN) ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN) ··· 31 28 enum reg1i20_op { 32 29 lu12iw_op = 0x0a, 33 30 lu32id_op = 0x0b, 31 + pcaddi_op = 0x0c, 34 32 pcaddu12i_op = 0x0e, 35 33 pcaddu18i_op = 0x0f, 36 34 }; ··· 39 35 enum reg1i21_op { 40 36 beqz_op = 0x10, 41 37 bnez_op = 0x11, 38 + bceqz_op = 0x12, /* bits[9:8] = 0x00 */ 39 + bcnez_op = 0x12, /* bits[9:8] = 0x01 */ 42 40 }; 43 41 44 42 enum reg2_op { ··· 82 76 ldbu_op = 0xa8, 83 77 ldhu_op = 0xa9, 84 78 ldwu_op = 0xaa, 79 + flds_op = 0xac, 80 + fsts_op = 0xad, 81 + fldd_op = 0xae, 82 + fstd_op = 0xaf, 85 83 }; 86 84 87 85 enum reg2i14_op { ··· 156 146 ldxbu_op = 0x7040, 157 147 ldxhu_op = 0x7048, 158 148 ldxwu_op = 0x7050, 149 + fldxs_op = 0x7060, 150 + fldxd_op = 0x7068, 151 + fstxs_op = 0x7070, 152 + fstxd_op = 0x7078, 159 153 amswapw_op = 0x70c0, 160 154 amswapd_op = 0x70c1, 161 155 amaddw_op = 0x70c2, ··· 321 307 return val & (1UL << (bit - 1)); 322 308 } 323 309 310 + static inline bool is_pc_ins(union loongarch_instruction *ip) 311 + { 312 + return ip->reg1i20_format.opcode >= pcaddi_op && 313 + ip->reg1i20_format.opcode <= pcaddu18i_op; 314 + } 315 + 324 316 static inline bool is_branch_ins(union loongarch_instruction *ip) 325 317 { 326 318 return ip->reg1i21_format.opcode >= beqz_op && ··· 351 331 is_imm12_negative(ip->reg2i12_format.immediate); 352 332 } 353 333 334 + int larch_insn_read(void *addr, u32 *insnp); 335 + int larch_insn_write(void *addr, u32 insn); 336 + int larch_insn_patch_text(void *addr, u32 insn); 337 + 338 + u32 larch_insn_gen_nop(void); 339 + u32 larch_insn_gen_b(unsigned long pc, unsigned long dest); 340 + u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest); 341 + 342 + u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj, enum loongarch_gpr rk); 343 + u32 larch_insn_gen_move(enum loongarch_gpr rd, enum loongarch_gpr rj); 344 + 345 + u32 larch_insn_gen_lu12iw(enum loongarch_gpr rd, int imm); 354 346 u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm); 355 347 u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm); 356 348 u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest); ··· 375 343 static inline bool unsigned_imm_check(unsigned long val, unsigned int bit) 376 344 { 377 345 return val < (1UL << bit); 346 + } 347 + 348 + static inline unsigned long sign_extend(unsigned long val, unsigned int idx) 349 + { 350 + if (!is_imm_negative(val, idx + 1)) 351 + return ((1UL << idx) - 1) & val; 352 + else 353 + return ~((1UL << idx) - 1) | val; 378 354 } 379 355 380 356 #define DEF_EMIT_REG0I26_FORMAT(NAME, OP) \ ··· 605 565 } 606 566 607 567 DEF_EMIT_REG3SA2_FORMAT(alsld, alsld_op) 568 + 569 + struct pt_regs; 570 + 571 + void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned int *pc); 572 + unsigned long unaligned_read(void __user *addr, void *value, unsigned long n, bool sign); 573 + unsigned long unaligned_write(void __user *addr, unsigned long value, unsigned long n); 608 574 609 575 #endif /* _ASM_INST_H */
+3
arch/loongarch/include/asm/loongson.h
··· 136 136 #define ls7a_writel(val, addr) *(volatile unsigned int *)TO_UNCACHE(addr) = (val) 137 137 #define ls7a_writeq(val, addr) *(volatile unsigned long *)TO_UNCACHE(addr) = (val) 138 138 139 + void enable_gpe_wakeup(void); 140 + void enable_pci_wakeup(void); 141 + 139 142 #endif /* __ASM_LOONGSON_H */
+16 -11
arch/loongarch/include/asm/module.h
··· 11 11 #define RELA_STACK_DEPTH 16 12 12 13 13 struct mod_section { 14 - Elf_Shdr *shdr; 14 + int shndx; 15 15 int num_entries; 16 16 int max_entries; 17 17 }; ··· 20 20 struct mod_section got; 21 21 struct mod_section plt; 22 22 struct mod_section plt_idx; 23 + 24 + /* For CONFIG_DYNAMIC_FTRACE */ 25 + struct plt_entry *ftrace_trampolines; 23 26 }; 24 27 25 28 struct got_entry { ··· 40 37 Elf_Addr symbol_addr; 41 38 }; 42 39 43 - Elf_Addr module_emit_got_entry(struct module *mod, Elf_Addr val); 44 - Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Addr val); 40 + Elf_Addr module_emit_got_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val); 41 + Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val); 45 42 46 43 static inline struct got_entry emit_got_entry(Elf_Addr val) 47 44 { ··· 52 49 { 53 50 u32 lu12iw, lu32id, lu52id, jirl; 54 51 55 - lu12iw = (lu12iw_op << 25 | (((val >> 12) & 0xfffff) << 5) | LOONGARCH_GPR_T1); 52 + lu12iw = larch_insn_gen_lu12iw(LOONGARCH_GPR_T1, ADDR_IMM(val, LU12IW)); 56 53 lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val, LU32ID)); 57 54 lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1, LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID)); 58 55 jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xfff)); ··· 65 62 return (struct plt_idx_entry) { val }; 66 63 } 67 64 68 - static inline int get_plt_idx(unsigned long val, const struct mod_section *sec) 65 + static inline int get_plt_idx(unsigned long val, Elf_Shdr *sechdrs, const struct mod_section *sec) 69 66 { 70 67 int i; 71 - struct plt_idx_entry *plt_idx = (struct plt_idx_entry *)sec->shdr->sh_addr; 68 + struct plt_idx_entry *plt_idx = (struct plt_idx_entry *)sechdrs[sec->shndx].sh_addr; 72 69 73 70 for (i = 0; i < sec->num_entries; i++) { 74 71 if (plt_idx[i].symbol_addr == val) ··· 79 76 } 80 77 81 78 static inline struct plt_entry *get_plt_entry(unsigned long val, 82 - const struct mod_section *sec_plt, 83 - const struct mod_section *sec_plt_idx) 79 + Elf_Shdr *sechdrs, 80 + const struct mod_section *sec_plt, 81 + const struct mod_section *sec_plt_idx) 84 82 { 85 - int plt_idx = get_plt_idx(val, sec_plt_idx); 86 - struct plt_entry *plt = (struct plt_entry *)sec_plt->shdr->sh_addr; 83 + int plt_idx = get_plt_idx(val, sechdrs, sec_plt_idx); 84 + struct plt_entry *plt = (struct plt_entry *)sechdrs[sec_plt->shndx].sh_addr; 87 85 88 86 if (plt_idx < 0) 89 87 return NULL; ··· 93 89 } 94 90 95 91 static inline struct got_entry *get_got_entry(Elf_Addr val, 92 + Elf_Shdr *sechdrs, 96 93 const struct mod_section *sec) 97 94 { 98 - struct got_entry *got = (struct got_entry *)sec->shdr->sh_addr; 99 95 int i; 96 + struct got_entry *got = (struct got_entry *)sechdrs[sec->shndx].sh_addr; 100 97 101 98 for (i = 0; i < sec->num_entries; i++) 102 99 if (got[i].symbol_addr == val)
+1
arch/loongarch/include/asm/module.lds.h
··· 5 5 .got : { BYTE(0) } 6 6 .plt : { BYTE(0) } 7 7 .plt.idx : { BYTE(0) } 8 + .ftrace_trampoline : { BYTE(0) } 8 9 }
+1
arch/loongarch/include/asm/setup.h
··· 13 13 14 14 extern unsigned long eentry; 15 15 extern unsigned long tlbrentry; 16 + extern char init_command_line[COMMAND_LINE_SIZE]; 16 17 extern void tlb_init(int cpu); 17 18 extern void cpu_cache_init(void); 18 19 extern void cache_error_setup(void);
+38
arch/loongarch/include/asm/stackprotector.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * GCC stack protector support. 4 + * 5 + * Stack protector works by putting predefined pattern at the start of 6 + * the stack frame and verifying that it hasn't been overwritten when 7 + * returning from the function. The pattern is called stack canary and 8 + * on LoongArch gcc expects it to be defined by a global variable called 9 + * "__stack_chk_guard". 10 + */ 11 + 12 + #ifndef _ASM_STACKPROTECTOR_H 13 + #define _ASM_STACKPROTECTOR_H 14 + 15 + #include <linux/random.h> 16 + #include <linux/version.h> 17 + 18 + extern unsigned long __stack_chk_guard; 19 + 20 + /* 21 + * Initialize the stackprotector canary value. 22 + * 23 + * NOTE: this must only be called from functions that never return, 24 + * and it must always be inlined. 25 + */ 26 + static __always_inline void boot_init_stack_canary(void) 27 + { 28 + unsigned long canary; 29 + 30 + /* Try to get a semi random initial value. */ 31 + get_random_bytes(&canary, sizeof(canary)); 32 + canary ^= LINUX_VERSION_CODE; 33 + 34 + current->stack_canary = canary; 35 + __stack_chk_guard = current->stack_canary; 36 + } 37 + 38 + #endif /* _ASM_STACKPROTECTOR_H */
+5
arch/loongarch/include/asm/string.h
··· 5 5 #ifndef _ASM_STRING_H 6 6 #define _ASM_STRING_H 7 7 8 + #define __HAVE_ARCH_MEMSET 8 9 extern void *memset(void *__s, int __c, size_t __count); 10 + 11 + #define __HAVE_ARCH_MEMCPY 9 12 extern void *memcpy(void *__to, __const__ void *__from, size_t __n); 13 + 14 + #define __HAVE_ARCH_MEMMOVE 10 15 extern void *memmove(void *__dest, __const__ void *__src, size_t __n); 11 16 12 17 #endif /* _ASM_STRING_H */
+1 -1
arch/loongarch/include/asm/thread_info.h
··· 38 38 #define INIT_THREAD_INFO(tsk) \ 39 39 { \ 40 40 .task = &tsk, \ 41 - .flags = 0, \ 41 + .flags = _TIF_FIXADE, \ 42 42 .cpu = 0, \ 43 43 .preempt_count = INIT_PREEMPT_COUNT, \ 44 44 }
+1
arch/loongarch/include/asm/time.h
··· 12 12 extern u64 cpu_clock_freq; 13 13 extern u64 const_clock_freq; 14 14 15 + extern void save_counter(void); 15 16 extern void sync_counter(void); 16 17 17 18 static inline unsigned int calc_const_freq(void)
+6 -18
arch/loongarch/include/asm/uaccess.h
··· 15 15 #include <linux/string.h> 16 16 #include <linux/extable.h> 17 17 #include <asm/pgtable.h> 18 - #include <asm-generic/extable.h> 18 + #include <asm/extable.h> 19 + #include <asm/asm-extable.h> 19 20 #include <asm-generic/access_ok.h> 20 21 21 22 extern u64 __ua_limit; ··· 161 160 __asm__ __volatile__( \ 162 161 "1: " insn " %1, %2 \n" \ 163 162 "2: \n" \ 164 - " .section .fixup,\"ax\" \n" \ 165 - "3: li.w %0, %3 \n" \ 166 - " move %1, $zero \n" \ 167 - " b 2b \n" \ 168 - " .previous \n" \ 169 - " .section __ex_table,\"a\" \n" \ 170 - " "__UA_ADDR "\t1b, 3b \n" \ 171 - " .previous \n" \ 163 + _ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 2b, %0, %1) \ 172 164 : "+r" (__gu_err), "=r" (__gu_tmp) \ 173 - : "m" (__m(ptr)), "i" (-EFAULT)); \ 165 + : "m" (__m(ptr))); \ 174 166 \ 175 167 (val) = (__typeof__(*(ptr))) __gu_tmp; \ 176 168 } ··· 186 192 __asm__ __volatile__( \ 187 193 "1: " insn " %z2, %1 # __put_user_asm\n" \ 188 194 "2: \n" \ 189 - " .section .fixup,\"ax\" \n" \ 190 - "3: li.w %0, %3 \n" \ 191 - " b 2b \n" \ 192 - " .previous \n" \ 193 - " .section __ex_table,\"a\" \n" \ 194 - " " __UA_ADDR " 1b, 3b \n" \ 195 - " .previous \n" \ 195 + _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %0) \ 196 196 : "+r" (__pu_err), "=m" (__m(ptr)) \ 197 - : "Jr" (__pu_val), "i" (-EFAULT)); \ 197 + : "Jr" (__pu_val)); \ 198 198 } 199 199 200 200 #define __get_kernel_nofault(dst, src, type, err_label) \
+2 -1
arch/loongarch/include/asm/unwind.h
··· 20 20 char type; /* UNWINDER_XXX */ 21 21 struct stack_info stack_info; 22 22 struct task_struct *task; 23 - bool first, error; 23 + bool first, error, is_ftrace; 24 + int graph_idx; 24 25 unsigned long sp, pc, ra; 25 26 }; 26 27
+15 -1
arch/loongarch/kernel/Makefile
··· 7 7 8 8 obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \ 9 9 traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \ 10 - elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o 10 + elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o \ 11 + alternative.o unaligned.o 11 12 12 13 obj-$(CONFIG_ACPI) += acpi.o 13 14 obj-$(CONFIG_EFI) += efi.o 14 15 15 16 obj-$(CONFIG_CPU_HAS_FPU) += fpu.o 17 + 18 + ifdef CONFIG_FUNCTION_TRACER 19 + ifndef CONFIG_DYNAMIC_FTRACE 20 + obj-y += mcount.o ftrace.o 21 + CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) 22 + else 23 + obj-y += mcount_dyn.o ftrace_dyn.o 24 + CFLAGS_REMOVE_ftrace_dyn.o = $(CC_FLAGS_FTRACE) 25 + endif 26 + CFLAGS_REMOVE_inst.o = $(CC_FLAGS_FTRACE) 27 + CFLAGS_REMOVE_time.o = $(CC_FLAGS_FTRACE) 28 + CFLAGS_REMOVE_perf_event.o = $(CC_FLAGS_FTRACE) 29 + endif 16 30 17 31 obj-$(CONFIG_MODULES) += module.o module-sections.o 18 32 obj-$(CONFIG_STACKTRACE) += stacktrace.o
+15 -2
arch/loongarch/kernel/acpi.c
··· 12 12 #include <linux/irq.h> 13 13 #include <linux/irqdomain.h> 14 14 #include <linux/memblock.h> 15 + #include <linux/of_fdt.h> 15 16 #include <linux/serial_core.h> 16 17 #include <asm/io.h> 17 18 #include <asm/numa.h> ··· 140 139 loongson_sysconf.nr_cpus = num_processors; 141 140 } 142 141 142 + #ifndef CONFIG_SUSPEND 143 + int (*acpi_suspend_lowlevel)(void); 144 + #else 145 + int (*acpi_suspend_lowlevel)(void) = loongarch_acpi_suspend; 146 + #endif 147 + 143 148 void __init acpi_boot_table_init(void) 144 149 { 145 150 /* 146 151 * If acpi_disabled, bail out 147 152 */ 148 153 if (acpi_disabled) 149 - return; 154 + goto fdt_earlycon; 150 155 151 156 /* 152 157 * Initialize the ACPI boot-time table parser. 153 158 */ 154 159 if (acpi_table_init()) { 155 160 disable_acpi(); 156 - return; 161 + goto fdt_earlycon; 157 162 } 158 163 159 164 loongson_sysconf.boot_cpu_id = read_csr_cpuid(); ··· 171 164 172 165 /* Do not enable ACPI SPCR console by default */ 173 166 acpi_parse_spcr(earlycon_acpi_spcr_enable, false); 167 + 168 + return; 169 + 170 + fdt_earlycon: 171 + if (earlycon_acpi_spcr_enable) 172 + early_init_dt_scan_chosen_stdout(); 174 173 } 175 174 176 175 #ifdef CONFIG_ACPI_NUMA
+246
arch/loongarch/kernel/alternative.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #include <linux/mm.h> 3 + #include <linux/module.h> 4 + #include <asm/alternative.h> 5 + #include <asm/cacheflush.h> 6 + #include <asm/inst.h> 7 + #include <asm/sections.h> 8 + 9 + int __read_mostly alternatives_patched; 10 + 11 + EXPORT_SYMBOL_GPL(alternatives_patched); 12 + 13 + #define MAX_PATCH_SIZE (((u8)(-1)) / LOONGARCH_INSN_SIZE) 14 + 15 + static int __initdata_or_module debug_alternative; 16 + 17 + static int __init debug_alt(char *str) 18 + { 19 + debug_alternative = 1; 20 + return 1; 21 + } 22 + __setup("debug-alternative", debug_alt); 23 + 24 + #define DPRINTK(fmt, args...) \ 25 + do { \ 26 + if (debug_alternative) \ 27 + printk(KERN_DEBUG "%s: " fmt "\n", __func__, ##args); \ 28 + } while (0) 29 + 30 + #define DUMP_WORDS(buf, count, fmt, args...) \ 31 + do { \ 32 + if (unlikely(debug_alternative)) { \ 33 + int _j; \ 34 + union loongarch_instruction *_buf = buf; \ 35 + \ 36 + if (!(count)) \ 37 + break; \ 38 + \ 39 + printk(KERN_DEBUG fmt, ##args); \ 40 + for (_j = 0; _j < count - 1; _j++) \ 41 + printk(KERN_CONT "<%08x> ", _buf[_j].word); \ 42 + printk(KERN_CONT "<%08x>\n", _buf[_j].word); \ 43 + } \ 44 + } while (0) 45 + 46 + /* Use this to add nops to a buffer, then text_poke the whole buffer. */ 47 + static void __init_or_module add_nops(union loongarch_instruction *insn, int count) 48 + { 49 + while (count--) { 50 + insn->word = INSN_NOP; 51 + insn++; 52 + } 53 + } 54 + 55 + /* Is the jump addr in local .altinstructions */ 56 + static inline bool in_alt_jump(unsigned long jump, void *start, void *end) 57 + { 58 + return jump >= (unsigned long)start && jump < (unsigned long)end; 59 + } 60 + 61 + static void __init_or_module recompute_jump(union loongarch_instruction *buf, 62 + union loongarch_instruction *dest, union loongarch_instruction *src, 63 + void *start, void *end) 64 + { 65 + unsigned int si, si_l, si_h; 66 + unsigned long cur_pc, jump_addr, pc; 67 + long offset; 68 + 69 + cur_pc = (unsigned long)src; 70 + pc = (unsigned long)dest; 71 + 72 + si_l = src->reg0i26_format.immediate_l; 73 + si_h = src->reg0i26_format.immediate_h; 74 + switch (src->reg0i26_format.opcode) { 75 + case b_op: 76 + case bl_op: 77 + jump_addr = cur_pc + sign_extend((si_h << 16 | si_l) << 2, 27); 78 + if (in_alt_jump(jump_addr, start, end)) 79 + return; 80 + offset = jump_addr - pc; 81 + BUG_ON(offset < -SZ_128M || offset >= SZ_128M); 82 + offset >>= 2; 83 + buf->reg0i26_format.immediate_h = offset >> 16; 84 + buf->reg0i26_format.immediate_l = offset; 85 + return; 86 + } 87 + 88 + si_l = src->reg1i21_format.immediate_l; 89 + si_h = src->reg1i21_format.immediate_h; 90 + switch (src->reg1i21_format.opcode) { 91 + case bceqz_op: /* bceqz_op = bcnez_op */ 92 + BUG_ON(buf->reg1i21_format.rj & BIT(4)); 93 + fallthrough; 94 + case beqz_op: 95 + case bnez_op: 96 + jump_addr = cur_pc + sign_extend((si_h << 16 | si_l) << 2, 22); 97 + if (in_alt_jump(jump_addr, start, end)) 98 + return; 99 + offset = jump_addr - pc; 100 + BUG_ON(offset < -SZ_4M || offset >= SZ_4M); 101 + offset >>= 2; 102 + buf->reg1i21_format.immediate_h = offset >> 16; 103 + buf->reg1i21_format.immediate_l = offset; 104 + return; 105 + } 106 + 107 + si = src->reg2i16_format.immediate; 108 + switch (src->reg2i16_format.opcode) { 109 + case beq_op: 110 + case bne_op: 111 + case blt_op: 112 + case bge_op: 113 + case bltu_op: 114 + case bgeu_op: 115 + jump_addr = cur_pc + sign_extend(si << 2, 17); 116 + if (in_alt_jump(jump_addr, start, end)) 117 + return; 118 + offset = jump_addr - pc; 119 + BUG_ON(offset < -SZ_128K || offset >= SZ_128K); 120 + offset >>= 2; 121 + buf->reg2i16_format.immediate = offset; 122 + return; 123 + } 124 + } 125 + 126 + static int __init_or_module copy_alt_insns(union loongarch_instruction *buf, 127 + union loongarch_instruction *dest, union loongarch_instruction *src, int nr) 128 + { 129 + int i; 130 + 131 + for (i = 0; i < nr; i++) { 132 + buf[i].word = src[i].word; 133 + 134 + if (is_pc_ins(&src[i])) { 135 + pr_err("Not support pcrel instruction at present!"); 136 + return -EINVAL; 137 + } 138 + 139 + if (is_branch_ins(&src[i]) && 140 + src[i].reg2i16_format.opcode != jirl_op) { 141 + recompute_jump(&buf[i], &dest[i], &src[i], src, src + nr); 142 + } 143 + } 144 + 145 + return 0; 146 + } 147 + 148 + /* 149 + * text_poke_early - Update instructions on a live kernel at boot time 150 + * 151 + * When you use this code to patch more than one byte of an instruction 152 + * you need to make sure that other CPUs cannot execute this code in parallel. 153 + * Also no thread must be currently preempted in the middle of these 154 + * instructions. And on the local CPU you need to be protected again NMI or MCE 155 + * handlers seeing an inconsistent instruction while you patch. 156 + */ 157 + static void *__init_or_module text_poke_early(union loongarch_instruction *insn, 158 + union loongarch_instruction *buf, unsigned int nr) 159 + { 160 + int i; 161 + unsigned long flags; 162 + 163 + local_irq_save(flags); 164 + 165 + for (i = 0; i < nr; i++) 166 + insn[i].word = buf[i].word; 167 + 168 + local_irq_restore(flags); 169 + 170 + wbflush(); 171 + flush_icache_range((unsigned long)insn, (unsigned long)(insn + nr)); 172 + 173 + return insn; 174 + } 175 + 176 + /* 177 + * Replace instructions with better alternatives for this CPU type. This runs 178 + * before SMP is initialized to avoid SMP problems with self modifying code. 179 + * This implies that asymmetric systems where APs have less capabilities than 180 + * the boot processor are not handled. Tough. Make sure you disable such 181 + * features by hand. 182 + */ 183 + void __init_or_module apply_alternatives(struct alt_instr *start, struct alt_instr *end) 184 + { 185 + struct alt_instr *a; 186 + unsigned int nr_instr, nr_repl, nr_insnbuf; 187 + union loongarch_instruction *instr, *replacement; 188 + union loongarch_instruction insnbuf[MAX_PATCH_SIZE]; 189 + 190 + DPRINTK("alt table %px, -> %px", start, end); 191 + /* 192 + * The scan order should be from start to end. A later scanned 193 + * alternative code can overwrite previously scanned alternative code. 194 + * Some kernel functions (e.g. memcpy, memset, etc) use this order to 195 + * patch code. 196 + * 197 + * So be careful if you want to change the scan order to any other 198 + * order. 199 + */ 200 + for (a = start; a < end; a++) { 201 + nr_insnbuf = 0; 202 + 203 + instr = (void *)&a->instr_offset + a->instr_offset; 204 + replacement = (void *)&a->replace_offset + a->replace_offset; 205 + 206 + BUG_ON(a->instrlen > sizeof(insnbuf)); 207 + BUG_ON(a->instrlen & 0x3); 208 + BUG_ON(a->replacementlen & 0x3); 209 + 210 + nr_instr = a->instrlen / LOONGARCH_INSN_SIZE; 211 + nr_repl = a->replacementlen / LOONGARCH_INSN_SIZE; 212 + 213 + if (!cpu_has(a->feature)) { 214 + DPRINTK("feat not exist: %d, old: (%px len: %d), repl: (%px, len: %d)", 215 + a->feature, instr, a->instrlen, 216 + replacement, a->replacementlen); 217 + 218 + continue; 219 + } 220 + 221 + DPRINTK("feat: %d, old: (%px len: %d), repl: (%px, len: %d)", 222 + a->feature, instr, a->instrlen, 223 + replacement, a->replacementlen); 224 + 225 + DUMP_WORDS(instr, nr_instr, "%px: old_insn: ", instr); 226 + DUMP_WORDS(replacement, nr_repl, "%px: rpl_insn: ", replacement); 227 + 228 + copy_alt_insns(insnbuf, instr, replacement, nr_repl); 229 + nr_insnbuf = nr_repl; 230 + 231 + if (nr_instr > nr_repl) { 232 + add_nops(insnbuf + nr_repl, nr_instr - nr_repl); 233 + nr_insnbuf += nr_instr - nr_repl; 234 + } 235 + DUMP_WORDS(insnbuf, nr_insnbuf, "%px: final_insn: ", instr); 236 + 237 + text_poke_early(instr, insnbuf, nr_insnbuf); 238 + } 239 + } 240 + 241 + void __init alternative_instructions(void) 242 + { 243 + apply_alternatives(__alt_instructions, __alt_instructions_end); 244 + 245 + alternatives_patched = 1; 246 + }
+15
arch/loongarch/kernel/asm-offsets.c
··· 68 68 OFFSET(TASK_FLAGS, task_struct, flags); 69 69 OFFSET(TASK_MM, task_struct, mm); 70 70 OFFSET(TASK_PID, task_struct, pid); 71 + #if defined(CONFIG_STACKPROTECTOR) 72 + OFFSET(TASK_STACK_CANARY, task_struct, stack_canary); 73 + #endif 71 74 DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct)); 72 75 BLANK(); 73 76 } ··· 257 254 COMMENT("Linux smp cpu boot offsets."); 258 255 OFFSET(CPU_BOOT_STACK, secondary_data, stack); 259 256 OFFSET(CPU_BOOT_TINFO, secondary_data, thread_info); 257 + BLANK(); 258 + } 259 + #endif 260 + 261 + #ifdef CONFIG_HIBERNATION 262 + void output_pbe_defines(void) 263 + { 264 + COMMENT(" Linux struct pbe offsets. "); 265 + OFFSET(PBE_ADDRESS, pbe, address); 266 + OFFSET(PBE_ORIG_ADDRESS, pbe, orig_address); 267 + OFFSET(PBE_NEXT, pbe, next); 268 + DEFINE(PBE_SIZE, sizeof(struct pbe)); 260 269 BLANK(); 261 270 } 262 271 #endif
+14 -1
arch/loongarch/kernel/efi.c
··· 28 28 static unsigned long efi_config_table; 29 29 30 30 static unsigned long __initdata boot_memmap = EFI_INVALID_TABLE_ADDR; 31 + static unsigned long __initdata fdt_pointer = EFI_INVALID_TABLE_ADDR; 31 32 32 33 static efi_system_table_t *efi_systab; 33 34 static efi_config_table_type_t arch_tables[] __initdata = { 34 35 {LINUX_EFI_BOOT_MEMMAP_GUID, &boot_memmap, "MEMMAP" }, 36 + {DEVICE_TREE_GUID, &fdt_pointer, "FDTPTR" }, 35 37 {}, 36 38 }; 37 39 40 + void __init *efi_fdt_pointer(void) 41 + { 42 + if (!efi_systab) 43 + return NULL; 44 + 45 + if (fdt_pointer == EFI_INVALID_TABLE_ADDR) 46 + return NULL; 47 + 48 + return early_memremap_ro(fdt_pointer, SZ_64K); 49 + } 50 + 38 51 void __init efi_runtime_init(void) 39 52 { 40 - if (!efi_enabled(EFI_BOOT)) 53 + if (!efi_enabled(EFI_BOOT) || !efi_systab->runtime) 41 54 return; 42 55 43 56 if (efi_runtime_disabled()) {
+2
arch/loongarch/kernel/env.c
··· 11 11 #include <asm/early_ioremap.h> 12 12 #include <asm/bootinfo.h> 13 13 #include <asm/loongson.h> 14 + #include <asm/setup.h> 14 15 15 16 u64 efi_system_table; 16 17 struct loongson_system_configuration loongson_sysconf; ··· 28 27 clear_bit(EFI_BOOT, &efi.flags); 29 28 30 29 strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE); 30 + strscpy(init_command_line, cmdline, COMMAND_LINE_SIZE); 31 31 early_memunmap(cmdline, COMMAND_LINE_SIZE); 32 32 33 33 efi_system_table = fw_arg2;
+2 -3
arch/loongarch/kernel/fpu.S
··· 8 8 */ 9 9 #include <asm/asm.h> 10 10 #include <asm/asmmacro.h> 11 + #include <asm/asm-extable.h> 11 12 #include <asm/asm-offsets.h> 12 13 #include <asm/errno.h> 13 14 #include <asm/export.h> ··· 22 21 23 22 .macro EX insn, reg, src, offs 24 23 .ex\@: \insn \reg, \src, \offs 25 - .section __ex_table,"a" 26 - PTR .ex\@, fault 27 - .previous 24 + _asm_extable .ex\@, fault 28 25 .endm 29 26 30 27 .macro sc_save_fp base
+73
arch/loongarch/kernel/ftrace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2022 Loongson Technology Corporation Limited 4 + */ 5 + 6 + #include <linux/init.h> 7 + #include <linux/ftrace.h> 8 + #include <linux/syscalls.h> 9 + #include <linux/uaccess.h> 10 + 11 + #include <asm/asm.h> 12 + #include <asm/asm-offsets.h> 13 + #include <asm/cacheflush.h> 14 + #include <asm/inst.h> 15 + #include <asm/loongarch.h> 16 + #include <asm/syscall.h> 17 + 18 + #include <asm-generic/sections.h> 19 + 20 + #ifdef CONFIG_FUNCTION_GRAPH_TRACER 21 + 22 + /* 23 + * As `call _mcount` follows LoongArch psABI, ra-saved operation and 24 + * stack operation can be found before this insn. 25 + */ 26 + 27 + static int ftrace_get_parent_ra_addr(unsigned long insn_addr, int *ra_off) 28 + { 29 + int limit = 32; 30 + union loongarch_instruction *insn; 31 + 32 + insn = (union loongarch_instruction *)insn_addr; 33 + 34 + do { 35 + insn--; 36 + limit--; 37 + 38 + if (is_ra_save_ins(insn)) 39 + *ra_off = -((1 << 12) - insn->reg2i12_format.immediate); 40 + 41 + } while (!is_stack_alloc_ins(insn) && limit); 42 + 43 + if (!limit) 44 + return -EINVAL; 45 + 46 + return 0; 47 + } 48 + 49 + void prepare_ftrace_return(unsigned long self_addr, 50 + unsigned long callsite_sp, unsigned long old) 51 + { 52 + int ra_off; 53 + unsigned long return_hooker = (unsigned long)&return_to_handler; 54 + 55 + if (unlikely(ftrace_graph_is_dead())) 56 + return; 57 + 58 + if (unlikely(atomic_read(&current->tracing_graph_pause))) 59 + return; 60 + 61 + if (ftrace_get_parent_ra_addr(self_addr, &ra_off)) 62 + goto out; 63 + 64 + if (!function_graph_enter(old, self_addr, 0, NULL)) 65 + *(unsigned long *)(callsite_sp + ra_off) = return_hooker; 66 + 67 + return; 68 + 69 + out: 70 + ftrace_graph_stop(); 71 + WARN_ON(1); 72 + } 73 + #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+273
arch/loongarch/kernel/ftrace_dyn.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Based on arch/arm64/kernel/ftrace.c 4 + * 5 + * Copyright (C) 2022 Loongson Technology Corporation Limited 6 + */ 7 + 8 + #include <linux/ftrace.h> 9 + #include <linux/uaccess.h> 10 + 11 + #include <asm/inst.h> 12 + #include <asm/module.h> 13 + 14 + static int ftrace_modify_code(unsigned long pc, u32 old, u32 new, bool validate) 15 + { 16 + u32 replaced; 17 + 18 + if (validate) { 19 + if (larch_insn_read((void *)pc, &replaced)) 20 + return -EFAULT; 21 + 22 + if (replaced != old) 23 + return -EINVAL; 24 + } 25 + 26 + if (larch_insn_patch_text((void *)pc, new)) 27 + return -EPERM; 28 + 29 + return 0; 30 + } 31 + 32 + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 33 + 34 + #ifdef CONFIG_MODULES 35 + static inline int __get_mod(struct module **mod, unsigned long addr) 36 + { 37 + preempt_disable(); 38 + *mod = __module_text_address(addr); 39 + preempt_enable(); 40 + 41 + if (WARN_ON(!(*mod))) 42 + return -EINVAL; 43 + 44 + return 0; 45 + } 46 + 47 + static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr) 48 + { 49 + struct plt_entry *plt = mod->arch.ftrace_trampolines; 50 + 51 + if (addr == FTRACE_ADDR) 52 + return &plt[FTRACE_PLT_IDX]; 53 + if (addr == FTRACE_REGS_ADDR && 54 + IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS)) 55 + return &plt[FTRACE_REGS_PLT_IDX]; 56 + 57 + return NULL; 58 + } 59 + 60 + static unsigned long get_plt_addr(struct module *mod, unsigned long addr) 61 + { 62 + struct plt_entry *plt; 63 + 64 + plt = get_ftrace_plt(mod, addr); 65 + if (!plt) { 66 + pr_err("ftrace: no module PLT for %ps\n", (void *)addr); 67 + return -EINVAL; 68 + } 69 + 70 + return (unsigned long)plt; 71 + } 72 + #endif 73 + 74 + int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long addr) 75 + { 76 + u32 old, new; 77 + unsigned long pc; 78 + long offset __maybe_unused; 79 + 80 + pc = rec->ip + LOONGARCH_INSN_SIZE; 81 + 82 + #ifdef CONFIG_MODULES 83 + offset = (long)pc - (long)addr; 84 + 85 + if (offset < -SZ_128M || offset >= SZ_128M) { 86 + int ret; 87 + struct module *mod; 88 + 89 + ret = __get_mod(&mod, pc); 90 + if (ret) 91 + return ret; 92 + 93 + addr = get_plt_addr(mod, addr); 94 + 95 + old_addr = get_plt_addr(mod, old_addr); 96 + } 97 + #endif 98 + 99 + new = larch_insn_gen_bl(pc, addr); 100 + old = larch_insn_gen_bl(pc, old_addr); 101 + 102 + return ftrace_modify_code(pc, old, new, true); 103 + } 104 + 105 + #endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ 106 + 107 + int ftrace_update_ftrace_func(ftrace_func_t func) 108 + { 109 + u32 new; 110 + unsigned long pc; 111 + 112 + pc = (unsigned long)&ftrace_call; 113 + new = larch_insn_gen_bl(pc, (unsigned long)func); 114 + 115 + return ftrace_modify_code(pc, 0, new, false); 116 + } 117 + 118 + /* 119 + * The compiler has inserted 2 NOPs before the regular function prologue. 120 + * T series registers are available and safe because of LoongArch's psABI. 121 + * 122 + * At runtime, we can replace nop with bl to enable ftrace call and replace bl 123 + * with nop to disable ftrace call. The bl requires us to save the original RA 124 + * value, so it saves RA at t0 here. 125 + * 126 + * Details are: 127 + * 128 + * | Compiled | Disabled | Enabled | 129 + * +------------+------------------------+------------------------+ 130 + * | nop | move t0, ra | move t0, ra | 131 + * | nop | nop | bl ftrace_caller | 132 + * | func_body | func_body | func_body | 133 + * 134 + * The RA value will be recovered by ftrace_regs_entry, and restored into RA 135 + * before returning to the regular function prologue. When a function is not 136 + * being traced, the "move t0, ra" is not harmful. 137 + */ 138 + 139 + int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec) 140 + { 141 + u32 old, new; 142 + unsigned long pc; 143 + 144 + pc = rec->ip; 145 + old = larch_insn_gen_nop(); 146 + new = larch_insn_gen_move(LOONGARCH_GPR_T0, LOONGARCH_GPR_RA); 147 + 148 + return ftrace_modify_code(pc, old, new, true); 149 + } 150 + 151 + int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) 152 + { 153 + u32 old, new; 154 + unsigned long pc; 155 + long offset __maybe_unused; 156 + 157 + pc = rec->ip + LOONGARCH_INSN_SIZE; 158 + 159 + #ifdef CONFIG_MODULES 160 + offset = (long)pc - (long)addr; 161 + 162 + if (offset < -SZ_128M || offset >= SZ_128M) { 163 + int ret; 164 + struct module *mod; 165 + 166 + ret = __get_mod(&mod, pc); 167 + if (ret) 168 + return ret; 169 + 170 + addr = get_plt_addr(mod, addr); 171 + } 172 + #endif 173 + 174 + old = larch_insn_gen_nop(); 175 + new = larch_insn_gen_bl(pc, addr); 176 + 177 + return ftrace_modify_code(pc, old, new, true); 178 + } 179 + 180 + int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) 181 + { 182 + u32 old, new; 183 + unsigned long pc; 184 + long offset __maybe_unused; 185 + 186 + pc = rec->ip + LOONGARCH_INSN_SIZE; 187 + 188 + #ifdef CONFIG_MODULES 189 + offset = (long)pc - (long)addr; 190 + 191 + if (offset < -SZ_128M || offset >= SZ_128M) { 192 + int ret; 193 + struct module *mod; 194 + 195 + ret = __get_mod(&mod, pc); 196 + if (ret) 197 + return ret; 198 + 199 + addr = get_plt_addr(mod, addr); 200 + } 201 + #endif 202 + 203 + new = larch_insn_gen_nop(); 204 + old = larch_insn_gen_bl(pc, addr); 205 + 206 + return ftrace_modify_code(pc, old, new, true); 207 + } 208 + 209 + void arch_ftrace_update_code(int command) 210 + { 211 + command |= FTRACE_MAY_SLEEP; 212 + ftrace_modify_all_code(command); 213 + } 214 + 215 + int __init ftrace_dyn_arch_init(void) 216 + { 217 + return 0; 218 + } 219 + 220 + #ifdef CONFIG_FUNCTION_GRAPH_TRACER 221 + void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent) 222 + { 223 + unsigned long old; 224 + unsigned long return_hooker = (unsigned long)&return_to_handler; 225 + 226 + if (unlikely(atomic_read(&current->tracing_graph_pause))) 227 + return; 228 + 229 + old = *parent; 230 + 231 + if (!function_graph_enter(old, self_addr, 0, parent)) 232 + *parent = return_hooker; 233 + } 234 + 235 + #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS 236 + void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, 237 + struct ftrace_ops *op, struct ftrace_regs *fregs) 238 + { 239 + struct pt_regs *regs = &fregs->regs; 240 + unsigned long *parent = (unsigned long *)&regs->regs[1]; 241 + 242 + prepare_ftrace_return(ip, (unsigned long *)parent); 243 + } 244 + #else 245 + static int ftrace_modify_graph_caller(bool enable) 246 + { 247 + u32 branch, nop; 248 + unsigned long pc, func; 249 + extern void ftrace_graph_call(void); 250 + 251 + pc = (unsigned long)&ftrace_graph_call; 252 + func = (unsigned long)&ftrace_graph_caller; 253 + 254 + nop = larch_insn_gen_nop(); 255 + branch = larch_insn_gen_b(pc, func); 256 + 257 + if (enable) 258 + return ftrace_modify_code(pc, nop, branch, true); 259 + else 260 + return ftrace_modify_code(pc, branch, nop, true); 261 + } 262 + 263 + int ftrace_enable_ftrace_graph_caller(void) 264 + { 265 + return ftrace_modify_graph_caller(true); 266 + } 267 + 268 + int ftrace_disable_ftrace_graph_caller(void) 269 + { 270 + return ftrace_modify_graph_caller(false); 271 + } 272 + #endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */ 273 + #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+127
arch/loongarch/kernel/inst.c
··· 2 2 /* 3 3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 4 */ 5 + #include <linux/sizes.h> 6 + #include <linux/uaccess.h> 7 + 8 + #include <asm/cacheflush.h> 5 9 #include <asm/inst.h> 10 + 11 + static DEFINE_RAW_SPINLOCK(patch_lock); 12 + 13 + int larch_insn_read(void *addr, u32 *insnp) 14 + { 15 + int ret; 16 + u32 val; 17 + 18 + ret = copy_from_kernel_nofault(&val, addr, LOONGARCH_INSN_SIZE); 19 + if (!ret) 20 + *insnp = val; 21 + 22 + return ret; 23 + } 24 + 25 + int larch_insn_write(void *addr, u32 insn) 26 + { 27 + int ret; 28 + unsigned long flags = 0; 29 + 30 + raw_spin_lock_irqsave(&patch_lock, flags); 31 + ret = copy_to_kernel_nofault(addr, &insn, LOONGARCH_INSN_SIZE); 32 + raw_spin_unlock_irqrestore(&patch_lock, flags); 33 + 34 + return ret; 35 + } 36 + 37 + int larch_insn_patch_text(void *addr, u32 insn) 38 + { 39 + int ret; 40 + u32 *tp = addr; 41 + 42 + if ((unsigned long)tp & 3) 43 + return -EINVAL; 44 + 45 + ret = larch_insn_write(tp, insn); 46 + if (!ret) 47 + flush_icache_range((unsigned long)tp, 48 + (unsigned long)tp + LOONGARCH_INSN_SIZE); 49 + 50 + return ret; 51 + } 52 + 53 + u32 larch_insn_gen_nop(void) 54 + { 55 + return INSN_NOP; 56 + } 57 + 58 + u32 larch_insn_gen_b(unsigned long pc, unsigned long dest) 59 + { 60 + long offset = dest - pc; 61 + unsigned int immediate_l, immediate_h; 62 + union loongarch_instruction insn; 63 + 64 + if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) { 65 + pr_warn("The generated b instruction is out of range.\n"); 66 + return INSN_BREAK; 67 + } 68 + 69 + offset >>= 2; 70 + 71 + immediate_l = offset & 0xffff; 72 + offset >>= 16; 73 + immediate_h = offset & 0x3ff; 74 + 75 + insn.reg0i26_format.opcode = b_op; 76 + insn.reg0i26_format.immediate_l = immediate_l; 77 + insn.reg0i26_format.immediate_h = immediate_h; 78 + 79 + return insn.word; 80 + } 81 + 82 + u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest) 83 + { 84 + long offset = dest - pc; 85 + unsigned int immediate_l, immediate_h; 86 + union loongarch_instruction insn; 87 + 88 + if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) { 89 + pr_warn("The generated bl instruction is out of range.\n"); 90 + return INSN_BREAK; 91 + } 92 + 93 + offset >>= 2; 94 + 95 + immediate_l = offset & 0xffff; 96 + offset >>= 16; 97 + immediate_h = offset & 0x3ff; 98 + 99 + insn.reg0i26_format.opcode = bl_op; 100 + insn.reg0i26_format.immediate_l = immediate_l; 101 + insn.reg0i26_format.immediate_h = immediate_h; 102 + 103 + return insn.word; 104 + } 105 + 106 + u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj, enum loongarch_gpr rk) 107 + { 108 + union loongarch_instruction insn; 109 + 110 + insn.reg3_format.opcode = or_op; 111 + insn.reg3_format.rd = rd; 112 + insn.reg3_format.rj = rj; 113 + insn.reg3_format.rk = rk; 114 + 115 + return insn.word; 116 + } 117 + 118 + u32 larch_insn_gen_move(enum loongarch_gpr rd, enum loongarch_gpr rj) 119 + { 120 + return larch_insn_gen_or(rd, rj, 0); 121 + } 122 + 123 + u32 larch_insn_gen_lu12iw(enum loongarch_gpr rd, int imm) 124 + { 125 + union loongarch_instruction insn; 126 + 127 + insn.reg1i20_format.opcode = lu12iw_op; 128 + insn.reg1i20_format.rd = rd; 129 + insn.reg1i20_format.immediate = imm; 130 + 131 + return insn.word; 132 + } 6 133 7 134 u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm) 8 135 {
+96
arch/loongarch/kernel/mcount.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * LoongArch specific _mcount support 4 + * 5 + * Copyright (C) 2022 Loongson Technology Corporation Limited 6 + */ 7 + 8 + #include <asm/export.h> 9 + #include <asm/ftrace.h> 10 + #include <asm/regdef.h> 11 + #include <asm/stackframe.h> 12 + 13 + .text 14 + 15 + #define MCOUNT_S0_OFFSET (0) 16 + #define MCOUNT_RA_OFFSET (SZREG) 17 + #define MCOUNT_STACK_SIZE (2 * SZREG) 18 + 19 + .macro MCOUNT_SAVE_REGS 20 + PTR_ADDI sp, sp, -MCOUNT_STACK_SIZE 21 + PTR_S s0, sp, MCOUNT_S0_OFFSET 22 + PTR_S ra, sp, MCOUNT_RA_OFFSET 23 + move s0, a0 24 + .endm 25 + 26 + .macro MCOUNT_RESTORE_REGS 27 + move a0, s0 28 + PTR_L ra, sp, MCOUNT_RA_OFFSET 29 + PTR_L s0, sp, MCOUNT_S0_OFFSET 30 + PTR_ADDI sp, sp, MCOUNT_STACK_SIZE 31 + .endm 32 + 33 + SYM_FUNC_START(_mcount) 34 + la.pcrel t1, ftrace_stub 35 + la.pcrel t2, ftrace_trace_function /* Prepare t2 for (1) */ 36 + PTR_L t2, t2, 0 37 + beq t1, t2, fgraph_trace 38 + 39 + MCOUNT_SAVE_REGS 40 + 41 + move a0, ra /* arg0: self return address */ 42 + move a1, s0 /* arg1: parent's return address */ 43 + jirl ra, t2, 0 /* (1) call *ftrace_trace_function */ 44 + 45 + MCOUNT_RESTORE_REGS 46 + 47 + fgraph_trace: 48 + #ifdef CONFIG_FUNCTION_GRAPH_TRACER 49 + la.pcrel t1, ftrace_stub 50 + la.pcrel t3, ftrace_graph_return 51 + PTR_L t3, t3, 0 52 + bne t1, t3, ftrace_graph_caller 53 + la.pcrel t1, ftrace_graph_entry_stub 54 + la.pcrel t3, ftrace_graph_entry 55 + PTR_L t3, t3, 0 56 + bne t1, t3, ftrace_graph_caller 57 + #endif 58 + 59 + SYM_INNER_LABEL(ftrace_stub, SYM_L_GLOBAL) 60 + jr ra 61 + #ifdef CONFIG_FUNCTION_GRAPH_TRACER 62 + SYM_INNER_LABEL(ftrace_graph_func, SYM_L_GLOBAL) 63 + bl ftrace_stub 64 + #endif 65 + SYM_FUNC_END(_mcount) 66 + EXPORT_SYMBOL(_mcount) 67 + 68 + #ifdef CONFIG_FUNCTION_GRAPH_TRACER 69 + SYM_FUNC_START(ftrace_graph_caller) 70 + MCOUNT_SAVE_REGS 71 + 72 + PTR_ADDI a0, ra, -4 /* arg0: Callsite self return addr */ 73 + PTR_ADDI a1, sp, MCOUNT_STACK_SIZE /* arg1: Callsite sp */ 74 + move a2, s0 /* arg2: Callsite parent ra */ 75 + bl prepare_ftrace_return 76 + 77 + MCOUNT_RESTORE_REGS 78 + jr ra 79 + SYM_FUNC_END(ftrace_graph_caller) 80 + 81 + SYM_FUNC_START(return_to_handler) 82 + PTR_ADDI sp, sp, -2 * SZREG 83 + PTR_S a0, sp, 0 84 + PTR_S a1, sp, SZREG 85 + 86 + bl ftrace_return_to_handler 87 + 88 + /* Restore the real parent address: a0 -> ra */ 89 + move ra, a0 90 + 91 + PTR_L a0, sp, 0 92 + PTR_L a1, sp, SZREG 93 + PTR_ADDI sp, sp, 2 * SZREG 94 + jr ra 95 + SYM_FUNC_END(return_to_handler) 96 + #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+149
arch/loongarch/kernel/mcount_dyn.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2022 Loongson Technology Corporation Limited 4 + */ 5 + 6 + #include <asm/export.h> 7 + #include <asm/ftrace.h> 8 + #include <asm/regdef.h> 9 + #include <asm/stackframe.h> 10 + 11 + .text 12 + /* 13 + * Due to -fpatchable-function-entry=2: the compiler inserted 2 NOPs before the 14 + * regular C function prologue. When PC arrived here, the last 2 instructions 15 + * are as follows: 16 + * move t0, ra 17 + * bl callsite (for modules, callsite is a tramplione) 18 + * 19 + * modules trampoline is as follows: 20 + * lu12i.w t1, callsite[31:12] 21 + * lu32i.d t1, callsite[51:32] 22 + * lu52i.d t1, t1, callsite[63:52] 23 + * jirl zero, t1, callsite[11:0] >> 2 24 + * 25 + * See arch/loongarch/kernel/ftrace_dyn.c for details. Here, pay attention to 26 + * that the T series regs are available and safe because each C functions 27 + * follows the LoongArch's psABI as well. 28 + */ 29 + 30 + .macro ftrace_regs_entry allregs=0 31 + PTR_ADDI sp, sp, -PT_SIZE 32 + PTR_S t0, sp, PT_R1 /* Save parent ra at PT_R1(RA) */ 33 + PTR_S a0, sp, PT_R4 34 + PTR_S a1, sp, PT_R5 35 + PTR_S a2, sp, PT_R6 36 + PTR_S a3, sp, PT_R7 37 + PTR_S a4, sp, PT_R8 38 + PTR_S a5, sp, PT_R9 39 + PTR_S a6, sp, PT_R10 40 + PTR_S a7, sp, PT_R11 41 + PTR_S fp, sp, PT_R22 42 + .if \allregs 43 + PTR_S tp, sp, PT_R2 44 + PTR_S t0, sp, PT_R12 45 + PTR_S t1, sp, PT_R13 46 + PTR_S t2, sp, PT_R14 47 + PTR_S t3, sp, PT_R15 48 + PTR_S t4, sp, PT_R16 49 + PTR_S t5, sp, PT_R17 50 + PTR_S t6, sp, PT_R18 51 + PTR_S t7, sp, PT_R19 52 + PTR_S t8, sp, PT_R20 53 + PTR_S u0, sp, PT_R21 54 + PTR_S s0, sp, PT_R23 55 + PTR_S s1, sp, PT_R24 56 + PTR_S s2, sp, PT_R25 57 + PTR_S s3, sp, PT_R26 58 + PTR_S s4, sp, PT_R27 59 + PTR_S s5, sp, PT_R28 60 + PTR_S s6, sp, PT_R29 61 + PTR_S s7, sp, PT_R30 62 + PTR_S s8, sp, PT_R31 63 + /* Clear it for later use as a flag sometimes. */ 64 + PTR_S zero, sp, PT_R0 65 + .endif 66 + PTR_S ra, sp, PT_ERA /* Save trace function ra at PT_ERA */ 67 + PTR_ADDI t8, sp, PT_SIZE 68 + PTR_S t8, sp, PT_R3 69 + .endm 70 + 71 + SYM_FUNC_START(ftrace_stub) 72 + jr ra 73 + SYM_FUNC_END(ftrace_stub) 74 + 75 + SYM_CODE_START(ftrace_common) 76 + PTR_ADDI a0, ra, -8 /* arg0: ip */ 77 + move a1, t0 /* arg1: parent_ip */ 78 + la.pcrel t1, function_trace_op 79 + PTR_L a2, t1, 0 /* arg2: op */ 80 + move a3, sp /* arg3: regs */ 81 + 82 + SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) 83 + bl ftrace_stub 84 + #ifdef CONFIG_FUNCTION_GRAPH_TRACER 85 + SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) 86 + nop /* b ftrace_graph_caller */ 87 + #endif 88 + 89 + /* 90 + * As we didn't use S series regs in this assmembly code and all calls 91 + * are C function which will save S series regs by themselves, there is 92 + * no need to restore S series regs. The T series is available and safe 93 + * at the callsite, so there is no need to restore the T series regs. 94 + */ 95 + ftrace_common_return: 96 + PTR_L ra, sp, PT_R1 97 + PTR_L a0, sp, PT_R4 98 + PTR_L a1, sp, PT_R5 99 + PTR_L a2, sp, PT_R6 100 + PTR_L a3, sp, PT_R7 101 + PTR_L a4, sp, PT_R8 102 + PTR_L a5, sp, PT_R9 103 + PTR_L a6, sp, PT_R10 104 + PTR_L a7, sp, PT_R11 105 + PTR_L fp, sp, PT_R22 106 + PTR_L t0, sp, PT_ERA 107 + PTR_ADDI sp, sp, PT_SIZE 108 + jr t0 109 + SYM_CODE_END(ftrace_common) 110 + 111 + SYM_CODE_START(ftrace_caller) 112 + ftrace_regs_entry allregs=0 113 + b ftrace_common 114 + SYM_CODE_END(ftrace_caller) 115 + 116 + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 117 + SYM_CODE_START(ftrace_regs_caller) 118 + ftrace_regs_entry allregs=1 119 + b ftrace_common 120 + SYM_CODE_END(ftrace_regs_caller) 121 + #endif 122 + 123 + #ifdef CONFIG_FUNCTION_GRAPH_TRACER 124 + SYM_CODE_START(ftrace_graph_caller) 125 + PTR_L a0, sp, PT_ERA 126 + PTR_ADDI a0, a0, -8 /* arg0: self_addr */ 127 + PTR_ADDI a1, sp, PT_R1 /* arg1: parent */ 128 + bl prepare_ftrace_return 129 + b ftrace_common_return 130 + SYM_CODE_END(ftrace_graph_caller) 131 + 132 + SYM_CODE_START(return_to_handler) 133 + /* Save return value regs */ 134 + PTR_ADDI sp, sp, -2 * SZREG 135 + PTR_S a0, sp, 0 136 + PTR_S a1, sp, SZREG 137 + 138 + move a0, zero 139 + bl ftrace_return_to_handler 140 + move ra, a0 141 + 142 + /* Restore return value regs */ 143 + PTR_L a0, sp, 0 144 + PTR_L a1, sp, SZREG 145 + PTR_ADDI sp, sp, 2 * SZREG 146 + 147 + jr ra 148 + SYM_CODE_END(return_to_handler) 149 + #endif
+39 -25
arch/loongarch/kernel/module-sections.c
··· 6 6 #include <linux/elf.h> 7 7 #include <linux/kernel.h> 8 8 #include <linux/module.h> 9 + #include <linux/ftrace.h> 9 10 10 - Elf_Addr module_emit_got_entry(struct module *mod, Elf_Addr val) 11 + Elf_Addr module_emit_got_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val) 11 12 { 12 13 struct mod_section *got_sec = &mod->arch.got; 13 14 int i = got_sec->num_entries; 14 - struct got_entry *got = get_got_entry(val, got_sec); 15 + struct got_entry *got = get_got_entry(val, sechdrs, got_sec); 15 16 16 17 if (got) 17 18 return (Elf_Addr)got; 18 19 19 20 /* There is no GOT entry for val yet, create a new one. */ 20 - got = (struct got_entry *)got_sec->shdr->sh_addr; 21 + got = (struct got_entry *)sechdrs[got_sec->shndx].sh_addr; 21 22 got[i] = emit_got_entry(val); 22 23 23 24 got_sec->num_entries++; ··· 34 33 return (Elf_Addr)&got[i]; 35 34 } 36 35 37 - Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Addr val) 36 + Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val) 38 37 { 39 38 int nr; 40 39 struct mod_section *plt_sec = &mod->arch.plt; 41 40 struct mod_section *plt_idx_sec = &mod->arch.plt_idx; 42 - struct plt_entry *plt = get_plt_entry(val, plt_sec, plt_idx_sec); 41 + struct plt_entry *plt = get_plt_entry(val, sechdrs, plt_sec, plt_idx_sec); 43 42 struct plt_idx_entry *plt_idx; 44 43 45 44 if (plt) ··· 48 47 nr = plt_sec->num_entries; 49 48 50 49 /* There is no duplicate entry, create a new one */ 51 - plt = (struct plt_entry *)plt_sec->shdr->sh_addr; 50 + plt = (struct plt_entry *)sechdrs[plt_sec->shndx].sh_addr; 52 51 plt[nr] = emit_plt_entry(val); 53 - plt_idx = (struct plt_idx_entry *)plt_idx_sec->shdr->sh_addr; 52 + plt_idx = (struct plt_idx_entry *)sechdrs[plt_idx_sec->shndx].sh_addr; 54 53 plt_idx[nr] = emit_plt_idx_entry(val); 55 54 56 55 plt_sec->num_entries++; ··· 104 103 char *secstrings, struct module *mod) 105 104 { 106 105 unsigned int i, num_plts = 0, num_gots = 0; 106 + Elf_Shdr *got_sec, *plt_sec, *plt_idx_sec, *tramp = NULL; 107 107 108 108 /* 109 109 * Find the empty .plt sections. 110 110 */ 111 111 for (i = 0; i < ehdr->e_shnum; i++) { 112 112 if (!strcmp(secstrings + sechdrs[i].sh_name, ".got")) 113 - mod->arch.got.shdr = sechdrs + i; 113 + mod->arch.got.shndx = i; 114 114 else if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt")) 115 - mod->arch.plt.shdr = sechdrs + i; 115 + mod->arch.plt.shndx = i; 116 116 else if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt.idx")) 117 - mod->arch.plt_idx.shdr = sechdrs + i; 117 + mod->arch.plt_idx.shndx = i; 118 + else if (!strcmp(secstrings + sechdrs[i].sh_name, ".ftrace_trampoline")) 119 + tramp = sechdrs + i; 118 120 } 119 121 120 - if (!mod->arch.got.shdr) { 122 + if (!mod->arch.got.shndx) { 121 123 pr_err("%s: module GOT section(s) missing\n", mod->name); 122 124 return -ENOEXEC; 123 125 } 124 - if (!mod->arch.plt.shdr) { 126 + if (!mod->arch.plt.shndx) { 125 127 pr_err("%s: module PLT section(s) missing\n", mod->name); 126 128 return -ENOEXEC; 127 129 } 128 - if (!mod->arch.plt_idx.shdr) { 130 + if (!mod->arch.plt_idx.shndx) { 129 131 pr_err("%s: module PLT.IDX section(s) missing\n", mod->name); 130 132 return -ENOEXEC; 131 133 } ··· 149 145 count_max_entries(relas, num_rela, &num_plts, &num_gots); 150 146 } 151 147 152 - mod->arch.got.shdr->sh_type = SHT_NOBITS; 153 - mod->arch.got.shdr->sh_flags = SHF_ALLOC; 154 - mod->arch.got.shdr->sh_addralign = L1_CACHE_BYTES; 155 - mod->arch.got.shdr->sh_size = (num_gots + 1) * sizeof(struct got_entry); 148 + got_sec = sechdrs + mod->arch.got.shndx; 149 + got_sec->sh_type = SHT_NOBITS; 150 + got_sec->sh_flags = SHF_ALLOC; 151 + got_sec->sh_addralign = L1_CACHE_BYTES; 152 + got_sec->sh_size = (num_gots + 1) * sizeof(struct got_entry); 156 153 mod->arch.got.num_entries = 0; 157 154 mod->arch.got.max_entries = num_gots; 158 155 159 - mod->arch.plt.shdr->sh_type = SHT_NOBITS; 160 - mod->arch.plt.shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC; 161 - mod->arch.plt.shdr->sh_addralign = L1_CACHE_BYTES; 162 - mod->arch.plt.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_entry); 156 + plt_sec = sechdrs + mod->arch.plt.shndx; 157 + plt_sec->sh_type = SHT_NOBITS; 158 + plt_sec->sh_flags = SHF_EXECINSTR | SHF_ALLOC; 159 + plt_sec->sh_addralign = L1_CACHE_BYTES; 160 + plt_sec->sh_size = (num_plts + 1) * sizeof(struct plt_entry); 163 161 mod->arch.plt.num_entries = 0; 164 162 mod->arch.plt.max_entries = num_plts; 165 163 166 - mod->arch.plt_idx.shdr->sh_type = SHT_NOBITS; 167 - mod->arch.plt_idx.shdr->sh_flags = SHF_ALLOC; 168 - mod->arch.plt_idx.shdr->sh_addralign = L1_CACHE_BYTES; 169 - mod->arch.plt_idx.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_idx_entry); 164 + plt_idx_sec = sechdrs + mod->arch.plt_idx.shndx; 165 + plt_idx_sec->sh_type = SHT_NOBITS; 166 + plt_idx_sec->sh_flags = SHF_ALLOC; 167 + plt_idx_sec->sh_addralign = L1_CACHE_BYTES; 168 + plt_idx_sec->sh_size = (num_plts + 1) * sizeof(struct plt_idx_entry); 170 169 mod->arch.plt_idx.num_entries = 0; 171 170 mod->arch.plt_idx.max_entries = num_plts; 171 + 172 + if (tramp) { 173 + tramp->sh_type = SHT_NOBITS; 174 + tramp->sh_flags = SHF_EXECINSTR | SHF_ALLOC; 175 + tramp->sh_addralign = __alignof__(struct plt_entry); 176 + tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry); 177 + } 172 178 173 179 return 0; 174 180 }
+63 -12
arch/loongarch/kernel/module.c
··· 15 15 #include <linux/vmalloc.h> 16 16 #include <linux/slab.h> 17 17 #include <linux/fs.h> 18 + #include <linux/ftrace.h> 18 19 #include <linux/string.h> 19 20 #include <linux/kernel.h> 21 + #include <asm/alternative.h> 22 + #include <asm/inst.h> 20 23 21 24 static int rela_stack_push(s64 stack_value, s64 *rela_stack, size_t *rela_stack_top) 22 25 { ··· 101 98 return 0; 102 99 } 103 100 104 - static int apply_r_larch_sop_push_plt_pcrel(struct module *mod, u32 *location, Elf_Addr v, 101 + static int apply_r_larch_sop_push_plt_pcrel(struct module *mod, 102 + Elf_Shdr *sechdrs, u32 *location, Elf_Addr v, 105 103 s64 *rela_stack, size_t *rela_stack_top, unsigned int type) 106 104 { 107 105 ptrdiff_t offset = (void *)v - (void *)location; 108 106 109 107 if (offset >= SZ_128M) 110 - v = module_emit_plt_entry(mod, v); 108 + v = module_emit_plt_entry(mod, sechdrs, v); 111 109 112 110 if (offset < -SZ_128M) 113 - v = module_emit_plt_entry(mod, v); 111 + v = module_emit_plt_entry(mod, sechdrs, v); 114 112 115 113 return apply_r_larch_sop_push_pcrel(mod, location, v, rela_stack, rela_stack_top, type); 116 114 } ··· 275 271 } 276 272 } 277 273 278 - static int apply_r_larch_b26(struct module *mod, u32 *location, Elf_Addr v, 274 + static int apply_r_larch_b26(struct module *mod, 275 + Elf_Shdr *sechdrs, u32 *location, Elf_Addr v, 279 276 s64 *rela_stack, size_t *rela_stack_top, unsigned int type) 280 277 { 281 278 ptrdiff_t offset = (void *)v - (void *)location; 282 279 union loongarch_instruction *insn = (union loongarch_instruction *)location; 283 280 284 281 if (offset >= SZ_128M) 285 - v = module_emit_plt_entry(mod, v); 282 + v = module_emit_plt_entry(mod, sechdrs, v); 286 283 287 284 if (offset < -SZ_128M) 288 - v = module_emit_plt_entry(mod, v); 285 + v = module_emit_plt_entry(mod, sechdrs, v); 289 286 290 287 offset = (void *)v - (void *)location; 291 288 ··· 343 338 return 0; 344 339 } 345 340 346 - static int apply_r_larch_got_pc(struct module *mod, u32 *location, Elf_Addr v, 341 + static int apply_r_larch_got_pc(struct module *mod, 342 + Elf_Shdr *sechdrs, u32 *location, Elf_Addr v, 347 343 s64 *rela_stack, size_t *rela_stack_top, unsigned int type) 348 344 { 349 - Elf_Addr got = module_emit_got_entry(mod, v); 345 + Elf_Addr got = module_emit_got_entry(mod, sechdrs, v); 350 346 351 347 if (!got) 352 348 return -EINVAL; ··· 392 386 [R_LARCH_SOP_PUSH_PCREL] = apply_r_larch_sop_push_pcrel, 393 387 [R_LARCH_SOP_PUSH_ABSOLUTE] = apply_r_larch_sop_push_absolute, 394 388 [R_LARCH_SOP_PUSH_DUP] = apply_r_larch_sop_push_dup, 395 - [R_LARCH_SOP_PUSH_PLT_PCREL] = apply_r_larch_sop_push_plt_pcrel, 396 389 [R_LARCH_SOP_SUB ... R_LARCH_SOP_IF_ELSE] = apply_r_larch_sop, 397 390 [R_LARCH_SOP_POP_32_S_10_5 ... R_LARCH_SOP_POP_32_U] = apply_r_larch_sop_imm_field, 398 391 [R_LARCH_ADD32 ... R_LARCH_SUB64] = apply_r_larch_add_sub, 399 - [R_LARCH_B26] = apply_r_larch_b26, 400 392 [R_LARCH_PCALA_HI20...R_LARCH_PCALA64_HI12] = apply_r_larch_pcala, 401 - [R_LARCH_GOT_PC_HI20...R_LARCH_GOT_PC_LO12] = apply_r_larch_got_pc, 402 393 }; 403 394 404 395 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, ··· 446 443 sym->st_value, rel[i].r_addend, (u64)location); 447 444 448 445 v = sym->st_value + rel[i].r_addend; 449 - err = handler(mod, location, v, rela_stack, &rela_stack_top, type); 446 + switch (type) { 447 + case R_LARCH_B26: 448 + err = apply_r_larch_b26(mod, sechdrs, location, 449 + v, rela_stack, &rela_stack_top, type); 450 + break; 451 + case R_LARCH_GOT_PC_HI20...R_LARCH_GOT_PC_LO12: 452 + err = apply_r_larch_got_pc(mod, sechdrs, location, 453 + v, rela_stack, &rela_stack_top, type); 454 + break; 455 + case R_LARCH_SOP_PUSH_PLT_PCREL: 456 + err = apply_r_larch_sop_push_plt_pcrel(mod, sechdrs, location, 457 + v, rela_stack, &rela_stack_top, type); 458 + break; 459 + default: 460 + err = handler(mod, location, v, rela_stack, &rela_stack_top, type); 461 + } 450 462 if (err) 451 463 return err; 452 464 } ··· 473 455 { 474 456 return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, 475 457 GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0)); 458 + } 459 + 460 + static void module_init_ftrace_plt(const Elf_Ehdr *hdr, 461 + const Elf_Shdr *sechdrs, struct module *mod) 462 + { 463 + #ifdef CONFIG_DYNAMIC_FTRACE 464 + struct plt_entry *ftrace_plts; 465 + 466 + ftrace_plts = (void *)sechdrs->sh_addr; 467 + 468 + ftrace_plts[FTRACE_PLT_IDX] = emit_plt_entry(FTRACE_ADDR); 469 + 470 + if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS)) 471 + ftrace_plts[FTRACE_REGS_PLT_IDX] = emit_plt_entry(FTRACE_REGS_ADDR); 472 + 473 + mod->arch.ftrace_trampolines = ftrace_plts; 474 + #endif 475 + } 476 + 477 + int module_finalize(const Elf_Ehdr *hdr, 478 + const Elf_Shdr *sechdrs, struct module *mod) 479 + { 480 + const Elf_Shdr *s, *se; 481 + const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 482 + 483 + for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { 484 + if (!strcmp(".altinstructions", secstrs + s->sh_name)) 485 + apply_alternatives((void *)s->sh_addr, (void *)s->sh_addr + s->sh_size); 486 + if (!strcmp(".ftrace_trampoline", secstrs + s->sh_name)) 487 + module_init_ftrace_plt(hdr, s, mod); 488 + } 489 + 490 + return 0; 476 491 }
+16 -1
arch/loongarch/kernel/numa.c
··· 388 388 } 389 389 } 390 390 391 + /* 392 + * fake_numa_init() - For Non-ACPI systems 393 + * Return: 0 on success, -errno on failure. 394 + */ 395 + static int __init fake_numa_init(void) 396 + { 397 + phys_addr_t start = memblock_start_of_DRAM(); 398 + phys_addr_t end = memblock_end_of_DRAM() - 1; 399 + 400 + node_set(0, numa_nodes_parsed); 401 + pr_info("Faking a node at [mem %pap-%pap]\n", &start, &end); 402 + 403 + return numa_add_memblk(0, start, end + 1); 404 + } 405 + 391 406 int __init init_numa_memory(void) 392 407 { 393 408 int i; ··· 419 404 memset(&numa_meminfo, 0, sizeof(numa_meminfo)); 420 405 421 406 /* Parse SRAT and SLIT if provided by firmware. */ 422 - ret = acpi_numa_init(); 407 + ret = acpi_disabled ? fake_numa_init() : acpi_numa_init(); 423 408 if (ret < 0) 424 409 return ret; 425 410
+6
arch/loongarch/kernel/process.c
··· 47 47 #include <asm/unwind.h> 48 48 #include <asm/vdso.h> 49 49 50 + #ifdef CONFIG_STACKPROTECTOR 51 + #include <linux/stackprotector.h> 52 + unsigned long __stack_chk_guard __read_mostly; 53 + EXPORT_SYMBOL(__stack_chk_guard); 54 + #endif 55 + 50 56 /* 51 57 * Idle related variables and functions 52 58 */
+5
arch/loongarch/kernel/reset.c
··· 15 15 #include <acpi/reboot.h> 16 16 #include <asm/idle.h> 17 17 #include <asm/loongarch.h> 18 + #include <asm/loongson.h> 18 19 19 20 void (*pm_power_off)(void); 20 21 EXPORT_SYMBOL(pm_power_off); ··· 42 41 #ifdef CONFIG_SMP 43 42 preempt_disable(); 44 43 smp_send_stop(); 44 + #endif 45 + #ifdef CONFIG_PM 46 + if (!acpi_disabled) 47 + enable_pci_wakeup(); 45 48 #endif 46 49 do_kernel_power_off(); 47 50 #ifdef CONFIG_EFI
+148 -1
arch/loongarch/kernel/setup.c
··· 28 28 #include <linux/sizes.h> 29 29 #include <linux/device.h> 30 30 #include <linux/dma-map-ops.h> 31 + #include <linux/libfdt.h> 32 + #include <linux/of_fdt.h> 33 + #include <linux/of_address.h> 34 + #include <linux/suspend.h> 31 35 #include <linux/swiotlb.h> 32 36 33 37 #include <asm/addrspace.h> 38 + #include <asm/alternative.h> 34 39 #include <asm/bootinfo.h> 40 + #include <asm/bugs.h> 35 41 #include <asm/cache.h> 36 42 #include <asm/cpu.h> 37 43 #include <asm/dma.h> ··· 73 67 * 74 68 * These are initialized so they are in the .data section 75 69 */ 70 + char init_command_line[COMMAND_LINE_SIZE] __initdata; 76 71 77 72 static int num_standard_resources; 78 73 static struct resource *standard_resources; ··· 85 78 const char *get_system_type(void) 86 79 { 87 80 return "generic-loongson-machine"; 81 + } 82 + 83 + void __init check_bugs(void) 84 + { 85 + alternative_instructions(); 88 86 } 89 87 90 88 static const char *dmi_string_parse(const struct dmi_header *dm, u8 s) ··· 258 246 #endif 259 247 } 260 248 249 + static void __init fdt_setup(void) 250 + { 251 + #ifdef CONFIG_OF_EARLY_FLATTREE 252 + void *fdt_pointer; 253 + 254 + /* ACPI-based systems do not require parsing fdt */ 255 + if (acpi_os_get_root_pointer()) 256 + return; 257 + 258 + /* Look for a device tree configuration table entry */ 259 + fdt_pointer = efi_fdt_pointer(); 260 + if (!fdt_pointer || fdt_check_header(fdt_pointer)) 261 + return; 262 + 263 + early_init_dt_scan(fdt_pointer); 264 + early_init_fdt_reserve_self(); 265 + 266 + max_low_pfn = PFN_PHYS(memblock_end_of_DRAM()); 267 + #endif 268 + } 269 + 270 + static void __init bootcmdline_init(char **cmdline_p) 271 + { 272 + /* 273 + * If CONFIG_CMDLINE_FORCE is enabled then initializing the command line 274 + * is trivial - we simply use the built-in command line unconditionally & 275 + * unmodified. 276 + */ 277 + if (IS_ENABLED(CONFIG_CMDLINE_FORCE)) { 278 + strscpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 279 + goto out; 280 + } 281 + 282 + #ifdef CONFIG_OF_FLATTREE 283 + /* 284 + * If CONFIG_CMDLINE_BOOTLOADER is enabled and we are in FDT-based system, 285 + * the boot_command_line will be overwritten by early_init_dt_scan_chosen(). 286 + * So we need to append init_command_line (the original copy of boot_command_line) 287 + * to boot_command_line. 288 + */ 289 + if (initial_boot_params) { 290 + if (boot_command_line[0]) 291 + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); 292 + 293 + strlcat(boot_command_line, init_command_line, COMMAND_LINE_SIZE); 294 + } 295 + #endif 296 + 297 + out: 298 + *cmdline_p = boot_command_line; 299 + } 300 + 261 301 void __init platform_init(void) 262 302 { 263 303 arch_reserve_vmcore(); ··· 322 258 acpi_gbl_use_default_register_widths = false; 323 259 acpi_boot_table_init(); 324 260 #endif 261 + unflatten_and_copy_device_tree(); 325 262 326 263 #ifdef CONFIG_NUMA 327 264 init_numa_memory(); ··· 355 290 356 291 check_kernel_sections_mem(); 357 292 293 + early_init_fdt_scan_reserved_mem(); 294 + 358 295 /* 359 296 * In order to reduce the possibility of kernel panic when failed to 360 297 * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate ··· 370 303 swiotlb_init(true, SWIOTLB_VERBOSE); 371 304 372 305 dma_contiguous_reserve(PFN_PHYS(max_low_pfn)); 306 + 307 + /* Reserve for hibernation. */ 308 + register_nosave_region(PFN_DOWN(__pa_symbol(&__nosave_begin)), 309 + PFN_UP(__pa_symbol(&__nosave_end))); 373 310 374 311 memblock_dump_all(); 375 312 ··· 434 363 #endif 435 364 } 436 365 366 + static int __init add_legacy_isa_io(struct fwnode_handle *fwnode, 367 + resource_size_t hw_start, resource_size_t size) 368 + { 369 + int ret = 0; 370 + unsigned long vaddr; 371 + struct logic_pio_hwaddr *range; 372 + 373 + range = kzalloc(sizeof(*range), GFP_ATOMIC); 374 + if (!range) 375 + return -ENOMEM; 376 + 377 + range->fwnode = fwnode; 378 + range->size = size = round_up(size, PAGE_SIZE); 379 + range->hw_start = hw_start; 380 + range->flags = LOGIC_PIO_CPU_MMIO; 381 + 382 + ret = logic_pio_register_range(range); 383 + if (ret) { 384 + kfree(range); 385 + return ret; 386 + } 387 + 388 + /* Legacy ISA must placed at the start of PCI_IOBASE */ 389 + if (range->io_start != 0) { 390 + logic_pio_unregister_range(range); 391 + kfree(range); 392 + return -EINVAL; 393 + } 394 + 395 + vaddr = (unsigned long)(PCI_IOBASE + range->io_start); 396 + ioremap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL)); 397 + 398 + return 0; 399 + } 400 + 401 + static __init int arch_reserve_pio_range(void) 402 + { 403 + struct device_node *np; 404 + 405 + for_each_node_by_name(np, "isa") { 406 + struct of_range range; 407 + struct of_range_parser parser; 408 + 409 + pr_info("ISA Bridge: %pOF\n", np); 410 + 411 + if (of_range_parser_init(&parser, np)) { 412 + pr_info("Failed to parse resources.\n"); 413 + of_node_put(np); 414 + break; 415 + } 416 + 417 + for_each_of_range(&parser, &range) { 418 + switch (range.flags & IORESOURCE_TYPE_BITS) { 419 + case IORESOURCE_IO: 420 + pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n", 421 + range.cpu_addr, 422 + range.cpu_addr + range.size - 1, 423 + range.bus_addr); 424 + if (add_legacy_isa_io(&np->fwnode, range.cpu_addr, range.size)) 425 + pr_warn("Failed to reserve legacy IO in Logic PIO\n"); 426 + break; 427 + case IORESOURCE_MEM: 428 + pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx\n", 429 + range.cpu_addr, 430 + range.cpu_addr + range.size - 1, 431 + range.bus_addr); 432 + break; 433 + } 434 + } 435 + } 436 + 437 + return 0; 438 + } 439 + arch_initcall(arch_reserve_pio_range); 440 + 437 441 static int __init reserve_memblock_reserved_regions(void) 438 442 { 439 443 u64 i, j; ··· 561 415 void __init setup_arch(char **cmdline_p) 562 416 { 563 417 cpu_probe(); 564 - *cmdline_p = boot_command_line; 565 418 566 419 init_environ(); 567 420 efi_init(); 421 + fdt_setup(); 568 422 memblock_init(); 569 423 pagetable_init(); 424 + bootcmdline_init(cmdline_p); 570 425 parse_early_param(); 571 426 reserve_initrd_mem(); 572 427
+35
arch/loongarch/kernel/smp.c
··· 16 16 #include <linux/smp.h> 17 17 #include <linux/threads.h> 18 18 #include <linux/export.h> 19 + #include <linux/syscore_ops.h> 19 20 #include <linux/time.h> 20 21 #include <linux/tracepoint.h> 21 22 #include <linux/sched/hotplug.h> ··· 181 180 return IRQ_HANDLED; 182 181 } 183 182 183 + static void __init fdt_smp_setup(void) 184 + { 185 + #ifdef CONFIG_OF 186 + unsigned int cpu, cpuid; 187 + struct device_node *node = NULL; 188 + 189 + for_each_of_cpu_node(node) { 190 + if (!of_device_is_available(node)) 191 + continue; 192 + 193 + cpuid = of_get_cpu_hwid(node, 0); 194 + if (cpuid >= nr_cpu_ids) 195 + continue; 196 + 197 + if (cpuid == loongson_sysconf.boot_cpu_id) { 198 + cpu = 0; 199 + numa_add_cpu(cpu); 200 + } else { 201 + cpu = cpumask_next_zero(-1, cpu_present_mask); 202 + } 203 + 204 + num_processors++; 205 + set_cpu_possible(cpu, true); 206 + set_cpu_present(cpu, true); 207 + __cpu_number_map[cpuid] = cpu; 208 + __cpu_logical_map[cpu] = cpuid; 209 + } 210 + 211 + loongson_sysconf.nr_cpus = num_processors; 212 + #endif 213 + } 214 + 184 215 void __init loongson_smp_setup(void) 185 216 { 217 + fdt_smp_setup(); 218 + 186 219 cpu_data[0].core = cpu_logical_map(0) % loongson_sysconf.cores_per_package; 187 220 cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package; 188 221
+5
arch/loongarch/kernel/switch.S
··· 23 23 stptr.d ra, a0, THREAD_REG01 24 24 stptr.d a3, a0, THREAD_SCHED_RA 25 25 stptr.d a4, a0, THREAD_SCHED_CFA 26 + #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP) 27 + la t7, __stack_chk_guard 28 + LONG_L t8, a1, TASK_STACK_CANARY 29 + LONG_S t8, t7, 0 30 + #endif 26 31 move tp, a2 27 32 cpu_restore_nonscratch a1 28 33
+8 -3
arch/loongarch/kernel/time.c
··· 115 115 return lpj; 116 116 } 117 117 118 - static long init_timeval; 118 + static long init_offset __nosavedata; 119 + 120 + void save_counter(void) 121 + { 122 + init_offset = drdtime(); 123 + } 119 124 120 125 void sync_counter(void) 121 126 { 122 127 /* Ensure counter begin at 0 */ 123 - csr_write64(-init_timeval, LOONGARCH_CSR_CNTC); 128 + csr_write64(init_offset, LOONGARCH_CSR_CNTC); 124 129 } 125 130 126 131 static int get_timer_irq(void) ··· 224 219 else 225 220 const_clock_freq = calc_const_freq(); 226 221 227 - init_timeval = drdtime() - csr_read64(LOONGARCH_CSR_CNTC); 222 + init_offset = -(drdtime() - csr_read64(LOONGARCH_CSR_CNTC)); 228 223 229 224 constant_clockevent_init(); 230 225 constant_clocksource_init();
+27
arch/loongarch/kernel/traps.c
··· 368 368 irqentry_exit(regs, state); 369 369 } 370 370 371 + /* sysctl hooks */ 372 + int unaligned_enabled __read_mostly = 1; /* Enabled by default */ 373 + int no_unaligned_warning __read_mostly = 1; /* Only 1 warning by default */ 374 + 371 375 asmlinkage void noinstr do_ale(struct pt_regs *regs) 372 376 { 377 + unsigned int *pc; 373 378 irqentry_state_t state = irqentry_enter(regs); 374 379 380 + perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->csr_badvaddr); 381 + 382 + /* 383 + * Did we catch a fault trying to load an instruction? 384 + */ 385 + if (regs->csr_badvaddr == regs->csr_era) 386 + goto sigbus; 387 + if (user_mode(regs) && !test_thread_flag(TIF_FIXADE)) 388 + goto sigbus; 389 + if (!unaligned_enabled) 390 + goto sigbus; 391 + if (!no_unaligned_warning) 392 + show_registers(regs); 393 + 394 + pc = (unsigned int *)exception_era(regs); 395 + 396 + emulate_load_store_insn(regs, (void __user *)regs->csr_badvaddr, pc); 397 + 398 + goto out; 399 + 400 + sigbus: 375 401 die_if_kernel("Kernel ale access", regs); 376 402 force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr); 377 403 404 + out: 378 405 irqentry_exit(regs, state); 379 406 } 380 407
+499
arch/loongarch/kernel/unaligned.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Handle unaligned accesses by emulation. 4 + * 5 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 6 + * 7 + * Derived from MIPS: 8 + * Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle 9 + * Copyright (C) 1999 Silicon Graphics, Inc. 10 + * Copyright (C) 2014 Imagination Technologies Ltd. 11 + */ 12 + #include <linux/mm.h> 13 + #include <linux/sched.h> 14 + #include <linux/signal.h> 15 + #include <linux/debugfs.h> 16 + #include <linux/perf_event.h> 17 + 18 + #include <asm/asm.h> 19 + #include <asm/branch.h> 20 + #include <asm/fpu.h> 21 + #include <asm/inst.h> 22 + 23 + #include "access-helper.h" 24 + 25 + #ifdef CONFIG_DEBUG_FS 26 + static u32 unaligned_instructions_user; 27 + static u32 unaligned_instructions_kernel; 28 + #endif 29 + 30 + static inline unsigned long read_fpr(unsigned int idx) 31 + { 32 + #define READ_FPR(idx, __value) \ 33 + __asm__ __volatile__("movfr2gr.d %0, $f"#idx"\n\t" : "=r"(__value)); 34 + 35 + unsigned long __value; 36 + 37 + switch (idx) { 38 + case 0: 39 + READ_FPR(0, __value); 40 + break; 41 + case 1: 42 + READ_FPR(1, __value); 43 + break; 44 + case 2: 45 + READ_FPR(2, __value); 46 + break; 47 + case 3: 48 + READ_FPR(3, __value); 49 + break; 50 + case 4: 51 + READ_FPR(4, __value); 52 + break; 53 + case 5: 54 + READ_FPR(5, __value); 55 + break; 56 + case 6: 57 + READ_FPR(6, __value); 58 + break; 59 + case 7: 60 + READ_FPR(7, __value); 61 + break; 62 + case 8: 63 + READ_FPR(8, __value); 64 + break; 65 + case 9: 66 + READ_FPR(9, __value); 67 + break; 68 + case 10: 69 + READ_FPR(10, __value); 70 + break; 71 + case 11: 72 + READ_FPR(11, __value); 73 + break; 74 + case 12: 75 + READ_FPR(12, __value); 76 + break; 77 + case 13: 78 + READ_FPR(13, __value); 79 + break; 80 + case 14: 81 + READ_FPR(14, __value); 82 + break; 83 + case 15: 84 + READ_FPR(15, __value); 85 + break; 86 + case 16: 87 + READ_FPR(16, __value); 88 + break; 89 + case 17: 90 + READ_FPR(17, __value); 91 + break; 92 + case 18: 93 + READ_FPR(18, __value); 94 + break; 95 + case 19: 96 + READ_FPR(19, __value); 97 + break; 98 + case 20: 99 + READ_FPR(20, __value); 100 + break; 101 + case 21: 102 + READ_FPR(21, __value); 103 + break; 104 + case 22: 105 + READ_FPR(22, __value); 106 + break; 107 + case 23: 108 + READ_FPR(23, __value); 109 + break; 110 + case 24: 111 + READ_FPR(24, __value); 112 + break; 113 + case 25: 114 + READ_FPR(25, __value); 115 + break; 116 + case 26: 117 + READ_FPR(26, __value); 118 + break; 119 + case 27: 120 + READ_FPR(27, __value); 121 + break; 122 + case 28: 123 + READ_FPR(28, __value); 124 + break; 125 + case 29: 126 + READ_FPR(29, __value); 127 + break; 128 + case 30: 129 + READ_FPR(30, __value); 130 + break; 131 + case 31: 132 + READ_FPR(31, __value); 133 + break; 134 + default: 135 + panic("unexpected idx '%d'", idx); 136 + } 137 + #undef READ_FPR 138 + return __value; 139 + } 140 + 141 + static inline void write_fpr(unsigned int idx, unsigned long value) 142 + { 143 + #define WRITE_FPR(idx, value) \ 144 + __asm__ __volatile__("movgr2fr.d $f"#idx", %0\n\t" :: "r"(value)); 145 + 146 + switch (idx) { 147 + case 0: 148 + WRITE_FPR(0, value); 149 + break; 150 + case 1: 151 + WRITE_FPR(1, value); 152 + break; 153 + case 2: 154 + WRITE_FPR(2, value); 155 + break; 156 + case 3: 157 + WRITE_FPR(3, value); 158 + break; 159 + case 4: 160 + WRITE_FPR(4, value); 161 + break; 162 + case 5: 163 + WRITE_FPR(5, value); 164 + break; 165 + case 6: 166 + WRITE_FPR(6, value); 167 + break; 168 + case 7: 169 + WRITE_FPR(7, value); 170 + break; 171 + case 8: 172 + WRITE_FPR(8, value); 173 + break; 174 + case 9: 175 + WRITE_FPR(9, value); 176 + break; 177 + case 10: 178 + WRITE_FPR(10, value); 179 + break; 180 + case 11: 181 + WRITE_FPR(11, value); 182 + break; 183 + case 12: 184 + WRITE_FPR(12, value); 185 + break; 186 + case 13: 187 + WRITE_FPR(13, value); 188 + break; 189 + case 14: 190 + WRITE_FPR(14, value); 191 + break; 192 + case 15: 193 + WRITE_FPR(15, value); 194 + break; 195 + case 16: 196 + WRITE_FPR(16, value); 197 + break; 198 + case 17: 199 + WRITE_FPR(17, value); 200 + break; 201 + case 18: 202 + WRITE_FPR(18, value); 203 + break; 204 + case 19: 205 + WRITE_FPR(19, value); 206 + break; 207 + case 20: 208 + WRITE_FPR(20, value); 209 + break; 210 + case 21: 211 + WRITE_FPR(21, value); 212 + break; 213 + case 22: 214 + WRITE_FPR(22, value); 215 + break; 216 + case 23: 217 + WRITE_FPR(23, value); 218 + break; 219 + case 24: 220 + WRITE_FPR(24, value); 221 + break; 222 + case 25: 223 + WRITE_FPR(25, value); 224 + break; 225 + case 26: 226 + WRITE_FPR(26, value); 227 + break; 228 + case 27: 229 + WRITE_FPR(27, value); 230 + break; 231 + case 28: 232 + WRITE_FPR(28, value); 233 + break; 234 + case 29: 235 + WRITE_FPR(29, value); 236 + break; 237 + case 30: 238 + WRITE_FPR(30, value); 239 + break; 240 + case 31: 241 + WRITE_FPR(31, value); 242 + break; 243 + default: 244 + panic("unexpected idx '%d'", idx); 245 + } 246 + #undef WRITE_FPR 247 + } 248 + 249 + void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned int *pc) 250 + { 251 + bool fp = false; 252 + bool sign, write; 253 + bool user = user_mode(regs); 254 + unsigned int res, size = 0; 255 + unsigned long value = 0; 256 + union loongarch_instruction insn; 257 + 258 + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); 259 + 260 + __get_inst(&insn.word, pc, user); 261 + 262 + switch (insn.reg2i12_format.opcode) { 263 + case ldh_op: 264 + size = 2; 265 + sign = true; 266 + write = false; 267 + break; 268 + case ldhu_op: 269 + size = 2; 270 + sign = false; 271 + write = false; 272 + break; 273 + case sth_op: 274 + size = 2; 275 + sign = true; 276 + write = true; 277 + break; 278 + case ldw_op: 279 + size = 4; 280 + sign = true; 281 + write = false; 282 + break; 283 + case ldwu_op: 284 + size = 4; 285 + sign = false; 286 + write = false; 287 + break; 288 + case stw_op: 289 + size = 4; 290 + sign = true; 291 + write = true; 292 + break; 293 + case ldd_op: 294 + size = 8; 295 + sign = true; 296 + write = false; 297 + break; 298 + case std_op: 299 + size = 8; 300 + sign = true; 301 + write = true; 302 + break; 303 + case flds_op: 304 + size = 4; 305 + fp = true; 306 + sign = true; 307 + write = false; 308 + break; 309 + case fsts_op: 310 + size = 4; 311 + fp = true; 312 + sign = true; 313 + write = true; 314 + break; 315 + case fldd_op: 316 + size = 8; 317 + fp = true; 318 + sign = true; 319 + write = false; 320 + break; 321 + case fstd_op: 322 + size = 8; 323 + fp = true; 324 + sign = true; 325 + write = true; 326 + break; 327 + } 328 + 329 + switch (insn.reg2i14_format.opcode) { 330 + case ldptrw_op: 331 + size = 4; 332 + sign = true; 333 + write = false; 334 + break; 335 + case stptrw_op: 336 + size = 4; 337 + sign = true; 338 + write = true; 339 + break; 340 + case ldptrd_op: 341 + size = 8; 342 + sign = true; 343 + write = false; 344 + break; 345 + case stptrd_op: 346 + size = 8; 347 + sign = true; 348 + write = true; 349 + break; 350 + } 351 + 352 + switch (insn.reg3_format.opcode) { 353 + case ldxh_op: 354 + size = 2; 355 + sign = true; 356 + write = false; 357 + break; 358 + case ldxhu_op: 359 + size = 2; 360 + sign = false; 361 + write = false; 362 + break; 363 + case stxh_op: 364 + size = 2; 365 + sign = true; 366 + write = true; 367 + break; 368 + case ldxw_op: 369 + size = 4; 370 + sign = true; 371 + write = false; 372 + break; 373 + case ldxwu_op: 374 + size = 4; 375 + sign = false; 376 + write = false; 377 + break; 378 + case stxw_op: 379 + size = 4; 380 + sign = true; 381 + write = true; 382 + break; 383 + case ldxd_op: 384 + size = 8; 385 + sign = true; 386 + write = false; 387 + break; 388 + case stxd_op: 389 + size = 8; 390 + sign = true; 391 + write = true; 392 + break; 393 + case fldxs_op: 394 + size = 4; 395 + fp = true; 396 + sign = true; 397 + write = false; 398 + break; 399 + case fstxs_op: 400 + size = 4; 401 + fp = true; 402 + sign = true; 403 + write = true; 404 + break; 405 + case fldxd_op: 406 + size = 8; 407 + fp = true; 408 + sign = true; 409 + write = false; 410 + break; 411 + case fstxd_op: 412 + size = 8; 413 + fp = true; 414 + sign = true; 415 + write = true; 416 + break; 417 + } 418 + 419 + if (!size) 420 + goto sigbus; 421 + if (user && !access_ok(addr, size)) 422 + goto sigbus; 423 + 424 + if (!write) { 425 + res = unaligned_read(addr, &value, size, sign); 426 + if (res) 427 + goto fault; 428 + 429 + /* Rd is the same field in any formats */ 430 + if (!fp) 431 + regs->regs[insn.reg3_format.rd] = value; 432 + else { 433 + if (is_fpu_owner()) 434 + write_fpr(insn.reg3_format.rd, value); 435 + else 436 + set_fpr64(&current->thread.fpu.fpr[insn.reg3_format.rd], 0, value); 437 + } 438 + } else { 439 + /* Rd is the same field in any formats */ 440 + if (!fp) 441 + value = regs->regs[insn.reg3_format.rd]; 442 + else { 443 + if (is_fpu_owner()) 444 + value = read_fpr(insn.reg3_format.rd); 445 + else 446 + value = get_fpr64(&current->thread.fpu.fpr[insn.reg3_format.rd], 0); 447 + } 448 + 449 + res = unaligned_write(addr, value, size); 450 + if (res) 451 + goto fault; 452 + } 453 + 454 + #ifdef CONFIG_DEBUG_FS 455 + if (user) 456 + unaligned_instructions_user++; 457 + else 458 + unaligned_instructions_kernel++; 459 + #endif 460 + 461 + compute_return_era(regs); 462 + 463 + return; 464 + 465 + fault: 466 + /* Did we have an exception handler installed? */ 467 + if (fixup_exception(regs)) 468 + return; 469 + 470 + die_if_kernel("Unhandled kernel unaligned access", regs); 471 + force_sig(SIGSEGV); 472 + 473 + return; 474 + 475 + sigbus: 476 + die_if_kernel("Unhandled kernel unaligned access", regs); 477 + force_sig(SIGBUS); 478 + 479 + return; 480 + } 481 + 482 + #ifdef CONFIG_DEBUG_FS 483 + static int __init debugfs_unaligned(void) 484 + { 485 + struct dentry *d; 486 + 487 + d = debugfs_create_dir("loongarch", NULL); 488 + if (!d) 489 + return -ENOMEM; 490 + 491 + debugfs_create_u32("unaligned_instructions_user", 492 + S_IRUGO, d, &unaligned_instructions_user); 493 + debugfs_create_u32("unaligned_instructions_kernel", 494 + S_IRUGO, d, &unaligned_instructions_kernel); 495 + 496 + return 0; 497 + } 498 + arch_initcall(debugfs_unaligned); 499 + #endif
+3 -1
arch/loongarch/kernel/unwind_guess.c
··· 3 3 * Copyright (C) 2022 Loongson Technology Corporation Limited 4 4 */ 5 5 #include <linux/kernel.h> 6 + #include <linux/ftrace.h> 6 7 7 8 #include <asm/unwind.h> 8 9 ··· 54 53 state->sp < info->end; 55 54 state->sp += sizeof(unsigned long)) { 56 55 addr = *(unsigned long *)(state->sp); 57 - 56 + state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx, 57 + addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); 58 58 if (__kernel_text_address(addr)) 59 59 return true; 60 60 }
+42 -8
arch/loongarch/kernel/unwind_prologue.c
··· 2 2 /* 3 3 * Copyright (C) 2022 Loongson Technology Corporation Limited 4 4 */ 5 + #include <linux/ftrace.h> 5 6 #include <linux/kallsyms.h> 6 7 7 8 #include <asm/inst.h> 8 9 #include <asm/ptrace.h> 9 10 #include <asm/unwind.h> 11 + 12 + static inline void unwind_state_fixup(struct unwind_state *state) 13 + { 14 + #ifdef CONFIG_DYNAMIC_FTRACE 15 + static unsigned long ftrace = (unsigned long)ftrace_call + 4; 16 + 17 + if (state->pc == ftrace) 18 + state->is_ftrace = true; 19 + #endif 20 + } 10 21 11 22 unsigned long unwind_get_return_address(struct unwind_state *state) 12 23 { ··· 43 32 state->sp < info->end; 44 33 state->sp += sizeof(unsigned long)) { 45 34 addr = *(unsigned long *)(state->sp); 35 + state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx, 36 + addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); 46 37 if (__kernel_text_address(addr)) 47 38 return true; 48 39 } ··· 54 41 55 42 static bool unwind_by_prologue(struct unwind_state *state) 56 43 { 57 - struct stack_info *info = &state->stack_info; 58 - union loongarch_instruction *ip, *ip_end; 59 44 long frame_ra = -1; 60 45 unsigned long frame_size = 0; 61 46 unsigned long size, offset, pc = state->pc; 47 + struct pt_regs *regs; 48 + struct stack_info *info = &state->stack_info; 49 + union loongarch_instruction *ip, *ip_end; 62 50 63 51 if (state->sp >= info->end || state->sp < info->begin) 64 52 return false; 53 + 54 + if (state->is_ftrace) { 55 + /* 56 + * As we meet ftrace_regs_entry, reset first flag like first doing 57 + * tracing. Prologue analysis will stop soon because PC is at entry. 58 + */ 59 + regs = (struct pt_regs *)state->sp; 60 + state->first = true; 61 + state->is_ftrace = false; 62 + state->pc = regs->csr_era; 63 + state->ra = regs->regs[1]; 64 + state->sp = regs->regs[3]; 65 + return true; 66 + } 65 67 66 68 if (!kallsyms_lookup_size_offset(pc, &size, &offset)) 67 69 return false; ··· 123 95 124 96 state->pc = *(unsigned long *)(state->sp + frame_ra); 125 97 state->sp = state->sp + frame_size; 126 - return !!__kernel_text_address(state->pc); 98 + goto out; 127 99 128 100 first: 129 101 state->first = false; ··· 132 104 133 105 state->pc = state->ra; 134 106 135 - return !!__kernel_text_address(state->ra); 107 + out: 108 + unwind_state_fixup(state); 109 + return !!__kernel_text_address(state->pc); 136 110 } 137 111 138 112 void unwind_start(struct unwind_state *state, struct task_struct *task, ··· 177 147 break; 178 148 179 149 case UNWINDER_PROLOGUE: 180 - if (unwind_by_prologue(state)) 150 + if (unwind_by_prologue(state)) { 151 + state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx, 152 + state->pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); 181 153 return true; 154 + } 182 155 183 156 if (info->type == STACK_TYPE_IRQ && 184 157 info->end == state->sp) { ··· 191 158 if (user_mode(regs) || !__kernel_text_address(pc)) 192 159 return false; 193 160 194 - state->pc = pc; 195 - state->sp = regs->regs[3]; 196 - state->ra = regs->regs[1]; 197 161 state->first = true; 162 + state->ra = regs->regs[1]; 163 + state->sp = regs->regs[3]; 164 + state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx, 165 + pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); 198 166 get_stack_info(state->sp, state->task, info); 199 167 200 168 return true;
+12 -1
arch/loongarch/kernel/vmlinux.lds.S
··· 4 4 #include <asm/thread_info.h> 5 5 6 6 #define PAGE_SIZE _PAGE_SIZE 7 + #define RO_EXCEPTION_TABLE_ALIGN 4 7 8 8 9 /* 9 10 * Put .bss..swapper_pg_dir as the first thing in .bss. This will ··· 54 53 . = ALIGN(PECOFF_SEGMENT_ALIGN); 55 54 _etext = .; 56 55 57 - EXCEPTION_TABLE(16) 56 + /* 57 + * struct alt_inst entries. From the header (alternative.h): 58 + * "Alternative instructions for different CPU types or capabilities" 59 + * Think locking instructions on spinlocks. 60 + */ 61 + . = ALIGN(4); 62 + .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { 63 + __alt_instructions = .; 64 + *(.altinstructions) 65 + __alt_instructions_end = .; 66 + } 58 67 59 68 .got : ALIGN(16) { *(.got) } 60 69 .plt : ALIGN(16) { *(.plt) }
+2 -1
arch/loongarch/lib/Makefile
··· 3 3 # Makefile for LoongArch-specific library files. 4 4 # 5 5 6 - lib-y += delay.o clear_user.o copy_user.o dump_tlb.o 6 + lib-y += delay.o memset.o memcpy.o memmove.o \ 7 + clear_user.o copy_user.o dump_tlb.o unaligned.o
+70 -15
arch/loongarch/lib/clear_user.S
··· 3 3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 4 */ 5 5 6 + #include <asm/alternative-asm.h> 6 7 #include <asm/asm.h> 7 8 #include <asm/asmmacro.h> 9 + #include <asm/asm-extable.h> 10 + #include <asm/cpu.h> 8 11 #include <asm/export.h> 9 12 #include <asm/regdef.h> 10 13 11 - .macro fixup_ex from, to, offset, fix 12 - .if \fix 13 - .section .fixup, "ax" 14 - \to: addi.d a0, a1, \offset 14 + .irp to, 0, 1, 2, 3, 4, 5, 6, 7 15 + .L_fixup_handle_\to\(): 16 + addi.d a0, a1, (\to) * (-8) 15 17 jr ra 16 - .previous 17 - .endif 18 - .section __ex_table, "a" 19 - PTR \from\()b, \to\()b 20 - .previous 21 - .endm 18 + .endr 19 + 20 + SYM_FUNC_START(__clear_user) 21 + /* 22 + * Some CPUs support hardware unaligned access 23 + */ 24 + ALTERNATIVE "b __clear_user_generic", \ 25 + "b __clear_user_fast", CPU_FEATURE_UAL 26 + SYM_FUNC_END(__clear_user) 27 + 28 + EXPORT_SYMBOL(__clear_user) 22 29 23 30 /* 24 - * unsigned long __clear_user(void *addr, size_t size) 31 + * unsigned long __clear_user_generic(void *addr, size_t size) 25 32 * 26 33 * a0: addr 27 34 * a1: size 28 35 */ 29 - SYM_FUNC_START(__clear_user) 36 + SYM_FUNC_START(__clear_user_generic) 30 37 beqz a1, 2f 31 38 32 39 1: st.b zero, a0, 0 ··· 44 37 2: move a0, a1 45 38 jr ra 46 39 47 - fixup_ex 1, 3, 0, 1 48 - SYM_FUNC_END(__clear_user) 40 + _asm_extable 1b, .L_fixup_handle_0 41 + SYM_FUNC_END(__clear_user_generic) 49 42 50 - EXPORT_SYMBOL(__clear_user) 43 + /* 44 + * unsigned long __clear_user_fast(void *addr, unsigned long size) 45 + * 46 + * a0: addr 47 + * a1: size 48 + */ 49 + SYM_FUNC_START(__clear_user_fast) 50 + beqz a1, 10f 51 + 52 + ori a2, zero, 64 53 + blt a1, a2, 9f 54 + 55 + /* set 64 bytes at a time */ 56 + 1: st.d zero, a0, 0 57 + 2: st.d zero, a0, 8 58 + 3: st.d zero, a0, 16 59 + 4: st.d zero, a0, 24 60 + 5: st.d zero, a0, 32 61 + 6: st.d zero, a0, 40 62 + 7: st.d zero, a0, 48 63 + 8: st.d zero, a0, 56 64 + 65 + addi.d a0, a0, 64 66 + addi.d a1, a1, -64 67 + bge a1, a2, 1b 68 + 69 + beqz a1, 10f 70 + 71 + /* set the remaining bytes */ 72 + 9: st.b zero, a0, 0 73 + addi.d a0, a0, 1 74 + addi.d a1, a1, -1 75 + bgt a1, zero, 9b 76 + 77 + /* return */ 78 + 10: move a0, a1 79 + jr ra 80 + 81 + /* fixup and ex_table */ 82 + _asm_extable 1b, .L_fixup_handle_0 83 + _asm_extable 2b, .L_fixup_handle_1 84 + _asm_extable 3b, .L_fixup_handle_2 85 + _asm_extable 4b, .L_fixup_handle_3 86 + _asm_extable 5b, .L_fixup_handle_4 87 + _asm_extable 6b, .L_fixup_handle_5 88 + _asm_extable 7b, .L_fixup_handle_6 89 + _asm_extable 8b, .L_fixup_handle_7 90 + _asm_extable 9b, .L_fixup_handle_0 91 + SYM_FUNC_END(__clear_user_fast)
+92 -16
arch/loongarch/lib/copy_user.S
··· 3 3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 4 */ 5 5 6 + #include <asm/alternative-asm.h> 6 7 #include <asm/asm.h> 7 8 #include <asm/asmmacro.h> 9 + #include <asm/asm-extable.h> 10 + #include <asm/cpu.h> 8 11 #include <asm/export.h> 9 12 #include <asm/regdef.h> 10 13 11 - .macro fixup_ex from, to, offset, fix 12 - .if \fix 13 - .section .fixup, "ax" 14 - \to: addi.d a0, a2, \offset 14 + .irp to, 0, 1, 2, 3, 4, 5, 6, 7 15 + .L_fixup_handle_\to\(): 16 + addi.d a0, a2, (\to) * (-8) 15 17 jr ra 16 - .previous 17 - .endif 18 - .section __ex_table, "a" 19 - PTR \from\()b, \to\()b 20 - .previous 21 - .endm 18 + .endr 19 + 20 + SYM_FUNC_START(__copy_user) 21 + /* 22 + * Some CPUs support hardware unaligned access 23 + */ 24 + ALTERNATIVE "b __copy_user_generic", \ 25 + "b __copy_user_fast", CPU_FEATURE_UAL 26 + SYM_FUNC_END(__copy_user) 27 + 28 + EXPORT_SYMBOL(__copy_user) 22 29 23 30 /* 24 - * unsigned long __copy_user(void *to, const void *from, size_t n) 31 + * unsigned long __copy_user_generic(void *to, const void *from, size_t n) 25 32 * 26 33 * a0: to 27 34 * a1: from 28 35 * a2: n 29 36 */ 30 - SYM_FUNC_START(__copy_user) 37 + SYM_FUNC_START(__copy_user_generic) 31 38 beqz a2, 3f 32 39 33 40 1: ld.b t0, a1, 0 ··· 47 40 3: move a0, a2 48 41 jr ra 49 42 50 - fixup_ex 1, 4, 0, 1 51 - fixup_ex 2, 4, 0, 0 52 - SYM_FUNC_END(__copy_user) 43 + _asm_extable 1b, .L_fixup_handle_0 44 + _asm_extable 2b, .L_fixup_handle_0 45 + SYM_FUNC_END(__copy_user_generic) 53 46 54 - EXPORT_SYMBOL(__copy_user) 47 + /* 48 + * unsigned long __copy_user_fast(void *to, const void *from, unsigned long n) 49 + * 50 + * a0: to 51 + * a1: from 52 + * a2: n 53 + */ 54 + SYM_FUNC_START(__copy_user_fast) 55 + beqz a2, 19f 56 + 57 + ori a3, zero, 64 58 + blt a2, a3, 17f 59 + 60 + /* copy 64 bytes at a time */ 61 + 1: ld.d t0, a1, 0 62 + 2: ld.d t1, a1, 8 63 + 3: ld.d t2, a1, 16 64 + 4: ld.d t3, a1, 24 65 + 5: ld.d t4, a1, 32 66 + 6: ld.d t5, a1, 40 67 + 7: ld.d t6, a1, 48 68 + 8: ld.d t7, a1, 56 69 + 9: st.d t0, a0, 0 70 + 10: st.d t1, a0, 8 71 + 11: st.d t2, a0, 16 72 + 12: st.d t3, a0, 24 73 + 13: st.d t4, a0, 32 74 + 14: st.d t5, a0, 40 75 + 15: st.d t6, a0, 48 76 + 16: st.d t7, a0, 56 77 + 78 + addi.d a0, a0, 64 79 + addi.d a1, a1, 64 80 + addi.d a2, a2, -64 81 + bge a2, a3, 1b 82 + 83 + beqz a2, 19f 84 + 85 + /* copy the remaining bytes */ 86 + 17: ld.b t0, a1, 0 87 + 18: st.b t0, a0, 0 88 + addi.d a0, a0, 1 89 + addi.d a1, a1, 1 90 + addi.d a2, a2, -1 91 + bgt a2, zero, 17b 92 + 93 + /* return */ 94 + 19: move a0, a2 95 + jr ra 96 + 97 + /* fixup and ex_table */ 98 + _asm_extable 1b, .L_fixup_handle_0 99 + _asm_extable 2b, .L_fixup_handle_1 100 + _asm_extable 3b, .L_fixup_handle_2 101 + _asm_extable 4b, .L_fixup_handle_3 102 + _asm_extable 5b, .L_fixup_handle_4 103 + _asm_extable 6b, .L_fixup_handle_5 104 + _asm_extable 7b, .L_fixup_handle_6 105 + _asm_extable 8b, .L_fixup_handle_7 106 + _asm_extable 9b, .L_fixup_handle_0 107 + _asm_extable 10b, .L_fixup_handle_1 108 + _asm_extable 11b, .L_fixup_handle_2 109 + _asm_extable 12b, .L_fixup_handle_3 110 + _asm_extable 13b, .L_fixup_handle_4 111 + _asm_extable 14b, .L_fixup_handle_5 112 + _asm_extable 15b, .L_fixup_handle_6 113 + _asm_extable 16b, .L_fixup_handle_7 114 + _asm_extable 17b, .L_fixup_handle_0 115 + _asm_extable 18b, .L_fixup_handle_0 116 + SYM_FUNC_END(__copy_user_fast)
+95
arch/loongarch/lib/memcpy.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 + */ 5 + 6 + #include <asm/alternative-asm.h> 7 + #include <asm/asm.h> 8 + #include <asm/asmmacro.h> 9 + #include <asm/cpu.h> 10 + #include <asm/export.h> 11 + #include <asm/regdef.h> 12 + 13 + SYM_FUNC_START(memcpy) 14 + /* 15 + * Some CPUs support hardware unaligned access 16 + */ 17 + ALTERNATIVE "b __memcpy_generic", \ 18 + "b __memcpy_fast", CPU_FEATURE_UAL 19 + SYM_FUNC_END(memcpy) 20 + 21 + EXPORT_SYMBOL(memcpy) 22 + 23 + /* 24 + * void *__memcpy_generic(void *dst, const void *src, size_t n) 25 + * 26 + * a0: dst 27 + * a1: src 28 + * a2: n 29 + */ 30 + SYM_FUNC_START(__memcpy_generic) 31 + move a3, a0 32 + beqz a2, 2f 33 + 34 + 1: ld.b t0, a1, 0 35 + st.b t0, a0, 0 36 + addi.d a0, a0, 1 37 + addi.d a1, a1, 1 38 + addi.d a2, a2, -1 39 + bgt a2, zero, 1b 40 + 41 + 2: move a0, a3 42 + jr ra 43 + SYM_FUNC_END(__memcpy_generic) 44 + 45 + /* 46 + * void *__memcpy_fast(void *dst, const void *src, size_t n) 47 + * 48 + * a0: dst 49 + * a1: src 50 + * a2: n 51 + */ 52 + SYM_FUNC_START(__memcpy_fast) 53 + move a3, a0 54 + beqz a2, 3f 55 + 56 + ori a4, zero, 64 57 + blt a2, a4, 2f 58 + 59 + /* copy 64 bytes at a time */ 60 + 1: ld.d t0, a1, 0 61 + ld.d t1, a1, 8 62 + ld.d t2, a1, 16 63 + ld.d t3, a1, 24 64 + ld.d t4, a1, 32 65 + ld.d t5, a1, 40 66 + ld.d t6, a1, 48 67 + ld.d t7, a1, 56 68 + st.d t0, a0, 0 69 + st.d t1, a0, 8 70 + st.d t2, a0, 16 71 + st.d t3, a0, 24 72 + st.d t4, a0, 32 73 + st.d t5, a0, 40 74 + st.d t6, a0, 48 75 + st.d t7, a0, 56 76 + 77 + addi.d a0, a0, 64 78 + addi.d a1, a1, 64 79 + addi.d a2, a2, -64 80 + bge a2, a4, 1b 81 + 82 + beqz a2, 3f 83 + 84 + /* copy the remaining bytes */ 85 + 2: ld.b t0, a1, 0 86 + st.b t0, a0, 0 87 + addi.d a0, a0, 1 88 + addi.d a1, a1, 1 89 + addi.d a2, a2, -1 90 + bgt a2, zero, 2b 91 + 92 + /* return */ 93 + 3: move a0, a3 94 + jr ra 95 + SYM_FUNC_END(__memcpy_fast)
+121
arch/loongarch/lib/memmove.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 + */ 5 + 6 + #include <asm/alternative-asm.h> 7 + #include <asm/asm.h> 8 + #include <asm/asmmacro.h> 9 + #include <asm/cpu.h> 10 + #include <asm/export.h> 11 + #include <asm/regdef.h> 12 + 13 + SYM_FUNC_START(memmove) 14 + blt a0, a1, 1f /* dst < src, memcpy */ 15 + blt a1, a0, 3f /* src < dst, rmemcpy */ 16 + jr ra /* dst == src, return */ 17 + 18 + /* if (src - dst) < 64, copy 1 byte at a time */ 19 + 1: ori a3, zero, 64 20 + sub.d t0, a1, a0 21 + blt t0, a3, 2f 22 + b memcpy 23 + 2: b __memcpy_generic 24 + 25 + /* if (dst - src) < 64, copy 1 byte at a time */ 26 + 3: ori a3, zero, 64 27 + sub.d t0, a0, a1 28 + blt t0, a3, 4f 29 + b rmemcpy 30 + 4: b __rmemcpy_generic 31 + SYM_FUNC_END(memmove) 32 + 33 + EXPORT_SYMBOL(memmove) 34 + 35 + SYM_FUNC_START(rmemcpy) 36 + /* 37 + * Some CPUs support hardware unaligned access 38 + */ 39 + ALTERNATIVE "b __rmemcpy_generic", \ 40 + "b __rmemcpy_fast", CPU_FEATURE_UAL 41 + SYM_FUNC_END(rmemcpy) 42 + 43 + /* 44 + * void *__rmemcpy_generic(void *dst, const void *src, size_t n) 45 + * 46 + * a0: dst 47 + * a1: src 48 + * a2: n 49 + */ 50 + SYM_FUNC_START(__rmemcpy_generic) 51 + move a3, a0 52 + beqz a2, 2f 53 + 54 + add.d a0, a0, a2 55 + add.d a1, a1, a2 56 + 57 + 1: ld.b t0, a1, -1 58 + st.b t0, a0, -1 59 + addi.d a0, a0, -1 60 + addi.d a1, a1, -1 61 + addi.d a2, a2, -1 62 + bgt a2, zero, 1b 63 + 64 + 2: move a0, a3 65 + jr ra 66 + SYM_FUNC_END(__rmemcpy_generic) 67 + 68 + /* 69 + * void *__rmemcpy_fast(void *dst, const void *src, size_t n) 70 + * 71 + * a0: dst 72 + * a1: src 73 + * a2: n 74 + */ 75 + SYM_FUNC_START(__rmemcpy_fast) 76 + move a3, a0 77 + beqz a2, 3f 78 + 79 + add.d a0, a0, a2 80 + add.d a1, a1, a2 81 + 82 + ori a4, zero, 64 83 + blt a2, a4, 2f 84 + 85 + /* copy 64 bytes at a time */ 86 + 1: ld.d t0, a1, -8 87 + ld.d t1, a1, -16 88 + ld.d t2, a1, -24 89 + ld.d t3, a1, -32 90 + ld.d t4, a1, -40 91 + ld.d t5, a1, -48 92 + ld.d t6, a1, -56 93 + ld.d t7, a1, -64 94 + st.d t0, a0, -8 95 + st.d t1, a0, -16 96 + st.d t2, a0, -24 97 + st.d t3, a0, -32 98 + st.d t4, a0, -40 99 + st.d t5, a0, -48 100 + st.d t6, a0, -56 101 + st.d t7, a0, -64 102 + 103 + addi.d a0, a0, -64 104 + addi.d a1, a1, -64 105 + addi.d a2, a2, -64 106 + bge a2, a4, 1b 107 + 108 + beqz a2, 3f 109 + 110 + /* copy the remaining bytes */ 111 + 2: ld.b t0, a1, -1 112 + st.b t0, a0, -1 113 + addi.d a0, a0, -1 114 + addi.d a1, a1, -1 115 + addi.d a2, a2, -1 116 + bgt a2, zero, 2b 117 + 118 + /* return */ 119 + 3: move a0, a3 120 + jr ra 121 + SYM_FUNC_END(__rmemcpy_fast)
+91
arch/loongarch/lib/memset.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 + */ 5 + 6 + #include <asm/alternative-asm.h> 7 + #include <asm/asm.h> 8 + #include <asm/asmmacro.h> 9 + #include <asm/cpu.h> 10 + #include <asm/export.h> 11 + #include <asm/regdef.h> 12 + 13 + .macro fill_to_64 r0 14 + bstrins.d \r0, \r0, 15, 8 15 + bstrins.d \r0, \r0, 31, 16 16 + bstrins.d \r0, \r0, 63, 32 17 + .endm 18 + 19 + SYM_FUNC_START(memset) 20 + /* 21 + * Some CPUs support hardware unaligned access 22 + */ 23 + ALTERNATIVE "b __memset_generic", \ 24 + "b __memset_fast", CPU_FEATURE_UAL 25 + SYM_FUNC_END(memset) 26 + 27 + EXPORT_SYMBOL(memset) 28 + 29 + /* 30 + * void *__memset_generic(void *s, int c, size_t n) 31 + * 32 + * a0: s 33 + * a1: c 34 + * a2: n 35 + */ 36 + SYM_FUNC_START(__memset_generic) 37 + move a3, a0 38 + beqz a2, 2f 39 + 40 + 1: st.b a1, a0, 0 41 + addi.d a0, a0, 1 42 + addi.d a2, a2, -1 43 + bgt a2, zero, 1b 44 + 45 + 2: move a0, a3 46 + jr ra 47 + SYM_FUNC_END(__memset_generic) 48 + 49 + /* 50 + * void *__memset_fast(void *s, int c, size_t n) 51 + * 52 + * a0: s 53 + * a1: c 54 + * a2: n 55 + */ 56 + SYM_FUNC_START(__memset_fast) 57 + move a3, a0 58 + beqz a2, 3f 59 + 60 + ori a4, zero, 64 61 + blt a2, a4, 2f 62 + 63 + /* fill a1 to 64 bits */ 64 + fill_to_64 a1 65 + 66 + /* set 64 bytes at a time */ 67 + 1: st.d a1, a0, 0 68 + st.d a1, a0, 8 69 + st.d a1, a0, 16 70 + st.d a1, a0, 24 71 + st.d a1, a0, 32 72 + st.d a1, a0, 40 73 + st.d a1, a0, 48 74 + st.d a1, a0, 56 75 + 76 + addi.d a0, a0, 64 77 + addi.d a2, a2, -64 78 + bge a2, a4, 1b 79 + 80 + beqz a2, 3f 81 + 82 + /* set the remaining bytes */ 83 + 2: st.b a1, a0, 0 84 + addi.d a0, a0, 1 85 + addi.d a2, a2, -1 86 + bgt a2, zero, 2b 87 + 88 + /* return */ 89 + 3: move a0, a3 90 + jr ra 91 + SYM_FUNC_END(__memset_fast)
+84
arch/loongarch/lib/unaligned.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 + */ 5 + 6 + #include <linux/linkage.h> 7 + 8 + #include <asm/asm.h> 9 + #include <asm/asmmacro.h> 10 + #include <asm/asm-extable.h> 11 + #include <asm/errno.h> 12 + #include <asm/export.h> 13 + #include <asm/regdef.h> 14 + 15 + .L_fixup_handle_unaligned: 16 + li.w a0, -EFAULT 17 + jr ra 18 + 19 + /* 20 + * unsigned long unaligned_read(void *addr, void *value, unsigned long n, bool sign) 21 + * 22 + * a0: addr 23 + * a1: value 24 + * a2: n 25 + * a3: sign 26 + */ 27 + SYM_FUNC_START(unaligned_read) 28 + beqz a2, 5f 29 + 30 + li.w t2, 0 31 + addi.d t0, a2, -1 32 + slli.d t1, t0, 3 33 + add.d a0, a0, t0 34 + 35 + beqz a3, 2f 36 + 1: ld.b t3, a0, 0 37 + b 3f 38 + 39 + 2: ld.bu t3, a0, 0 40 + 3: sll.d t3, t3, t1 41 + or t2, t2, t3 42 + addi.d t1, t1, -8 43 + addi.d a0, a0, -1 44 + addi.d a2, a2, -1 45 + bgtz a2, 2b 46 + 4: st.d t2, a1, 0 47 + 48 + move a0, a2 49 + jr ra 50 + 51 + 5: li.w a0, -EFAULT 52 + jr ra 53 + 54 + _asm_extable 1b, .L_fixup_handle_unaligned 55 + _asm_extable 2b, .L_fixup_handle_unaligned 56 + _asm_extable 4b, .L_fixup_handle_unaligned 57 + SYM_FUNC_END(unaligned_read) 58 + 59 + /* 60 + * unsigned long unaligned_write(void *addr, unsigned long value, unsigned long n) 61 + * 62 + * a0: addr 63 + * a1: value 64 + * a2: n 65 + */ 66 + SYM_FUNC_START(unaligned_write) 67 + beqz a2, 3f 68 + 69 + li.w t0, 0 70 + 1: srl.d t1, a1, t0 71 + 2: st.b t1, a0, 0 72 + addi.d t0, t0, 8 73 + addi.d a2, a2, -1 74 + addi.d a0, a0, 1 75 + bgtz a2, 1b 76 + 77 + move a0, a2 78 + jr ra 79 + 80 + 3: li.w a0, -EFAULT 81 + jr ra 82 + 83 + _asm_extable 2b, .L_fixup_handle_unaligned 84 + SYM_FUNC_END(unaligned_write)
+50 -9
arch/loongarch/mm/extable.c
··· 2 2 /* 3 3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 4 */ 5 + #include <linux/bitfield.h> 5 6 #include <linux/extable.h> 6 - #include <linux/spinlock.h> 7 - #include <asm/branch.h> 8 7 #include <linux/uaccess.h> 8 + #include <asm/asm-extable.h> 9 + #include <asm/branch.h> 9 10 10 - int fixup_exception(struct pt_regs *regs) 11 + static inline unsigned long 12 + get_ex_fixup(const struct exception_table_entry *ex) 11 13 { 12 - const struct exception_table_entry *fixup; 14 + return ((unsigned long)&ex->fixup + ex->fixup); 15 + } 13 16 14 - fixup = search_exception_tables(exception_era(regs)); 15 - if (fixup) { 16 - regs->csr_era = fixup->fixup; 17 + static inline void regs_set_gpr(struct pt_regs *regs, 18 + unsigned int offset, unsigned long val) 19 + { 20 + if (offset && offset <= MAX_REG_OFFSET) 21 + *(unsigned long *)((unsigned long)regs + offset) = val; 22 + } 17 23 18 - return 1; 24 + static bool ex_handler_fixup(const struct exception_table_entry *ex, 25 + struct pt_regs *regs) 26 + { 27 + regs->csr_era = get_ex_fixup(ex); 28 + 29 + return true; 30 + } 31 + 32 + static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex, 33 + struct pt_regs *regs) 34 + { 35 + int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data); 36 + int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data); 37 + 38 + regs_set_gpr(regs, reg_err * sizeof(unsigned long), -EFAULT); 39 + regs_set_gpr(regs, reg_zero * sizeof(unsigned long), 0); 40 + regs->csr_era = get_ex_fixup(ex); 41 + 42 + return true; 43 + } 44 + 45 + bool fixup_exception(struct pt_regs *regs) 46 + { 47 + const struct exception_table_entry *ex; 48 + 49 + ex = search_exception_tables(exception_era(regs)); 50 + if (!ex) 51 + return false; 52 + 53 + switch (ex->type) { 54 + case EX_TYPE_FIXUP: 55 + return ex_handler_fixup(ex, regs); 56 + case EX_TYPE_UACCESS_ERR_ZERO: 57 + return ex_handler_uaccess_err_zero(ex, regs); 58 + case EX_TYPE_BPF: 59 + return ex_handler_bpf(ex, regs); 19 60 } 20 61 21 - return 0; 62 + BUG(); 22 63 }
+81 -5
arch/loongarch/net/bpf_jit.c
··· 387 387 cond == BPF_JSGE || cond == BPF_JSLE; 388 388 } 389 389 390 + #define BPF_FIXUP_REG_MASK GENMASK(31, 27) 391 + #define BPF_FIXUP_OFFSET_MASK GENMASK(26, 0) 392 + 393 + bool ex_handler_bpf(const struct exception_table_entry *ex, 394 + struct pt_regs *regs) 395 + { 396 + int dst_reg = FIELD_GET(BPF_FIXUP_REG_MASK, ex->fixup); 397 + off_t offset = FIELD_GET(BPF_FIXUP_OFFSET_MASK, ex->fixup); 398 + 399 + regs->regs[dst_reg] = 0; 400 + regs->csr_era = (unsigned long)&ex->fixup - offset; 401 + 402 + return true; 403 + } 404 + 405 + /* For accesses to BTF pointers, add an entry to the exception table */ 406 + static int add_exception_handler(const struct bpf_insn *insn, 407 + struct jit_ctx *ctx, 408 + int dst_reg) 409 + { 410 + unsigned long pc; 411 + off_t offset; 412 + struct exception_table_entry *ex; 413 + 414 + if (!ctx->image || !ctx->prog->aux->extable || BPF_MODE(insn->code) != BPF_PROBE_MEM) 415 + return 0; 416 + 417 + if (WARN_ON_ONCE(ctx->num_exentries >= ctx->prog->aux->num_exentries)) 418 + return -EINVAL; 419 + 420 + ex = &ctx->prog->aux->extable[ctx->num_exentries]; 421 + pc = (unsigned long)&ctx->image[ctx->idx - 1]; 422 + 423 + offset = pc - (long)&ex->insn; 424 + if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN)) 425 + return -ERANGE; 426 + 427 + ex->insn = offset; 428 + 429 + /* 430 + * Since the extable follows the program, the fixup offset is always 431 + * negative and limited to BPF_JIT_REGION_SIZE. Store a positive value 432 + * to keep things simple, and put the destination register in the upper 433 + * bits. We don't need to worry about buildtime or runtime sort 434 + * modifying the upper bits because the table is already sorted, and 435 + * isn't part of the main exception table. 436 + */ 437 + offset = (long)&ex->fixup - (pc + LOONGARCH_INSN_SIZE); 438 + if (!FIELD_FIT(BPF_FIXUP_OFFSET_MASK, offset)) 439 + return -ERANGE; 440 + 441 + ex->type = EX_TYPE_BPF; 442 + ex->fixup = FIELD_PREP(BPF_FIXUP_OFFSET_MASK, offset) | FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg); 443 + 444 + ctx->num_exentries++; 445 + 446 + return 0; 447 + } 448 + 390 449 static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool extra_pass) 391 450 { 392 451 u8 tm = -1; ··· 875 816 case BPF_LDX | BPF_MEM | BPF_H: 876 817 case BPF_LDX | BPF_MEM | BPF_W: 877 818 case BPF_LDX | BPF_MEM | BPF_DW: 819 + case BPF_LDX | BPF_PROBE_MEM | BPF_DW: 820 + case BPF_LDX | BPF_PROBE_MEM | BPF_W: 821 + case BPF_LDX | BPF_PROBE_MEM | BPF_H: 822 + case BPF_LDX | BPF_PROBE_MEM | BPF_B: 878 823 switch (BPF_SIZE(code)) { 879 824 case BPF_B: 880 825 if (is_signed_imm12(off)) { ··· 917 854 } 918 855 break; 919 856 } 857 + 858 + ret = add_exception_handler(insn, ctx, dst); 859 + if (ret) 860 + return ret; 920 861 break; 921 862 922 863 /* *(size *)(dst + off) = imm */ ··· 1085 1018 return -1; 1086 1019 } 1087 1020 1021 + if (WARN_ON_ONCE(ctx->num_exentries != ctx->prog->aux->num_exentries)) 1022 + return -1; 1023 + 1088 1024 return 0; 1089 1025 } 1090 1026 ··· 1095 1025 { 1096 1026 bool tmp_blinded = false, extra_pass = false; 1097 1027 u8 *image_ptr; 1098 - int image_size; 1028 + int image_size, prog_size, extable_size; 1099 1029 struct jit_ctx ctx; 1100 1030 struct jit_data *jit_data; 1101 1031 struct bpf_binary_header *header; ··· 1136 1066 image_ptr = jit_data->image; 1137 1067 header = jit_data->header; 1138 1068 extra_pass = true; 1139 - image_size = sizeof(u32) * ctx.idx; 1069 + prog_size = sizeof(u32) * ctx.idx; 1140 1070 goto skip_init_ctx; 1141 1071 } 1142 1072 ··· 1158 1088 ctx.epilogue_offset = ctx.idx; 1159 1089 build_epilogue(&ctx); 1160 1090 1091 + extable_size = prog->aux->num_exentries * sizeof(struct exception_table_entry); 1092 + 1161 1093 /* Now we know the actual image size. 1162 1094 * As each LoongArch instruction is of length 32bit, 1163 1095 * we are translating number of JITed intructions into 1164 1096 * the size required to store these JITed code. 1165 1097 */ 1166 - image_size = sizeof(u32) * ctx.idx; 1098 + prog_size = sizeof(u32) * ctx.idx; 1099 + image_size = prog_size + extable_size; 1167 1100 /* Now we know the size of the structure to make */ 1168 1101 header = bpf_jit_binary_alloc(image_size, &image_ptr, 1169 1102 sizeof(u32), jit_fill_hole); ··· 1177 1104 1178 1105 /* 2. Now, the actual pass to generate final JIT code */ 1179 1106 ctx.image = (union loongarch_instruction *)image_ptr; 1107 + if (extable_size) 1108 + prog->aux->extable = (void *)image_ptr + prog_size; 1180 1109 1181 1110 skip_init_ctx: 1182 1111 ctx.idx = 0; 1112 + ctx.num_exentries = 0; 1183 1113 1184 1114 build_prologue(&ctx); 1185 1115 if (build_body(&ctx, extra_pass)) { ··· 1201 1125 1202 1126 /* And we're done */ 1203 1127 if (bpf_jit_enable > 1) 1204 - bpf_jit_dump(prog->len, image_size, 2, ctx.image); 1128 + bpf_jit_dump(prog->len, prog_size, 2, ctx.image); 1205 1129 1206 1130 /* Update the icache */ 1207 1131 flush_icache_range((unsigned long)header, (unsigned long)(ctx.image + ctx.idx)); ··· 1223 1147 jit_data->header = header; 1224 1148 } 1225 1149 prog->jited = 1; 1226 - prog->jited_len = image_size; 1150 + prog->jited_len = prog_size; 1227 1151 prog->bpf_func = (void *)ctx.image; 1228 1152 1229 1153 if (!prog->is_func || extra_pass) {
+2
arch/loongarch/net/bpf_jit.h
··· 4 4 * 5 5 * Copyright (C) 2022 Loongson Technology Corporation Limited 6 6 */ 7 + #include <linux/bitfield.h> 7 8 #include <linux/bpf.h> 8 9 #include <linux/filter.h> 9 10 #include <asm/cacheflush.h> ··· 16 15 unsigned int flags; 17 16 unsigned int epilogue_offset; 18 17 u32 *offset; 18 + int num_exentries; 19 19 union loongarch_instruction *image; 20 20 u32 stack_size; 21 21 };
+5 -2
arch/loongarch/pci/acpi.c
··· 26 26 27 27 int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) 28 28 { 29 - struct pci_config_window *cfg = bridge->bus->sysdata; 30 - struct acpi_device *adev = to_acpi_device(cfg->parent); 29 + struct acpi_device *adev = NULL; 31 30 struct device *bus_dev = &bridge->bus->dev; 31 + struct pci_config_window *cfg = bridge->bus->sysdata; 32 + 33 + if (!acpi_disabled) 34 + adev = to_acpi_device(cfg->parent); 32 35 33 36 ACPI_COMPANION_SET(&bridge->dev, adev); 34 37 set_dev_node(bus_dev, pa_to_nid(cfg->res.start));
+4
arch/loongarch/power/Makefile
··· 1 + obj-y += platform.o 2 + 3 + obj-$(CONFIG_SUSPEND) += suspend.o suspend_asm.o 4 + obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o
+62
arch/loongarch/power/hibernate.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <asm/fpu.h> 3 + #include <asm/loongson.h> 4 + #include <asm/sections.h> 5 + #include <asm/tlbflush.h> 6 + #include <linux/suspend.h> 7 + 8 + static u32 saved_crmd; 9 + static u32 saved_prmd; 10 + static u32 saved_euen; 11 + static u32 saved_ecfg; 12 + static u64 saved_pcpu_base; 13 + struct pt_regs saved_regs; 14 + 15 + void save_processor_state(void) 16 + { 17 + saved_crmd = csr_read32(LOONGARCH_CSR_CRMD); 18 + saved_prmd = csr_read32(LOONGARCH_CSR_PRMD); 19 + saved_euen = csr_read32(LOONGARCH_CSR_EUEN); 20 + saved_ecfg = csr_read32(LOONGARCH_CSR_ECFG); 21 + saved_pcpu_base = csr_read64(PERCPU_BASE_KS); 22 + 23 + if (is_fpu_owner()) 24 + save_fp(current); 25 + } 26 + 27 + void restore_processor_state(void) 28 + { 29 + csr_write32(saved_crmd, LOONGARCH_CSR_CRMD); 30 + csr_write32(saved_prmd, LOONGARCH_CSR_PRMD); 31 + csr_write32(saved_euen, LOONGARCH_CSR_EUEN); 32 + csr_write32(saved_ecfg, LOONGARCH_CSR_ECFG); 33 + csr_write64(saved_pcpu_base, PERCPU_BASE_KS); 34 + 35 + if (is_fpu_owner()) 36 + restore_fp(current); 37 + } 38 + 39 + int pfn_is_nosave(unsigned long pfn) 40 + { 41 + unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin)); 42 + unsigned long nosave_end_pfn = PFN_UP(__pa(&__nosave_end)); 43 + 44 + return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); 45 + } 46 + 47 + extern int swsusp_asm_suspend(void); 48 + 49 + int swsusp_arch_suspend(void) 50 + { 51 + enable_pci_wakeup(); 52 + return swsusp_asm_suspend(); 53 + } 54 + 55 + extern int swsusp_asm_resume(void); 56 + 57 + int swsusp_arch_resume(void) 58 + { 59 + /* Avoid TLB mismatch during and after kernel resume */ 60 + local_flush_tlb_all(); 61 + return swsusp_asm_resume(); 62 + }
+66
arch/loongarch/power/hibernate_asm.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Hibernation support specific for LoongArch 4 + * 5 + * Author: Huacai Chen <chenhuacai@loongson.cn> 6 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 7 + */ 8 + #include <linux/linkage.h> 9 + #include <asm/asm.h> 10 + #include <asm/asm-offsets.h> 11 + #include <asm/regdef.h> 12 + 13 + .text 14 + SYM_FUNC_START(swsusp_asm_suspend) 15 + la.pcrel t0, saved_regs 16 + PTR_S ra, t0, PT_R1 17 + PTR_S tp, t0, PT_R2 18 + PTR_S sp, t0, PT_R3 19 + PTR_S u0, t0, PT_R21 20 + PTR_S fp, t0, PT_R22 21 + PTR_S s0, t0, PT_R23 22 + PTR_S s1, t0, PT_R24 23 + PTR_S s2, t0, PT_R25 24 + PTR_S s3, t0, PT_R26 25 + PTR_S s4, t0, PT_R27 26 + PTR_S s5, t0, PT_R28 27 + PTR_S s6, t0, PT_R29 28 + PTR_S s7, t0, PT_R30 29 + PTR_S s8, t0, PT_R31 30 + b swsusp_save 31 + SYM_FUNC_END(swsusp_asm_suspend) 32 + 33 + SYM_FUNC_START(swsusp_asm_resume) 34 + la.pcrel t0, restore_pblist 35 + PTR_L t0, t0, 0 36 + 0: 37 + PTR_L t1, t0, PBE_ADDRESS /* source */ 38 + PTR_L t2, t0, PBE_ORIG_ADDRESS /* destination */ 39 + PTR_LI t3, _PAGE_SIZE 40 + PTR_ADD t3, t3, t1 41 + 1: 42 + REG_L t8, t1, 0 43 + REG_S t8, t2, 0 44 + PTR_ADDI t1, t1, SZREG 45 + PTR_ADDI t2, t2, SZREG 46 + bne t1, t3, 1b 47 + PTR_L t0, t0, PBE_NEXT 48 + bnez t0, 0b 49 + la.pcrel t0, saved_regs 50 + PTR_L ra, t0, PT_R1 51 + PTR_L tp, t0, PT_R2 52 + PTR_L sp, t0, PT_R3 53 + PTR_L u0, t0, PT_R21 54 + PTR_L fp, t0, PT_R22 55 + PTR_L s0, t0, PT_R23 56 + PTR_L s1, t0, PT_R24 57 + PTR_L s2, t0, PT_R25 58 + PTR_L s3, t0, PT_R26 59 + PTR_L s4, t0, PT_R27 60 + PTR_L s5, t0, PT_R28 61 + PTR_L s6, t0, PT_R29 62 + PTR_L s7, t0, PT_R30 63 + PTR_L s8, t0, PT_R31 64 + PTR_LI a0, 0x0 65 + jirl zero, ra, 0 66 + SYM_FUNC_END(swsusp_asm_resume)
+57
arch/loongarch/power/platform.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Author: Huacai Chen <chenhuacai@loongson.cn> 4 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 5 + */ 6 + #include <linux/acpi.h> 7 + #include <linux/platform_device.h> 8 + 9 + #include <asm/bootinfo.h> 10 + #include <asm/loongson.h> 11 + 12 + void enable_gpe_wakeup(void) 13 + { 14 + if (acpi_disabled) 15 + return; 16 + 17 + if (acpi_gbl_reduced_hardware) 18 + return; 19 + 20 + acpi_enable_all_wakeup_gpes(); 21 + } 22 + 23 + void enable_pci_wakeup(void) 24 + { 25 + if (acpi_disabled) 26 + return; 27 + 28 + if (acpi_gbl_reduced_hardware) 29 + return; 30 + 31 + acpi_write_bit_register(ACPI_BITREG_PCIEXP_WAKE_STATUS, 1); 32 + 33 + if (acpi_gbl_FADT.flags & ACPI_FADT_PCI_EXPRESS_WAKE) 34 + acpi_write_bit_register(ACPI_BITREG_PCIEXP_WAKE_DISABLE, 0); 35 + } 36 + 37 + static int __init loongson3_acpi_suspend_init(void) 38 + { 39 + #ifdef CONFIG_ACPI 40 + acpi_status status; 41 + uint64_t suspend_addr = 0; 42 + 43 + if (acpi_disabled || acpi_gbl_reduced_hardware) 44 + return 0; 45 + 46 + acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1); 47 + status = acpi_evaluate_integer(NULL, "\\SADR", NULL, &suspend_addr); 48 + if (ACPI_FAILURE(status) || !suspend_addr) { 49 + pr_err("ACPI S3 is not support!\n"); 50 + return -1; 51 + } 52 + loongson_sysconf.suspend_addr = (u64)phys_to_virt(PHYSADDR(suspend_addr)); 53 + #endif 54 + return 0; 55 + } 56 + 57 + device_initcall(loongson3_acpi_suspend_init);
+73
arch/loongarch/power/suspend.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * loongson-specific suspend support 4 + * 5 + * Author: Huacai Chen <chenhuacai@loongson.cn> 6 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 7 + */ 8 + #include <linux/acpi.h> 9 + #include <linux/pm.h> 10 + #include <linux/suspend.h> 11 + 12 + #include <asm/loongarch.h> 13 + #include <asm/loongson.h> 14 + #include <asm/setup.h> 15 + #include <asm/time.h> 16 + #include <asm/tlbflush.h> 17 + 18 + u64 loongarch_suspend_addr; 19 + 20 + struct saved_registers { 21 + u32 ecfg; 22 + u32 euen; 23 + u64 pgd; 24 + u64 kpgd; 25 + u32 pwctl0; 26 + u32 pwctl1; 27 + }; 28 + static struct saved_registers saved_regs; 29 + 30 + static void arch_common_suspend(void) 31 + { 32 + save_counter(); 33 + saved_regs.pgd = csr_read64(LOONGARCH_CSR_PGDL); 34 + saved_regs.kpgd = csr_read64(LOONGARCH_CSR_PGDH); 35 + saved_regs.pwctl0 = csr_read32(LOONGARCH_CSR_PWCTL0); 36 + saved_regs.pwctl1 = csr_read32(LOONGARCH_CSR_PWCTL1); 37 + saved_regs.ecfg = csr_read32(LOONGARCH_CSR_ECFG); 38 + saved_regs.euen = csr_read32(LOONGARCH_CSR_EUEN); 39 + 40 + loongarch_suspend_addr = loongson_sysconf.suspend_addr; 41 + } 42 + 43 + static void arch_common_resume(void) 44 + { 45 + sync_counter(); 46 + local_flush_tlb_all(); 47 + csr_write64(per_cpu_offset(0), PERCPU_BASE_KS); 48 + csr_write64(eentry, LOONGARCH_CSR_EENTRY); 49 + csr_write64(eentry, LOONGARCH_CSR_MERRENTRY); 50 + csr_write64(tlbrentry, LOONGARCH_CSR_TLBRENTRY); 51 + 52 + csr_write64(saved_regs.pgd, LOONGARCH_CSR_PGDL); 53 + csr_write64(saved_regs.kpgd, LOONGARCH_CSR_PGDH); 54 + csr_write32(saved_regs.pwctl0, LOONGARCH_CSR_PWCTL0); 55 + csr_write32(saved_regs.pwctl1, LOONGARCH_CSR_PWCTL1); 56 + csr_write32(saved_regs.ecfg, LOONGARCH_CSR_ECFG); 57 + csr_write32(saved_regs.euen, LOONGARCH_CSR_EUEN); 58 + } 59 + 60 + int loongarch_acpi_suspend(void) 61 + { 62 + enable_gpe_wakeup(); 63 + enable_pci_wakeup(); 64 + 65 + arch_common_suspend(); 66 + 67 + /* processor specific suspend */ 68 + loongarch_suspend_enter(); 69 + 70 + arch_common_resume(); 71 + 72 + return 0; 73 + }
+89
arch/loongarch/power/suspend_asm.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Sleep helper for Loongson-3 sleep mode. 4 + * 5 + * Author: Huacai Chen <chenhuacai@loongson.cn> 6 + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 7 + */ 8 + 9 + #include <asm/asm.h> 10 + #include <asm/asmmacro.h> 11 + #include <asm/addrspace.h> 12 + #include <asm/loongarch.h> 13 + #include <asm/stackframe.h> 14 + 15 + /* preparatory stuff */ 16 + .macro SETUP_SLEEP 17 + addi.d sp, sp, -PT_SIZE 18 + st.d $r1, sp, PT_R1 19 + st.d $r2, sp, PT_R2 20 + st.d $r3, sp, PT_R3 21 + st.d $r4, sp, PT_R4 22 + st.d $r21, sp, PT_R21 23 + st.d $r22, sp, PT_R22 24 + st.d $r23, sp, PT_R23 25 + st.d $r24, sp, PT_R24 26 + st.d $r25, sp, PT_R25 27 + st.d $r26, sp, PT_R26 28 + st.d $r27, sp, PT_R27 29 + st.d $r28, sp, PT_R28 30 + st.d $r29, sp, PT_R29 31 + st.d $r30, sp, PT_R30 32 + st.d $r31, sp, PT_R31 33 + 34 + la.pcrel t0, acpi_saved_sp 35 + st.d sp, t0, 0 36 + .endm 37 + 38 + .macro SETUP_WAKEUP 39 + ld.d $r1, sp, PT_R1 40 + ld.d $r2, sp, PT_R2 41 + ld.d $r3, sp, PT_R3 42 + ld.d $r4, sp, PT_R4 43 + ld.d $r21, sp, PT_R21 44 + ld.d $r22, sp, PT_R22 45 + ld.d $r23, sp, PT_R23 46 + ld.d $r24, sp, PT_R24 47 + ld.d $r25, sp, PT_R25 48 + ld.d $r26, sp, PT_R26 49 + ld.d $r27, sp, PT_R27 50 + ld.d $r28, sp, PT_R28 51 + ld.d $r29, sp, PT_R29 52 + ld.d $r30, sp, PT_R30 53 + ld.d $r31, sp, PT_R31 54 + .endm 55 + 56 + .text 57 + .align 12 58 + 59 + /* Sleep/wakeup code for Loongson-3 */ 60 + SYM_FUNC_START(loongarch_suspend_enter) 61 + SETUP_SLEEP 62 + bl __flush_cache_all 63 + 64 + /* Pass RA and SP to BIOS */ 65 + addi.d a1, sp, 0 66 + la.pcrel a0, loongarch_wakeup_start 67 + la.pcrel t0, loongarch_suspend_addr 68 + ld.d t0, t0, 0 69 + jirl a0, t0, 0 /* Call BIOS's STR sleep routine */ 70 + 71 + /* 72 + * This is where we return upon wakeup. 73 + * Reload all of the registers and return. 74 + */ 75 + SYM_INNER_LABEL(loongarch_wakeup_start, SYM_L_GLOBAL) 76 + li.d t0, CSR_DMW0_INIT # UC, PLV0 77 + csrwr t0, LOONGARCH_CSR_DMWIN0 78 + li.d t0, CSR_DMW1_INIT # CA, PLV0 79 + csrwr t0, LOONGARCH_CSR_DMWIN1 80 + 81 + la.abs t0, 0f 82 + jr t0 83 + 0: 84 + la.pcrel t0, acpi_saved_sp 85 + ld.d sp, t0, 0 86 + SETUP_WAKEUP 87 + addi.d sp, sp, PT_SIZE 88 + jr ra 89 + SYM_FUNC_END(loongarch_suspend_enter)
+13
scripts/mod/modpost.c
··· 1523 1523 #define R_RISCV_SUB32 39 1524 1524 #endif 1525 1525 1526 + #ifndef EM_LOONGARCH 1527 + #define EM_LOONGARCH 258 1528 + #endif 1529 + 1530 + #ifndef R_LARCH_SUB32 1531 + #define R_LARCH_SUB32 55 1532 + #endif 1533 + 1526 1534 static void section_rela(const char *modname, struct elf_info *elf, 1527 1535 Elf_Shdr *sechdr) 1528 1536 { ··· 1570 1562 case EM_RISCV: 1571 1563 if (!strcmp("__ex_table", fromsec) && 1572 1564 ELF_R_TYPE(r.r_info) == R_RISCV_SUB32) 1565 + continue; 1566 + break; 1567 + case EM_LOONGARCH: 1568 + if (!strcmp("__ex_table", fromsec) && 1569 + ELF_R_TYPE(r.r_info) == R_LARCH_SUB32) 1573 1570 continue; 1574 1571 break; 1575 1572 }
+39
scripts/recordmcount.c
··· 38 38 #define R_AARCH64_ABS64 257 39 39 #endif 40 40 41 + #ifndef EM_LOONGARCH 42 + #define EM_LOONGARCH 258 43 + #define R_LARCH_32 1 44 + #define R_LARCH_64 2 45 + #define R_LARCH_MARK_LA 20 46 + #define R_LARCH_SOP_PUSH_PLT_PCREL 29 47 + #endif 48 + 41 49 #define R_ARM_PC24 1 42 50 #define R_ARM_THM_CALL 10 43 51 #define R_ARM_CALL 28 ··· 449 441 return ELF64_R_TYPE(w8(rp->r_info)) != R_AARCH64_CALL26; 450 442 } 451 443 444 + static int LARCH32_is_fake_mcount(Elf32_Rel const *rp) 445 + { 446 + switch (ELF64_R_TYPE(w(rp->r_info))) { 447 + case R_LARCH_MARK_LA: 448 + case R_LARCH_SOP_PUSH_PLT_PCREL: 449 + return 0; 450 + } 451 + 452 + return 1; 453 + } 454 + 455 + static int LARCH64_is_fake_mcount(Elf64_Rel const *rp) 456 + { 457 + switch (ELF64_R_TYPE(w(rp->r_info))) { 458 + case R_LARCH_MARK_LA: 459 + case R_LARCH_SOP_PUSH_PLT_PCREL: 460 + return 0; 461 + } 462 + 463 + return 1; 464 + } 465 + 452 466 /* 64-bit EM_MIPS has weird ELF64_Rela.r_info. 453 467 * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf 454 468 * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40] ··· 588 558 break; 589 559 case EM_IA_64: reltype = R_IA64_IMM64; break; 590 560 case EM_MIPS: /* reltype: e_class */ break; 561 + case EM_LOONGARCH: /* reltype: e_class */ break; 591 562 case EM_PPC: reltype = R_PPC_ADDR32; break; 592 563 case EM_PPC64: reltype = R_PPC64_ADDR64; break; 593 564 case EM_S390: /* reltype: e_class */ break; ··· 620 589 reltype = R_MIPS_32; 621 590 is_fake_mcount32 = MIPS32_is_fake_mcount; 622 591 } 592 + if (w2(ehdr->e_machine) == EM_LOONGARCH) { 593 + reltype = R_LARCH_32; 594 + is_fake_mcount32 = LARCH32_is_fake_mcount; 595 + } 623 596 if (do32(ehdr, fname, reltype) < 0) 624 597 goto out; 625 598 break; ··· 644 609 Elf64_r_sym = MIPS64_r_sym; 645 610 Elf64_r_info = MIPS64_r_info; 646 611 is_fake_mcount64 = MIPS64_is_fake_mcount; 612 + } 613 + if (w2(ghdr->e_machine) == EM_LOONGARCH) { 614 + reltype = R_LARCH_64; 615 + is_fake_mcount64 = LARCH64_is_fake_mcount; 647 616 } 648 617 if (do64(ghdr, fname, reltype) < 0) 649 618 goto out;
+1 -1
scripts/sorttable.c
··· 304 304 switch (r2(&ehdr->e_machine)) { 305 305 case EM_386: 306 306 case EM_AARCH64: 307 + case EM_LOONGARCH: 307 308 case EM_RISCV: 308 309 case EM_S390: 309 310 case EM_X86_64: ··· 318 317 case EM_ARCOMPACT: 319 318 case EM_ARCV2: 320 319 case EM_ARM: 321 - case EM_LOONGARCH: 322 320 case EM_MICROBLAZE: 323 321 case EM_MIPS: 324 322 case EM_XTENSA: