History

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 ...

Linus Torvalds committed 3 years ago

Commit 2f26e422 parents 96bab5b 5535f4f72 files · +3645 −187Browse files

Unified · Split

72 files
  1. Documentation/admin-guide/sysctl/kernel.rst +4 −4
  2. arch/loongarch/Kconfig +20 −0
  3. arch/loongarch/Makefile +8 −0
  4. arch/loongarch/configs/loongson3_defconfig +32 −24
  5. arch/loongarch/include/asm/acpi.h +10 −0
  6. arch/loongarch/include/asm/alternative-asm.h +82 −0
  7. arch/loongarch/include/asm/alternative.h +111 −0
  8. arch/loongarch/include/asm/asm-extable.h +65 −0
  9. arch/loongarch/include/asm/bootinfo.h +1 −0
  10. arch/loongarch/include/asm/bugs.h +15 −0
  11. arch/loongarch/include/asm/efi.h +1 −0
  12. arch/loongarch/include/asm/extable.h +47 −0
  13. arch/loongarch/include/asm/ftrace.h +68 −0
  14. arch/loongarch/include/asm/futex.h +7 −20
  15. arch/loongarch/include/asm/gpr-num.h +22 −0
  16. arch/loongarch/include/asm/inst.h +46 −0
  17. arch/loongarch/include/asm/loongson.h +3 −0
  18. arch/loongarch/include/asm/module.h +16 −11
  19. arch/loongarch/include/asm/module.lds.h +1 −0
  20. arch/loongarch/include/asm/setup.h +1 −0
  21. arch/loongarch/include/asm/stackprotector.h +38 −0
  22. arch/loongarch/include/asm/string.h +5 −0
  23. arch/loongarch/include/asm/thread_info.h +1 −1
  24. arch/loongarch/include/asm/time.h +1 −0
  25. arch/loongarch/include/asm/uaccess.h +6 −18
  26. arch/loongarch/include/asm/unwind.h +2 −1
  27. arch/loongarch/kernel/Makefile +15 −1
  28. arch/loongarch/kernel/acpi.c +15 −2
  29. arch/loongarch/kernel/alternative.c +246 −0
  30. arch/loongarch/kernel/asm-offsets.c +15 −0
  31. arch/loongarch/kernel/efi.c +14 −1
  32. arch/loongarch/kernel/env.c +2 −0
  33. arch/loongarch/kernel/fpu.S +2 −3
  34. arch/loongarch/kernel/ftrace.c +73 −0
  35. arch/loongarch/kernel/ftrace_dyn.c +273 −0
  36. arch/loongarch/kernel/inst.c +127 −0
  37. arch/loongarch/kernel/mcount.S +96 −0
  38. arch/loongarch/kernel/mcount_dyn.S +149 −0
  39. arch/loongarch/kernel/module-sections.c +39 −25
  40. arch/loongarch/kernel/module.c +63 −12
  41. arch/loongarch/kernel/numa.c +16 −1
  42. arch/loongarch/kernel/process.c +6 −0
  43. arch/loongarch/kernel/reset.c +5 −0
  44. arch/loongarch/kernel/setup.c +148 −1
  45. arch/loongarch/kernel/smp.c +35 −0
  46. arch/loongarch/kernel/switch.S +5 −0
  47. arch/loongarch/kernel/time.c +8 −3
  48. arch/loongarch/kernel/traps.c +27 −0
  49. arch/loongarch/kernel/unaligned.c +499 −0
  50. arch/loongarch/kernel/unwind_guess.c +3 −1
  51. arch/loongarch/kernel/unwind_prologue.c +42 −8
  52. arch/loongarch/kernel/vmlinux.lds.S +12 −1
  53. arch/loongarch/lib/Makefile +2 −1
  54. arch/loongarch/lib/clear_user.S +70 −15
  55. arch/loongarch/lib/copy_user.S +92 −16
  56. arch/loongarch/lib/memcpy.S +95 −0
  57. arch/loongarch/lib/memmove.S +121 −0
  58. arch/loongarch/lib/memset.S +91 −0
  59. arch/loongarch/lib/unaligned.S +84 −0
  60. arch/loongarch/mm/extable.c +50 −9
  61. arch/loongarch/net/bpf_jit.c +81 −5
  62. arch/loongarch/net/bpf_jit.h +2 −0
  63. arch/loongarch/pci/acpi.c +5 −2
  64. arch/loongarch/power/Makefile +4 −0
  65. arch/loongarch/power/hibernate.c +62 −0
  66. arch/loongarch/power/hibernate_asm.S +66 −0
  67. arch/loongarch/power/platform.c +57 −0
  68. arch/loongarch/power/suspend.c +73 −0
  69. arch/loongarch/power/suspend_asm.S +89 −0
  70. scripts/mod/modpost.c +13 −0
  71. scripts/recordmcount.c +39 −0
  72. scripts/sorttable.c +1 −1
Documentation/admin-guide/sysctl/kernel.rst+4−4
@@ -436,8 +436,8 @@ ignore-unaligned-usertrap · 435 unmodified lines
436 436
437On architectures where unaligned accesses cause traps, and where this437On architectures where unaligned accesses cause traps, and where this
438feature is supported (``CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN``;438feature is supported (``CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN``;
439currently, ``arc`` and ``ia64``), controls whether all unaligned traps439currently, ``arc``, ``ia64`` and ``loongarch``), controls whether all
440are logged.440unaligned traps are logged.
441 441
442= =============================================================442= =============================================================
4430 Log all unaligned accesses.4430 Log all unaligned accesses.
@@ -1492,8 +1492,8 @@ unaligned-trap · 1048 unmodified lines
1492 1492
1493On architectures where unaligned accesses cause traps, and where this1493On architectures where unaligned accesses cause traps, and where this
1494feature is supported (``CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW``; currently,1494feature is supported (``CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW``; currently,
1495``arc`` and ``parisc``), controls whether unaligned traps are caught1495``arc``, ``parisc`` and ``loongarch``), controls whether unaligned traps
1496and emulated (instead of failing).1496are caught and emulated (instead of failing).
1497 1497
1498= ========================================================1498= ========================================================
14990 Do not emulate unaligned accesses.14990 Do not emulate unaligned accesses.
arch/loongarch/Kconfig+20−0
@@ -58,6 +58,7 @@ config LOONGARCH · 57 unmodified lines
58 select ARCH_WANTS_NO_INSTR58 select ARCH_WANTS_NO_INSTR
59 select BUILDTIME_TABLE_SORT59 select BUILDTIME_TABLE_SORT
60 select COMMON_CLK60 select COMMON_CLK
61 select CPU_PM
61 select EFI62 select EFI
62 select GENERIC_CLOCKEVENTS63 select GENERIC_CLOCKEVENTS
63 select GENERIC_CMOS_UPDATE64 select GENERIC_CMOS_UPDATE
@@ -86,11 +87,18 @@ config LOONGARCH · 22 unmodified lines
86 select HAVE_ARCH_TRANSPARENT_HUGEPAGE87 select HAVE_ARCH_TRANSPARENT_HUGEPAGE
87 select HAVE_ASM_MODVERSIONS88 select HAVE_ASM_MODVERSIONS
88 select HAVE_CONTEXT_TRACKING_USER89 select HAVE_CONTEXT_TRACKING_USER
90 select HAVE_C_RECORDMCOUNT
89 select HAVE_DEBUG_STACKOVERFLOW91 select HAVE_DEBUG_STACKOVERFLOW
90 select HAVE_DMA_CONTIGUOUS92 select HAVE_DMA_CONTIGUOUS
93 select HAVE_DYNAMIC_FTRACE
94 select HAVE_DYNAMIC_FTRACE_WITH_ARGS
95 select HAVE_DYNAMIC_FTRACE_WITH_REGS
91 select HAVE_EBPF_JIT96 select HAVE_EBPF_JIT
92 select HAVE_EXIT_THREAD97 select HAVE_EXIT_THREAD
93 select HAVE_FAST_GUP98 select HAVE_FAST_GUP
99 select HAVE_FTRACE_MCOUNT_RECORD
100 select HAVE_FUNCTION_GRAPH_TRACER
101 select HAVE_FUNCTION_TRACER
94 select HAVE_GENERIC_VDSO102 select HAVE_GENERIC_VDSO
95 select HAVE_IOREMAP_PROT103 select HAVE_IOREMAP_PROT
96 select HAVE_IRQ_EXIT_ON_IRQ_STACK104 select HAVE_IRQ_EXIT_ON_IRQ_STACK
@@ -104,6 +112,7 @@ config LOONGARCH · 7 unmodified lines
104 select HAVE_REGS_AND_STACK_ACCESS_API112 select HAVE_REGS_AND_STACK_ACCESS_API
105 select HAVE_RSEQ113 select HAVE_RSEQ
106 select HAVE_SETUP_PER_CPU_AREA if NUMA114 select HAVE_SETUP_PER_CPU_AREA if NUMA
115 select HAVE_STACKPROTECTOR
107 select HAVE_SYSCALL_TRACEPOINTS116 select HAVE_SYSCALL_TRACEPOINTS
108 select HAVE_TIF_NOHZ117 select HAVE_TIF_NOHZ
109 select HAVE_VIRT_CPU_ACCOUNTING_GEN if !SMP118 select HAVE_VIRT_CPU_ACCOUNTING_GEN if !SMP
@@ -113,6 +122,8 @@ config LOONGARCH · 3 unmodified lines
113 select MODULES_USE_ELF_RELA if MODULES122 select MODULES_USE_ELF_RELA if MODULES
114 select NEED_PER_CPU_EMBED_FIRST_CHUNK123 select NEED_PER_CPU_EMBED_FIRST_CHUNK
115 select NEED_PER_CPU_PAGE_FIRST_CHUNK124 select NEED_PER_CPU_PAGE_FIRST_CHUNK
125 select OF
126 select OF_EARLY_FLATTREE
116 select PCI127 select PCI
117 select PCI_DOMAINS_GENERIC128 select PCI_DOMAINS_GENERIC
118 select PCI_ECAM if ACPI129 select PCI_ECAM if ACPI
@@ -123,6 +134,8 @@ config LOONGARCH · 4 unmodified lines
123 select RTC_LIB134 select RTC_LIB
124 select SMP135 select SMP
125 select SPARSE_IRQ136 select SPARSE_IRQ
137 select SYSCTL_ARCH_UNALIGN_ALLOW
138 select SYSCTL_ARCH_UNALIGN_NO_WARN
126 select SYSCTL_EXCEPTION_TRACE139 select SYSCTL_EXCEPTION_TRACE
127 select SWIOTLB140 select SWIOTLB
128 select TRACE_IRQFLAGS_SUPPORT141 select TRACE_IRQFLAGS_SUPPORT
@@ -516,6 +529,13 @@ config ARCH_MMAP_RND_BITS_MAX · 387 unmodified lines
516 529
517menu "Power management options"530menu "Power management options"
518 531
532config ARCH_SUSPEND_POSSIBLE
533 def_bool y
534
535config ARCH_HIBERNATION_POSSIBLE
536 def_bool y
537
538source "kernel/power/Kconfig"
519source "drivers/acpi/Kconfig"539source "drivers/acpi/Kconfig"
520 540
521endmenu541endmenu
arch/loongarch/Makefile+8−0
@@ -25,6 +25,11 @@ endif · 24 unmodified lines
2532bit-emul = elf32loongarch2532bit-emul = elf32loongarch
2664bit-emul = elf64loongarch2664bit-emul = elf64loongarch
27 27
28ifdef CONFIG_DYNAMIC_FTRACE
29KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
30CC_FLAGS_FTRACE := -fpatchable-function-entry=2
31endif
32
28ifdef CONFIG_64BIT33ifdef CONFIG_64BIT
29tool-archpref = $(64bit-tool-archpref)34tool-archpref = $(64bit-tool-archpref)
30UTS_MACHINE := loongarch6435UTS_MACHINE := loongarch64
@@ -104,6 +109,9 @@ endif · 73 unmodified lines
104libs-y += arch/loongarch/lib/109libs-y += arch/loongarch/lib/
105libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a110libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
106 111
112# suspend and hibernation support
113drivers-$(CONFIG_PM) += arch/loongarch/power/
114
107ifeq ($(KBUILD_EXTMOD),)115ifeq ($(KBUILD_EXTMOD),)
108prepare: vdso_prepare116prepare: vdso_prepare
109vdso_prepare: prepare0117vdso_prepare: prepare0
arch/loongarch/configs/loongson3_defconfig+32−24
@@ -34,12 +34,13 @@ CONFIG_SYSFS_DEPRECATED=y · 33 unmodified lines
34CONFIG_RELAY=y34CONFIG_RELAY=y
35CONFIG_BLK_DEV_INITRD=y35CONFIG_BLK_DEV_INITRD=y
36CONFIG_EXPERT=y36CONFIG_EXPERT=y
37CONFIG_USERFAULTFD=y37CONFIG_KALLSYMS_ALL=y
38CONFIG_PERF_EVENTS=y38CONFIG_PERF_EVENTS=y
39# CONFIG_COMPAT_BRK is not set
40CONFIG_LOONGARCH=y39CONFIG_LOONGARCH=y
41CONFIG_64BIT=y40CONFIG_64BIT=y
42CONFIG_MACH_LOONGSON64=y41CONFIG_MACH_LOONGSON64=y
42CONFIG_PAGE_SIZE_16KB=y
43CONFIG_HZ_250=y
43CONFIG_DMI=y44CONFIG_DMI=y
44CONFIG_EFI=y45CONFIG_EFI=y
45CONFIG_SMP=y46CONFIG_SMP=y
@@ -47,14 +48,14 @@ CONFIG_HOTPLUG_CPU=y · 1 unmodified line
47CONFIG_NR_CPUS=6448CONFIG_NR_CPUS=64
48CONFIG_NUMA=y49CONFIG_NUMA=y
49CONFIG_KEXEC=y50CONFIG_KEXEC=y
50CONFIG_PAGE_SIZE_16KB=y51CONFIG_SUSPEND=y
51CONFIG_HZ_250=y52CONFIG_HIBERNATION=y
52CONFIG_ACPI=y53CONFIG_ACPI=y
53CONFIG_ACPI_SPCR_TABLE=y54CONFIG_ACPI_SPCR_TABLE=y
54CONFIG_ACPI_HOTPLUG_CPU=y
55CONFIG_ACPI_TAD=y55CONFIG_ACPI_TAD=y
56CONFIG_ACPI_DOCK=y56CONFIG_ACPI_DOCK=y
57CONFIG_ACPI_IPMI=m57CONFIG_ACPI_IPMI=m
58CONFIG_ACPI_HOTPLUG_CPU=y
58CONFIG_ACPI_PCI_SLOT=y59CONFIG_ACPI_PCI_SLOT=y
59CONFIG_ACPI_HOTPLUG_MEMORY=y60CONFIG_ACPI_HOTPLUG_MEMORY=y
60CONFIG_EFI_ZBOOT=y61CONFIG_EFI_ZBOOT=y
@@ -73,17 +74,19 @@ CONFIG_UNIXWARE_DISKLABEL=y · 12 unmodified lines
73CONFIG_IOSCHED_BFQ=y74CONFIG_IOSCHED_BFQ=y
74CONFIG_BFQ_GROUP_IOSCHED=y75CONFIG_BFQ_GROUP_IOSCHED=y
75CONFIG_BINFMT_MISC=m76CONFIG_BINFMT_MISC=m
76CONFIG_MEMORY_HOTPLUG=y77CONFIG_ZPOOL=y
77CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y
78CONFIG_MEMORY_HOTREMOVE=y
79CONFIG_KSM=y
80CONFIG_TRANSPARENT_HUGEPAGE=y
81CONFIG_ZSWAP=y78CONFIG_ZSWAP=y
82CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y79CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y
83CONFIG_ZPOOL=y
84CONFIG_ZBUD=y80CONFIG_ZBUD=y
85CONFIG_Z3FOLD=y81CONFIG_Z3FOLD=y
86CONFIG_ZSMALLOC=m82CONFIG_ZSMALLOC=m
83# CONFIG_COMPAT_BRK is not set
84CONFIG_MEMORY_HOTPLUG=y
85CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y
86CONFIG_MEMORY_HOTREMOVE=y
87CONFIG_KSM=y
88CONFIG_TRANSPARENT_HUGEPAGE=y
89CONFIG_USERFAULTFD=y
87CONFIG_NET=y90CONFIG_NET=y
88CONFIG_PACKET=y91CONFIG_PACKET=y
89CONFIG_UNIX=y92CONFIG_UNIX=y
@@ -118,7 +121,6 @@ CONFIG_NETFILTER=y · 28 unmodified lines
118CONFIG_BRIDGE_NETFILTER=m121CONFIG_BRIDGE_NETFILTER=m
119CONFIG_NETFILTER_NETLINK_LOG=m122CONFIG_NETFILTER_NETLINK_LOG=m
120CONFIG_NF_CONNTRACK=m123CONFIG_NF_CONNTRACK=m
121CONFIG_NF_LOG_NETDEV=m
122CONFIG_NF_CONNTRACK_AMANDA=m124CONFIG_NF_CONNTRACK_AMANDA=m
123CONFIG_NF_CONNTRACK_FTP=m125CONFIG_NF_CONNTRACK_FTP=m
124CONFIG_NF_CONNTRACK_NETBIOS_NS=m126CONFIG_NF_CONNTRACK_NETBIOS_NS=m
@@ -416,6 +418,7 @@ CONFIG_SCSI_VIRTIO=m · 291 unmodified lines
416CONFIG_ATA=y418CONFIG_ATA=y
417CONFIG_SATA_AHCI=y419CONFIG_SATA_AHCI=y
418CONFIG_SATA_AHCI_PLATFORM=y420CONFIG_SATA_AHCI_PLATFORM=y
421CONFIG_AHCI_DWC=y
419CONFIG_PATA_ATIIXP=y422CONFIG_PATA_ATIIXP=y
420CONFIG_PATA_PCMCIA=m423CONFIG_PATA_PCMCIA=m
421CONFIG_MD=y424CONFIG_MD=y
@@ -469,13 +472,11 @@ CONFIG_VIRTIO_NET=m · 47 unmodified lines
469# CONFIG_NET_VENDOR_ARC is not set472# CONFIG_NET_VENDOR_ARC is not set
470# CONFIG_NET_VENDOR_ATHEROS is not set473# CONFIG_NET_VENDOR_ATHEROS is not set
471CONFIG_BNX2=y474CONFIG_BNX2=y
472# CONFIG_NET_VENDOR_BROCADE is not set
473# CONFIG_NET_VENDOR_CAVIUM is not set475# CONFIG_NET_VENDOR_CAVIUM is not set
474CONFIG_CHELSIO_T1=m476CONFIG_CHELSIO_T1=m
475CONFIG_CHELSIO_T1_1G=y477CONFIG_CHELSIO_T1_1G=y
476CONFIG_CHELSIO_T3=m478CONFIG_CHELSIO_T3=m
477CONFIG_CHELSIO_T4=m479CONFIG_CHELSIO_T4=m
478# CONFIG_NET_VENDOR_CIRRUS is not set
479# CONFIG_NET_VENDOR_CISCO is not set480# CONFIG_NET_VENDOR_CISCO is not set
480# CONFIG_NET_VENDOR_DEC is not set481# CONFIG_NET_VENDOR_DEC is not set
481# CONFIG_NET_VENDOR_DLINK is not set482# CONFIG_NET_VENDOR_DLINK is not set
@@ -496,6 +497,7 @@ CONFIG_IXGBE=y · 14 unmodified lines
496# CONFIG_NET_VENDOR_NVIDIA is not set497# CONFIG_NET_VENDOR_NVIDIA is not set
497# CONFIG_NET_VENDOR_OKI is not set498# CONFIG_NET_VENDOR_OKI is not set
498# CONFIG_NET_VENDOR_QLOGIC is not set499# CONFIG_NET_VENDOR_QLOGIC is not set
500# CONFIG_NET_VENDOR_BROCADE is not set
499# CONFIG_NET_VENDOR_QUALCOMM is not set501# CONFIG_NET_VENDOR_QUALCOMM is not set
500# CONFIG_NET_VENDOR_RDC is not set502# CONFIG_NET_VENDOR_RDC is not set
501CONFIG_8139CP=m503CONFIG_8139CP=m
@@ -505,9 +507,9 @@ CONFIG_R8169=y · 3 unmodified lines
505# CONFIG_NET_VENDOR_ROCKER is not set507# CONFIG_NET_VENDOR_ROCKER is not set
506# CONFIG_NET_VENDOR_SAMSUNG is not set508# CONFIG_NET_VENDOR_SAMSUNG is not set
507# CONFIG_NET_VENDOR_SEEQ is not set509# CONFIG_NET_VENDOR_SEEQ is not set
508# CONFIG_NET_VENDOR_SOLARFLARE is not set
509# CONFIG_NET_VENDOR_SILAN is not set510# CONFIG_NET_VENDOR_SILAN is not set
510# CONFIG_NET_VENDOR_SIS is not set511# CONFIG_NET_VENDOR_SIS is not set
512# CONFIG_NET_VENDOR_SOLARFLARE is not set
511# CONFIG_NET_VENDOR_SMSC is not set513# CONFIG_NET_VENDOR_SMSC is not set
512CONFIG_STMMAC_ETH=y514CONFIG_STMMAC_ETH=y
513# CONFIG_NET_VENDOR_SUN is not set515# CONFIG_NET_VENDOR_SUN is not set
@@ -588,6 +590,7 @@ CONFIG_SERIAL_8250_EXTENDED=y · 74 unmodified lines
588CONFIG_SERIAL_8250_MANY_PORTS=y590CONFIG_SERIAL_8250_MANY_PORTS=y
589CONFIG_SERIAL_8250_SHARE_IRQ=y591CONFIG_SERIAL_8250_SHARE_IRQ=y
590CONFIG_SERIAL_8250_RSA=y592CONFIG_SERIAL_8250_RSA=y
593CONFIG_SERIAL_OF_PLATFORM=y
591CONFIG_SERIAL_NONSTANDARD=y594CONFIG_SERIAL_NONSTANDARD=y
592CONFIG_PRINTER=m595CONFIG_PRINTER=m
593CONFIG_VIRTIO_CONSOLE=y596CONFIG_VIRTIO_CONSOLE=y
@@ -602,6 +605,11 @@ CONFIG_I2C_GPIO=y · 8 unmodified lines
602CONFIG_SPI=y605CONFIG_SPI=y
603CONFIG_GPIO_SYSFS=y606CONFIG_GPIO_SYSFS=y
604CONFIG_GPIO_LOONGSON=y607CONFIG_GPIO_LOONGSON=y
608CONFIG_POWER_RESET=y
609CONFIG_POWER_RESET_RESTART=y
610CONFIG_POWER_RESET_SYSCON=y
611CONFIG_POWER_RESET_SYSCON_POWEROFF=y
612CONFIG_SYSCON_REBOOT_MODE=y
605CONFIG_SENSORS_LM75=m613CONFIG_SENSORS_LM75=m
606CONFIG_SENSORS_LM93=m614CONFIG_SENSORS_LM93=m
607CONFIG_SENSORS_W83795=m615CONFIG_SENSORS_W83795=m
@@ -609,16 +617,16 @@ CONFIG_SENSORS_W83627HF=m · 1 unmodified line
609CONFIG_RC_CORE=m617CONFIG_RC_CORE=m
610CONFIG_LIRC=y618CONFIG_LIRC=y
611CONFIG_RC_DECODERS=y619CONFIG_RC_DECODERS=y
620CONFIG_IR_IMON_DECODER=m
621CONFIG_IR_JVC_DECODER=m
622CONFIG_IR_MCE_KBD_DECODER=m
612CONFIG_IR_NEC_DECODER=m623CONFIG_IR_NEC_DECODER=m
613CONFIG_IR_RC5_DECODER=m624CONFIG_IR_RC5_DECODER=m
614CONFIG_IR_RC6_DECODER=m625CONFIG_IR_RC6_DECODER=m
615CONFIG_IR_JVC_DECODER=m
616CONFIG_IR_SONY_DECODER=m
617CONFIG_IR_SANYO_DECODER=m626CONFIG_IR_SANYO_DECODER=m
618CONFIG_IR_SHARP_DECODER=m627CONFIG_IR_SHARP_DECODER=m
619CONFIG_IR_MCE_KBD_DECODER=m628CONFIG_IR_SONY_DECODER=m
620CONFIG_IR_XMP_DECODER=m629CONFIG_IR_XMP_DECODER=m
621CONFIG_IR_IMON_DECODER=m
622CONFIG_MEDIA_SUPPORT=m630CONFIG_MEDIA_SUPPORT=m
623CONFIG_MEDIA_USB_SUPPORT=y631CONFIG_MEDIA_USB_SUPPORT=y
624CONFIG_USB_VIDEO_CLASS=m632CONFIG_USB_VIDEO_CLASS=m
@@ -638,6 +646,7 @@ CONFIG_DRM_VIRTIO_GPU=m · 13 unmodified lines
638CONFIG_FB=y646CONFIG_FB=y
639CONFIG_FB_EFI=y647CONFIG_FB_EFI=y
640CONFIG_FB_RADEON=y648CONFIG_FB_RADEON=y
649CONFIG_LCD_CLASS_DEVICE=y
641CONFIG_LCD_PLATFORM=m650CONFIG_LCD_PLATFORM=m
642# CONFIG_VGA_CONSOLE is not set651# CONFIG_VGA_CONSOLE is not set
643CONFIG_FRAMEBUFFER_CONSOLE=y652CONFIG_FRAMEBUFFER_CONSOLE=y
@@ -647,7 +656,6 @@ CONFIG_SOUND=y · 3 unmodified lines
647CONFIG_SND=y656CONFIG_SND=y
648CONFIG_SND_SEQUENCER=m657CONFIG_SND_SEQUENCER=m
649CONFIG_SND_SEQ_DUMMY=m658CONFIG_SND_SEQ_DUMMY=m
650# CONFIG_SND_ISA is not set
651CONFIG_SND_BT87X=m659CONFIG_SND_BT87X=m
652CONFIG_SND_BT87X_OVERCLOCK=y660CONFIG_SND_BT87X_OVERCLOCK=y
653CONFIG_SND_HDA_INTEL=y661CONFIG_SND_HDA_INTEL=y
@@ -818,10 +826,6 @@ CONFIG_CRYPTO_USER=m · 164 unmodified lines
818# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set826# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
819CONFIG_CRYPTO_PCRYPT=m827CONFIG_CRYPTO_PCRYPT=m
820CONFIG_CRYPTO_CRYPTD=m828CONFIG_CRYPTO_CRYPTD=m
821CONFIG_CRYPTO_CHACHA20POLY1305=m
822CONFIG_CRYPTO_HMAC=y
823CONFIG_CRYPTO_VMAC=m
824CONFIG_CRYPTO_WP512=m
825CONFIG_CRYPTO_ANUBIS=m829CONFIG_CRYPTO_ANUBIS=m
826CONFIG_CRYPTO_BLOWFISH=m830CONFIG_CRYPTO_BLOWFISH=m
827CONFIG_CRYPTO_CAST5=m831CONFIG_CRYPTO_CAST5=m
@@ -831,6 +835,9 @@ CONFIG_CRYPTO_SEED=m · 3 unmodified lines
831CONFIG_CRYPTO_SERPENT=m835CONFIG_CRYPTO_SERPENT=m
832CONFIG_CRYPTO_TEA=m836CONFIG_CRYPTO_TEA=m
833CONFIG_CRYPTO_TWOFISH=m837CONFIG_CRYPTO_TWOFISH=m
838CONFIG_CRYPTO_CHACHA20POLY1305=m
839CONFIG_CRYPTO_VMAC=m
840CONFIG_CRYPTO_WP512=m
834CONFIG_CRYPTO_DEFLATE=m841CONFIG_CRYPTO_DEFLATE=m
835CONFIG_CRYPTO_LZO=m842CONFIG_CRYPTO_LZO=m
836CONFIG_CRYPTO_842=m843CONFIG_CRYPTO_842=m
@@ -844,6 +851,7 @@ CONFIG_CRYPTO_DEV_VIRTIO=m · 7 unmodified lines
844CONFIG_PRINTK_TIME=y851CONFIG_PRINTK_TIME=y
845CONFIG_STRIP_ASM_SYMS=y852CONFIG_STRIP_ASM_SYMS=y
846CONFIG_MAGIC_SYSRQ=y853CONFIG_MAGIC_SYSRQ=y
854CONFIG_DEBUG_FS=y
847# CONFIG_SCHED_DEBUG is not set855# CONFIG_SCHED_DEBUG is not set
848CONFIG_SCHEDSTATS=y856CONFIG_SCHEDSTATS=y
849# CONFIG_DEBUG_PREEMPT is not set857# CONFIG_DEBUG_PREEMPT is not set
arch/loongarch/include/asm/acpi.h+10−0
@@ -35,4 +35,14 @@ extern struct list_head acpi_wakeup_device_list; · 34 unmodified lines
35 35
36#define ACPI_TABLE_UPGRADE_MAX_PHYS ARCH_LOW_ADDRESS_LIMIT36#define ACPI_TABLE_UPGRADE_MAX_PHYS ARCH_LOW_ADDRESS_LIMIT
37 37
38extern int loongarch_acpi_suspend(void);
39extern int (*acpi_suspend_lowlevel)(void);
40extern void loongarch_suspend_enter(void);
41
42static 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#endif /* _ASM_LOONGARCH_ACPI_H */48#endif /* _ASM_LOONGARCH_ACPI_H */
arch/loongarch/include/asm/alternative-asm.h+82−0
@@ -0,0 +1,82 @@
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
30140 :
31 \oldinstr
32141 :
33 .fill - (((144f-143f)-(141b-140b)) > 0) * ((144f-143f)-(141b-140b)) / 4, 4, 0x03400000
34142 :
35
36 .pushsection .altinstructions, "a"
37 altinstruction_entry 140b, 143f, \feature, 142b-140b, 144f-143f
38 .popsection
39
40 .subsection 1
41143 :
42 \newinstr
43144 :
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
59140 :
60 \oldinstr
61141 :
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
64142 :
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
72143 :
73 \newinstr1
74144 :
75 \newinstr2
76145 :
77 .previous
78.endm
79
80#endif /* __ASSEMBLY__ */
81
82#endif /* _ASM_ALTERNATIVE_ASM_H */
arch/loongarch/include/asm/alternative.h+111−0
@@ -0,0 +1,111 @@
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
12struct 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 */
24extern int alternatives_patched;
25extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
26
27extern void alternative_instructions(void);
28extern 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 */
arch/loongarch/include/asm/asm-extable.h+65−0
@@ -0,0 +1,65 @@
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 */
arch/loongarch/include/asm/bootinfo.h+1−0
@@ -32,6 +32,7 @@ struct loongson_system_configuration { · 31 unmodified lines
32 int cores_per_node;32 int cores_per_node;
33 int cores_per_package;33 int cores_per_package;
34 unsigned long cores_io_master;34 unsigned long cores_io_master;
35 unsigned long suspend_addr;
35 const char *cpuname;36 const char *cpuname;
36};37};
37 38
arch/loongarch/include/asm/bugs.h+15−0
@@ -0,0 +1,15 @@
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
13extern void check_bugs(void);
14
15#endif /* _ASM_BUGS_H */
arch/loongarch/include/asm/efi.h+1−0
@@ -9,6 +9,7 @@ · 8 unmodified lines
9 9
10void __init efi_init(void);10void __init efi_init(void);
11void __init efi_runtime_init(void);11void __init efi_runtime_init(void);
12void __init *efi_fdt_pointer(void);
12void efifb_setup_from_dmi(struct screen_info *si, const char *opt);13void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
13 14
14#define ARCH_EFI_IRQ_FLAGS_MASK 0x00000004 /* Bit 2: CSR.CRMD.IE */15#define ARCH_EFI_IRQ_FLAGS_MASK 0x00000004 /* Bit 2: CSR.CRMD.IE */
arch/loongarch/include/asm/extable.h+47−0
@@ -0,0 +1,47 @@
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
18struct 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) \
26do { \
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
36bool ex_handler_bpf(const struct exception_table_entry *ex, struct pt_regs *regs);
37#else
38static inline
39bool ex_handler_bpf(const struct exception_table_entry *ex, struct pt_regs *regs)
40{
41 return false;
42}
43#endif /* !CONFIG_BPF_JIT */
44
45bool fixup_exception(struct pt_regs *regs);
46
47#endif
arch/loongarch/include/asm/ftrace.h+68−0
@@ -0,0 +1,68 @@
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
24extern void _mcount(void);
25extern void prepare_ftrace_return(unsigned long self_addr, unsigned long callsite_sp, unsigned long old);
26
27#else
28
29struct dyn_ftrace;
30struct 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
36int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
37
38static inline unsigned long ftrace_call_adjust(unsigned long addr)
39{
40 return addr;
41}
42
43void 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
48struct ftrace_ops;
49
50struct ftrace_regs {
51 struct pt_regs regs;
52};
53
54static __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
60void 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 */
arch/loongarch/include/asm/futex.h+7−20
@@ -7,6 +7,7 @@ · 6 unmodified lines
7 7
8#include <linux/futex.h>8#include <linux/futex.h>
9#include <linux/uaccess.h>9#include <linux/uaccess.h>
10#include <asm/asm-extable.h>
10#include <asm/barrier.h>11#include <asm/barrier.h>
11#include <asm/errno.h>12#include <asm/errno.h>
12 13
@@ -18,18 +19,11 @@ · 5 unmodified lines
18 "2: sc.w $t0, %2 \n" \19 "2: sc.w $t0, %2 \n" \
19 " beqz $t0, 1b \n" \20 " beqz $t0, 1b \n" \
20 "3: \n" \21 "3: \n" \
21 " .section .fixup,\"ax\" \n" \22 _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0) \
22 "4: li.w %0, %6 \n" \23 _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0) \
23 " b 3b \n" \
24 " .previous \n" \
25 " .section __ex_table,\"a\" \n" \
26 " "__UA_ADDR "\t1b, 4b \n" \
27 " "__UA_ADDR "\t2b, 4b \n" \
28 " .previous \n" \
29 : "=r" (ret), "=&r" (oldval), \24 : "=r" (ret), "=&r" (oldval), \
30 "=ZC" (*uaddr) \25 "=ZC" (*uaddr) \
31 : "0" (0), "ZC" (*uaddr), "Jr" (oparg), \26 : "0" (0), "ZC" (*uaddr), "Jr" (oparg) \
32 "i" (-EFAULT) \
33 : "memory", "t0"); \27 : "memory", "t0"); \
34}28}
35 29
@@ -86,17 +80,10 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newv · 50 unmodified lines
86 " beqz $t0, 1b \n"80 " beqz $t0, 1b \n"
87 "3: \n"81 "3: \n"
88 __WEAK_LLSC_MB82 __WEAK_LLSC_MB
89 " .section .fixup,\"ax\" \n"83 _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0)
90 "4: li.d %0, %6 \n"84 _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0)
91 " b 3b \n"
92 " .previous \n"
93 " .section __ex_table,\"a\" \n"
94 " "__UA_ADDR "\t1b, 4b \n"
95 " "__UA_ADDR "\t2b, 4b \n"
96 " .previous \n"
97 : "+r" (ret), "=&r" (val), "=ZC" (*uaddr)85 : "+r" (ret), "=&r" (val), "=ZC" (*uaddr)
98 : "ZC" (*uaddr), "Jr" (oldval), "Jr" (newval),86 : "ZC" (*uaddr), "Jr" (oldval), "Jr" (newval)
99 "i" (-EFAULT)
100 : "memory", "t0");87 : "memory", "t0");
101 88
102 *uval = val;89 *uval = val;
arch/loongarch/include/asm/gpr-num.h+22−0
@@ -0,0 +1,22 @@
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 */
arch/loongarch/include/asm/inst.h+46−0
@@ -8,14 +8,17 @@ · 7 unmodified lines
8#include <linux/types.h>8#include <linux/types.h>
9#include <asm/asm.h>9#include <asm/asm.h>
10 10
11#define INSN_NOP 0x03400000
11#define INSN_BREAK 0x002a000012#define INSN_BREAK 0x002a0000
12 13
13#define ADDR_IMMMASK_LU52ID 0xFFF000000000000014#define ADDR_IMMMASK_LU52ID 0xFFF0000000000000
14#define ADDR_IMMMASK_LU32ID 0x000FFFFF0000000015#define ADDR_IMMMASK_LU32ID 0x000FFFFF00000000
16#define ADDR_IMMMASK_LU12IW 0x00000000FFFFF000
15#define ADDR_IMMMASK_ADDU16ID 0x00000000FFFF000017#define ADDR_IMMMASK_ADDU16ID 0x00000000FFFF0000
16 18
17#define ADDR_IMMSHIFT_LU52ID 5219#define ADDR_IMMSHIFT_LU52ID 52
18#define ADDR_IMMSHIFT_LU32ID 3220#define ADDR_IMMSHIFT_LU32ID 32
21#define ADDR_IMMSHIFT_LU12IW 12
19#define ADDR_IMMSHIFT_ADDU16ID 1622#define ADDR_IMMSHIFT_ADDU16ID 16
20 23
21#define ADDR_IMM(addr, INSN) ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN)24#define ADDR_IMM(addr, INSN) ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN)
@@ -28,6 +31,7 @@ enum reg0i26_op { · 6 unmodified lines
28enum reg1i20_op {31enum reg1i20_op {
29 lu12iw_op = 0x0a,32 lu12iw_op = 0x0a,
30 lu32id_op = 0x0b,33 lu32id_op = 0x0b,
34 pcaddi_op = 0x0c,
31 pcaddu12i_op = 0x0e,35 pcaddu12i_op = 0x0e,
32 pcaddu18i_op = 0x0f,36 pcaddu18i_op = 0x0f,
33};37};
@@ -35,6 +39,8 @@ enum reg1i20_op { · 1 unmodified line
35enum reg1i21_op {39enum reg1i21_op {
36 beqz_op = 0x10,40 beqz_op = 0x10,
37 bnez_op = 0x11,41 bnez_op = 0x11,
42 bceqz_op = 0x12, /* bits[9:8] = 0x00 */
43 bcnez_op = 0x12, /* bits[9:8] = 0x01 */
38};44};
39 45
40enum reg2_op {46enum reg2_op {
@@ -76,6 +82,10 @@ enum reg2i12_op { · 35 unmodified lines
76 ldbu_op = 0xa8,82 ldbu_op = 0xa8,
77 ldhu_op = 0xa9,83 ldhu_op = 0xa9,
78 ldwu_op = 0xaa,84 ldwu_op = 0xaa,
85 flds_op = 0xac,
86 fsts_op = 0xad,
87 fldd_op = 0xae,
88 fstd_op = 0xaf,
79};89};
80 90
81enum reg2i14_op {91enum reg2i14_op {
@@ -146,6 +156,10 @@ enum reg3_op { · 64 unmodified lines
146 ldxbu_op = 0x7040,156 ldxbu_op = 0x7040,
147 ldxhu_op = 0x7048,157 ldxhu_op = 0x7048,
148 ldxwu_op = 0x7050,158 ldxwu_op = 0x7050,
159 fldxs_op = 0x7060,
160 fldxd_op = 0x7068,
161 fstxs_op = 0x7070,
162 fstxd_op = 0x7078,
149 amswapw_op = 0x70c0,163 amswapw_op = 0x70c0,
150 amswapd_op = 0x70c1,164 amswapd_op = 0x70c1,
151 amaddw_op = 0x70c2,165 amaddw_op = 0x70c2,
@@ -307,6 +321,12 @@ static inline bool is_imm_negative(unsigned long val, unsigned int bit) · 155 unmodified lines
307 return val & (1UL << (bit - 1));321 return val & (1UL << (bit - 1));
308}322}
309 323
324static inline bool is_pc_ins(union loongarch_instruction *ip)
325{
326 return ip->reg1i20_format.opcode >= pcaddi_op &&
327 ip->reg1i20_format.opcode <= pcaddu18i_op;
328}
329
310static inline bool is_branch_ins(union loongarch_instruction *ip)330static inline bool is_branch_ins(union loongarch_instruction *ip)
311{331{
312 return ip->reg1i21_format.opcode >= beqz_op &&332 return ip->reg1i21_format.opcode >= beqz_op &&
@@ -331,6 +351,18 @@ static inline bool is_stack_alloc_ins(union loongarch_instruction *ip) · 18 unmodified lines
331 is_imm12_negative(ip->reg2i12_format.immediate);351 is_imm12_negative(ip->reg2i12_format.immediate);
332}352}
333 353
354int larch_insn_read(void *addr, u32 *insnp);
355int larch_insn_write(void *addr, u32 insn);
356int larch_insn_patch_text(void *addr, u32 insn);
357
358u32 larch_insn_gen_nop(void);
359u32 larch_insn_gen_b(unsigned long pc, unsigned long dest);
360u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest);
361
362u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj, enum loongarch_gpr rk);
363u32 larch_insn_gen_move(enum loongarch_gpr rd, enum loongarch_gpr rj);
364
365u32 larch_insn_gen_lu12iw(enum loongarch_gpr rd, int imm);
334u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm);366u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm);
335u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);367u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
336u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest);368u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest);
@@ -345,6 +377,14 @@ static inline bool unsigned_imm_check(unsigned long val, unsigned int bit) · 8 unmodified lines
345 return val < (1UL << bit);377 return val < (1UL << bit);
346}378}
347 379
380static inline unsigned long sign_extend(unsigned long val, unsigned int idx)
381{
382 if (!is_imm_negative(val, idx + 1))
383 return ((1UL << idx) - 1) & val;
384 else
385 return ~((1UL << idx) - 1) | val;
386}
387
348#define DEF_EMIT_REG0I26_FORMAT(NAME, OP) \388#define DEF_EMIT_REG0I26_FORMAT(NAME, OP) \
349static inline void emit_##NAME(union loongarch_instruction *insn, \389static inline void emit_##NAME(union loongarch_instruction *insn, \
350 int offset) \390 int offset) \
@@ -566,4 +606,10 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \ · 215 unmodified lines
566 606
567DEF_EMIT_REG3SA2_FORMAT(alsld, alsld_op)607DEF_EMIT_REG3SA2_FORMAT(alsld, alsld_op)
568 608
609struct pt_regs;
610
611void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned int *pc);
612unsigned long unaligned_read(void __user *addr, void *value, unsigned long n, bool sign);
613unsigned long unaligned_write(void __user *addr, unsigned long value, unsigned long n);
614
569#endif /* _ASM_INST_H */615#endif /* _ASM_INST_H */
arch/loongarch/include/asm/loongson.h+3−0
@@ -136,4 +136,7 @@ typedef enum { · 135 unmodified lines
136#define ls7a_writel(val, addr) *(volatile unsigned int *)TO_UNCACHE(addr) = (val)136#define ls7a_writel(val, addr) *(volatile unsigned int *)TO_UNCACHE(addr) = (val)
137#define ls7a_writeq(val, addr) *(volatile unsigned long *)TO_UNCACHE(addr) = (val)137#define ls7a_writeq(val, addr) *(volatile unsigned long *)TO_UNCACHE(addr) = (val)
138 138
139void enable_gpe_wakeup(void);
140void enable_pci_wakeup(void);
141
139#endif /* __ASM_LOONGSON_H */142#endif /* __ASM_LOONGSON_H */
arch/loongarch/include/asm/module.h+16−11
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#define RELA_STACK_DEPTH 1611#define RELA_STACK_DEPTH 16
12 12
13struct mod_section {13struct mod_section {
14 Elf_Shdr *shdr;14 int shndx;
15 int num_entries;15 int num_entries;
16 int max_entries;16 int max_entries;
17};17};
@@ -20,6 +20,9 @@ struct mod_arch_specific { · 2 unmodified lines
20 struct mod_section got;20 struct mod_section got;
21 struct mod_section plt;21 struct mod_section plt;
22 struct mod_section plt_idx;22 struct mod_section plt_idx;
23
24 /* For CONFIG_DYNAMIC_FTRACE */
25 struct plt_entry *ftrace_trampolines;
23};26};
24 27
25struct got_entry {28struct got_entry {
@@ -37,8 +40,8 @@ struct plt_idx_entry { · 11 unmodified lines
37 Elf_Addr symbol_addr;40 Elf_Addr symbol_addr;
38};41};
39 42
40Elf_Addr module_emit_got_entry(struct module *mod, Elf_Addr val);43Elf_Addr module_emit_got_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val);
41Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Addr val);44Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val);
42 45
43static inline struct got_entry emit_got_entry(Elf_Addr val)46static inline struct got_entry emit_got_entry(Elf_Addr val)
44{47{
@@ -49,7 +52,7 @@ static inline struct plt_entry emit_plt_entry(unsigned long val) · 4 unmodified lines
49{52{
50 u32 lu12iw, lu32id, lu52id, jirl;53 u32 lu12iw, lu32id, lu52id, jirl;
51 54
52 lu12iw = (lu12iw_op << 25 | (((val >> 12) & 0xfffff) << 5) | LOONGARCH_GPR_T1);55 lu12iw = larch_insn_gen_lu12iw(LOONGARCH_GPR_T1, ADDR_IMM(val, LU12IW));
53 lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val, LU32ID));56 lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val, LU32ID));
54 lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1, LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID));57 lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1, LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID));
55 jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xfff));58 jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xfff));
@@ -62,10 +65,10 @@ static inline struct plt_idx_entry emit_plt_idx_entry(unsigned long val) · 6 unmodified lines
62 return (struct plt_idx_entry) { val };65 return (struct plt_idx_entry) { val };
63}66}
64 67
65static inline int get_plt_idx(unsigned long val, const struct mod_section *sec)68static inline int get_plt_idx(unsigned long val, Elf_Shdr *sechdrs, const struct mod_section *sec)
66{69{
67 int i;70 int i;
68 struct plt_idx_entry *plt_idx = (struct plt_idx_entry *)sec->shdr->sh_addr;71 struct plt_idx_entry *plt_idx = (struct plt_idx_entry *)sechdrs[sec->shndx].sh_addr;
69 72
70 for (i = 0; i < sec->num_entries; i++) {73 for (i = 0; i < sec->num_entries; i++) {
71 if (plt_idx[i].symbol_addr == val)74 if (plt_idx[i].symbol_addr == val)
@@ -76,11 +79,12 @@ static inline int get_plt_idx(unsigned long val, const struct mod_section *sec) · 4 unmodified lines
76}79}
77 80
78static inline struct plt_entry *get_plt_entry(unsigned long val,81static inline struct plt_entry *get_plt_entry(unsigned long val,
79 const struct mod_section *sec_plt,82 Elf_Shdr *sechdrs,
80 const struct mod_section *sec_plt_idx)83 const struct mod_section *sec_plt,
84 const struct mod_section *sec_plt_idx)
81{85{
82 int plt_idx = get_plt_idx(val, sec_plt_idx);86 int plt_idx = get_plt_idx(val, sechdrs, sec_plt_idx);
83 struct plt_entry *plt = (struct plt_entry *)sec_plt->shdr->sh_addr;87 struct plt_entry *plt = (struct plt_entry *)sechdrs[sec_plt->shndx].sh_addr;
84 88
85 if (plt_idx < 0)89 if (plt_idx < 0)
86 return NULL;90 return NULL;
@@ -89,10 +93,11 @@ static inline struct plt_entry *get_plt_entry(unsigned long val, · 2 unmodified lines
89}93}
90 94
91static inline struct got_entry *get_got_entry(Elf_Addr val,95static inline struct got_entry *get_got_entry(Elf_Addr val,
96 Elf_Shdr *sechdrs,
92 const struct mod_section *sec)97 const struct mod_section *sec)
93{98{
94 struct got_entry *got = (struct got_entry *)sec->shdr->sh_addr;
95 int i;99 int i;
100 struct got_entry *got = (struct got_entry *)sechdrs[sec->shndx].sh_addr;
96 101
97 for (i = 0; i < sec->num_entries; i++)102 for (i = 0; i < sec->num_entries; i++)
98 if (got[i].symbol_addr == val)103 if (got[i].symbol_addr == val)
arch/loongarch/include/asm/module.lds.h+1−0
@@ -5,4 +5,5 @@ SECTIONS { · 4 unmodified lines
5 .got : { BYTE(0) }5 .got : { BYTE(0) }
6 .plt : { BYTE(0) }6 .plt : { BYTE(0) }
7 .plt.idx : { BYTE(0) }7 .plt.idx : { BYTE(0) }
8 .ftrace_trampoline : { BYTE(0) }
8}9}
arch/loongarch/include/asm/setup.h+1−0
@@ -13,6 +13,7 @@ · 12 unmodified lines
13 13
14extern unsigned long eentry;14extern unsigned long eentry;
15extern unsigned long tlbrentry;15extern unsigned long tlbrentry;
16extern char init_command_line[COMMAND_LINE_SIZE];
16extern void tlb_init(int cpu);17extern void tlb_init(int cpu);
17extern void cpu_cache_init(void);18extern void cpu_cache_init(void);
18extern void cache_error_setup(void);19extern void cache_error_setup(void);
arch/loongarch/include/asm/stackprotector.h+38−0
@@ -0,0 +1,38 @@
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
18extern 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 */
26static __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 */
arch/loongarch/include/asm/string.h+5−0
@@ -5,8 +5,13 @@ · 4 unmodified lines
5#ifndef _ASM_STRING_H5#ifndef _ASM_STRING_H
6#define _ASM_STRING_H6#define _ASM_STRING_H
7 7
8#define __HAVE_ARCH_MEMSET
8extern void *memset(void *__s, int __c, size_t __count);9extern void *memset(void *__s, int __c, size_t __count);
10
11#define __HAVE_ARCH_MEMCPY
9extern void *memcpy(void *__to, __const__ void *__from, size_t __n);12extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
13
14#define __HAVE_ARCH_MEMMOVE
10extern void *memmove(void *__dest, __const__ void *__src, size_t __n);15extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
11 16
12#endif /* _ASM_STRING_H */17#endif /* _ASM_STRING_H */
arch/loongarch/include/asm/thread_info.h+1−1
@@ -38,7 +38,7 @@ struct thread_info { · 37 unmodified lines
38#define INIT_THREAD_INFO(tsk) \38#define INIT_THREAD_INFO(tsk) \
39{ \39{ \
40 .task = &tsk, \40 .task = &tsk, \
41 .flags = 0, \41 .flags = _TIF_FIXADE, \
42 .cpu = 0, \42 .cpu = 0, \
43 .preempt_count = INIT_PREEMPT_COUNT, \43 .preempt_count = INIT_PREEMPT_COUNT, \
44}44}
arch/loongarch/include/asm/time.h+1−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
12extern u64 cpu_clock_freq;12extern u64 cpu_clock_freq;
13extern u64 const_clock_freq;13extern u64 const_clock_freq;
14 14
15extern void save_counter(void);
15extern void sync_counter(void);16extern void sync_counter(void);
16 17
17static inline unsigned int calc_const_freq(void)18static inline unsigned int calc_const_freq(void)
arch/loongarch/include/asm/uaccess.h+6−18
@@ -15,7 +15,8 @@ · 14 unmodified lines
15#include <linux/string.h>15#include <linux/string.h>
16#include <linux/extable.h>16#include <linux/extable.h>
17#include <asm/pgtable.h>17#include <asm/pgtable.h>
18#include <asm-generic/extable.h>18#include <asm/extable.h>
19#include <asm/asm-extable.h>
19#include <asm-generic/access_ok.h>20#include <asm-generic/access_ok.h>
20 21
21extern u64 __ua_limit;22extern u64 __ua_limit;
@@ -160,16 +161,9 @@ do { \ · 138 unmodified lines
160 __asm__ __volatile__( \161 __asm__ __volatile__( \
161 "1: " insn " %1, %2 \n" \162 "1: " insn " %1, %2 \n" \
162 "2: \n" \163 "2: \n" \
163 " .section .fixup,\"ax\" \n" \164 _ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 2b, %0, %1) \
164 "3: li.w %0, %3 \n" \
165 " move %1, $zero \n" \
166 " b 2b \n" \
167 " .previous \n" \
168 " .section __ex_table,\"a\" \n" \
169 " "__UA_ADDR "\t1b, 3b \n" \
170 " .previous \n" \
171 : "+r" (__gu_err), "=r" (__gu_tmp) \165 : "+r" (__gu_err), "=r" (__gu_tmp) \
172 : "m" (__m(ptr)), "i" (-EFAULT)); \166 : "m" (__m(ptr))); \
173 \167 \
174 (val) = (__typeof__(*(ptr))) __gu_tmp; \168 (val) = (__typeof__(*(ptr))) __gu_tmp; \
175}169}
@@ -192,15 +186,9 @@ do { \ · 16 unmodified lines
192 __asm__ __volatile__( \186 __asm__ __volatile__( \
193 "1: " insn " %z2, %1 # __put_user_asm\n" \187 "1: " insn " %z2, %1 # __put_user_asm\n" \
194 "2: \n" \188 "2: \n" \
195 " .section .fixup,\"ax\" \n" \189 _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %0) \
196 "3: li.w %0, %3 \n" \
197 " b 2b \n" \
198 " .previous \n" \
199 " .section __ex_table,\"a\" \n" \
200 " " __UA_ADDR " 1b, 3b \n" \
201 " .previous \n" \
202 : "+r" (__pu_err), "=m" (__m(ptr)) \190 : "+r" (__pu_err), "=m" (__m(ptr)) \
203 : "Jr" (__pu_val), "i" (-EFAULT)); \191 : "Jr" (__pu_val)); \
204}192}
205 193
206#define __get_kernel_nofault(dst, src, type, err_label) \194#define __get_kernel_nofault(dst, src, type, err_label) \
arch/loongarch/include/asm/unwind.h+2−1
@@ -20,7 +20,8 @@ struct unwind_state { · 19 unmodified lines
20 char type; /* UNWINDER_XXX */20 char type; /* UNWINDER_XXX */
21 struct stack_info stack_info;21 struct stack_info stack_info;
22 struct task_struct *task;22 struct task_struct *task;
23 bool first, error;23 bool first, error, is_ftrace;
24 int graph_idx;
24 unsigned long sp, pc, ra;25 unsigned long sp, pc, ra;
25};26};
26 27
arch/loongarch/kernel/Makefile+15−1
@@ -7,13 +7,27 @@ extra-y := vmlinux.lds · 6 unmodified lines
7 7
8obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \8obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
9 traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \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.o10 elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o \
11 alternative.o unaligned.o
11 12
12obj-$(CONFIG_ACPI) += acpi.o13obj-$(CONFIG_ACPI) += acpi.o
13obj-$(CONFIG_EFI) += efi.o14obj-$(CONFIG_EFI) += efi.o
14 15
15obj-$(CONFIG_CPU_HAS_FPU) += fpu.o16obj-$(CONFIG_CPU_HAS_FPU) += fpu.o
16 17
18ifdef 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)
29endif
30
17obj-$(CONFIG_MODULES) += module.o module-sections.o31obj-$(CONFIG_MODULES) += module.o module-sections.o
18obj-$(CONFIG_STACKTRACE) += stacktrace.o32obj-$(CONFIG_STACKTRACE) += stacktrace.o
19 33
arch/loongarch/kernel/acpi.c+15−2
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include <linux/irq.h>12#include <linux/irq.h>
13#include <linux/irqdomain.h>13#include <linux/irqdomain.h>
14#include <linux/memblock.h>14#include <linux/memblock.h>
15#include <linux/of_fdt.h>
15#include <linux/serial_core.h>16#include <linux/serial_core.h>
16#include <asm/io.h>17#include <asm/io.h>
17#include <asm/numa.h>18#include <asm/numa.h>
@@ -139,20 +140,26 @@ static void __init acpi_process_madt(void) · 121 unmodified lines
139 loongson_sysconf.nr_cpus = num_processors;140 loongson_sysconf.nr_cpus = num_processors;
140}141}
141 142
143#ifndef CONFIG_SUSPEND
144int (*acpi_suspend_lowlevel)(void);
145#else
146int (*acpi_suspend_lowlevel)(void) = loongarch_acpi_suspend;
147#endif
148
142void __init acpi_boot_table_init(void)149void __init acpi_boot_table_init(void)
143{150{
144 /*151 /*
145 * If acpi_disabled, bail out152 * If acpi_disabled, bail out
146 */153 */
147 if (acpi_disabled)154 if (acpi_disabled)
148 return;155 goto fdt_earlycon;
149 156
150 /*157 /*
151 * Initialize the ACPI boot-time table parser.158 * Initialize the ACPI boot-time table parser.
152 */159 */
153 if (acpi_table_init()) {160 if (acpi_table_init()) {
154 disable_acpi();161 disable_acpi();
155 return;162 goto fdt_earlycon;
156 }163 }
157 164
158 loongson_sysconf.boot_cpu_id = read_csr_cpuid();165 loongson_sysconf.boot_cpu_id = read_csr_cpuid();
@@ -164,6 +171,12 @@ void __init acpi_boot_table_init(void) · 5 unmodified lines
164 171
165 /* Do not enable ACPI SPCR console by default */172 /* Do not enable ACPI SPCR console by default */
166 acpi_parse_spcr(earlycon_acpi_spcr_enable, false);173 acpi_parse_spcr(earlycon_acpi_spcr_enable, false);
174
175 return;
176
177fdt_earlycon:
178 if (earlycon_acpi_spcr_enable)
179 early_init_dt_scan_chosen_stdout();
167}180}
168 181
169#ifdef CONFIG_ACPI_NUMA182#ifdef CONFIG_ACPI_NUMA
arch/loongarch/kernel/alternative.c+246−0
@@ -0,0 +1,246 @@
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
9int __read_mostly alternatives_patched;
10
11EXPORT_SYMBOL_GPL(alternatives_patched);
12
13#define MAX_PATCH_SIZE (((u8)(-1)) / LOONGARCH_INSN_SIZE)
14
15static int __initdata_or_module debug_alternative;
16
17static 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...) \
25do { \
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...) \
31do { \
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. */
47static 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 */
56static 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
61static 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
126static 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 */
157static 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 */
183void __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
241void __init alternative_instructions(void)
242{
243 apply_alternatives(__alt_instructions, __alt_instructions_end);
244
245 alternatives_patched = 1;
246}
arch/loongarch/kernel/asm-offsets.c+15−0
@@ -68,6 +68,9 @@ void output_task_defines(void) · 67 unmodified lines
68 OFFSET(TASK_FLAGS, task_struct, flags);68 OFFSET(TASK_FLAGS, task_struct, flags);
69 OFFSET(TASK_MM, task_struct, mm);69 OFFSET(TASK_MM, task_struct, mm);
70 OFFSET(TASK_PID, task_struct, pid);70 OFFSET(TASK_PID, task_struct, pid);
71#if defined(CONFIG_STACKPROTECTOR)
72 OFFSET(TASK_STACK_CANARY, task_struct, stack_canary);
73#endif
71 DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));74 DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));
72 BLANK();75 BLANK();
73}76}
@@ -257,3 +260,15 @@ void output_smpboot_defines(void) · 183 unmodified lines
257 BLANK();260 BLANK();
258}261}
259#endif262#endif
263
264#ifdef CONFIG_HIBERNATION
265void output_pbe_defines(void)
266{
267 COMMENT(" Linux struct pbe offsets. ");
268 OFFSET(PBE_ADDRESS, pbe, address);
269 OFFSET(PBE_ORIG_ADDRESS, pbe, orig_address);
270 OFFSET(PBE_NEXT, pbe, next);
271 DEFINE(PBE_SIZE, sizeof(struct pbe));
272 BLANK();
273}
274#endif
arch/loongarch/kernel/efi.c+14−1
@@ -28,16 +28,29 @@ static unsigned long efi_nr_tables; · 27 unmodified lines
28static unsigned long efi_config_table;28static unsigned long efi_config_table;
29 29
30static unsigned long __initdata boot_memmap = EFI_INVALID_TABLE_ADDR;30static unsigned long __initdata boot_memmap = EFI_INVALID_TABLE_ADDR;
31static unsigned long __initdata fdt_pointer = EFI_INVALID_TABLE_ADDR;
31 32
32static efi_system_table_t *efi_systab;33static efi_system_table_t *efi_systab;
33static efi_config_table_type_t arch_tables[] __initdata = {34static efi_config_table_type_t arch_tables[] __initdata = {
34 {LINUX_EFI_BOOT_MEMMAP_GUID, &boot_memmap, "MEMMAP" },35 {LINUX_EFI_BOOT_MEMMAP_GUID, &boot_memmap, "MEMMAP" },
36 {DEVICE_TREE_GUID, &fdt_pointer, "FDTPTR" },
35 {},37 {},
36};38};
37 39
40void __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
38void __init efi_runtime_init(void)51void __init efi_runtime_init(void)
39{52{
40 if (!efi_enabled(EFI_BOOT))53 if (!efi_enabled(EFI_BOOT) || !efi_systab->runtime)
41 return;54 return;
42 55
43 if (efi_runtime_disabled()) {56 if (efi_runtime_disabled()) {
arch/loongarch/kernel/env.c+2−0
@@ -11,6 +11,7 @@ · 10 unmodified lines
11#include <asm/early_ioremap.h>11#include <asm/early_ioremap.h>
12#include <asm/bootinfo.h>12#include <asm/bootinfo.h>
13#include <asm/loongson.h>13#include <asm/loongson.h>
14#include <asm/setup.h>
14 15
15u64 efi_system_table;16u64 efi_system_table;
16struct loongson_system_configuration loongson_sysconf;17struct loongson_system_configuration loongson_sysconf;
@@ -27,6 +28,7 @@ void __init init_environ(void) · 10 unmodified lines
27 clear_bit(EFI_BOOT, &efi.flags);28 clear_bit(EFI_BOOT, &efi.flags);
28 29
29 strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE);30 strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE);
31 strscpy(init_command_line, cmdline, COMMAND_LINE_SIZE);
30 early_memunmap(cmdline, COMMAND_LINE_SIZE);32 early_memunmap(cmdline, COMMAND_LINE_SIZE);
31 33
32 efi_system_table = fw_arg2;34 efi_system_table = fw_arg2;
arch/loongarch/kernel/fpu.S+2−3
@@ -8,6 +8,7 @@ · 7 unmodified lines
8 */8 */
9#include <asm/asm.h>9#include <asm/asm.h>
10#include <asm/asmmacro.h>10#include <asm/asmmacro.h>
11#include <asm/asm-extable.h>
11#include <asm/asm-offsets.h>12#include <asm/asm-offsets.h>
12#include <asm/errno.h>13#include <asm/errno.h>
13#include <asm/export.h>14#include <asm/export.h>
@@ -21,9 +22,7 @@ · 7 unmodified lines
21 22
22 .macro EX insn, reg, src, offs23 .macro EX insn, reg, src, offs
23.ex\@: \insn \reg, \src, \offs24.ex\@: \insn \reg, \src, \offs
24 .section __ex_table,"a"25 _asm_extable .ex\@, fault
25 PTR .ex\@, fault
26 .previous
27 .endm26 .endm
28 27
29 .macro sc_save_fp base28 .macro sc_save_fp base
arch/loongarch/kernel/ftrace.c+73−0
@@ -0,0 +1,73 @@
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
27static 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
49void 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
69out:
70 ftrace_graph_stop();
71 WARN_ON(1);
72}
73#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
arch/loongarch/kernel/ftrace_dyn.c+273−0
@@ -0,0 +1,273 @@
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
14static 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
35static 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
47static 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
60static 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
74int 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
107int 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
139int 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
151int 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
180int 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
209void arch_ftrace_update_code(int command)
210{
211 command |= FTRACE_MAY_SLEEP;
212 ftrace_modify_all_code(command);
213}
214
215int __init ftrace_dyn_arch_init(void)
216{
217 return 0;
218}
219
220#ifdef CONFIG_FUNCTION_GRAPH_TRACER
221void 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
236void 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
245static 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
263int ftrace_enable_ftrace_graph_caller(void)
264{
265 return ftrace_modify_graph_caller(true);
266}
267
268int 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 */
arch/loongarch/kernel/inst.c+127−0
@@ -2,8 +2,135 @@ · 1 unmodified line
2/*2/*
3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited3 * 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#include <asm/inst.h>9#include <asm/inst.h>
6 10
11static DEFINE_RAW_SPINLOCK(patch_lock);
12
13int 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
25int 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
37int 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
53u32 larch_insn_gen_nop(void)
54{
55 return INSN_NOP;
56}
57
58u32 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
82u32 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
106u32 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
118u32 larch_insn_gen_move(enum loongarch_gpr rd, enum loongarch_gpr rj)
119{
120 return larch_insn_gen_or(rd, rj, 0);
121}
122
123u32 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}
133
7u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm)134u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm)
8{135{
9 union loongarch_instruction insn;136 union loongarch_instruction insn;
arch/loongarch/kernel/mcount.S+96−0
@@ -0,0 +1,96 @@
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
33SYM_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
47fgraph_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
59SYM_INNER_LABEL(ftrace_stub, SYM_L_GLOBAL)
60 jr ra
61#ifdef CONFIG_FUNCTION_GRAPH_TRACER
62SYM_INNER_LABEL(ftrace_graph_func, SYM_L_GLOBAL)
63 bl ftrace_stub
64#endif
65SYM_FUNC_END(_mcount)
66EXPORT_SYMBOL(_mcount)
67
68#ifdef CONFIG_FUNCTION_GRAPH_TRACER
69SYM_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
79SYM_FUNC_END(ftrace_graph_caller)
80
81SYM_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
95SYM_FUNC_END(return_to_handler)
96#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
arch/loongarch/kernel/mcount_dyn.S+149−0
@@ -0,0 +1,149 @@
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
71SYM_FUNC_START(ftrace_stub)
72 jr ra
73SYM_FUNC_END(ftrace_stub)
74
75SYM_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
82SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
83 bl ftrace_stub
84#ifdef CONFIG_FUNCTION_GRAPH_TRACER
85SYM_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 */
95ftrace_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
109SYM_CODE_END(ftrace_common)
110
111SYM_CODE_START(ftrace_caller)
112 ftrace_regs_entry allregs=0
113 b ftrace_common
114SYM_CODE_END(ftrace_caller)
115
116#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
117SYM_CODE_START(ftrace_regs_caller)
118 ftrace_regs_entry allregs=1
119 b ftrace_common
120SYM_CODE_END(ftrace_regs_caller)
121#endif
122
123#ifdef CONFIG_FUNCTION_GRAPH_TRACER
124SYM_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
130SYM_CODE_END(ftrace_graph_caller)
131
132SYM_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
148SYM_CODE_END(return_to_handler)
149#endif
arch/loongarch/kernel/module-sections.c+39−25
@@ -6,18 +6,19 @@ · 5 unmodified lines
6#include <linux/elf.h>6#include <linux/elf.h>
7#include <linux/kernel.h>7#include <linux/kernel.h>
8#include <linux/module.h>8#include <linux/module.h>
9#include <linux/ftrace.h>
9 10
10Elf_Addr module_emit_got_entry(struct module *mod, Elf_Addr val)11Elf_Addr module_emit_got_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val)
11{12{
12 struct mod_section *got_sec = &mod->arch.got;13 struct mod_section *got_sec = &mod->arch.got;
13 int i = got_sec->num_entries;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 if (got)17 if (got)
17 return (Elf_Addr)got;18 return (Elf_Addr)got;
18 19
19 /* There is no GOT entry for val yet, create a new one. */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 got[i] = emit_got_entry(val);22 got[i] = emit_got_entry(val);
22 23
23 got_sec->num_entries++;24 got_sec->num_entries++;
@@ -33,12 +34,12 @@ Elf_Addr module_emit_got_entry(struct module *mod, Elf_Addr val) · 9 unmodified lines
33 return (Elf_Addr)&got[i];34 return (Elf_Addr)&got[i];
34}35}
35 36
36Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Addr val)37Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val)
37{38{
38 int nr;39 int nr;
39 struct mod_section *plt_sec = &mod->arch.plt;40 struct mod_section *plt_sec = &mod->arch.plt;
40 struct mod_section *plt_idx_sec = &mod->arch.plt_idx;41 struct mod_section *plt_idx_sec = &mod->arch.plt_idx;
41 struct plt_entry *plt = get_plt_entry(val, plt_sec, plt_idx_sec);42 struct plt_entry *plt = get_plt_entry(val, sechdrs, plt_sec, plt_idx_sec);
42 struct plt_idx_entry *plt_idx;43 struct plt_idx_entry *plt_idx;
43 44
44 if (plt)45 if (plt)
@@ -47,9 +48,9 @@ Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Addr val) · 2 unmodified lines
47 nr = plt_sec->num_entries;48 nr = plt_sec->num_entries;
48 49
49 /* There is no duplicate entry, create a new one */50 /* There is no duplicate entry, create a new one */
50 plt = (struct plt_entry *)plt_sec->shdr->sh_addr;51 plt = (struct plt_entry *)sechdrs[plt_sec->shndx].sh_addr;
51 plt[nr] = emit_plt_entry(val);52 plt[nr] = emit_plt_entry(val);
52 plt_idx = (struct plt_idx_entry *)plt_idx_sec->shdr->sh_addr;53 plt_idx = (struct plt_idx_entry *)sechdrs[plt_idx_sec->shndx].sh_addr;
53 plt_idx[nr] = emit_plt_idx_entry(val);54 plt_idx[nr] = emit_plt_idx_entry(val);
54 55
55 plt_sec->num_entries++;56 plt_sec->num_entries++;
@@ -103,28 +104,31 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, · 47 unmodified lines
103 char *secstrings, struct module *mod)104 char *secstrings, struct module *mod)
104{105{
105 unsigned int i, num_plts = 0, num_gots = 0;106 unsigned int i, num_plts = 0, num_gots = 0;
107 Elf_Shdr *got_sec, *plt_sec, *plt_idx_sec, *tramp = NULL;
106 108
107 /*109 /*
108 * Find the empty .plt sections.110 * Find the empty .plt sections.
109 */111 */
110 for (i = 0; i < ehdr->e_shnum; i++) {112 for (i = 0; i < ehdr->e_shnum; i++) {
111 if (!strcmp(secstrings + sechdrs[i].sh_name, ".got"))113 if (!strcmp(secstrings + sechdrs[i].sh_name, ".got"))
112 mod->arch.got.shdr = sechdrs + i;114 mod->arch.got.shndx = i;
113 else if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt"))115 else if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt"))
114 mod->arch.plt.shdr = sechdrs + i;116 mod->arch.plt.shndx = i;
115 else if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt.idx"))117 else if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt.idx"))
116 mod->arch.plt_idx.shdr = sechdrs + i;118 mod->arch.plt_idx.shndx = i;
119 else if (!strcmp(secstrings + sechdrs[i].sh_name, ".ftrace_trampoline"))
120 tramp = sechdrs + i;
117 }121 }
118 122
119 if (!mod->arch.got.shdr) {123 if (!mod->arch.got.shndx) {
120 pr_err("%s: module GOT section(s) missing\n", mod->name);124 pr_err("%s: module GOT section(s) missing\n", mod->name);
121 return -ENOEXEC;125 return -ENOEXEC;
122 }126 }
123 if (!mod->arch.plt.shdr) {127 if (!mod->arch.plt.shndx) {
124 pr_err("%s: module PLT section(s) missing\n", mod->name);128 pr_err("%s: module PLT section(s) missing\n", mod->name);
125 return -ENOEXEC;129 return -ENOEXEC;
126 }130 }
127 if (!mod->arch.plt_idx.shdr) {131 if (!mod->arch.plt_idx.shndx) {
128 pr_err("%s: module PLT.IDX section(s) missing\n", mod->name);132 pr_err("%s: module PLT.IDX section(s) missing\n", mod->name);
129 return -ENOEXEC;133 return -ENOEXEC;
130 }134 }
@@ -145,26 +149,36 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, · 14 unmodified lines
145 count_max_entries(relas, num_rela, &num_plts, &num_gots);149 count_max_entries(relas, num_rela, &num_plts, &num_gots);
146 }150 }
147 151
148 mod->arch.got.shdr->sh_type = SHT_NOBITS;152 got_sec = sechdrs + mod->arch.got.shndx;
149 mod->arch.got.shdr->sh_flags = SHF_ALLOC;153 got_sec->sh_type = SHT_NOBITS;
150 mod->arch.got.shdr->sh_addralign = L1_CACHE_BYTES;154 got_sec->sh_flags = SHF_ALLOC;
151 mod->arch.got.shdr->sh_size = (num_gots + 1) * sizeof(struct got_entry);155 got_sec->sh_addralign = L1_CACHE_BYTES;
156 got_sec->sh_size = (num_gots + 1) * sizeof(struct got_entry);
152 mod->arch.got.num_entries = 0;157 mod->arch.got.num_entries = 0;
153 mod->arch.got.max_entries = num_gots;158 mod->arch.got.max_entries = num_gots;
154 159
155 mod->arch.plt.shdr->sh_type = SHT_NOBITS;160 plt_sec = sechdrs + mod->arch.plt.shndx;
156 mod->arch.plt.shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;161 plt_sec->sh_type = SHT_NOBITS;
157 mod->arch.plt.shdr->sh_addralign = L1_CACHE_BYTES;162 plt_sec->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
158 mod->arch.plt.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_entry);163 plt_sec->sh_addralign = L1_CACHE_BYTES;
164 plt_sec->sh_size = (num_plts + 1) * sizeof(struct plt_entry);
159 mod->arch.plt.num_entries = 0;165 mod->arch.plt.num_entries = 0;
160 mod->arch.plt.max_entries = num_plts;166 mod->arch.plt.max_entries = num_plts;
161 167
162 mod->arch.plt_idx.shdr->sh_type = SHT_NOBITS;168 plt_idx_sec = sechdrs + mod->arch.plt_idx.shndx;
163 mod->arch.plt_idx.shdr->sh_flags = SHF_ALLOC;169 plt_idx_sec->sh_type = SHT_NOBITS;
164 mod->arch.plt_idx.shdr->sh_addralign = L1_CACHE_BYTES;170 plt_idx_sec->sh_flags = SHF_ALLOC;
165 mod->arch.plt_idx.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_idx_entry);171 plt_idx_sec->sh_addralign = L1_CACHE_BYTES;
172 plt_idx_sec->sh_size = (num_plts + 1) * sizeof(struct plt_idx_entry);
166 mod->arch.plt_idx.num_entries = 0;173 mod->arch.plt_idx.num_entries = 0;
167 mod->arch.plt_idx.max_entries = num_plts;174 mod->arch.plt_idx.max_entries = num_plts;
168 175
176 if (tramp) {
177 tramp->sh_type = SHT_NOBITS;
178 tramp->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
179 tramp->sh_addralign = __alignof__(struct plt_entry);
180 tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry);
181 }
182
169 return 0;183 return 0;
170}184}
arch/loongarch/kernel/module.c+63−12
@@ -15,8 +15,11 @@ · 14 unmodified lines
15#include <linux/vmalloc.h>15#include <linux/vmalloc.h>
16#include <linux/slab.h>16#include <linux/slab.h>
17#include <linux/fs.h>17#include <linux/fs.h>
18#include <linux/ftrace.h>
18#include <linux/string.h>19#include <linux/string.h>
19#include <linux/kernel.h>20#include <linux/kernel.h>
21#include <asm/alternative.h>
22#include <asm/inst.h>
20 23
21static int rela_stack_push(s64 stack_value, s64 *rela_stack, size_t *rela_stack_top)24static int rela_stack_push(s64 stack_value, s64 *rela_stack, size_t *rela_stack_top)
22{25{
@@ -98,16 +101,17 @@ static int apply_r_larch_sop_push_dup(struct module *mod, u32 *location, Elf_Add · 75 unmodified lines
98 return 0;101 return 0;
99}102}
100 103
101static int apply_r_larch_sop_push_plt_pcrel(struct module *mod, u32 *location, Elf_Addr v,104static int apply_r_larch_sop_push_plt_pcrel(struct module *mod,
105 Elf_Shdr *sechdrs, u32 *location, Elf_Addr v,
102 s64 *rela_stack, size_t *rela_stack_top, unsigned int type)106 s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
103{107{
104 ptrdiff_t offset = (void *)v - (void *)location;108 ptrdiff_t offset = (void *)v - (void *)location;
105 109
106 if (offset >= SZ_128M)110 if (offset >= SZ_128M)
107 v = module_emit_plt_entry(mod, v);111 v = module_emit_plt_entry(mod, sechdrs, v);
108 112
109 if (offset < -SZ_128M)113 if (offset < -SZ_128M)
110 v = module_emit_plt_entry(mod, v);114 v = module_emit_plt_entry(mod, sechdrs, v);
111 115
112 return apply_r_larch_sop_push_pcrel(mod, location, v, rela_stack, rela_stack_top, type);116 return apply_r_larch_sop_push_pcrel(mod, location, v, rela_stack, rela_stack_top, type);
113}117}
@@ -271,17 +275,18 @@ static int apply_r_larch_add_sub(struct module *mod, u32 *location, Elf_Addr v, · 157 unmodified lines
271 }275 }
272}276}
273 277
274static int apply_r_larch_b26(struct module *mod, u32 *location, Elf_Addr v,278static int apply_r_larch_b26(struct module *mod,
279 Elf_Shdr *sechdrs, u32 *location, Elf_Addr v,
275 s64 *rela_stack, size_t *rela_stack_top, unsigned int type)280 s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
276{281{
277 ptrdiff_t offset = (void *)v - (void *)location;282 ptrdiff_t offset = (void *)v - (void *)location;
278 union loongarch_instruction *insn = (union loongarch_instruction *)location;283 union loongarch_instruction *insn = (union loongarch_instruction *)location;
279 284
280 if (offset >= SZ_128M)285 if (offset >= SZ_128M)
281 v = module_emit_plt_entry(mod, v);286 v = module_emit_plt_entry(mod, sechdrs, v);
282 287
283 if (offset < -SZ_128M)288 if (offset < -SZ_128M)
284 v = module_emit_plt_entry(mod, v);289 v = module_emit_plt_entry(mod, sechdrs, v);
285 290
286 offset = (void *)v - (void *)location;291 offset = (void *)v - (void *)location;
287 292
@@ -338,10 +343,11 @@ static int apply_r_larch_pcala(struct module *mod, u32 *location, Elf_Addr v, · 50 unmodified lines
338 return 0;343 return 0;
339}344}
340 345
341static int apply_r_larch_got_pc(struct module *mod, u32 *location, Elf_Addr v,346static int apply_r_larch_got_pc(struct module *mod,
347 Elf_Shdr *sechdrs, u32 *location, Elf_Addr v,
342 s64 *rela_stack, size_t *rela_stack_top, unsigned int type)348 s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
343{349{
344 Elf_Addr got = module_emit_got_entry(mod, v);350 Elf_Addr got = module_emit_got_entry(mod, sechdrs, v);
345 351
346 if (!got)352 if (!got)
347 return -EINVAL;353 return -EINVAL;
@@ -386,13 +392,10 @@ static reloc_rela_handler reloc_rela_handlers[] = { · 38 unmodified lines
386 [R_LARCH_SOP_PUSH_PCREL] = apply_r_larch_sop_push_pcrel,392 [R_LARCH_SOP_PUSH_PCREL] = apply_r_larch_sop_push_pcrel,
387 [R_LARCH_SOP_PUSH_ABSOLUTE] = apply_r_larch_sop_push_absolute,393 [R_LARCH_SOP_PUSH_ABSOLUTE] = apply_r_larch_sop_push_absolute,
388 [R_LARCH_SOP_PUSH_DUP] = apply_r_larch_sop_push_dup,394 [R_LARCH_SOP_PUSH_DUP] = apply_r_larch_sop_push_dup,
389 [R_LARCH_SOP_PUSH_PLT_PCREL] = apply_r_larch_sop_push_plt_pcrel,
390 [R_LARCH_SOP_SUB ... R_LARCH_SOP_IF_ELSE] = apply_r_larch_sop,395 [R_LARCH_SOP_SUB ... R_LARCH_SOP_IF_ELSE] = apply_r_larch_sop,
391 [R_LARCH_SOP_POP_32_S_10_5 ... R_LARCH_SOP_POP_32_U] = apply_r_larch_sop_imm_field,396 [R_LARCH_SOP_POP_32_S_10_5 ... R_LARCH_SOP_POP_32_U] = apply_r_larch_sop_imm_field,
392 [R_LARCH_ADD32 ... R_LARCH_SUB64] = apply_r_larch_add_sub,397 [R_LARCH_ADD32 ... R_LARCH_SUB64] = apply_r_larch_add_sub,
393 [R_LARCH_B26] = apply_r_larch_b26,
394 [R_LARCH_PCALA_HI20...R_LARCH_PCALA64_HI12] = apply_r_larch_pcala,398 [R_LARCH_PCALA_HI20...R_LARCH_PCALA64_HI12] = apply_r_larch_pcala,
395 [R_LARCH_GOT_PC_HI20...R_LARCH_GOT_PC_LO12] = apply_r_larch_got_pc,
396};399};
397 400
398int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,401int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
@@ -443,7 +446,22 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, · 44 unmodified lines
443 sym->st_value, rel[i].r_addend, (u64)location);446 sym->st_value, rel[i].r_addend, (u64)location);
444 447
445 v = sym->st_value + rel[i].r_addend;448 v = sym->st_value + rel[i].r_addend;
446 err = handler(mod, location, v, rela_stack, &rela_stack_top, type);449 switch (type) {
450 case R_LARCH_B26:
451 err = apply_r_larch_b26(mod, sechdrs, location,
452 v, rela_stack, &rela_stack_top, type);
453 break;
454 case R_LARCH_GOT_PC_HI20...R_LARCH_GOT_PC_LO12:
455 err = apply_r_larch_got_pc(mod, sechdrs, location,
456 v, rela_stack, &rela_stack_top, type);
457 break;
458 case R_LARCH_SOP_PUSH_PLT_PCREL:
459 err = apply_r_larch_sop_push_plt_pcrel(mod, sechdrs, location,
460 v, rela_stack, &rela_stack_top, type);
461 break;
462 default:
463 err = handler(mod, location, v, rela_stack, &rela_stack_top, type);
464 }
447 if (err)465 if (err)
448 return err;466 return err;
449 }467 }
@@ -456,3 +474,36 @@ void *module_alloc(unsigned long size) · 6 unmodified lines
456 return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,474 return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
457 GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0));475 GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0));
458}476}
477
478static void module_init_ftrace_plt(const Elf_Ehdr *hdr,
479 const Elf_Shdr *sechdrs, struct module *mod)
480{
481#ifdef CONFIG_DYNAMIC_FTRACE
482 struct plt_entry *ftrace_plts;
483
484 ftrace_plts = (void *)sechdrs->sh_addr;
485
486 ftrace_plts[FTRACE_PLT_IDX] = emit_plt_entry(FTRACE_ADDR);
487
488 if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
489 ftrace_plts[FTRACE_REGS_PLT_IDX] = emit_plt_entry(FTRACE_REGS_ADDR);
490
491 mod->arch.ftrace_trampolines = ftrace_plts;
492#endif
493}
494
495int module_finalize(const Elf_Ehdr *hdr,
496 const Elf_Shdr *sechdrs, struct module *mod)
497{
498 const Elf_Shdr *s, *se;
499 const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
500
501 for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
502 if (!strcmp(".altinstructions", secstrs + s->sh_name))
503 apply_alternatives((void *)s->sh_addr, (void *)s->sh_addr + s->sh_size);
504 if (!strcmp(".ftrace_trampoline", secstrs + s->sh_name))
505 module_init_ftrace_plt(hdr, s, mod);
506 }
507
508 return 0;
509}
arch/loongarch/kernel/numa.c+16−1
@@ -388,6 +388,21 @@ static void __init numa_default_distance(void) · 387 unmodified lines
388 }388 }
389}389}
390 390
391/*
392 * fake_numa_init() - For Non-ACPI systems
393 * Return: 0 on success, -errno on failure.
394 */
395static 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
391int __init init_numa_memory(void)406int __init init_numa_memory(void)
392{407{
393 int i;408 int i;
@@ -404,7 +419,7 @@ int __init init_numa_memory(void) · 10 unmodified lines
404 memset(&numa_meminfo, 0, sizeof(numa_meminfo));419 memset(&numa_meminfo, 0, sizeof(numa_meminfo));
405 420
406 /* Parse SRAT and SLIT if provided by firmware. */421 /* Parse SRAT and SLIT if provided by firmware. */
407 ret = acpi_numa_init();422 ret = acpi_disabled ? fake_numa_init() : acpi_numa_init();
408 if (ret < 0)423 if (ret < 0)
409 return ret;424 return ret;
410 425
arch/loongarch/kernel/process.c+6−0
@@ -47,6 +47,12 @@ · 46 unmodified lines
47#include <asm/unwind.h>47#include <asm/unwind.h>
48#include <asm/vdso.h>48#include <asm/vdso.h>
49 49
50#ifdef CONFIG_STACKPROTECTOR
51#include <linux/stackprotector.h>
52unsigned long __stack_chk_guard __read_mostly;
53EXPORT_SYMBOL(__stack_chk_guard);
54#endif
55
50/*56/*
51 * Idle related variables and functions57 * Idle related variables and functions
52 */58 */
arch/loongarch/kernel/reset.c+5−0
@@ -15,6 +15,7 @@ · 14 unmodified lines
15#include <acpi/reboot.h>15#include <acpi/reboot.h>
16#include <asm/idle.h>16#include <asm/idle.h>
17#include <asm/loongarch.h>17#include <asm/loongarch.h>
18#include <asm/loongson.h>
18 19
19void (*pm_power_off)(void);20void (*pm_power_off)(void);
20EXPORT_SYMBOL(pm_power_off);21EXPORT_SYMBOL(pm_power_off);
@@ -41,6 +42,10 @@ void machine_power_off(void) · 20 unmodified lines
41#ifdef CONFIG_SMP42#ifdef CONFIG_SMP
42 preempt_disable();43 preempt_disable();
43 smp_send_stop();44 smp_send_stop();
45#endif
46#ifdef CONFIG_PM
47 if (!acpi_disabled)
48 enable_pci_wakeup();
44#endif49#endif
45 do_kernel_power_off();50 do_kernel_power_off();
46#ifdef CONFIG_EFI51#ifdef CONFIG_EFI
arch/loongarch/kernel/setup.c+148−1
@@ -28,10 +28,16 @@ · 27 unmodified lines
28#include <linux/sizes.h>28#include <linux/sizes.h>
29#include <linux/device.h>29#include <linux/device.h>
30#include <linux/dma-map-ops.h>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#include <linux/swiotlb.h>35#include <linux/swiotlb.h>
32 36
33#include <asm/addrspace.h>37#include <asm/addrspace.h>
38#include <asm/alternative.h>
34#include <asm/bootinfo.h>39#include <asm/bootinfo.h>
40#include <asm/bugs.h>
35#include <asm/cache.h>41#include <asm/cache.h>
36#include <asm/cpu.h>42#include <asm/cpu.h>
37#include <asm/dma.h>43#include <asm/dma.h>
@@ -67,6 +73,7 @@ static const char dmi_empty_string[] = " "; · 29 unmodified lines
67 *73 *
68 * These are initialized so they are in the .data section74 * These are initialized so they are in the .data section
69 */75 */
76char init_command_line[COMMAND_LINE_SIZE] __initdata;
70 77
71static int num_standard_resources;78static int num_standard_resources;
72static struct resource *standard_resources;79static struct resource *standard_resources;
@@ -80,6 +87,11 @@ const char *get_system_type(void) · 7 unmodified lines
80 return "generic-loongson-machine";87 return "generic-loongson-machine";
81}88}
82 89
90void __init check_bugs(void)
91{
92 alternative_instructions();
93}
94
83static const char *dmi_string_parse(const struct dmi_header *dm, u8 s)95static const char *dmi_string_parse(const struct dmi_header *dm, u8 s)
84{96{
85 const u8 *bp = ((u8 *) dm) + dm->length;97 const u8 *bp = ((u8 *) dm) + dm->length;
@@ -246,6 +258,58 @@ static void __init arch_parse_crashkernel(void) · 160 unmodified lines
246#endif258#endif
247}259}
248 260
261static void __init fdt_setup(void)
262{
263#ifdef CONFIG_OF_EARLY_FLATTREE
264 void *fdt_pointer;
265
266 /* ACPI-based systems do not require parsing fdt */
267 if (acpi_os_get_root_pointer())
268 return;
269
270 /* Look for a device tree configuration table entry */
271 fdt_pointer = efi_fdt_pointer();
272 if (!fdt_pointer || fdt_check_header(fdt_pointer))
273 return;
274
275 early_init_dt_scan(fdt_pointer);
276 early_init_fdt_reserve_self();
277
278 max_low_pfn = PFN_PHYS(memblock_end_of_DRAM());
279#endif
280}
281
282static void __init bootcmdline_init(char **cmdline_p)
283{
284 /*
285 * If CONFIG_CMDLINE_FORCE is enabled then initializing the command line
286 * is trivial - we simply use the built-in command line unconditionally &
287 * unmodified.
288 */
289 if (IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
290 strscpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
291 goto out;
292 }
293
294#ifdef CONFIG_OF_FLATTREE
295 /*
296 * If CONFIG_CMDLINE_BOOTLOADER is enabled and we are in FDT-based system,
297 * the boot_command_line will be overwritten by early_init_dt_scan_chosen().
298 * So we need to append init_command_line (the original copy of boot_command_line)
299 * to boot_command_line.
300 */
301 if (initial_boot_params) {
302 if (boot_command_line[0])
303 strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
304
305 strlcat(boot_command_line, init_command_line, COMMAND_LINE_SIZE);
306 }
307#endif
308
309out:
310 *cmdline_p = boot_command_line;
311}
312
249void __init platform_init(void)313void __init platform_init(void)
250{314{
251 arch_reserve_vmcore();315 arch_reserve_vmcore();
@@ -258,6 +322,7 @@ void __init platform_init(void) · 6 unmodified lines
258 acpi_gbl_use_default_register_widths = false;322 acpi_gbl_use_default_register_widths = false;
259 acpi_boot_table_init();323 acpi_boot_table_init();
260#endif324#endif
325 unflatten_and_copy_device_tree();
261 326
262#ifdef CONFIG_NUMA327#ifdef CONFIG_NUMA
263 init_numa_memory();328 init_numa_memory();
@@ -290,6 +355,8 @@ static void __init arch_mem_init(char **cmdline_p) · 26 unmodified lines
290 355
291 check_kernel_sections_mem();356 check_kernel_sections_mem();
292 357
358 early_init_fdt_scan_reserved_mem();
359
293 /*360 /*
294 * In order to reduce the possibility of kernel panic when failed to361 * In order to reduce the possibility of kernel panic when failed to
295 * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate362 * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
@@ -304,6 +371,10 @@ static void __init arch_mem_init(char **cmdline_p) · 8 unmodified lines
304 371
305 dma_contiguous_reserve(PFN_PHYS(max_low_pfn));372 dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
306 373
374 /* Reserve for hibernation. */
375 register_nosave_region(PFN_DOWN(__pa_symbol(&__nosave_begin)),
376 PFN_UP(__pa_symbol(&__nosave_end)));
377
307 memblock_dump_all();378 memblock_dump_all();
308 379
309 early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));380 early_memtest(PFN_PHYS(ARCH_PFN_OFFSET), PFN_PHYS(max_low_pfn));
@@ -363,6 +434,81 @@ static void __init resource_init(void) · 53 unmodified lines
363#endif434#endif
364}435}
365 436
437static int __init add_legacy_isa_io(struct fwnode_handle *fwnode,
438 resource_size_t hw_start, resource_size_t size)
439{
440 int ret = 0;
441 unsigned long vaddr;
442 struct logic_pio_hwaddr *range;
443
444 range = kzalloc(sizeof(*range), GFP_ATOMIC);
445 if (!range)
446 return -ENOMEM;
447
448 range->fwnode = fwnode;
449 range->size = size = round_up(size, PAGE_SIZE);
450 range->hw_start = hw_start;
451 range->flags = LOGIC_PIO_CPU_MMIO;
452
453 ret = logic_pio_register_range(range);
454 if (ret) {
455 kfree(range);
456 return ret;
457 }
458
459 /* Legacy ISA must placed at the start of PCI_IOBASE */
460 if (range->io_start != 0) {
461 logic_pio_unregister_range(range);
462 kfree(range);
463 return -EINVAL;
464 }
465
466 vaddr = (unsigned long)(PCI_IOBASE + range->io_start);
467 ioremap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL));
468
469 return 0;
470}
471
472static __init int arch_reserve_pio_range(void)
473{
474 struct device_node *np;
475
476 for_each_node_by_name(np, "isa") {
477 struct of_range range;
478 struct of_range_parser parser;
479
480 pr_info("ISA Bridge: %pOF\n", np);
481
482 if (of_range_parser_init(&parser, np)) {
483 pr_info("Failed to parse resources.\n");
484 of_node_put(np);
485 break;
486 }
487
488 for_each_of_range(&parser, &range) {
489 switch (range.flags & IORESOURCE_TYPE_BITS) {
490 case IORESOURCE_IO:
491 pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
492 range.cpu_addr,
493 range.cpu_addr + range.size - 1,
494 range.bus_addr);
495 if (add_legacy_isa_io(&np->fwnode, range.cpu_addr, range.size))
496 pr_warn("Failed to reserve legacy IO in Logic PIO\n");
497 break;
498 case IORESOURCE_MEM:
499 pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx\n",
500 range.cpu_addr,
501 range.cpu_addr + range.size - 1,
502 range.bus_addr);
503 break;
504 }
505 }
506 }
507
508 return 0;
509}
510arch_initcall(arch_reserve_pio_range);
511
366static int __init reserve_memblock_reserved_regions(void)512static int __init reserve_memblock_reserved_regions(void)
367{513{
368 u64 i, j;514 u64 i, j;
@@ -415,12 +561,13 @@ static void __init prefill_possible_map(void) · 46 unmodified lines
415void __init setup_arch(char **cmdline_p)561void __init setup_arch(char **cmdline_p)
416{562{
417 cpu_probe();563 cpu_probe();
418 *cmdline_p = boot_command_line;
419 564
420 init_environ();565 init_environ();
421 efi_init();566 efi_init();
567 fdt_setup();
422 memblock_init();568 memblock_init();
423 pagetable_init();569 pagetable_init();
570 bootcmdline_init(cmdline_p);
424 parse_early_param();571 parse_early_param();
425 reserve_initrd_mem();572 reserve_initrd_mem();
426 573
arch/loongarch/kernel/smp.c+35−0
@@ -16,6 +16,7 @@ · 15 unmodified lines
16#include <linux/smp.h>16#include <linux/smp.h>
17#include <linux/threads.h>17#include <linux/threads.h>
18#include <linux/export.h>18#include <linux/export.h>
19#include <linux/syscore_ops.h>
19#include <linux/time.h>20#include <linux/time.h>
20#include <linux/tracepoint.h>21#include <linux/tracepoint.h>
21#include <linux/sched/hotplug.h>22#include <linux/sched/hotplug.h>
@@ -180,8 +181,42 @@ irqreturn_t loongson_ipi_interrupt(int irq, void *dev) · 158 unmodified lines
180 return IRQ_HANDLED;181 return IRQ_HANDLED;
181}182}
182 183
184static void __init fdt_smp_setup(void)
185{
186#ifdef CONFIG_OF
187 unsigned int cpu, cpuid;
188 struct device_node *node = NULL;
189
190 for_each_of_cpu_node(node) {
191 if (!of_device_is_available(node))
192 continue;
193
194 cpuid = of_get_cpu_hwid(node, 0);
195 if (cpuid >= nr_cpu_ids)
196 continue;
197
198 if (cpuid == loongson_sysconf.boot_cpu_id) {
199 cpu = 0;
200 numa_add_cpu(cpu);
201 } else {
202 cpu = cpumask_next_zero(-1, cpu_present_mask);
203 }
204
205 num_processors++;
206 set_cpu_possible(cpu, true);
207 set_cpu_present(cpu, true);
208 __cpu_number_map[cpuid] = cpu;
209 __cpu_logical_map[cpu] = cpuid;
210 }
211
212 loongson_sysconf.nr_cpus = num_processors;
213#endif
214}
215
183void __init loongson_smp_setup(void)216void __init loongson_smp_setup(void)
184{217{
218 fdt_smp_setup();
219
185 cpu_data[0].core = cpu_logical_map(0) % loongson_sysconf.cores_per_package;220 cpu_data[0].core = cpu_logical_map(0) % loongson_sysconf.cores_per_package;
186 cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package;221 cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package;
187 222
arch/loongarch/kernel/switch.S+5−0
@@ -23,6 +23,11 @@ SYM_FUNC_START(__switch_to) · 22 unmodified lines
23 stptr.d ra, a0, THREAD_REG0123 stptr.d ra, a0, THREAD_REG01
24 stptr.d a3, a0, THREAD_SCHED_RA24 stptr.d a3, a0, THREAD_SCHED_RA
25 stptr.d a4, a0, THREAD_SCHED_CFA25 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 move tp, a231 move tp, a2
27 cpu_restore_nonscratch a132 cpu_restore_nonscratch a1
28 33
arch/loongarch/kernel/time.c+8−3
@@ -115,12 +115,17 @@ static unsigned long __init get_loops_per_jiffy(void) · 114 unmodified lines
115 return lpj;115 return lpj;
116}116}
117 117
118static long init_timeval;118static long init_offset __nosavedata;
119
120void save_counter(void)
121{
122 init_offset = drdtime();
123}
119 124
120void sync_counter(void)125void sync_counter(void)
121{126{
122 /* Ensure counter begin at 0 */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
126static int get_timer_irq(void)131static int get_timer_irq(void)
@@ -219,7 +224,7 @@ void __init time_init(void) · 92 unmodified lines
219 else224 else
220 const_clock_freq = calc_const_freq();225 const_clock_freq = calc_const_freq();
221 226
222 init_timeval = drdtime() - csr_read64(LOONGARCH_CSR_CNTC);227 init_offset = -(drdtime() - csr_read64(LOONGARCH_CSR_CNTC));
223 228
224 constant_clockevent_init();229 constant_clockevent_init();
225 constant_clocksource_init();230 constant_clocksource_init();
arch/loongarch/kernel/traps.c+27−0
@@ -368,13 +368,40 @@ asmlinkage void noinstr do_ade(struct pt_regs *regs) · 367 unmodified lines
368 irqentry_exit(regs, state);368 irqentry_exit(regs, state);
369}369}
370 370
371/* sysctl hooks */
372int unaligned_enabled __read_mostly = 1; /* Enabled by default */
373int no_unaligned_warning __read_mostly = 1; /* Only 1 warning by default */
374
371asmlinkage void noinstr do_ale(struct pt_regs *regs)375asmlinkage void noinstr do_ale(struct pt_regs *regs)
372{376{
377 unsigned int *pc;
373 irqentry_state_t state = irqentry_enter(regs);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
400sigbus:
375 die_if_kernel("Kernel ale access", regs);401 die_if_kernel("Kernel ale access", regs);
376 force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);402 force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);
377 403
404out:
378 irqentry_exit(regs, state);405 irqentry_exit(regs, state);
379}406}
380 407
arch/loongarch/kernel/unaligned.c+499−0
@@ -0,0 +1,499 @@
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
26static u32 unaligned_instructions_user;
27static u32 unaligned_instructions_kernel;
28#endif
29
30static 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
141static 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
249void 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
465fault:
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
475sigbus:
476 die_if_kernel("Unhandled kernel unaligned access", regs);
477 force_sig(SIGBUS);
478
479 return;
480}
481
482#ifdef CONFIG_DEBUG_FS
483static 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}
498arch_initcall(debugfs_unaligned);
499#endif
arch/loongarch/kernel/unwind_guess.c+3−1
@@ -3,6 +3,7 @@ · 2 unmodified lines
3 * Copyright (C) 2022 Loongson Technology Corporation Limited3 * Copyright (C) 2022 Loongson Technology Corporation Limited
4 */4 */
5#include <linux/kernel.h>5#include <linux/kernel.h>
6#include <linux/ftrace.h>
6 7
7#include <asm/unwind.h>8#include <asm/unwind.h>
8 9
@@ -53,7 +54,8 @@ bool unwind_next_frame(struct unwind_state *state) · 44 unmodified lines
53 state->sp < info->end;54 state->sp < info->end;
54 state->sp += sizeof(unsigned long)) {55 state->sp += sizeof(unsigned long)) {
55 addr = *(unsigned long *)(state->sp);56 addr = *(unsigned long *)(state->sp);
56 57 state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
58 addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
57 if (__kernel_text_address(addr))59 if (__kernel_text_address(addr))
58 return true;60 return true;
59 }61 }
arch/loongarch/kernel/unwind_prologue.c+42−8
@@ -2,12 +2,23 @@ · 1 unmodified line
2/*2/*
3 * Copyright (C) 2022 Loongson Technology Corporation Limited3 * Copyright (C) 2022 Loongson Technology Corporation Limited
4 */4 */
5#include <linux/ftrace.h>
5#include <linux/kallsyms.h>6#include <linux/kallsyms.h>
6 7
7#include <asm/inst.h>8#include <asm/inst.h>
8#include <asm/ptrace.h>9#include <asm/ptrace.h>
9#include <asm/unwind.h>10#include <asm/unwind.h>
10 11
12static 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}
21
11unsigned long unwind_get_return_address(struct unwind_state *state)22unsigned long unwind_get_return_address(struct unwind_state *state)
12{23{
13 24
@@ -32,6 +43,8 @@ static bool unwind_by_guess(struct unwind_state *state) · 18 unmodified lines
32 state->sp < info->end;43 state->sp < info->end;
33 state->sp += sizeof(unsigned long)) {44 state->sp += sizeof(unsigned long)) {
34 addr = *(unsigned long *)(state->sp);45 addr = *(unsigned long *)(state->sp);
46 state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
47 addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
35 if (__kernel_text_address(addr))48 if (__kernel_text_address(addr))
36 return true;49 return true;
37 }50 }
@@ -41,15 +54,30 @@ static bool unwind_by_guess(struct unwind_state *state) · 3 unmodified lines
41 54
42static bool unwind_by_prologue(struct unwind_state *state)55static bool unwind_by_prologue(struct unwind_state *state)
43{56{
44 struct stack_info *info = &state->stack_info;
45 union loongarch_instruction *ip, *ip_end;
46 long frame_ra = -1;57 long frame_ra = -1;
47 unsigned long frame_size = 0;58 unsigned long frame_size = 0;
48 unsigned long size, offset, pc = state->pc;59 unsigned long size, offset, pc = state->pc;
60 struct pt_regs *regs;
61 struct stack_info *info = &state->stack_info;
62 union loongarch_instruction *ip, *ip_end;
49 63
50 if (state->sp >= info->end || state->sp < info->begin)64 if (state->sp >= info->end || state->sp < info->begin)
51 return false;65 return false;
52 66
67 if (state->is_ftrace) {
68 /*
69 * As we meet ftrace_regs_entry, reset first flag like first doing
70 * tracing. Prologue analysis will stop soon because PC is at entry.
71 */
72 regs = (struct pt_regs *)state->sp;
73 state->first = true;
74 state->is_ftrace = false;
75 state->pc = regs->csr_era;
76 state->ra = regs->regs[1];
77 state->sp = regs->regs[3];
78 return true;
79 }
80
53 if (!kallsyms_lookup_size_offset(pc, &size, &offset))81 if (!kallsyms_lookup_size_offset(pc, &size, &offset))
54 return false;82 return false;
55 83
@@ -95,7 +123,7 @@ static bool unwind_by_prologue(struct unwind_state *state) · 39 unmodified lines
95 123
96 state->pc = *(unsigned long *)(state->sp + frame_ra);124 state->pc = *(unsigned long *)(state->sp + frame_ra);
97 state->sp = state->sp + frame_size;125 state->sp = state->sp + frame_size;
98 return !!__kernel_text_address(state->pc);126 goto out;
99 127
100first:128first:
101 state->first = false;129 state->first = false;
@@ -104,7 +132,9 @@ first: · 2 unmodified lines
104 132
105 state->pc = state->ra;133 state->pc = state->ra;
106 134
107 return !!__kernel_text_address(state->ra);135out:
136 unwind_state_fixup(state);
137 return !!__kernel_text_address(state->pc);
108}138}
109 139
110void unwind_start(struct unwind_state *state, struct task_struct *task,140void unwind_start(struct unwind_state *state, struct task_struct *task,
@@ -147,8 +177,11 @@ bool unwind_next_frame(struct unwind_state *state) · 36 unmodified lines
147 break;177 break;
148 178
149 case UNWINDER_PROLOGUE:179 case UNWINDER_PROLOGUE:
150 if (unwind_by_prologue(state))180 if (unwind_by_prologue(state)) {
181 state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
182 state->pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
151 return true;183 return true;
184 }
152 185
153 if (info->type == STACK_TYPE_IRQ &&186 if (info->type == STACK_TYPE_IRQ &&
154 info->end == state->sp) {187 info->end == state->sp) {
@@ -158,10 +191,11 @@ bool unwind_next_frame(struct unwind_state *state) · 3 unmodified lines
158 if (user_mode(regs) || !__kernel_text_address(pc))191 if (user_mode(regs) || !__kernel_text_address(pc))
159 return false;192 return false;
160 193
161 state->pc = pc;
162 state->sp = regs->regs[3];
163 state->ra = regs->regs[1];
164 state->first = true;194 state->first = true;
195 state->ra = regs->regs[1];
196 state->sp = regs->regs[3];
197 state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
198 pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
165 get_stack_info(state->sp, state->task, info);199 get_stack_info(state->sp, state->task, info);
166 200
167 return true;201 return true;
arch/loongarch/kernel/vmlinux.lds.S+12−1
@@ -4,6 +4,7 @@ · 3 unmodified lines
4#include <asm/thread_info.h>4#include <asm/thread_info.h>
5 5
6#define PAGE_SIZE _PAGE_SIZE6#define PAGE_SIZE _PAGE_SIZE
7#define RO_EXCEPTION_TABLE_ALIGN 4
7 8
8/*9/*
9 * Put .bss..swapper_pg_dir as the first thing in .bss. This will10 * Put .bss..swapper_pg_dir as the first thing in .bss. This will
@@ -53,7 +54,17 @@ SECTIONS · 43 unmodified lines
53 . = ALIGN(PECOFF_SEGMENT_ALIGN);54 . = ALIGN(PECOFF_SEGMENT_ALIGN);
54 _etext = .;55 _etext = .;
55 56
56 EXCEPTION_TABLE(16)57 /*
58 * struct alt_inst entries. From the header (alternative.h):
59 * "Alternative instructions for different CPU types or capabilities"
60 * Think locking instructions on spinlocks.
61 */
62 . = ALIGN(4);
63 .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
64 __alt_instructions = .;
65 *(.altinstructions)
66 __alt_instructions_end = .;
67 }
57 68
58 .got : ALIGN(16) { *(.got) }69 .got : ALIGN(16) { *(.got) }
59 .plt : ALIGN(16) { *(.plt) }70 .plt : ALIGN(16) { *(.plt) }
arch/loongarch/lib/Makefile+2−1
@@ -3,4 +3,5 @@ · 2 unmodified lines
3# Makefile for LoongArch-specific library files.3# Makefile for LoongArch-specific library files.
4#4#
5 5
6lib-y += delay.o clear_user.o copy_user.o dump_tlb.o6lib-y += delay.o memset.o memcpy.o memmove.o \
7 clear_user.o copy_user.o dump_tlb.o unaligned.o
arch/loongarch/lib/clear_user.S+70−15
@@ -3,30 +3,37 @@ · 2 unmodified lines
3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4 */4 */
5 5
6#include <asm/alternative-asm.h>
6#include <asm/asm.h>7#include <asm/asm.h>
7#include <asm/asmmacro.h>8#include <asm/asmmacro.h>
9#include <asm/asm-extable.h>
10#include <asm/cpu.h>
8#include <asm/export.h>11#include <asm/export.h>
9#include <asm/regdef.h>12#include <asm/regdef.h>
10 13
11.macro fixup_ex from, to, offset, fix14.irp to, 0, 1, 2, 3, 4, 5, 6, 7
12.if \fix15.L_fixup_handle_\to\():
13 .section .fixup, "ax"16 addi.d a0, a1, (\to) * (-8)
14\to: addi.d a0, a1, \offset
15 jr ra17 jr ra
16 .previous18.endr
17.endif19
18 .section __ex_table, "a"20SYM_FUNC_START(__clear_user)
19 PTR \from\()b, \to\()b21 /*
20 .previous22 * Some CPUs support hardware unaligned access
21.endm23 */
24 ALTERNATIVE "b __clear_user_generic", \
25 "b __clear_user_fast", CPU_FEATURE_UAL
26SYM_FUNC_END(__clear_user)
27
28EXPORT_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 * a0: addr33 * a0: addr
27 * a1: size34 * a1: size
28 */35 */
29SYM_FUNC_START(__clear_user)36SYM_FUNC_START(__clear_user_generic)
30 beqz a1, 2f37 beqz a1, 2f
31 38
321: st.b zero, a0, 0391: st.b zero, a0, 0
@@ -37,7 +44,55 @@ SYM_FUNC_START(__clear_user) · 4 unmodified lines
372: move a0, a1442: move a0, a1
38 jr ra45 jr ra
39 46
40 fixup_ex 1, 3, 0, 147 _asm_extable 1b, .L_fixup_handle_0
41SYM_FUNC_END(__clear_user)48SYM_FUNC_END(__clear_user_generic)
42 49
43EXPORT_SYMBOL(__clear_user)50/*
51 * unsigned long __clear_user_fast(void *addr, unsigned long size)
52 *
53 * a0: addr
54 * a1: size
55 */
56SYM_FUNC_START(__clear_user_fast)
57 beqz a1, 10f
58
59 ori a2, zero, 64
60 blt a1, a2, 9f
61
62 /* set 64 bytes at a time */
631: st.d zero, a0, 0
642: st.d zero, a0, 8
653: st.d zero, a0, 16
664: st.d zero, a0, 24
675: st.d zero, a0, 32
686: st.d zero, a0, 40
697: st.d zero, a0, 48
708: st.d zero, a0, 56
71
72 addi.d a0, a0, 64
73 addi.d a1, a1, -64
74 bge a1, a2, 1b
75
76 beqz a1, 10f
77
78 /* set the remaining bytes */
799: st.b zero, a0, 0
80 addi.d a0, a0, 1
81 addi.d a1, a1, -1
82 bgt a1, zero, 9b
83
84 /* return */
8510: move a0, a1
86 jr ra
87
88 /* fixup and ex_table */
89 _asm_extable 1b, .L_fixup_handle_0
90 _asm_extable 2b, .L_fixup_handle_1
91 _asm_extable 3b, .L_fixup_handle_2
92 _asm_extable 4b, .L_fixup_handle_3
93 _asm_extable 5b, .L_fixup_handle_4
94 _asm_extable 6b, .L_fixup_handle_5
95 _asm_extable 7b, .L_fixup_handle_6
96 _asm_extable 8b, .L_fixup_handle_7
97 _asm_extable 9b, .L_fixup_handle_0
98SYM_FUNC_END(__clear_user_fast)
arch/loongarch/lib/copy_user.S+92−16
@@ -3,31 +3,38 @@ · 2 unmodified lines
3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4 */4 */
5 5
6#include <asm/alternative-asm.h>
6#include <asm/asm.h>7#include <asm/asm.h>
7#include <asm/asmmacro.h>8#include <asm/asmmacro.h>
9#include <asm/asm-extable.h>
10#include <asm/cpu.h>
8#include <asm/export.h>11#include <asm/export.h>
9#include <asm/regdef.h>12#include <asm/regdef.h>
10 13
11.macro fixup_ex from, to, offset, fix14.irp to, 0, 1, 2, 3, 4, 5, 6, 7
12.if \fix15.L_fixup_handle_\to\():
13 .section .fixup, "ax"16 addi.d a0, a2, (\to) * (-8)
14\to: addi.d a0, a2, \offset
15 jr ra17 jr ra
16 .previous18.endr
17.endif19
18 .section __ex_table, "a"20SYM_FUNC_START(__copy_user)
19 PTR \from\()b, \to\()b21 /*
20 .previous22 * Some CPUs support hardware unaligned access
21.endm23 */
24 ALTERNATIVE "b __copy_user_generic", \
25 "b __copy_user_fast", CPU_FEATURE_UAL
26SYM_FUNC_END(__copy_user)
27
28EXPORT_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 * a0: to33 * a0: to
27 * a1: from34 * a1: from
28 * a2: n35 * a2: n
29 */36 */
30SYM_FUNC_START(__copy_user)37SYM_FUNC_START(__copy_user_generic)
31 beqz a2, 3f38 beqz a2, 3f
32 39
331: ld.b t0, a1, 0401: ld.b t0, a1, 0
@@ -40,8 +47,77 @@ SYM_FUNC_START(__copy_user) · 6 unmodified lines
403: move a0, a2473: move a0, a2
41 jr ra48 jr ra
42 49
43 fixup_ex 1, 4, 0, 150 _asm_extable 1b, .L_fixup_handle_0
44 fixup_ex 2, 4, 0, 051 _asm_extable 2b, .L_fixup_handle_0
45SYM_FUNC_END(__copy_user)52SYM_FUNC_END(__copy_user_generic)
46 53
47EXPORT_SYMBOL(__copy_user)54/*
55 * unsigned long __copy_user_fast(void *to, const void *from, unsigned long n)
56 *
57 * a0: to
58 * a1: from
59 * a2: n
60 */
61SYM_FUNC_START(__copy_user_fast)
62 beqz a2, 19f
63
64 ori a3, zero, 64
65 blt a2, a3, 17f
66
67 /* copy 64 bytes at a time */
681: ld.d t0, a1, 0
692: ld.d t1, a1, 8
703: ld.d t2, a1, 16
714: ld.d t3, a1, 24
725: ld.d t4, a1, 32
736: ld.d t5, a1, 40
747: ld.d t6, a1, 48
758: ld.d t7, a1, 56
769: st.d t0, a0, 0
7710: st.d t1, a0, 8
7811: st.d t2, a0, 16
7912: st.d t3, a0, 24
8013: st.d t4, a0, 32
8114: st.d t5, a0, 40
8215: st.d t6, a0, 48
8316: st.d t7, a0, 56
84
85 addi.d a0, a0, 64
86 addi.d a1, a1, 64
87 addi.d a2, a2, -64
88 bge a2, a3, 1b
89
90 beqz a2, 19f
91
92 /* copy the remaining bytes */
9317: ld.b t0, a1, 0
9418: st.b t0, a0, 0
95 addi.d a0, a0, 1
96 addi.d a1, a1, 1
97 addi.d a2, a2, -1
98 bgt a2, zero, 17b
99
100 /* return */
10119: move a0, a2
102 jr ra
103
104 /* fixup and ex_table */
105 _asm_extable 1b, .L_fixup_handle_0
106 _asm_extable 2b, .L_fixup_handle_1
107 _asm_extable 3b, .L_fixup_handle_2
108 _asm_extable 4b, .L_fixup_handle_3
109 _asm_extable 5b, .L_fixup_handle_4
110 _asm_extable 6b, .L_fixup_handle_5
111 _asm_extable 7b, .L_fixup_handle_6
112 _asm_extable 8b, .L_fixup_handle_7
113 _asm_extable 9b, .L_fixup_handle_0
114 _asm_extable 10b, .L_fixup_handle_1
115 _asm_extable 11b, .L_fixup_handle_2
116 _asm_extable 12b, .L_fixup_handle_3
117 _asm_extable 13b, .L_fixup_handle_4
118 _asm_extable 14b, .L_fixup_handle_5
119 _asm_extable 15b, .L_fixup_handle_6
120 _asm_extable 16b, .L_fixup_handle_7
121 _asm_extable 17b, .L_fixup_handle_0
122 _asm_extable 18b, .L_fixup_handle_0
123SYM_FUNC_END(__copy_user_fast)
arch/loongarch/lib/memcpy.S+95−0
@@ -0,0 +1,95 @@
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
13SYM_FUNC_START(memcpy)
14 /*
15 * Some CPUs support hardware unaligned access
16 */
17 ALTERNATIVE "b __memcpy_generic", \
18 "b __memcpy_fast", CPU_FEATURE_UAL
19SYM_FUNC_END(memcpy)
20
21EXPORT_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 */
30SYM_FUNC_START(__memcpy_generic)
31 move a3, a0
32 beqz a2, 2f
33
341: 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
412: move a0, a3
42 jr ra
43SYM_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 */
52SYM_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 */
601: 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 */
852: 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 */
933: move a0, a3
94 jr ra
95SYM_FUNC_END(__memcpy_fast)
arch/loongarch/lib/memmove.S+121−0
@@ -0,0 +1,121 @@
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
13SYM_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 */
191: ori a3, zero, 64
20 sub.d t0, a1, a0
21 blt t0, a3, 2f
22 b memcpy
232: b __memcpy_generic
24
25 /* if (dst - src) < 64, copy 1 byte at a time */
263: ori a3, zero, 64
27 sub.d t0, a0, a1
28 blt t0, a3, 4f
29 b rmemcpy
304: b __rmemcpy_generic
31SYM_FUNC_END(memmove)
32
33EXPORT_SYMBOL(memmove)
34
35SYM_FUNC_START(rmemcpy)
36 /*
37 * Some CPUs support hardware unaligned access
38 */
39 ALTERNATIVE "b __rmemcpy_generic", \
40 "b __rmemcpy_fast", CPU_FEATURE_UAL
41SYM_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 */
50SYM_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
571: 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
642: move a0, a3
65 jr ra
66SYM_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 */
75SYM_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 */
861: 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 */
1112: 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 */
1193: move a0, a3
120 jr ra
121SYM_FUNC_END(__rmemcpy_fast)
arch/loongarch/lib/memset.S+91−0
@@ -0,0 +1,91 @@
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
19SYM_FUNC_START(memset)
20 /*
21 * Some CPUs support hardware unaligned access
22 */
23 ALTERNATIVE "b __memset_generic", \
24 "b __memset_fast", CPU_FEATURE_UAL
25SYM_FUNC_END(memset)
26
27EXPORT_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 */
36SYM_FUNC_START(__memset_generic)
37 move a3, a0
38 beqz a2, 2f
39
401: st.b a1, a0, 0
41 addi.d a0, a0, 1
42 addi.d a2, a2, -1
43 bgt a2, zero, 1b
44
452: move a0, a3
46 jr ra
47SYM_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 */
56SYM_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 */
671: 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 */
832: 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 */
893: move a0, a3
90 jr ra
91SYM_FUNC_END(__memset_fast)
arch/loongarch/lib/unaligned.S+84−0
@@ -0,0 +1,84 @@
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 */
27SYM_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
361: ld.b t3, a0, 0
37 b 3f
38
392: ld.bu t3, a0, 0
403: 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
464: st.d t2, a1, 0
47
48 move a0, a2
49 jr ra
50
515: 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
57SYM_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 */
66SYM_FUNC_START(unaligned_write)
67 beqz a2, 3f
68
69 li.w t0, 0
701: srl.d t1, a1, t0
712: 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
803: li.w a0, -EFAULT
81 jr ra
82
83 _asm_extable 2b, .L_fixup_handle_unaligned
84SYM_FUNC_END(unaligned_write)
arch/loongarch/mm/extable.c+50−9
@@ -2,21 +2,62 @@ · 1 unmodified line
2/*2/*
3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4 */4 */
5#include <linux/bitfield.h>
5#include <linux/extable.h>6#include <linux/extable.h>
6#include <linux/spinlock.h>
7#include <asm/branch.h>
8#include <linux/uaccess.h>7#include <linux/uaccess.h>
8#include <asm/asm-extable.h>
9#include <asm/branch.h>
10
11static inline unsigned long
12get_ex_fixup(const struct exception_table_entry *ex)
13{
14 return ((unsigned long)&ex->fixup + ex->fixup);
15}
16
17static 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}
23
24static 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
32static 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}
9 44
10int fixup_exception(struct pt_regs *regs)45bool fixup_exception(struct pt_regs *regs)
11{46{
12 const struct exception_table_entry *fixup;47 const struct exception_table_entry *ex;
13 48
14 fixup = search_exception_tables(exception_era(regs));49 ex = search_exception_tables(exception_era(regs));
15 if (fixup) {50 if (!ex)
16 regs->csr_era = fixup->fixup;51 return false;
17 52
18 return 1;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}
arch/loongarch/net/bpf_jit.c+81−5
@@ -387,6 +387,65 @@ static bool is_signed_bpf_cond(u8 cond) · 386 unmodified lines
387 cond == BPF_JSGE || cond == BPF_JSLE;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
393bool 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 */
406static 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
390static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool extra_pass)449static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool extra_pass)
391{450{
392 u8 tm = -1;451 u8 tm = -1;
@@ -816,6 +875,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext · 423 unmodified lines
816 case BPF_LDX | BPF_MEM | BPF_H:875 case BPF_LDX | BPF_MEM | BPF_H:
817 case BPF_LDX | BPF_MEM | BPF_W:876 case BPF_LDX | BPF_MEM | BPF_W:
818 case BPF_LDX | BPF_MEM | BPF_DW:877 case BPF_LDX | BPF_MEM | BPF_DW:
878 case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
879 case BPF_LDX | BPF_PROBE_MEM | BPF_W:
880 case BPF_LDX | BPF_PROBE_MEM | BPF_H:
881 case BPF_LDX | BPF_PROBE_MEM | BPF_B:
819 switch (BPF_SIZE(code)) {882 switch (BPF_SIZE(code)) {
820 case BPF_B:883 case BPF_B:
821 if (is_signed_imm12(off)) {884 if (is_signed_imm12(off)) {
@@ -854,6 +917,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext · 32 unmodified lines
854 }917 }
855 break;918 break;
856 }919 }
920
921 ret = add_exception_handler(insn, ctx, dst);
922 if (ret)
923 return ret;
857 break;924 break;
858 925
859 /* *(size *)(dst + off) = imm */926 /* *(size *)(dst + off) = imm */
@@ -1018,6 +1085,9 @@ static int validate_code(struct jit_ctx *ctx) · 158 unmodified lines
1018 return -1;1085 return -1;
1019 }1086 }
1020 1087
1088 if (WARN_ON_ONCE(ctx->num_exentries != ctx->prog->aux->num_exentries))
1089 return -1;
1090
1021 return 0;1091 return 0;
1022}1092}
1023 1093
@@ -1025,7 +1095,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) · 1 unmodified line
1025{1095{
1026 bool tmp_blinded = false, extra_pass = false;1096 bool tmp_blinded = false, extra_pass = false;
1027 u8 *image_ptr;1097 u8 *image_ptr;
1028 int image_size;1098 int image_size, prog_size, extable_size;
1029 struct jit_ctx ctx;1099 struct jit_ctx ctx;
1030 struct jit_data *jit_data;1100 struct jit_data *jit_data;
1031 struct bpf_binary_header *header;1101 struct bpf_binary_header *header;
@@ -1066,7 +1136,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) · 34 unmodified lines
1066 image_ptr = jit_data->image;1136 image_ptr = jit_data->image;
1067 header = jit_data->header;1137 header = jit_data->header;
1068 extra_pass = true;1138 extra_pass = true;
1069 image_size = sizeof(u32) * ctx.idx;1139 prog_size = sizeof(u32) * ctx.idx;
1070 goto skip_init_ctx;1140 goto skip_init_ctx;
1071 }1141 }
1072 1142
@@ -1088,12 +1158,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) · 15 unmodified lines
1088 ctx.epilogue_offset = ctx.idx;1158 ctx.epilogue_offset = ctx.idx;
1089 build_epilogue(&ctx);1159 build_epilogue(&ctx);
1090 1160
1161 extable_size = prog->aux->num_exentries * sizeof(struct exception_table_entry);
1162
1091 /* Now we know the actual image size.1163 /* Now we know the actual image size.
1092 * As each LoongArch instruction is of length 32bit,1164 * As each LoongArch instruction is of length 32bit,
1093 * we are translating number of JITed intructions into1165 * we are translating number of JITed intructions into
1094 * the size required to store these JITed code.1166 * the size required to store these JITed code.
1095 */1167 */
1096 image_size = sizeof(u32) * ctx.idx;1168 prog_size = sizeof(u32) * ctx.idx;
1169 image_size = prog_size + extable_size;
1097 /* Now we know the size of the structure to make */1170 /* Now we know the size of the structure to make */
1098 header = bpf_jit_binary_alloc(image_size, &image_ptr,1171 header = bpf_jit_binary_alloc(image_size, &image_ptr,
1099 sizeof(u32), jit_fill_hole);1172 sizeof(u32), jit_fill_hole);
@@ -1104,9 +1177,12 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) · 4 unmodified lines
1104 1177
1105 /* 2. Now, the actual pass to generate final JIT code */1178 /* 2. Now, the actual pass to generate final JIT code */
1106 ctx.image = (union loongarch_instruction *)image_ptr;1179 ctx.image = (union loongarch_instruction *)image_ptr;
1180 if (extable_size)
1181 prog->aux->extable = (void *)image_ptr + prog_size;
1107 1182
1108skip_init_ctx:1183skip_init_ctx:
1109 ctx.idx = 0;1184 ctx.idx = 0;
1185 ctx.num_exentries = 0;
1110 1186
1111 build_prologue(&ctx);1187 build_prologue(&ctx);
1112 if (build_body(&ctx, extra_pass)) {1188 if (build_body(&ctx, extra_pass)) {
@@ -1125,7 +1201,7 @@ skip_init_ctx: · 12 unmodified lines
1125 1201
1126 /* And we're done */1202 /* And we're done */
1127 if (bpf_jit_enable > 1)1203 if (bpf_jit_enable > 1)
1128 bpf_jit_dump(prog->len, image_size, 2, ctx.image);1204 bpf_jit_dump(prog->len, prog_size, 2, ctx.image);
1129 1205
1130 /* Update the icache */1206 /* Update the icache */
1131 flush_icache_range((unsigned long)header, (unsigned long)(ctx.image + ctx.idx));1207 flush_icache_range((unsigned long)header, (unsigned long)(ctx.image + ctx.idx));
@@ -1147,7 +1223,7 @@ skip_init_ctx: · 15 unmodified lines
1147 jit_data->header = header;1223 jit_data->header = header;
1148 }1224 }
1149 prog->jited = 1;1225 prog->jited = 1;
1150 prog->jited_len = image_size;1226 prog->jited_len = prog_size;
1151 prog->bpf_func = (void *)ctx.image;1227 prog->bpf_func = (void *)ctx.image;
1152 1228
1153 if (!prog->is_func || extra_pass) {1229 if (!prog->is_func || extra_pass) {
arch/loongarch/net/bpf_jit.h+2−0
@@ -4,6 +4,7 @@ · 3 unmodified lines
4 *4 *
5 * Copyright (C) 2022 Loongson Technology Corporation Limited5 * Copyright (C) 2022 Loongson Technology Corporation Limited
6 */6 */
7#include <linux/bitfield.h>
7#include <linux/bpf.h>8#include <linux/bpf.h>
8#include <linux/filter.h>9#include <linux/filter.h>
9#include <asm/cacheflush.h>10#include <asm/cacheflush.h>
@@ -15,6 +16,7 @@ struct jit_ctx { · 5 unmodified lines
15 unsigned int flags;16 unsigned int flags;
16 unsigned int epilogue_offset;17 unsigned int epilogue_offset;
17 u32 *offset;18 u32 *offset;
19 int num_exentries;
18 union loongarch_instruction *image;20 union loongarch_instruction *image;
19 u32 stack_size;21 u32 stack_size;
20};22};
arch/loongarch/pci/acpi.c+5−2
@@ -26,9 +26,12 @@ void pcibios_add_bus(struct pci_bus *bus) · 25 unmodified lines
26 26
27int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)27int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
28{28{
29 struct pci_config_window *cfg = bridge->bus->sysdata;29 struct acpi_device *adev = NULL;
30 struct acpi_device *adev = to_acpi_device(cfg->parent);
31 struct device *bus_dev = &bridge->bus->dev;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 ACPI_COMPANION_SET(&bridge->dev, adev);36 ACPI_COMPANION_SET(&bridge->dev, adev);
34 set_dev_node(bus_dev, pa_to_nid(cfg->res.start));37 set_dev_node(bus_dev, pa_to_nid(cfg->res.start));
arch/loongarch/power/Makefile+4−0
@@ -0,0 +1,4 @@
1obj-y += platform.o
2
3obj-$(CONFIG_SUSPEND) += suspend.o suspend_asm.o
4obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o
arch/loongarch/power/hibernate.c+62−0
@@ -0,0 +1,62 @@
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
8static u32 saved_crmd;
9static u32 saved_prmd;
10static u32 saved_euen;
11static u32 saved_ecfg;
12static u64 saved_pcpu_base;
13struct pt_regs saved_regs;
14
15void 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
27void 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
39int 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
47extern int swsusp_asm_suspend(void);
48
49int swsusp_arch_suspend(void)
50{
51 enable_pci_wakeup();
52 return swsusp_asm_suspend();
53}
54
55extern int swsusp_asm_resume(void);
56
57int 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}
arch/loongarch/power/hibernate_asm.S+66−0
@@ -0,0 +1,66 @@
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
14SYM_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
31SYM_FUNC_END(swsusp_asm_suspend)
32
33SYM_FUNC_START(swsusp_asm_resume)
34 la.pcrel t0, restore_pblist
35 PTR_L t0, t0, 0
360:
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
411:
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
66SYM_FUNC_END(swsusp_asm_resume)
arch/loongarch/power/platform.c+57−0
@@ -0,0 +1,57 @@
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
12void 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
23void 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
37static 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
57device_initcall(loongson3_acpi_suspend_init);
arch/loongarch/power/suspend.c+73−0
@@ -0,0 +1,73 @@
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
18u64 loongarch_suspend_addr;
19
20struct saved_registers {
21 u32 ecfg;
22 u32 euen;
23 u64 pgd;
24 u64 kpgd;
25 u32 pwctl0;
26 u32 pwctl1;
27};
28static struct saved_registers saved_regs;
29
30static 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
43static 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
60int 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}
arch/loongarch/power/suspend_asm.S+89−0
@@ -0,0 +1,89 @@
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 */
60SYM_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 */
75SYM_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
830:
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
89SYM_FUNC_END(loongarch_suspend_enter)
scripts/mod/modpost.c+13−0
@@ -1523,6 +1523,14 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) · 1522 unmodified lines
1523#define R_RISCV_SUB32 391523#define R_RISCV_SUB32 39
1524#endif1524#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
1526static void section_rela(const char *modname, struct elf_info *elf,1534static void section_rela(const char *modname, struct elf_info *elf,
1527 Elf_Shdr *sechdr)1535 Elf_Shdr *sechdr)
1528{1536{
@@ -1564,6 +1572,11 @@ static void section_rela(const char *modname, struct elf_info *elf, · 35 unmodified lines
1564 ELF_R_TYPE(r.r_info) == R_RISCV_SUB32)1572 ELF_R_TYPE(r.r_info) == R_RISCV_SUB32)
1565 continue;1573 continue;
1566 break;1574 break;
1575 case EM_LOONGARCH:
1576 if (!strcmp("__ex_table", fromsec) &&
1577 ELF_R_TYPE(r.r_info) == R_LARCH_SUB32)
1578 continue;
1579 break;
1567 }1580 }
1568 sym = elf->symtab_start + r_sym;1581 sym = elf->symtab_start + r_sym;
1569 /* Skip special sections */1582 /* Skip special sections */
scripts/recordmcount.c+39−0
@@ -38,6 +38,14 @@ · 37 unmodified lines
38#define R_AARCH64_ABS64 25738#define R_AARCH64_ABS64 257
39#endif39#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#define R_ARM_PC24 149#define R_ARM_PC24 1
42#define R_ARM_THM_CALL 1050#define R_ARM_THM_CALL 10
43#define R_ARM_CALL 2851#define R_ARM_CALL 28
@@ -441,6 +449,28 @@ static int arm64_is_fake_mcount(Elf64_Rel const *rp) · 397 unmodified lines
441 return ELF64_R_TYPE(w8(rp->r_info)) != R_AARCH64_CALL26;449 return ELF64_R_TYPE(w8(rp->r_info)) != R_AARCH64_CALL26;
442}450}
443 451
452static int LARCH32_is_fake_mcount(Elf32_Rel const *rp)
453{
454 switch (ELF64_R_TYPE(w(rp->r_info))) {
455 case R_LARCH_MARK_LA:
456 case R_LARCH_SOP_PUSH_PLT_PCREL:
457 return 0;
458 }
459
460 return 1;
461}
462
463static int LARCH64_is_fake_mcount(Elf64_Rel const *rp)
464{
465 switch (ELF64_R_TYPE(w(rp->r_info))) {
466 case R_LARCH_MARK_LA:
467 case R_LARCH_SOP_PUSH_PLT_PCREL:
468 return 0;
469 }
470
471 return 1;
472}
473
444/* 64-bit EM_MIPS has weird ELF64_Rela.r_info.474/* 64-bit EM_MIPS has weird ELF64_Rela.r_info.
445 * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf475 * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf
446 * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40]476 * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40]
@@ -558,6 +588,7 @@ static int do_file(char const *const fname) · 111 unmodified lines
558 break;588 break;
559 case EM_IA_64: reltype = R_IA64_IMM64; break;589 case EM_IA_64: reltype = R_IA64_IMM64; break;
560 case EM_MIPS: /* reltype: e_class */ break;590 case EM_MIPS: /* reltype: e_class */ break;
591 case EM_LOONGARCH: /* reltype: e_class */ break;
561 case EM_PPC: reltype = R_PPC_ADDR32; break;592 case EM_PPC: reltype = R_PPC_ADDR32; break;
562 case EM_PPC64: reltype = R_PPC64_ADDR64; break;593 case EM_PPC64: reltype = R_PPC64_ADDR64; break;
563 case EM_S390: /* reltype: e_class */ break;594 case EM_S390: /* reltype: e_class */ break;
@@ -589,6 +620,10 @@ static int do_file(char const *const fname) · 25 unmodified lines
589 reltype = R_MIPS_32;620 reltype = R_MIPS_32;
590 is_fake_mcount32 = MIPS32_is_fake_mcount;621 is_fake_mcount32 = MIPS32_is_fake_mcount;
591 }622 }
623 if (w2(ehdr->e_machine) == EM_LOONGARCH) {
624 reltype = R_LARCH_32;
625 is_fake_mcount32 = LARCH32_is_fake_mcount;
626 }
592 if (do32(ehdr, fname, reltype) < 0)627 if (do32(ehdr, fname, reltype) < 0)
593 goto out;628 goto out;
594 break;629 break;
@@ -610,6 +645,10 @@ static int do_file(char const *const fname) · 15 unmodified lines
610 Elf64_r_info = MIPS64_r_info;645 Elf64_r_info = MIPS64_r_info;
611 is_fake_mcount64 = MIPS64_is_fake_mcount;646 is_fake_mcount64 = MIPS64_is_fake_mcount;
612 }647 }
648 if (w2(ghdr->e_machine) == EM_LOONGARCH) {
649 reltype = R_LARCH_64;
650 is_fake_mcount64 = LARCH64_is_fake_mcount;
651 }
613 if (do64(ghdr, fname, reltype) < 0)652 if (do64(ghdr, fname, reltype) < 0)
614 goto out;653 goto out;
615 break;654 break;
scripts/sorttable.c+1−1
@@ -304,6 +304,7 @@ static int do_file(char const *const fname, void *addr) · 303 unmodified lines
304 switch (r2(&ehdr->e_machine)) {304 switch (r2(&ehdr->e_machine)) {
305 case EM_386:305 case EM_386:
306 case EM_AARCH64:306 case EM_AARCH64:
307 case EM_LOONGARCH:
307 case EM_RISCV:308 case EM_RISCV:
308 case EM_S390:309 case EM_S390:
309 case EM_X86_64:310 case EM_X86_64:
@@ -317,7 +318,6 @@ static int do_file(char const *const fname, void *addr) · 7 unmodified lines
317 case EM_ARCOMPACT:318 case EM_ARCOMPACT:
318 case EM_ARCV2:319 case EM_ARCV2:
319 case EM_ARM:320 case EM_ARM:
320 case EM_LOONGARCH:
321 case EM_MICROBLAZE:321 case EM_MICROBLAZE:
322 case EM_MIPS:322 case EM_MIPS:
323 case EM_XTENSA:323 case EM_XTENSA: