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

Merge tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm

Pull ARM updates from Russell King:
"Updates for IRQ stacks and virtually mapped stack support, and ftrace:

- Support for IRQ and vmap'ed stacks

This covers all the work related to implementing IRQ stacks and
vmap'ed stacks for all 32-bit ARM systems that are currently
supported by the Linux kernel, including RiscPC and Footbridge. It
has been submitted for review in four different waves:

- IRQ stacks support for v7 SMP systems [0]

- vmap'ed stacks support for v7 SMP systems[1]

- extending support for both IRQ stacks and vmap'ed stacks for all
remaining configurations, including v6/v7 SMP multiplatform
kernels and uniprocessor configurations including v7-M [2]

- fixes and updates in [3]

- ftrace fixes and cleanups

Make all flavors of ftrace available on all builds, regardless of
ISA choice, unwinder choice or compiler [4]:

- use ADD not POP where possible

- fix a couple of Thumb2 related issues

- enable HAVE_FUNCTION_GRAPH_FP_TEST for robustness

- enable the graph tracer with the EABI unwinder

- avoid clobbering frame pointer registers to make Clang happy

- Fixes for the above"

[0] https://lore.kernel.org/linux-arm-kernel/20211115084732.3704393-1-ardb@kernel.org/
[1] https://lore.kernel.org/linux-arm-kernel/20211122092816.2865873-1-ardb@kernel.org/
[2] https://lore.kernel.org/linux-arm-kernel/20211206164659.1495084-1-ardb@kernel.org/
[3] https://lore.kernel.org/linux-arm-kernel/20220124174744.1054712-1-ardb@kernel.org/
[4] https://lore.kernel.org/linux-arm-kernel/20220203082204.1176734-1-ardb@kernel.org/

* tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm: (62 commits)
ARM: fix building NOMMU ARMv4/v5 kernels
ARM: unwind: only permit stack switch when unwinding call_with_stack()
ARM: Revert "unwind: dump exception stack from calling frame"
ARM: entry: fix unwinder problems caused by IRQ stacks
ARM: unwind: set frame.pc correctly for current-thread unwinding
ARM: 9184/1: return_address: disable again for CONFIG_ARM_UNWIND=y
ARM: 9183/1: unwind: avoid spurious warnings on bogus code addresses
Revert "ARM: 9144/1: forbid ftrace with clang and thumb2_kernel"
ARM: mach-bcm: disable ftrace in SMC invocation routines
ARM: cacheflush: avoid clobbering the frame pointer
ARM: kprobes: treat R7 as the frame pointer register in Thumb2 builds
ARM: ftrace: enable the graph tracer with the EABI unwinder
ARM: unwind: track location of LR value in stack frame
ARM: ftrace: enable HAVE_FUNCTION_GRAPH_FP_TEST
ARM: ftrace: avoid unnecessary literal loads
ARM: ftrace: avoid redundant loads or clobbering IP
ARM: ftrace: use trampolines to keep .init.text in branching range
ARM: ftrace: use ADD not POP to counter PUSH at entry
ARM: ftrace: ensure that ADR takes the Thumb bit into account
ARM: make get_current() and __my_cpu_offset() __always_inline
...

+1436 -866
+28 -18
arch/arm/Kconfig
··· 60 60 select GENERIC_CPU_AUTOPROBE 61 61 select GENERIC_EARLY_IOREMAP 62 62 select GENERIC_IDLE_POLL_SETUP 63 + select GENERIC_IRQ_MULTI_HANDLER 63 64 select GENERIC_IRQ_PROBE 64 65 select GENERIC_IRQ_SHOW 65 66 select GENERIC_IRQ_SHOW_LEVEL ··· 95 94 select HAVE_EXIT_THREAD 96 95 select HAVE_FAST_GUP if ARM_LPAE 97 96 select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL 98 - select HAVE_FUNCTION_GRAPH_TRACER if !THUMB2_KERNEL && !CC_IS_CLANG 99 - select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !(THUMB2_KERNEL && CC_IS_CLANG) 97 + select HAVE_FUNCTION_GRAPH_TRACER 98 + select HAVE_FUNCTION_TRACER if !XIP_KERNEL 100 99 select HAVE_GCC_PLUGINS 101 100 select HAVE_HW_BREAKPOINT if PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7) 102 101 select HAVE_IRQ_TIME_ACCOUNTING ··· 130 129 select PERF_USE_VMALLOC 131 130 select RTC_LIB 132 131 select SYS_SUPPORTS_APM_EMULATION 133 - select THREAD_INFO_IN_TASK if CURRENT_POINTER_IN_TPIDRURO 132 + select THREAD_INFO_IN_TASK 133 + select HAVE_ARCH_VMAP_STACK if MMU && ARM_HAS_GROUP_RELOCS 134 134 select TRACE_IRQFLAGS_SUPPORT if !CPU_V7M 135 135 # Above selects are sorted alphabetically; please add new ones 136 136 # according to that. Thanks. ··· 142 140 manufactured, but legacy ARM-based PC hardware remains popular in 143 141 Europe. There is an ARM Linux project with a web page at 144 142 <http://www.arm.linux.org.uk/>. 143 + 144 + config ARM_HAS_GROUP_RELOCS 145 + def_bool y 146 + depends on !LD_IS_LLD || LLD_VERSION >= 140000 147 + depends on !COMPILE_TEST 148 + help 149 + Whether or not to use R_ARM_ALU_PC_Gn or R_ARM_LDR_PC_Gn group 150 + relocations, which have been around for a long time, but were not 151 + supported in LLD until version 14. The combined range is -/+ 256 MiB, 152 + which is usually sufficient, but not for allyesconfig, so we disable 153 + this feature when doing compile testing. 145 154 146 155 config ARM_HAS_SG_CHAIN 147 156 bool ··· 240 227 bool 241 228 242 229 config FIQ 243 - bool 244 - 245 - config NEED_RET_TO_USER 246 230 bool 247 231 248 232 config ARCH_MTD_XIP ··· 335 325 select AUTO_ZRELADDR 336 326 select TIMER_OF 337 327 select COMMON_CLK 338 - select GENERIC_IRQ_MULTI_HANDLER 339 328 select HAVE_PCI 340 329 select PCI_DOMAINS_GENERIC if PCI 341 330 select SPARSE_IRQ ··· 358 349 select ARM_AMBA 359 350 imply ARM_PATCH_PHYS_VIRT 360 351 select ARM_VIC 361 - select GENERIC_IRQ_MULTI_HANDLER 362 352 select AUTO_ZRELADDR 363 353 select CLKSRC_MMIO 364 354 select CPU_ARM920T ··· 382 374 select CPU_XSCALE 383 375 select GPIO_IOP 384 376 select GPIOLIB 385 - select NEED_RET_TO_USER 386 377 select FORCE_PCI 387 378 select PLAT_IOP 388 379 help ··· 395 388 select ARCH_SUPPORTS_BIG_ENDIAN 396 389 select CPU_XSCALE 397 390 select DMABOUNCE if PCI 398 - select GENERIC_IRQ_MULTI_HANDLER 399 391 select GPIO_IXP4XX 400 392 select GPIOLIB 401 393 select HAVE_PCI ··· 410 404 config ARCH_DOVE 411 405 bool "Marvell Dove" 412 406 select CPU_PJ4 413 - select GENERIC_IRQ_MULTI_HANDLER 414 407 select GPIOLIB 415 408 select HAVE_PCI 416 409 select MVEBU_MBUS ··· 432 427 select CLKSRC_MMIO 433 428 select TIMER_OF 434 429 select CPU_XSCALE if !CPU_XSC3 435 - select GENERIC_IRQ_MULTI_HANDLER 436 430 select GPIO_PXA 437 431 select GPIOLIB 438 432 select IRQ_DOMAIN ··· 470 466 select COMMON_CLK 471 467 select CPU_FREQ 472 468 select CPU_SA1100 473 - select GENERIC_IRQ_MULTI_HANDLER 474 469 select GPIOLIB 475 470 select IRQ_DOMAIN 476 471 select ISA ··· 484 481 select CLKSRC_SAMSUNG_PWM 485 482 select GPIO_SAMSUNG 486 483 select GPIOLIB 487 - select GENERIC_IRQ_MULTI_HANDLER 488 484 select NEED_MACH_IO_H 489 485 select S3C2410_WATCHDOG 490 486 select SAMSUNG_ATAGS ··· 501 499 select ARCH_OMAP 502 500 select CLKSRC_MMIO 503 501 select GENERIC_IRQ_CHIP 504 - select GENERIC_IRQ_MULTI_HANDLER 505 502 select GPIOLIB 506 503 select HAVE_LEGACY_CLK 507 504 select IRQ_DOMAIN ··· 1167 1166 1168 1167 config CURRENT_POINTER_IN_TPIDRURO 1169 1168 def_bool y 1170 - depends on SMP && CPU_32v6K && !CPU_V6 1169 + depends on CPU_32v6K && !CPU_V6 1170 + 1171 + config IRQSTACKS 1172 + def_bool y 1173 + select HAVE_IRQ_EXIT_ON_IRQ_STACK 1174 + select HAVE_SOFTIRQ_ON_OWN_STACK 1171 1175 1172 1176 config ARM_CPU_TOPOLOGY 1173 1177 bool "Support cpu topology definition" ··· 1613 1607 help 1614 1608 Say Y if you want to run Linux in a Virtual Machine on Xen on ARM. 1615 1609 1610 + config CC_HAVE_STACKPROTECTOR_TLS 1611 + def_bool $(cc-option,-mtp=cp15 -mstack-protector-guard=tls -mstack-protector-guard-offset=0) 1612 + 1616 1613 config STACKPROTECTOR_PER_TASK 1617 1614 bool "Use a unique stack canary value for each task" 1618 - depends on GCC_PLUGINS && STACKPROTECTOR && THREAD_INFO_IN_TASK && !XIP_DEFLATED_DATA 1619 - select GCC_PLUGIN_ARM_SSP_PER_TASK 1615 + depends on STACKPROTECTOR && CURRENT_POINTER_IN_TPIDRURO && !XIP_DEFLATED_DATA 1616 + depends on GCC_PLUGINS || CC_HAVE_STACKPROTECTOR_TLS 1617 + select GCC_PLUGIN_ARM_SSP_PER_TASK if !CC_HAVE_STACKPROTECTOR_TLS 1620 1618 default y 1621 1619 help 1622 1620 Due to the fact that GCC uses an ordinary symbol reference from
+1 -1
arch/arm/Kconfig.debug
··· 65 65 66 66 config UNWINDER_ARM 67 67 bool "ARM EABI stack unwinder" 68 - depends on AEABI && !FUNCTION_GRAPH_TRACER 68 + depends on AEABI 69 69 select ARM_UNWIND 70 70 help 71 71 This option enables stack unwinding support in the kernel
+9
arch/arm/Makefile
··· 275 275 276 276 ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y) 277 277 prepare: stack_protector_prepare 278 + ifeq ($(CONFIG_CC_HAVE_STACKPROTECTOR_TLS),y) 279 + stack_protector_prepare: prepare0 280 + $(eval KBUILD_CFLAGS += \ 281 + -mstack-protector-guard=tls \ 282 + -mstack-protector-guard-offset=$(shell \ 283 + awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}'\ 284 + include/generated/asm-offsets.h)) 285 + else 278 286 stack_protector_prepare: prepare0 279 287 $(eval SSP_PLUGIN_CFLAGS := \ 280 288 -fplugin-arg-arm_ssp_per_task_plugin-offset=$(shell \ ··· 290 282 include/generated/asm-offsets.h)) 291 283 $(eval KBUILD_CFLAGS += $(SSP_PLUGIN_CFLAGS)) 292 284 $(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS)) 285 + endif 293 286 endif 294 287 295 288 all: $(notdir $(KBUILD_IMAGE))
+1 -5
arch/arm/boot/compressed/Makefile
··· 92 92 OBJS += $(libfdt_objs) fdt_check_mem_start.o 93 93 endif 94 94 95 - # -fstack-protector-strong triggers protection checks in this code, 96 - # but it is being used too early to link to meaningful stack_chk logic. 97 - $(foreach o, $(libfdt_objs) atags_to_fdt.o fdt_check_mem_start.o, \ 98 - $(eval CFLAGS_$(o) := -I $(srctree)/scripts/dtc/libfdt -fno-stack-protector)) 99 - 100 95 targets := vmlinux vmlinux.lds piggy_data piggy.o \ 101 96 head.o $(OBJS) 102 97 103 98 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING 104 99 105 100 ccflags-y := -fpic $(call cc-option,-mno-single-pic-base,) -fno-builtin \ 101 + -I$(srctree)/scripts/dtc/libfdt -fno-stack-protector \ 106 102 -I$(obj) $(DISABLE_ARM_SSP_PER_TASK_PLUGIN) 107 103 ccflags-remove-$(CONFIG_FUNCTION_TRACER) += -pg 108 104 asflags-y := -DZIMAGE
-7
arch/arm/boot/compressed/misc.c
··· 128 128 error("Attempting division by 0!"); 129 129 } 130 130 131 - const unsigned long __stack_chk_guard = 0x000a0dff; 132 - 133 - void __stack_chk_fail(void) 134 - { 135 - error("stack-protector: Kernel stack is corrupted\n"); 136 - } 137 - 138 131 extern int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)); 139 132 140 133
+169 -35
arch/arm/include/asm/assembler.h
··· 86 86 87 87 #define IMM12_MASK 0xfff 88 88 89 + /* the frame pointer used for stack unwinding */ 90 + ARM( fpreg .req r11 ) 91 + THUMB( fpreg .req r7 ) 92 + 89 93 /* 90 94 * Enable and disable interrupts 91 95 */ ··· 213 209 .endm 214 210 .endr 215 211 216 - .macro get_current, rd 217 - #ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO 218 - mrc p15, 0, \rd, c13, c0, 3 @ get TPIDRURO register 219 - #else 220 - get_thread_info \rd 221 - ldr \rd, [\rd, #TI_TASK] 222 - #endif 223 - .endm 224 - 225 - .macro set_current, rn 226 - #ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO 227 - mcr p15, 0, \rn, c13, c0, 3 @ set TPIDRURO register 228 - #endif 229 - .endm 230 - 231 - .macro reload_current, t1:req, t2:req 232 - #ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO 233 - adr_l \t1, __entry_task @ get __entry_task base address 234 - mrc p15, 0, \t2, c13, c0, 4 @ get per-CPU offset 235 - ldr \t1, [\t1, \t2] @ load variable 236 - mcr p15, 0, \t1, c13, c0, 3 @ store in TPIDRURO 237 - #endif 238 - .endm 239 - 240 212 /* 241 213 * Get current thread_info. 242 214 */ 243 215 .macro get_thread_info, rd 244 - #ifdef CONFIG_THREAD_INFO_IN_TASK 245 216 /* thread_info is the first member of struct task_struct */ 246 217 get_current \rd 247 - #else 248 - ARM( mov \rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT ) 249 - THUMB( mov \rd, sp ) 250 - THUMB( lsr \rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT ) 251 - mov \rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT 252 - #endif 253 218 .endm 254 219 255 220 /* ··· 292 319 #define ALT_UP(instr...) instr 293 320 #define ALT_UP_B(label) b label 294 321 #endif 322 + 323 + /* 324 + * this_cpu_offset - load the per-CPU offset of this CPU into 325 + * register 'rd' 326 + */ 327 + .macro this_cpu_offset, rd:req 328 + #ifdef CONFIG_SMP 329 + ALT_SMP(mrc p15, 0, \rd, c13, c0, 4) 330 + #ifdef CONFIG_CPU_V6 331 + ALT_UP_B(.L1_\@) 332 + .L0_\@: 333 + .subsection 1 334 + .L1_\@: ldr_va \rd, __per_cpu_offset 335 + b .L0_\@ 336 + .previous 337 + #endif 338 + #else 339 + mov \rd, #0 340 + #endif 341 + .endm 342 + 343 + /* 344 + * set_current - store the task pointer of this CPU's current task 345 + */ 346 + .macro set_current, rn:req, tmp:req 347 + #if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP) 348 + 9998: mcr p15, 0, \rn, c13, c0, 3 @ set TPIDRURO register 349 + #ifdef CONFIG_CPU_V6 350 + ALT_UP_B(.L0_\@) 351 + .subsection 1 352 + .L0_\@: str_va \rn, __current, \tmp 353 + b .L1_\@ 354 + .previous 355 + .L1_\@: 356 + #endif 357 + #else 358 + str_va \rn, __current, \tmp 359 + #endif 360 + .endm 361 + 362 + /* 363 + * get_current - load the task pointer of this CPU's current task 364 + */ 365 + .macro get_current, rd:req 366 + #if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP) 367 + 9998: mrc p15, 0, \rd, c13, c0, 3 @ get TPIDRURO register 368 + #ifdef CONFIG_CPU_V6 369 + ALT_UP_B(.L0_\@) 370 + .subsection 1 371 + .L0_\@: ldr_va \rd, __current 372 + b .L1_\@ 373 + .previous 374 + .L1_\@: 375 + #endif 376 + #else 377 + ldr_va \rd, __current 378 + #endif 379 + .endm 380 + 381 + /* 382 + * reload_current - reload the task pointer of this CPU's current task 383 + * into the TLS register 384 + */ 385 + .macro reload_current, t1:req, t2:req 386 + #if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP) 387 + #ifdef CONFIG_CPU_V6 388 + ALT_SMP(nop) 389 + ALT_UP_B(.L0_\@) 390 + #endif 391 + ldr_this_cpu \t1, __entry_task, \t1, \t2 392 + mcr p15, 0, \t1, c13, c0, 3 @ store in TPIDRURO 393 + .L0_\@: 394 + #endif 395 + .endm 295 396 296 397 /* 297 398 * Instruction barrier ··· 623 576 /* 624 577 * mov_l - move a constant value or [relocated] address into a register 625 578 */ 626 - .macro mov_l, dst:req, imm:req 579 + .macro mov_l, dst:req, imm:req, cond 627 580 .if __LINUX_ARM_ARCH__ < 7 628 - ldr \dst, =\imm 581 + ldr\cond \dst, =\imm 629 582 .else 630 - movw \dst, #:lower16:\imm 631 - movt \dst, #:upper16:\imm 583 + movw\cond \dst, #:lower16:\imm 584 + movt\cond \dst, #:upper16:\imm 632 585 .endif 633 586 .endm 634 587 ··· 666 619 __adldst_l str, \src, \sym, \tmp, \cond 667 620 .endm 668 621 622 + .macro __ldst_va, op, reg, tmp, sym, cond 623 + #if __LINUX_ARM_ARCH__ >= 7 || \ 624 + !defined(CONFIG_ARM_HAS_GROUP_RELOCS) || \ 625 + (defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) 626 + mov_l \tmp, \sym, \cond 627 + \op\cond \reg, [\tmp] 628 + #else 629 + /* 630 + * Avoid a literal load, by emitting a sequence of ADD/LDR instructions 631 + * with the appropriate relocations. The combined sequence has a range 632 + * of -/+ 256 MiB, which should be sufficient for the core kernel and 633 + * for modules loaded into the module region. 634 + */ 635 + .globl \sym 636 + .reloc .L0_\@, R_ARM_ALU_PC_G0_NC, \sym 637 + .reloc .L1_\@, R_ARM_ALU_PC_G1_NC, \sym 638 + .reloc .L2_\@, R_ARM_LDR_PC_G2, \sym 639 + .L0_\@: sub\cond \tmp, pc, #8 640 + .L1_\@: sub\cond \tmp, \tmp, #4 641 + .L2_\@: \op\cond \reg, [\tmp, #0] 642 + #endif 643 + .endm 644 + 645 + /* 646 + * ldr_va - load a 32-bit word from the virtual address of \sym 647 + */ 648 + .macro ldr_va, rd:req, sym:req, cond 649 + __ldst_va ldr, \rd, \rd, \sym, \cond 650 + .endm 651 + 652 + /* 653 + * str_va - store a 32-bit word to the virtual address of \sym 654 + */ 655 + .macro str_va, rn:req, sym:req, tmp:req, cond 656 + __ldst_va str, \rn, \tmp, \sym, \cond 657 + .endm 658 + 659 + /* 660 + * ldr_this_cpu_armv6 - Load a 32-bit word from the per-CPU variable 'sym', 661 + * without using a temp register. Supported in ARM mode 662 + * only. 663 + */ 664 + .macro ldr_this_cpu_armv6, rd:req, sym:req 665 + this_cpu_offset \rd 666 + .globl \sym 667 + .reloc .L0_\@, R_ARM_ALU_PC_G0_NC, \sym 668 + .reloc .L1_\@, R_ARM_ALU_PC_G1_NC, \sym 669 + .reloc .L2_\@, R_ARM_LDR_PC_G2, \sym 670 + add \rd, \rd, pc 671 + .L0_\@: sub \rd, \rd, #4 672 + .L1_\@: sub \rd, \rd, #0 673 + .L2_\@: ldr \rd, [\rd, #4] 674 + .endm 675 + 676 + /* 677 + * ldr_this_cpu - Load a 32-bit word from the per-CPU variable 'sym' 678 + * into register 'rd', which may be the stack pointer, 679 + * using 't1' and 't2' as general temp registers. These 680 + * are permitted to overlap with 'rd' if != sp 681 + */ 682 + .macro ldr_this_cpu, rd:req, sym:req, t1:req, t2:req 683 + #if __LINUX_ARM_ARCH__ >= 7 || \ 684 + !defined(CONFIG_ARM_HAS_GROUP_RELOCS) || \ 685 + (defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) 686 + this_cpu_offset \t1 687 + mov_l \t2, \sym 688 + ldr \rd, [\t1, \t2] 689 + #else 690 + ldr_this_cpu_armv6 \rd, \sym 691 + #endif 692 + .endm 693 + 669 694 /* 670 695 * rev_l - byte-swap a 32-bit value 671 696 * ··· 752 633 eor \val, \val, \tmp, lsr #8 753 634 .else 754 635 rev \val, \val 636 + .endif 637 + .endm 638 + 639 + /* 640 + * bl_r - branch and link to register 641 + * 642 + * @dst: target to branch to 643 + * @c: conditional opcode suffix 644 + */ 645 + .macro bl_r, dst:req, c 646 + .if __LINUX_ARM_ARCH__ < 6 647 + mov\c lr, pc 648 + mov\c pc, \dst 649 + .else 650 + blx\c \dst 755 651 .endif 756 652 .endm 757 653
+3 -9
arch/arm/include/asm/cacheflush.h
··· 445 445 * however some exceptions may exist. Caveat emptor. 446 446 * 447 447 * - The clobber list is dictated by the call to v7_flush_dcache_*. 448 - * fp is preserved to the stack explicitly prior disabling the cache 449 - * since adding it to the clobber list is incompatible with having 450 - * CONFIG_FRAME_POINTER=y. ip is saved as well if ever r12-clobbering 451 - * trampoline are inserted by the linker and to keep sp 64-bit aligned. 452 448 */ 453 449 #define v7_exit_coherency_flush(level) \ 454 450 asm volatile( \ 455 451 ".arch armv7-a \n\t" \ 456 - "stmfd sp!, {fp, ip} \n\t" \ 457 452 "mrc p15, 0, r0, c1, c0, 0 @ get SCTLR \n\t" \ 458 453 "bic r0, r0, #"__stringify(CR_C)" \n\t" \ 459 454 "mcr p15, 0, r0, c1, c0, 0 @ set SCTLR \n\t" \ ··· 458 463 "bic r0, r0, #(1 << 6) @ disable local coherency \n\t" \ 459 464 "mcr p15, 0, r0, c1, c0, 1 @ set ACTLR \n\t" \ 460 465 "isb \n\t" \ 461 - "dsb \n\t" \ 462 - "ldmfd sp!, {fp, ip}" \ 463 - : : : "r0","r1","r2","r3","r4","r5","r6","r7", \ 464 - "r9","r10","lr","memory" ) 466 + "dsb" \ 467 + : : : "r0","r1","r2","r3","r4","r5","r6", \ 468 + "r9","r10","ip","lr","memory" ) 465 469 466 470 void flush_uprobe_xol_access(struct page *page, unsigned long uaddr, 467 471 void *kaddr, unsigned long len);
+31 -15
arch/arm/include/asm/current.h
··· 8 8 #define _ASM_ARM_CURRENT_H 9 9 10 10 #ifndef __ASSEMBLY__ 11 + #include <asm/insn.h> 11 12 12 13 struct task_struct; 13 14 14 - static inline void set_current(struct task_struct *cur) 15 - { 16 - if (!IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO)) 17 - return; 15 + extern struct task_struct *__current; 18 16 19 - /* Set TPIDRURO */ 20 - asm("mcr p15, 0, %0, c13, c0, 3" :: "r"(cur) : "memory"); 21 - } 22 - 23 - #ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO 24 - 25 - static inline struct task_struct *get_current(void) 17 + static __always_inline __attribute_const__ struct task_struct *get_current(void) 26 18 { 27 19 struct task_struct *cur; 28 20 29 21 #if __has_builtin(__builtin_thread_pointer) && \ 22 + defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) && \ 30 23 !(defined(CONFIG_THUMB2_KERNEL) && \ 31 24 defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 130001) 32 25 /* ··· 32 39 * https://github.com/ClangBuiltLinux/linux/issues/1485 33 40 */ 34 41 cur = __builtin_thread_pointer(); 42 + #elif defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP) 43 + asm("0: mrc p15, 0, %0, c13, c0, 3 \n\t" 44 + #ifdef CONFIG_CPU_V6 45 + "1: \n\t" 46 + " .subsection 1 \n\t" 47 + #if defined(CONFIG_ARM_HAS_GROUP_RELOCS) && \ 48 + !(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) 49 + "2: " LOAD_SYM_ARMV6(%0, __current) " \n\t" 50 + " b 1b \n\t" 35 51 #else 36 - asm("mrc p15, 0, %0, c13, c0, 3" : "=r"(cur)); 52 + "2: ldr %0, 3f \n\t" 53 + " ldr %0, [%0] \n\t" 54 + " b 1b \n\t" 55 + "3: .long __current \n\t" 56 + #endif 57 + " .previous \n\t" 58 + " .pushsection \".alt.smp.init\", \"a\" \n\t" 59 + " .long 0b - . \n\t" 60 + " b . + (2b - 0b) \n\t" 61 + " .popsection \n\t" 62 + #endif 63 + : "=r"(cur)); 64 + #elif __LINUX_ARM_ARCH__>= 7 || \ 65 + !defined(CONFIG_ARM_HAS_GROUP_RELOCS) || \ 66 + (defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) 67 + cur = __current; 68 + #else 69 + asm(LOAD_SYM_ARMV6(%0, __current) : "=r"(cur)); 37 70 #endif 38 71 return cur; 39 72 } 40 73 41 74 #define current get_current() 42 - #else 43 - #include <asm-generic/current.h> 44 - #endif /* CONFIG_CURRENT_POINTER_IN_TPIDRURO */ 45 75 46 76 #endif /* __ASSEMBLY__ */ 47 77
+3
arch/arm/include/asm/elf.h
··· 61 61 #define R_ARM_MOVT_ABS 44 62 62 #define R_ARM_MOVW_PREL_NC 45 63 63 #define R_ARM_MOVT_PREL 46 64 + #define R_ARM_ALU_PC_G0_NC 57 65 + #define R_ARM_ALU_PC_G1_NC 59 66 + #define R_ARM_LDR_PC_G2 63 64 67 65 68 #define R_ARM_THM_CALL 10 66 69 #define R_ARM_THM_JUMP24 30
-40
arch/arm/include/asm/entry-macro-multi.S
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #include <asm/assembler.h> 3 - 4 - /* 5 - * Interrupt handling. Preserves r7, r8, r9 6 - */ 7 - .macro arch_irq_handler_default 8 - get_irqnr_preamble r6, lr 9 - 1: get_irqnr_and_base r0, r2, r6, lr 10 - movne r1, sp 11 - @ 12 - @ routine called with r0 = irq number, r1 = struct pt_regs * 13 - @ 14 - badrne lr, 1b 15 - bne asm_do_IRQ 16 - 17 - #ifdef CONFIG_SMP 18 - /* 19 - * XXX 20 - * 21 - * this macro assumes that irqstat (r2) and base (r6) are 22 - * preserved from get_irqnr_and_base above 23 - */ 24 - ALT_SMP(test_for_ipi r0, r2, r6, lr) 25 - ALT_UP_B(9997f) 26 - movne r1, sp 27 - badrne lr, 1b 28 - bne do_IPI 29 - #endif 30 - 9997: 31 - .endm 32 - 33 - .macro arch_irq_handler, symbol_name 34 - .align 5 35 - .global \symbol_name 36 - \symbol_name: 37 - mov r8, lr 38 - arch_irq_handler_default 39 - ret r8 40 - .endm
+3 -1
arch/arm/include/asm/ftrace.h
··· 2 2 #ifndef _ASM_ARM_FTRACE 3 3 #define _ASM_ARM_FTRACE 4 4 5 + #define HAVE_FUNCTION_GRAPH_FP_TEST 6 + 5 7 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 6 8 #define ARCH_SUPPORTS_FTRACE_OPS 1 7 9 #endif ··· 50 48 51 49 static inline void *return_address(unsigned int level) 52 50 { 53 - return NULL; 51 + return NULL; 54 52 } 55 53 56 54 #endif
-131
arch/arm/include/asm/hardware/entry-macro-iomd.S
··· 1 - /* 2 - * arch/arm/include/asm/hardware/entry-macro-iomd.S 3 - * 4 - * Low-level IRQ helper macros for IOC/IOMD based platforms 5 - * 6 - * This file is licensed under the terms of the GNU General Public 7 - * License version 2. This program is licensed "as is" without any 8 - * warranty of any kind, whether express or implied. 9 - */ 10 - 11 - /* IOC / IOMD based hardware */ 12 - #include <asm/hardware/iomd.h> 13 - 14 - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp 15 - ldrb \irqstat, [\base, #IOMD_IRQREQB] @ get high priority first 16 - ldr \tmp, =irq_prio_h 17 - teq \irqstat, #0 18 - #ifdef IOMD_BASE 19 - ldrbeq \irqstat, [\base, #IOMD_DMAREQ] @ get dma 20 - addeq \tmp, \tmp, #256 @ irq_prio_h table size 21 - teqeq \irqstat, #0 22 - bne 2406f 23 - #endif 24 - ldrbeq \irqstat, [\base, #IOMD_IRQREQA] @ get low priority 25 - addeq \tmp, \tmp, #256 @ irq_prio_d table size 26 - teqeq \irqstat, #0 27 - #ifdef IOMD_IRQREQC 28 - ldrbeq \irqstat, [\base, #IOMD_IRQREQC] 29 - addeq \tmp, \tmp, #256 @ irq_prio_l table size 30 - teqeq \irqstat, #0 31 - #endif 32 - #ifdef IOMD_IRQREQD 33 - ldrbeq \irqstat, [\base, #IOMD_IRQREQD] 34 - addeq \tmp, \tmp, #256 @ irq_prio_lc table size 35 - teqeq \irqstat, #0 36 - #endif 37 - 2406: ldrbne \irqnr, [\tmp, \irqstat] @ get IRQ number 38 - .endm 39 - 40 - /* 41 - * Interrupt table (incorporates priority). Please note that we 42 - * rely on the order of these tables (see above code). 43 - */ 44 - .align 5 45 - irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 46 - .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 47 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 48 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 49 - .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 50 - .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 51 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 52 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 53 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 54 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 55 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 56 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 57 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 58 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 59 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 60 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 61 - #ifdef IOMD_BASE 62 - irq_prio_d: .byte 0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 63 - .byte 20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 64 - .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 65 - .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 66 - .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 67 - .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 68 - .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 69 - .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 70 - .byte 23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 71 - .byte 23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 72 - .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 73 - .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 74 - .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 75 - .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 76 - .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 77 - .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 78 - #endif 79 - irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 80 - .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 81 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 82 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 83 - .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 84 - .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 85 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 86 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 87 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 88 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 89 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 90 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 91 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 92 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 93 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 94 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 95 - #ifdef IOMD_IRQREQC 96 - irq_prio_lc: .byte 24,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27 97 - .byte 28,24,25,24,26,26,26,26,27,27,27,27,27,27,27,27 98 - .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 99 - .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 100 - .byte 30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27 101 - .byte 30,30,30,30,30,30,30,30,27,27,27,27,27,27,27,27 102 - .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 103 - .byte 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 104 - .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 105 - .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 106 - .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 107 - .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 108 - .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 109 - .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 110 - .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 111 - .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 112 - #endif 113 - #ifdef IOMD_IRQREQD 114 - irq_prio_ld: .byte 40,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43 115 - .byte 44,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43 116 - .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 117 - .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 118 - .byte 46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43 119 - .byte 46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43 120 - .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 121 - .byte 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45 122 - .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 123 - .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 124 - .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 125 - .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 126 - .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 127 - .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 128 - .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 129 - .byte 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47 130 - #endif 131 -
+17
arch/arm/include/asm/insn.h
··· 2 2 #ifndef __ASM_ARM_INSN_H 3 3 #define __ASM_ARM_INSN_H 4 4 5 + #include <linux/types.h> 6 + 7 + /* 8 + * Avoid a literal load by emitting a sequence of ADD/LDR instructions with the 9 + * appropriate relocations. The combined sequence has a range of -/+ 256 MiB, 10 + * which should be sufficient for the core kernel as well as modules loaded 11 + * into the module region. (Not supported by LLD before release 14) 12 + */ 13 + #define LOAD_SYM_ARMV6(reg, sym) \ 14 + " .globl " #sym " \n\t" \ 15 + " .reloc 10f, R_ARM_ALU_PC_G0_NC, " #sym " \n\t" \ 16 + " .reloc 11f, R_ARM_ALU_PC_G1_NC, " #sym " \n\t" \ 17 + " .reloc 12f, R_ARM_LDR_PC_G2, " #sym " \n\t" \ 18 + "10: sub " #reg ", pc, #8 \n\t" \ 19 + "11: sub " #reg ", " #reg ", #4 \n\t" \ 20 + "12: ldr " #reg ", [" #reg ", #0] \n\t" 21 + 5 22 static inline unsigned long 6 23 arm_gen_nop(void) 7 24 {
-1
arch/arm/include/asm/irq.h
··· 26 26 struct irqaction; 27 27 struct pt_regs; 28 28 29 - extern void asm_do_IRQ(unsigned int, struct pt_regs *); 30 29 void handle_IRQ(unsigned int, struct pt_regs *); 31 30 void init_IRQ(void); 32 31
-2
arch/arm/include/asm/mach/arch.h
··· 56 56 void (*init_time)(void); 57 57 void (*init_machine)(void); 58 58 void (*init_late)(void); 59 - #ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER 60 59 void (*handle_irq)(struct pt_regs *); 61 - #endif 62 60 void (*restart)(enum reboot_mode, const char *); 63 61 }; 64 62
+1 -1
arch/arm/include/asm/mmu.h
··· 10 10 #else 11 11 int switch_pending; 12 12 #endif 13 - unsigned int vmalloc_seq; 13 + atomic_t vmalloc_seq; 14 14 unsigned long sigpage; 15 15 #ifdef CONFIG_VDSO 16 16 unsigned long vdso;
+20 -2
arch/arm/include/asm/mmu_context.h
··· 23 23 24 24 void __check_vmalloc_seq(struct mm_struct *mm); 25 25 26 + #ifdef CONFIG_MMU 27 + static inline void check_vmalloc_seq(struct mm_struct *mm) 28 + { 29 + if (!IS_ENABLED(CONFIG_ARM_LPAE) && 30 + unlikely(atomic_read(&mm->context.vmalloc_seq) != 31 + atomic_read(&init_mm.context.vmalloc_seq))) 32 + __check_vmalloc_seq(mm); 33 + } 34 + #endif 35 + 26 36 #ifdef CONFIG_CPU_HAS_ASID 27 37 28 38 void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk); ··· 62 52 static inline void check_and_switch_context(struct mm_struct *mm, 63 53 struct task_struct *tsk) 64 54 { 65 - if (unlikely(mm->context.vmalloc_seq != init_mm.context.vmalloc_seq)) 66 - __check_vmalloc_seq(mm); 55 + check_vmalloc_seq(mm); 67 56 68 57 if (irqs_disabled()) 69 58 /* ··· 137 128 } 138 129 #endif 139 130 } 131 + 132 + #ifdef CONFIG_VMAP_STACK 133 + static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) 134 + { 135 + if (mm != &init_mm) 136 + check_vmalloc_seq(mm); 137 + } 138 + #define enter_lazy_tlb enter_lazy_tlb 139 + #endif 140 140 141 141 #include <asm-generic/mmu_context.h> 142 142
+3
arch/arm/include/asm/page.h
··· 147 147 #include <asm/pgtable-3level-types.h> 148 148 #else 149 149 #include <asm/pgtable-2level-types.h> 150 + #ifdef CONFIG_VMAP_STACK 151 + #define ARCH_PAGE_TABLE_SYNC_MASK PGTBL_PMD_MODIFIED 152 + #endif 150 153 #endif 151 154 152 155 #endif /* CONFIG_MMU */
+31 -4
arch/arm/include/asm/percpu.h
··· 5 5 #ifndef _ASM_ARM_PERCPU_H_ 6 6 #define _ASM_ARM_PERCPU_H_ 7 7 8 + #include <asm/insn.h> 9 + 8 10 register unsigned long current_stack_pointer asm ("sp"); 9 11 10 12 /* 11 13 * Same as asm-generic/percpu.h, except that we store the per cpu offset 12 14 * in the TPIDRPRW. TPIDRPRW only exists on V6K and V7 13 15 */ 14 - #if defined(CONFIG_SMP) && !defined(CONFIG_CPU_V6) 16 + #ifdef CONFIG_SMP 15 17 static inline void set_my_cpu_offset(unsigned long off) 16 18 { 19 + extern unsigned int smp_on_up; 20 + 21 + if (IS_ENABLED(CONFIG_CPU_V6) && !smp_on_up) 22 + return; 23 + 17 24 /* Set TPIDRPRW */ 18 25 asm volatile("mcr p15, 0, %0, c13, c0, 4" : : "r" (off) : "memory"); 19 26 } 20 27 21 - static inline unsigned long __my_cpu_offset(void) 28 + static __always_inline unsigned long __my_cpu_offset(void) 22 29 { 23 30 unsigned long off; 24 31 ··· 34 27 * We want to allow caching the value, so avoid using volatile and 35 28 * instead use a fake stack read to hazard against barrier(). 36 29 */ 37 - asm("mrc p15, 0, %0, c13, c0, 4" : "=r" (off) 38 - : "Q" (*(const unsigned long *)current_stack_pointer)); 30 + asm("0: mrc p15, 0, %0, c13, c0, 4 \n\t" 31 + #ifdef CONFIG_CPU_V6 32 + "1: \n\t" 33 + " .subsection 1 \n\t" 34 + #if defined(CONFIG_ARM_HAS_GROUP_RELOCS) && \ 35 + !(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) 36 + "2: " LOAD_SYM_ARMV6(%0, __per_cpu_offset) " \n\t" 37 + " b 1b \n\t" 38 + #else 39 + "2: ldr %0, 3f \n\t" 40 + " ldr %0, [%0] \n\t" 41 + " b 1b \n\t" 42 + "3: .long __per_cpu_offset \n\t" 43 + #endif 44 + " .previous \n\t" 45 + " .pushsection \".alt.smp.init\", \"a\" \n\t" 46 + " .long 0b - . \n\t" 47 + " b . + (2b - 0b) \n\t" 48 + " .popsection \n\t" 49 + #endif 50 + : "=r" (off) 51 + : "Q" (*(const unsigned long *)current_stack_pointer)); 39 52 40 53 return off; 41 54 }
-5
arch/arm/include/asm/smp.h
··· 25 25 extern void show_ipi_list(struct seq_file *, int); 26 26 27 27 /* 28 - * Called from assembly code, this handles an IPI. 29 - */ 30 - asmlinkage void do_IPI(int ipinr, struct pt_regs *regs); 31 - 32 - /* 33 28 * Called from C code, this handles an IPI. 34 29 */ 35 30 void handle_IPI(int ipinr, struct pt_regs *regs);
+5
arch/arm/include/asm/stacktrace.h
··· 14 14 unsigned long sp; 15 15 unsigned long lr; 16 16 unsigned long pc; 17 + 18 + /* address of the LR value on the stack */ 19 + unsigned long *lr_addr; 17 20 #ifdef CONFIG_KRETPROBES 18 21 struct llist_node *kr_cur; 19 22 struct task_struct *tsk; ··· 39 36 extern int unwind_frame(struct stackframe *frame); 40 37 extern void walk_stackframe(struct stackframe *frame, 41 38 int (*fn)(struct stackframe *, void *), void *data); 39 + extern void dump_mem(const char *lvl, const char *str, unsigned long bottom, 40 + unsigned long top); 42 41 43 42 #endif /* __ASM_STACKTRACE_H */
+2 -1
arch/arm/include/asm/switch_to.h
··· 3 3 #define __ASM_ARM_SWITCH_TO_H 4 4 5 5 #include <linux/thread_info.h> 6 + #include <asm/smp_plat.h> 6 7 7 8 /* 8 9 * For v7 SMP cores running a preemptible kernel we may be pre-empted ··· 27 26 #define switch_to(prev,next,last) \ 28 27 do { \ 29 28 __complete_pending_tlbi(); \ 30 - if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO)) \ 29 + if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || is_smp()) \ 31 30 __this_cpu_write(__entry_task, next); \ 32 31 last = __switch_to(prev,task_thread_info(prev), task_thread_info(next)); \ 33 32 } while (0)
+8 -27
arch/arm/include/asm/thread_info.h
··· 25 25 #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) 26 26 #define THREAD_START_SP (THREAD_SIZE - 8) 27 27 28 + #ifdef CONFIG_VMAP_STACK 29 + #define THREAD_ALIGN (2 * THREAD_SIZE) 30 + #else 31 + #define THREAD_ALIGN THREAD_SIZE 32 + #endif 33 + 34 + #define OVERFLOW_STACK_SIZE SZ_4K 35 + 28 36 #ifndef __ASSEMBLY__ 29 37 30 38 struct task_struct; ··· 62 54 struct thread_info { 63 55 unsigned long flags; /* low level flags */ 64 56 int preempt_count; /* 0 => preemptable, <0 => bug */ 65 - #ifndef CONFIG_THREAD_INFO_IN_TASK 66 - struct task_struct *task; /* main task structure */ 67 - #endif 68 57 __u32 cpu; /* cpu */ 69 58 __u32 cpu_domain; /* cpu domain */ 70 59 struct cpu_context_save cpu_context; /* cpu context */ ··· 77 72 78 73 #define INIT_THREAD_INFO(tsk) \ 79 74 { \ 80 - INIT_THREAD_INFO_TASK(tsk) \ 81 75 .flags = 0, \ 82 76 .preempt_count = INIT_PREEMPT_COUNT, \ 83 77 } 84 - 85 - #ifdef CONFIG_THREAD_INFO_IN_TASK 86 - #define INIT_THREAD_INFO_TASK(tsk) 87 78 88 79 static inline struct task_struct *thread_task(struct thread_info* ti) 89 80 { 90 81 return (struct task_struct *)ti; 91 82 } 92 - 93 - #else 94 - #define INIT_THREAD_INFO_TASK(tsk) .task = &(tsk), 95 - 96 - static inline struct task_struct *thread_task(struct thread_info* ti) 97 - { 98 - return ti->task; 99 - } 100 - 101 - /* 102 - * how to get the thread information struct from C 103 - */ 104 - static inline struct thread_info *current_thread_info(void) __attribute_const__; 105 - 106 - static inline struct thread_info *current_thread_info(void) 107 - { 108 - return (struct thread_info *) 109 - (current_stack_pointer & ~(THREAD_SIZE - 1)); 110 - } 111 - #endif 112 83 113 84 #define thread_saved_pc(tsk) \ 114 85 ((unsigned long)(task_thread_info(tsk)->cpu_context.pc))
+21 -10
arch/arm/include/asm/tls.h
··· 18 18 .endm 19 19 20 20 .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2 21 - ldr \tmp1, =elf_hwcap 22 - ldr \tmp1, [\tmp1, #0] 21 + #ifdef CONFIG_SMP 22 + ALT_SMP(nop) 23 + ALT_UP_B(.L0_\@) 24 + .subsection 1 25 + #endif 26 + .L0_\@: 27 + ldr_va \tmp1, elf_hwcap 23 28 mov \tmp2, #0xffff0fff 24 29 tst \tmp1, #HWCAP_TLS @ hardware TLS available? 25 30 streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0 26 - mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register 27 - mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register 28 - mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register 29 - strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it 31 + beq .L2_\@ 32 + mcr p15, 0, \tp, c13, c0, 3 @ yes, set TLS register 33 + #ifdef CONFIG_SMP 34 + b .L1_\@ 35 + .previous 36 + #endif 37 + .L1_\@: switch_tls_v6k \base, \tp, \tpuser, \tmp1, \tmp2 38 + .L2_\@: 30 39 .endm 31 40 32 41 .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2 33 42 mov \tmp1, #0xffff0fff 34 43 str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0 35 44 .endm 45 + #else 46 + #include <asm/smp_plat.h> 36 47 #endif 37 48 38 49 #ifdef CONFIG_TLS_REG_EMUL ··· 54 43 #elif defined(CONFIG_CPU_V6) 55 44 #define tls_emu 0 56 45 #define has_tls_reg (elf_hwcap & HWCAP_TLS) 57 - #define defer_tls_reg_update 0 46 + #define defer_tls_reg_update is_smp() 58 47 #define switch_tls switch_tls_v6 59 48 #elif defined(CONFIG_CPU_32v6K) 60 49 #define tls_emu 0 ··· 92 81 */ 93 82 barrier(); 94 83 95 - if (!tls_emu && !defer_tls_reg_update) { 96 - if (has_tls_reg) { 84 + if (!tls_emu) { 85 + if (has_tls_reg && !defer_tls_reg_update) { 97 86 asm("mcr p15, 0, %0, c13, c0, 3" 98 87 : : "r" (val)); 99 - } else { 88 + } else if (!has_tls_reg) { 100 89 #ifdef CONFIG_KUSER_HELPERS 101 90 /* 102 91 * User space must never try to access this
+2 -1
arch/arm/include/asm/v7m.h
··· 13 13 #define V7M_SCB_ICSR_PENDSVSET (1 << 28) 14 14 #define V7M_SCB_ICSR_PENDSVCLR (1 << 27) 15 15 #define V7M_SCB_ICSR_RETTOBASE (1 << 11) 16 + #define V7M_SCB_ICSR_VECTACTIVE 0x000001ff 16 17 17 18 #define V7M_SCB_VTOR 0x08 18 19 ··· 39 38 #define V7M_SCB_SHCSR_MEMFAULTENA (1 << 16) 40 39 41 40 #define V7M_xPSR_FRAMEPTRALIGN 0x00000200 42 - #define V7M_xPSR_EXCEPTIONNO 0x000001ff 41 + #define V7M_xPSR_EXCEPTIONNO V7M_SCB_ICSR_VECTACTIVE 43 42 44 43 /* 45 44 * When branching to an address that has bits [31:28] == 0xf an exception return
+1
arch/arm/kernel/Makefile
··· 10 10 CFLAGS_REMOVE_ftrace.o = -pg 11 11 CFLAGS_REMOVE_insn.o = -pg 12 12 CFLAGS_REMOVE_patch.o = -pg 13 + CFLAGS_REMOVE_unwind.o = -pg 13 14 endif 14 15 15 16 CFLAGS_REMOVE_return_address.o = -pg
-3
arch/arm/kernel/asm-offsets.c
··· 43 43 BLANK(); 44 44 DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); 45 45 DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); 46 - #ifndef CONFIG_THREAD_INFO_IN_TASK 47 - DEFINE(TI_TASK, offsetof(struct thread_info, task)); 48 - #endif 49 46 DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); 50 47 DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain)); 51 48 DEFINE(TI_CPU_SAVE, offsetof(struct thread_info, cpu_context));
+144 -39
arch/arm/kernel/entry-armv.S
··· 19 19 #include <asm/glue-df.h> 20 20 #include <asm/glue-pf.h> 21 21 #include <asm/vfpmacros.h> 22 - #ifndef CONFIG_GENERIC_IRQ_MULTI_HANDLER 23 - #include <mach/entry-macro.S> 24 - #endif 25 22 #include <asm/thread_notify.h> 26 23 #include <asm/unwind.h> 27 24 #include <asm/unistd.h> ··· 27 30 #include <asm/uaccess-asm.h> 28 31 29 32 #include "entry-header.S" 30 - #include <asm/entry-macro-multi.S> 31 33 #include <asm/probes.h> 32 34 33 35 /* 34 36 * Interrupt handling. 35 37 */ 36 - .macro irq_handler 37 - #ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER 38 - mov r0, sp 39 - bl generic_handle_arch_irq 40 - #else 41 - arch_irq_handler_default 38 + .macro irq_handler, from_user:req 39 + mov r1, sp 40 + ldr_this_cpu r2, irq_stack_ptr, r2, r3 41 + .if \from_user == 0 42 + @ 43 + @ If we took the interrupt while running in the kernel, we may already 44 + @ be using the IRQ stack, so revert to the original value in that case. 45 + @ 46 + subs r3, r2, r1 @ SP above bottom of IRQ stack? 47 + rsbscs r3, r3, #THREAD_SIZE @ ... and below the top? 48 + #ifdef CONFIG_VMAP_STACK 49 + ldr_va r3, high_memory, cc @ End of the linear region 50 + cmpcc r3, r1 @ Stack pointer was below it? 42 51 #endif 52 + bcc 0f @ If not, switch to the IRQ stack 53 + mov r0, r1 54 + bl generic_handle_arch_irq 55 + b 1f 56 + 0: 57 + .endif 58 + 59 + mov_l r0, generic_handle_arch_irq 60 + bl call_with_stack 61 + 1: 43 62 .endm 44 63 45 64 .macro pabt_helper ··· 153 140 #define SPFIX(code...) 154 141 #endif 155 142 156 - .macro svc_entry, stack_hole=0, trace=1, uaccess=1 143 + .macro svc_entry, stack_hole=0, trace=1, uaccess=1, overflow_check=1 157 144 UNWIND(.fnstart ) 158 - UNWIND(.save {r0 - pc} ) 159 - sub sp, sp, #(SVC_REGS_SIZE + \stack_hole - 4) 145 + sub sp, sp, #(SVC_REGS_SIZE + \stack_hole) 146 + THUMB( add sp, r1 ) @ get SP in a GPR without 147 + THUMB( sub r1, sp, r1 ) @ using a temp register 148 + 149 + .if \overflow_check 150 + UNWIND(.save {r0 - pc} ) 151 + do_overflow_check (SVC_REGS_SIZE + \stack_hole) 152 + .endif 153 + 160 154 #ifdef CONFIG_THUMB2_KERNEL 161 - SPFIX( str r0, [sp] ) @ temporarily saved 162 - SPFIX( mov r0, sp ) 163 - SPFIX( tst r0, #4 ) @ test original stack alignment 164 - SPFIX( ldr r0, [sp] ) @ restored 155 + tst r1, #4 @ test stack pointer alignment 156 + sub r1, sp, r1 @ restore original R1 157 + sub sp, r1 @ restore original SP 165 158 #else 166 159 SPFIX( tst sp, #4 ) 167 160 #endif 168 - SPFIX( subeq sp, sp, #4 ) 169 - stmia sp, {r1 - r12} 161 + SPFIX( subne sp, sp, #4 ) 162 + 163 + ARM( stmib sp, {r1 - r12} ) 164 + THUMB( stmia sp, {r0 - r12} ) @ No STMIB in Thumb-2 170 165 171 166 ldmia r0, {r3 - r5} 172 - add r7, sp, #S_SP - 4 @ here for interlock avoidance 167 + add r7, sp, #S_SP @ here for interlock avoidance 173 168 mov r6, #-1 @ "" "" "" "" 174 - add r2, sp, #(SVC_REGS_SIZE + \stack_hole - 4) 175 - SPFIX( addeq r2, r2, #4 ) 176 - str r3, [sp, #-4]! @ save the "real" r0 copied 169 + add r2, sp, #(SVC_REGS_SIZE + \stack_hole) 170 + SPFIX( addne r2, r2, #4 ) 171 + str r3, [sp] @ save the "real" r0 copied 177 172 @ from the exception stack 178 173 179 174 mov r3, lr ··· 220 199 .align 5 221 200 __irq_svc: 222 201 svc_entry 223 - irq_handler 202 + irq_handler from_user=0 224 203 225 204 #ifdef CONFIG_PREEMPTION 226 205 ldr r8, [tsk, #TI_PREEMPT] @ get preempt count ··· 447 426 __irq_usr: 448 427 usr_entry 449 428 kuser_cmpxchg_check 450 - irq_handler 429 + irq_handler from_user=1 451 430 get_thread_info tsk 452 431 mov why, #0 453 432 b ret_to_user_from_irq ··· 773 752 ldr r6, [r2, #TI_CPU_DOMAIN] 774 753 #endif 775 754 switch_tls r1, r4, r5, r3, r7 776 - #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP) 777 - ldr r7, [r2, #TI_TASK] 755 + #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP) && \ 756 + !defined(CONFIG_STACKPROTECTOR_PER_TASK) 778 757 ldr r8, =__stack_chk_guard 779 758 .if (TSK_STACK_CANARY > IMM12_MASK) 780 - add r7, r7, #TSK_STACK_CANARY & ~IMM12_MASK 759 + add r9, r2, #TSK_STACK_CANARY & ~IMM12_MASK 760 + ldr r9, [r9, #TSK_STACK_CANARY & IMM12_MASK] 761 + .else 762 + ldr r9, [r2, #TSK_STACK_CANARY & IMM12_MASK] 781 763 .endif 782 - ldr r7, [r7, #TSK_STACK_CANARY & IMM12_MASK] 783 - #elif defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) 784 - mov r7, r2 @ Preserve 'next' 785 764 #endif 765 + mov r7, r2 @ Preserve 'next' 786 766 #ifdef CONFIG_CPU_USE_DOMAINS 787 767 mcr p15, 0, r6, c3, c0, 0 @ Set domain register 788 768 #endif ··· 792 770 ldr r0, =thread_notify_head 793 771 mov r1, #THREAD_NOTIFY_SWITCH 794 772 bl atomic_notifier_call_chain 795 - #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP) 796 - str r7, [r8] 773 + #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP) && \ 774 + !defined(CONFIG_STACKPROTECTOR_PER_TASK) 775 + str r9, [r8] 797 776 #endif 798 - THUMB( mov ip, r4 ) 799 777 mov r0, r5 800 - set_current r7 801 - ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @ Load all regs saved previously 802 - THUMB( ldmia ip!, {r4 - sl, fp} ) @ Load all regs saved previously 803 - THUMB( ldr sp, [ip], #4 ) 804 - THUMB( ldr pc, [ip] ) 778 + #if !defined(CONFIG_THUMB2_KERNEL) && !defined(CONFIG_VMAP_STACK) 779 + set_current r7, r8 780 + ldmia r4, {r4 - sl, fp, sp, pc} @ Load all regs saved previously 781 + #else 782 + mov r1, r7 783 + ldmia r4, {r4 - sl, fp, ip, lr} @ Load all regs saved previously 784 + #ifdef CONFIG_VMAP_STACK 785 + @ 786 + @ Do a dummy read from the new stack while running from the old one so 787 + @ that we can rely on do_translation_fault() to fix up any stale PMD 788 + @ entries covering the vmalloc region. 789 + @ 790 + ldr r2, [ip] 791 + #endif 792 + 793 + @ When CONFIG_THREAD_INFO_IN_TASK=n, the update of SP itself is what 794 + @ effectuates the task switch, as that is what causes the observable 795 + @ values of current and current_thread_info to change. When 796 + @ CONFIG_THREAD_INFO_IN_TASK=y, setting current (and therefore 797 + @ current_thread_info) is done explicitly, and the update of SP just 798 + @ switches us to another stack, with few other side effects. In order 799 + @ to prevent this distinction from causing any inconsistencies, let's 800 + @ keep the 'set_current' call as close as we can to the update of SP. 801 + set_current r1, r2 802 + mov sp, ip 803 + ret lr 804 + #endif 805 805 UNWIND(.fnend ) 806 806 ENDPROC(__switch_to) 807 + 808 + #ifdef CONFIG_VMAP_STACK 809 + .text 810 + .align 2 811 + __bad_stack: 812 + @ 813 + @ We've just detected an overflow. We need to load the address of this 814 + @ CPU's overflow stack into the stack pointer register. We have only one 815 + @ scratch register so let's use a sequence of ADDs including one 816 + @ involving the PC, and decorate them with PC-relative group 817 + @ relocations. As these are ARM only, switch to ARM mode first. 818 + @ 819 + @ We enter here with IP clobbered and its value stashed on the mode 820 + @ stack. 821 + @ 822 + THUMB( bx pc ) 823 + THUMB( nop ) 824 + THUMB( .arm ) 825 + ldr_this_cpu_armv6 ip, overflow_stack_ptr 826 + 827 + str sp, [ip, #-4]! @ Preserve original SP value 828 + mov sp, ip @ Switch to overflow stack 829 + pop {ip} @ Original SP in IP 830 + 831 + #if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC) 832 + mov ip, ip @ mov expected by unwinder 833 + push {fp, ip, lr, pc} @ GCC flavor frame record 834 + #else 835 + str ip, [sp, #-8]! @ store original SP 836 + push {fpreg, lr} @ Clang flavor frame record 837 + #endif 838 + UNWIND( ldr ip, [r0, #4] ) @ load exception LR 839 + UNWIND( str ip, [sp, #12] ) @ store in the frame record 840 + ldr ip, [r0, #12] @ reload IP 841 + 842 + @ Store the original GPRs to the new stack. 843 + svc_entry uaccess=0, overflow_check=0 844 + 845 + UNWIND( .save {sp, pc} ) 846 + UNWIND( .save {fpreg, lr} ) 847 + UNWIND( .setfp fpreg, sp ) 848 + 849 + ldr fpreg, [sp, #S_SP] @ Add our frame record 850 + @ to the linked list 851 + #if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC) 852 + ldr r1, [fp, #4] @ reload SP at entry 853 + add fp, fp, #12 854 + #else 855 + ldr r1, [fpreg, #8] 856 + #endif 857 + str r1, [sp, #S_SP] @ store in pt_regs 858 + 859 + @ Stash the regs for handle_bad_stack 860 + mov r0, sp 861 + 862 + @ Time to die 863 + bl handle_bad_stack 864 + nop 865 + UNWIND( .fnend ) 866 + ENDPROC(__bad_stack) 867 + #endif 807 868 808 869 __INIT 809 870
+9 -7
arch/arm/kernel/entry-common.S
··· 16 16 17 17 .equ NR_syscalls, __NR_syscalls 18 18 19 - #ifdef CONFIG_NEED_RET_TO_USER 20 - #include <mach/entry-macro.S> 21 - #else 22 - .macro arch_ret_to_user, tmp1, tmp2 23 - .endm 19 + .macro arch_ret_to_user, tmp 20 + #ifdef CONFIG_ARCH_IOP32X 21 + mrc p15, 0, \tmp, c15, c1, 0 22 + tst \tmp, #(1 << 6) 23 + bicne \tmp, \tmp, #(1 << 6) 24 + mcrne p15, 0, \tmp, c15, c1, 0 @ Disable cp6 access 24 25 #endif 26 + .endm 25 27 26 28 #include "entry-header.S" 27 29 ··· 57 55 58 56 59 57 /* perform architecture specific actions before user return */ 60 - arch_ret_to_user r1, lr 58 + arch_ret_to_user r1 61 59 62 60 restore_user_regs fast = 1, offset = S_OFF 63 61 UNWIND(.fnend ) ··· 130 128 asm_trace_hardirqs_on save = 0 131 129 132 130 /* perform architecture specific actions before user return */ 133 - arch_ret_to_user r1, lr 131 + arch_ret_to_user r1 134 132 ct_user_enter save = 0 135 133 136 134 restore_user_regs fast = 0, offset = 0
+72 -56
arch/arm/kernel/entry-ftrace.S
··· 22 22 * mcount can be thought of as a function called in the middle of a subroutine 23 23 * call. As such, it needs to be transparent for both the caller and the 24 24 * callee: the original lr needs to be restored when leaving mcount, and no 25 - * registers should be clobbered. (In the __gnu_mcount_nc implementation, we 26 - * clobber the ip register. This is OK because the ARM calling convention 27 - * allows it to be clobbered in subroutines and doesn't use it to hold 28 - * parameters.) 25 + * registers should be clobbered. 29 26 * 30 - * When using dynamic ftrace, we patch out the mcount call by a "pop {lr}" 27 + * When using dynamic ftrace, we patch out the mcount call by a "add sp, #4" 31 28 * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c). 32 29 */ 33 30 ··· 35 38 36 39 .macro __mcount suffix 37 40 mcount_enter 38 - ldr r0, =ftrace_trace_function 39 - ldr r2, [r0] 40 - adr r0, .Lftrace_stub 41 + ldr_va r2, ftrace_trace_function 42 + badr r0, .Lftrace_stub 41 43 cmp r0, r2 42 44 bne 1f 43 45 44 46 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 45 - ldr r1, =ftrace_graph_return 46 - ldr r2, [r1] 47 - cmp r0, r2 48 - bne ftrace_graph_caller\suffix 47 + ldr_va r2, ftrace_graph_return 48 + cmp r0, r2 49 + bne ftrace_graph_caller\suffix 49 50 50 - ldr r1, =ftrace_graph_entry 51 - ldr r2, [r1] 52 - ldr r0, =ftrace_graph_entry_stub 53 - cmp r0, r2 54 - bne ftrace_graph_caller\suffix 51 + ldr_va r2, ftrace_graph_entry 52 + mov_l r0, ftrace_graph_entry_stub 53 + cmp r0, r2 54 + bne ftrace_graph_caller\suffix 55 55 #endif 56 56 57 57 mcount_exit ··· 64 70 65 71 .macro __ftrace_regs_caller 66 72 67 - sub sp, sp, #8 @ space for PC and CPSR OLD_R0, 73 + str lr, [sp, #-8]! @ store LR as PC and make space for CPSR/OLD_R0, 68 74 @ OLD_R0 will overwrite previous LR 69 75 70 - add ip, sp, #12 @ move in IP the value of SP as it was 71 - @ before the push {lr} of the mcount mechanism 72 - 73 - str lr, [sp, #0] @ store LR instead of PC 74 - 75 - ldr lr, [sp, #8] @ get previous LR 76 + ldr lr, [sp, #8] @ get previous LR 76 77 77 78 str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR 78 79 79 - stmdb sp!, {ip, lr} 80 - stmdb sp!, {r0-r11, lr} 80 + str lr, [sp, #-4]! @ store previous LR as LR 81 + 82 + add lr, sp, #16 @ move in LR the value of SP as it was 83 + @ before the push {lr} of the mcount mechanism 84 + 85 + push {r0-r11, ip, lr} 81 86 82 87 @ stack content at this point: 83 88 @ 0 4 48 52 56 60 64 68 72 84 - @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 | 89 + @ R0 | R1 | ... | IP | SP + 4 | previous LR | LR | PSR | OLD_R0 | 85 90 86 - mov r3, sp @ struct pt_regs* 91 + mov r3, sp @ struct pt_regs* 87 92 88 - ldr r2, =function_trace_op 89 - ldr r2, [r2] @ pointer to the current 93 + ldr_va r2, function_trace_op @ pointer to the current 90 94 @ function tracing op 91 95 92 96 ldr r1, [sp, #S_LR] @ lr of instrumented func ··· 100 108 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 101 109 .globl ftrace_graph_regs_call 102 110 ftrace_graph_regs_call: 103 - mov r0, r0 111 + ARM( mov r0, r0 ) 112 + THUMB( nop.w ) 104 113 #endif 105 114 106 115 @ pop saved regs 107 - ldmia sp!, {r0-r12} @ restore r0 through r12 108 - ldr ip, [sp, #8] @ restore PC 109 - ldr lr, [sp, #4] @ restore LR 110 - ldr sp, [sp, #0] @ restore SP 111 - mov pc, ip @ return 116 + pop {r0-r11, ip, lr} @ restore r0 through r12 117 + ldr lr, [sp], #4 @ restore LR 118 + ldr pc, [sp], #12 112 119 .endm 113 120 114 121 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 115 122 .macro __ftrace_graph_regs_caller 116 123 117 - sub r0, fp, #4 @ lr of instrumented routine (parent) 124 + #ifdef CONFIG_UNWINDER_FRAME_POINTER 125 + sub r0, fp, #4 @ lr of instrumented routine (parent) 126 + #else 127 + add r0, sp, #S_LR 128 + #endif 118 129 119 130 @ called from __ftrace_regs_caller 120 - ldr r1, [sp, #S_PC] @ instrumented routine (func) 131 + ldr r1, [sp, #S_PC] @ instrumented routine (func) 121 132 mcount_adjust_addr r1, r1 122 133 123 - mov r2, fp @ frame pointer 134 + mov r2, fpreg @ frame pointer 135 + add r3, sp, #PT_REGS_SIZE 124 136 bl prepare_ftrace_return 125 137 126 138 @ pop registers saved in ftrace_regs_caller 127 - ldmia sp!, {r0-r12} @ restore r0 through r12 128 - ldr ip, [sp, #8] @ restore PC 129 - ldr lr, [sp, #4] @ restore LR 130 - ldr sp, [sp, #0] @ restore SP 131 - mov pc, ip @ return 139 + pop {r0-r11, ip, lr} @ restore r0 through r12 140 + ldr lr, [sp], #4 @ restore LR 141 + ldr pc, [sp], #12 132 142 133 143 .endm 134 144 #endif ··· 143 149 mcount_adjust_addr r0, lr @ instrumented function 144 150 145 151 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 146 - ldr r2, =function_trace_op 147 - ldr r2, [r2] @ pointer to the current 152 + ldr_va r2, function_trace_op @ pointer to the current 148 153 @ function tracing op 149 154 mov r3, #0 @ regs is NULL 150 155 #endif ··· 155 162 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 156 163 .globl ftrace_graph_call\suffix 157 164 ftrace_graph_call\suffix: 158 - mov r0, r0 165 + ARM( mov r0, r0 ) 166 + THUMB( nop.w ) 159 167 #endif 160 168 161 169 mcount_exit 162 170 .endm 163 171 164 172 .macro __ftrace_graph_caller 173 + #ifdef CONFIG_UNWINDER_FRAME_POINTER 165 174 sub r0, fp, #4 @ &lr of instrumented routine (&parent) 175 + #else 176 + add r0, sp, #20 177 + #endif 166 178 #ifdef CONFIG_DYNAMIC_FTRACE 167 179 @ called from __ftrace_caller, saved in mcount_enter 168 180 ldr r1, [sp, #16] @ instrumented routine (func) ··· 176 178 @ called from __mcount, untouched in lr 177 179 mcount_adjust_addr r1, lr @ instrumented routine (func) 178 180 #endif 179 - mov r2, fp @ frame pointer 181 + mov r2, fpreg @ frame pointer 182 + add r3, sp, #24 180 183 bl prepare_ftrace_return 181 184 mcount_exit 182 185 .endm ··· 201 202 .endm 202 203 203 204 .macro mcount_exit 204 - ldmia sp!, {r0-r3, ip, lr} 205 - ret ip 205 + ldmia sp!, {r0-r3} 206 + ldr lr, [sp, #4] 207 + ldr pc, [sp], #8 206 208 .endm 207 209 208 210 ENTRY(__gnu_mcount_nc) 209 211 UNWIND(.fnstart) 210 212 #ifdef CONFIG_DYNAMIC_FTRACE 211 - mov ip, lr 212 - ldmia sp!, {lr} 213 - ret ip 213 + push {lr} 214 + ldr lr, [sp, #4] 215 + ldr pc, [sp], #8 214 216 #else 215 217 __mcount 216 218 #endif ··· 256 256 .purgem mcount_exit 257 257 258 258 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 259 - .globl return_to_handler 260 - return_to_handler: 259 + ENTRY(return_to_handler) 261 260 stmdb sp!, {r0-r3} 262 - mov r0, fp @ frame pointer 261 + add r0, sp, #16 @ sp at exit of instrumented routine 263 262 bl ftrace_return_to_handler 264 263 mov lr, r0 @ r0 has real ret addr 265 264 ldmia sp!, {r0-r3} 266 265 ret lr 266 + ENDPROC(return_to_handler) 267 267 #endif 268 268 269 269 ENTRY(ftrace_stub) 270 270 .Lftrace_stub: 271 271 ret lr 272 272 ENDPROC(ftrace_stub) 273 + 274 + #ifdef CONFIG_DYNAMIC_FTRACE 275 + 276 + __INIT 277 + 278 + .macro init_tramp, dst:req 279 + ENTRY(\dst\()_from_init) 280 + ldr pc, =\dst 281 + ENDPROC(\dst\()_from_init) 282 + .endm 283 + 284 + init_tramp ftrace_caller 285 + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 286 + init_tramp ftrace_regs_caller 287 + #endif 288 + #endif
+45 -2
arch/arm/kernel/entry-header.S
··· 292 292 293 293 294 294 .macro restore_user_regs, fast = 0, offset = 0 295 - #if defined(CONFIG_CPU_32v6K) && !defined(CONFIG_CPU_V6) 295 + #if defined(CONFIG_CPU_32v6K) && \ 296 + (!defined(CONFIG_CPU_V6) || defined(CONFIG_SMP)) 297 + #ifdef CONFIG_CPU_V6 298 + ALT_SMP(nop) 299 + ALT_UP_B(.L1_\@) 300 + #endif 296 301 @ The TLS register update is deferred until return to user space so we 297 302 @ can use it for other things while running in the kernel 298 - get_thread_info r1 303 + mrc p15, 0, r1, c13, c0, 3 @ get current_thread_info pointer 299 304 ldr r1, [r1, #TI_TP_VALUE] 300 305 mcr p15, 0, r1, c13, c0, 3 @ set TLS register 306 + .L1_\@: 301 307 #endif 302 308 303 309 uaccess_enable r1, isb=0 ··· 429 423 tbl .req r8 @ syscall table pointer 430 424 why .req r8 @ Linux syscall (!= 0) 431 425 tsk .req r9 @ current thread_info 426 + 427 + .macro do_overflow_check, frame_size:req 428 + #ifdef CONFIG_VMAP_STACK 429 + @ 430 + @ Test whether the SP has overflowed. Task and IRQ stacks are aligned 431 + @ so that SP & BIT(THREAD_SIZE_ORDER + PAGE_SHIFT) should always be 432 + @ zero. 433 + @ 434 + ARM( tst sp, #1 << (THREAD_SIZE_ORDER + PAGE_SHIFT) ) 435 + THUMB( tst r1, #1 << (THREAD_SIZE_ORDER + PAGE_SHIFT) ) 436 + THUMB( it ne ) 437 + bne .Lstack_overflow_check\@ 438 + 439 + .pushsection .text 440 + .Lstack_overflow_check\@: 441 + @ 442 + @ The stack pointer is not pointing to a valid vmap'ed stack, but it 443 + @ may be pointing into the linear map instead, which may happen if we 444 + @ are already running from the overflow stack. We cannot detect overflow 445 + @ in such cases so just carry on. 446 + @ 447 + str ip, [r0, #12] @ Stash IP on the mode stack 448 + ldr_va ip, high_memory @ Start of VMALLOC space 449 + ARM( cmp sp, ip ) @ SP in vmalloc space? 450 + THUMB( cmp r1, ip ) 451 + THUMB( itt lo ) 452 + ldrlo ip, [r0, #12] @ Restore IP 453 + blo .Lout\@ @ Carry on 454 + 455 + THUMB( sub r1, sp, r1 ) @ Restore original R1 456 + THUMB( sub sp, r1 ) @ Restore original SP 457 + add sp, sp, #\frame_size @ Undo svc_entry's SP change 458 + b __bad_stack @ Handle VMAP stack overflow 459 + .popsection 460 + .Lout\@: 461 + #endif 462 + .endm
+24 -13
arch/arm/kernel/entry-v7m.S
··· 39 39 @ 40 40 @ Invoke the IRQ handler 41 41 @ 42 - mrs r0, ipsr 43 - ldr r1, =V7M_xPSR_EXCEPTIONNO 44 - and r0, r1 45 - sub r0, #16 46 - mov r1, sp 47 - stmdb sp!, {lr} 48 - @ routine called with r0 = irq number, r1 = struct pt_regs * 49 - bl nvic_handle_irq 42 + mov r0, sp 43 + ldr_this_cpu sp, irq_stack_ptr, r1, r2 50 44 51 - pop {lr} 45 + @ 46 + @ If we took the interrupt while running in the kernel, we may already 47 + @ be using the IRQ stack, so revert to the original value in that case. 48 + @ 49 + subs r2, sp, r0 @ SP above bottom of IRQ stack? 50 + rsbscs r2, r2, #THREAD_SIZE @ ... and below the top? 51 + movcs sp, r0 52 + 53 + push {r0, lr} @ preserve LR and original SP 54 + 55 + @ routine called with r0 = struct pt_regs * 56 + bl generic_handle_arch_irq 57 + 58 + pop {r0, lr} 59 + mov sp, r0 60 + 52 61 @ 53 62 @ Check for any pending work if returning to user 54 63 @ ··· 110 101 str sp, [ip], #4 111 102 str lr, [ip], #4 112 103 mov r5, r0 104 + mov r6, r2 @ Preserve 'next' 113 105 add r4, r2, #TI_CPU_SAVE 114 106 ldr r0, =thread_notify_head 115 107 mov r1, #THREAD_NOTIFY_SWITCH 116 108 bl atomic_notifier_call_chain 117 - mov ip, r4 118 109 mov r0, r5 119 - ldmia ip!, {r4 - r11} @ Load all regs saved previously 120 - ldr sp, [ip] 121 - ldr pc, [ip, #4]! 110 + mov r1, r6 111 + ldmia r4, {r4 - r12, lr} @ Load all regs saved previously 112 + set_current r1, r2 113 + mov sp, ip 114 + bx lr 122 115 .fnend 123 116 ENDPROC(__switch_to) 124 117
+55 -7
arch/arm/kernel/ftrace.c
··· 22 22 #include <asm/ftrace.h> 23 23 #include <asm/insn.h> 24 24 #include <asm/set_memory.h> 25 + #include <asm/stacktrace.h> 25 26 #include <asm/patch.h> 26 27 28 + /* 29 + * The compiler emitted profiling hook consists of 30 + * 31 + * PUSH {LR} 32 + * BL __gnu_mcount_nc 33 + * 34 + * To turn this combined sequence into a NOP, we need to restore the value of 35 + * SP before the PUSH. Let's use an ADD rather than a POP into LR, as LR is not 36 + * modified anyway, and reloading LR from memory is highly likely to be less 37 + * efficient. 38 + */ 27 39 #ifdef CONFIG_THUMB2_KERNEL 28 - #define NOP 0xf85deb04 /* pop.w {lr} */ 40 + #define NOP 0xf10d0d04 /* add.w sp, sp, #4 */ 29 41 #else 30 - #define NOP 0xe8bd4000 /* pop {lr} */ 42 + #define NOP 0xe28dd004 /* add sp, sp, #4 */ 31 43 #endif 32 44 33 45 #ifdef CONFIG_DYNAMIC_FTRACE ··· 63 51 return NOP; 64 52 } 65 53 66 - static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) 54 + void ftrace_caller_from_init(void); 55 + void ftrace_regs_caller_from_init(void); 56 + 57 + static unsigned long __ref adjust_address(struct dyn_ftrace *rec, 58 + unsigned long addr) 67 59 { 68 - return addr; 60 + if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE) || 61 + system_state >= SYSTEM_FREEING_INITMEM || 62 + likely(!is_kernel_inittext(rec->ip))) 63 + return addr; 64 + if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS) || 65 + addr == (unsigned long)&ftrace_caller) 66 + return (unsigned long)&ftrace_caller_from_init; 67 + return (unsigned long)&ftrace_regs_caller_from_init; 69 68 } 70 69 71 70 int ftrace_arch_code_modify_prepare(void) ··· 212 189 #endif 213 190 214 191 new = ftrace_nop_replace(rec); 215 - ret = ftrace_modify_code(ip, old, new, true); 192 + /* 193 + * Locations in .init.text may call __gnu_mcount_mc via a linker 194 + * emitted veneer if they are too far away from its implementation, and 195 + * so validation may fail spuriously in such cases. Let's work around 196 + * this by omitting those from validation. 197 + */ 198 + ret = ftrace_modify_code(ip, old, new, !is_kernel_inittext(ip)); 216 199 217 200 return ret; 218 201 } 219 202 #endif /* CONFIG_DYNAMIC_FTRACE */ 220 203 221 204 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 205 + asmlinkage 222 206 void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, 223 - unsigned long frame_pointer) 207 + unsigned long frame_pointer, 208 + unsigned long stack_pointer) 224 209 { 225 210 unsigned long return_hooker = (unsigned long) &return_to_handler; 226 211 unsigned long old; 227 212 228 213 if (unlikely(atomic_read(&current->tracing_graph_pause))) 229 214 return; 215 + 216 + if (IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER)) { 217 + /* FP points one word below parent's top of stack */ 218 + frame_pointer += 4; 219 + } else { 220 + struct stackframe frame = { 221 + .fp = frame_pointer, 222 + .sp = stack_pointer, 223 + .lr = self_addr, 224 + .pc = self_addr, 225 + }; 226 + if (unwind_frame(&frame) < 0) 227 + return; 228 + if (frame.lr != self_addr) 229 + parent = frame.lr_addr; 230 + frame_pointer = frame.sp; 231 + } 230 232 231 233 old = *parent; 232 234 *parent = return_hooker; ··· 273 225 unsigned long caller_fn = (unsigned long) func; 274 226 unsigned long pc = (unsigned long) callsite; 275 227 unsigned long branch = arm_gen_branch(pc, caller_fn); 276 - unsigned long nop = 0xe1a00000; /* mov r0, r0 */ 228 + unsigned long nop = arm_gen_nop(); 277 229 unsigned long old = enable ? nop : branch; 278 230 unsigned long new = enable ? branch : nop; 279 231
+1 -3
arch/arm/kernel/head-common.S
··· 105 105 mov r1, #0 106 106 bl __memset @ clear .bss 107 107 108 - #ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO 109 108 adr_l r0, init_task @ get swapper task_struct 110 - set_current r0 111 - #endif 109 + set_current r0, r1 112 110 113 111 ldmia r4, {r0, r1, r2, r3} 114 112 str r9, [r0] @ Save processor ID
+7
arch/arm/kernel/head.S
··· 424 424 ENDPROC(secondary_startup_arm) 425 425 426 426 ENTRY(__secondary_switched) 427 + #if defined(CONFIG_VMAP_STACK) && !defined(CONFIG_ARM_LPAE) 428 + @ Before using the vmap'ed stack, we have to switch to swapper_pg_dir 429 + @ as the ID map does not cover the vmalloc region. 430 + mrc p15, 0, ip, c2, c0, 1 @ read TTBR1 431 + mcr p15, 0, ip, c2, c0, 0 @ set TTBR0 432 + instr_sync 433 + #endif 427 434 adr_l r7, secondary_data + 12 @ get secondary_data.stack 428 435 ldr sp, [r7] 429 436 ldr r0, [r7, #4] @ get secondary_data.task
+44 -17
arch/arm/kernel/irq.c
··· 36 36 #include <asm/hardware/cache-l2x0.h> 37 37 #include <asm/hardware/cache-uniphier.h> 38 38 #include <asm/outercache.h> 39 + #include <asm/softirq_stack.h> 39 40 #include <asm/exception.h> 40 41 #include <asm/mach/arch.h> 41 42 #include <asm/mach/irq.h> 42 43 #include <asm/mach/time.h> 43 44 45 + #include "reboot.h" 46 + 44 47 unsigned long irq_err_count; 48 + 49 + #ifdef CONFIG_IRQSTACKS 50 + 51 + asmlinkage DEFINE_PER_CPU_READ_MOSTLY(u8 *, irq_stack_ptr); 52 + 53 + static void __init init_irq_stacks(void) 54 + { 55 + u8 *stack; 56 + int cpu; 57 + 58 + for_each_possible_cpu(cpu) { 59 + if (!IS_ENABLED(CONFIG_VMAP_STACK)) 60 + stack = (u8 *)__get_free_pages(GFP_KERNEL, 61 + THREAD_SIZE_ORDER); 62 + else 63 + stack = __vmalloc_node(THREAD_SIZE, THREAD_ALIGN, 64 + THREADINFO_GFP, NUMA_NO_NODE, 65 + __builtin_return_address(0)); 66 + 67 + if (WARN_ON(!stack)) 68 + break; 69 + per_cpu(irq_stack_ptr, cpu) = &stack[THREAD_SIZE]; 70 + } 71 + } 72 + 73 + static void ____do_softirq(void *arg) 74 + { 75 + __do_softirq(); 76 + } 77 + 78 + void do_softirq_own_stack(void) 79 + { 80 + call_with_stack(____do_softirq, NULL, 81 + __this_cpu_read(irq_stack_ptr)); 82 + } 83 + 84 + #endif 45 85 46 86 int arch_show_interrupts(struct seq_file *p, int prec) 47 87 { ··· 120 80 ack_bad_irq(irq); 121 81 } 122 82 123 - /* 124 - * asm_do_IRQ is the interface to be used from assembly code. 125 - */ 126 - asmlinkage void __exception_irq_entry 127 - asm_do_IRQ(unsigned int irq, struct pt_regs *regs) 128 - { 129 - struct pt_regs *old_regs; 130 - 131 - irq_enter(); 132 - old_regs = set_irq_regs(regs); 133 - 134 - handle_IRQ(irq, regs); 135 - 136 - set_irq_regs(old_regs); 137 - irq_exit(); 138 - } 139 - 140 83 void __init init_IRQ(void) 141 84 { 142 85 int ret; 86 + 87 + #ifdef CONFIG_IRQSTACKS 88 + init_irq_stacks(); 89 + #endif 143 90 144 91 if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq) 145 92 irqchip_init();
+90
arch/arm/kernel/module.c
··· 68 68 strstarts(name, ".ARM.exidx.exit"); 69 69 } 70 70 71 + #ifdef CONFIG_ARM_HAS_GROUP_RELOCS 72 + /* 73 + * This implements the partitioning algorithm for group relocations as 74 + * documented in the ARM AArch32 ELF psABI (IHI 0044). 75 + * 76 + * A single PC-relative symbol reference is divided in up to 3 add or subtract 77 + * operations, where the final one could be incorporated into a load/store 78 + * instruction with immediate offset. E.g., 79 + * 80 + * ADD Rd, PC, #... or ADD Rd, PC, #... 81 + * ADD Rd, Rd, #... ADD Rd, Rd, #... 82 + * LDR Rd, [Rd, #...] ADD Rd, Rd, #... 83 + * 84 + * The latter has a guaranteed range of only 16 MiB (3x8 == 24 bits), so it is 85 + * of limited use in the kernel. However, the ADD/ADD/LDR combo has a range of 86 + * -/+ 256 MiB, (2x8 + 12 == 28 bits), which means it has sufficient range for 87 + * any in-kernel symbol reference (unless module PLTs are being used). 88 + * 89 + * The main advantage of this approach over the typical pattern using a literal 90 + * load is that literal loads may miss in the D-cache, and generally lead to 91 + * lower cache efficiency for variables that are referenced often from many 92 + * different places in the code. 93 + */ 94 + static u32 get_group_rem(u32 group, u32 *offset) 95 + { 96 + u32 val = *offset; 97 + u32 shift; 98 + do { 99 + shift = val ? (31 - __fls(val)) & ~1 : 32; 100 + *offset = val; 101 + if (!val) 102 + break; 103 + val &= 0xffffff >> shift; 104 + } while (group--); 105 + return shift; 106 + } 107 + #endif 108 + 71 109 int 72 110 apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, 73 111 unsigned int relindex, struct module *module) ··· 120 82 unsigned long loc; 121 83 Elf32_Sym *sym; 122 84 const char *symname; 85 + #ifdef CONFIG_ARM_HAS_GROUP_RELOCS 86 + u32 shift, group = 1; 87 + #endif 123 88 s32 offset; 124 89 u32 tmp; 125 90 #ifdef CONFIG_THUMB2_KERNEL ··· 253 212 *(u32 *)loc = __opcode_to_mem_arm(tmp); 254 213 break; 255 214 215 + #ifdef CONFIG_ARM_HAS_GROUP_RELOCS 216 + case R_ARM_ALU_PC_G0_NC: 217 + group = 0; 218 + fallthrough; 219 + case R_ARM_ALU_PC_G1_NC: 220 + tmp = __mem_to_opcode_arm(*(u32 *)loc); 221 + offset = ror32(tmp & 0xff, (tmp & 0xf00) >> 7); 222 + if (tmp & BIT(22)) 223 + offset = -offset; 224 + offset += sym->st_value - loc; 225 + if (offset < 0) { 226 + offset = -offset; 227 + tmp = (tmp & ~BIT(23)) | BIT(22); // SUB opcode 228 + } else { 229 + tmp = (tmp & ~BIT(22)) | BIT(23); // ADD opcode 230 + } 231 + 232 + shift = get_group_rem(group, &offset); 233 + if (shift < 24) { 234 + offset >>= 24 - shift; 235 + offset |= (shift + 8) << 7; 236 + } 237 + *(u32 *)loc = __opcode_to_mem_arm((tmp & ~0xfff) | offset); 238 + break; 239 + 240 + case R_ARM_LDR_PC_G2: 241 + tmp = __mem_to_opcode_arm(*(u32 *)loc); 242 + offset = tmp & 0xfff; 243 + if (~tmp & BIT(23)) // U bit cleared? 244 + offset = -offset; 245 + offset += sym->st_value - loc; 246 + if (offset < 0) { 247 + offset = -offset; 248 + tmp &= ~BIT(23); // clear U bit 249 + } else { 250 + tmp |= BIT(23); // set U bit 251 + } 252 + get_group_rem(2, &offset); 253 + 254 + if (offset > 0xfff) { 255 + pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", 256 + module->name, relindex, i, symname, 257 + ELF32_R_TYPE(rel->r_info), loc, 258 + sym->st_value); 259 + return -ENOEXEC; 260 + } 261 + *(u32 *)loc = __opcode_to_mem_arm((tmp & ~0xfff) | offset); 262 + break; 263 + #endif 256 264 #ifdef CONFIG_THUMB2_KERNEL 257 265 case R_ARM_THM_CALL: 258 266 case R_ARM_THM_JUMP24:
+6 -1
arch/arm/kernel/process.c
··· 36 36 37 37 #include "signal.h" 38 38 39 - #ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO 39 + #if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP) 40 40 DEFINE_PER_CPU(struct task_struct *, __entry_task); 41 41 #endif 42 42 ··· 44 44 #include <linux/stackprotector.h> 45 45 unsigned long __stack_chk_guard __read_mostly; 46 46 EXPORT_SYMBOL(__stack_chk_guard); 47 + #endif 48 + 49 + #ifndef CONFIG_CURRENT_POINTER_IN_TPIDRURO 50 + asmlinkage struct task_struct *__current; 51 + EXPORT_SYMBOL(__current); 47 52 #endif 48 53 49 54 static const char *processor_modes[] __maybe_unused = {
+2 -1
arch/arm/kernel/return_address.c
··· 41 41 frame.fp = (unsigned long)__builtin_frame_address(0); 42 42 frame.sp = current_stack_pointer; 43 43 frame.lr = (unsigned long)__builtin_return_address(0); 44 - frame.pc = (unsigned long)return_address; 44 + here: 45 + frame.pc = (unsigned long)&&here; 45 46 #ifdef CONFIG_KRETPROBES 46 47 frame.kr_cur = NULL; 47 48 frame.tsk = current;
+4 -4
arch/arm/kernel/setup.c
··· 141 141 int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN; 142 142 143 143 struct stack { 144 - u32 irq[3]; 145 - u32 abt[3]; 146 - u32 und[3]; 147 - u32 fiq[3]; 144 + u32 irq[4]; 145 + u32 abt[4]; 146 + u32 und[4]; 147 + u32 fiq[4]; 148 148 } ____cacheline_aligned; 149 149 150 150 #ifndef CONFIG_CPU_V7M
+13
arch/arm/kernel/sleep.S
··· 67 67 ldr r4, =cpu_suspend_size 68 68 #endif 69 69 mov r5, sp @ current virtual SP 70 + #ifdef CONFIG_VMAP_STACK 71 + @ Run the suspend code from the overflow stack so we don't have to rely 72 + @ on vmalloc-to-phys conversions anywhere in the arch suspend code. 73 + @ The original SP value captured in R5 will be restored on the way out. 74 + ldr_this_cpu sp, overflow_stack_ptr, r6, r7 75 + #endif 70 76 add r4, r4, #12 @ Space for pgd, virt sp, phys resume fn 71 77 sub sp, sp, r4 @ allocate CPU state on stack 72 78 ldr r3, =sleep_save_sp ··· 119 113 ENDPROC(cpu_resume_mmu) 120 114 .popsection 121 115 cpu_resume_after_mmu: 116 + #if defined(CONFIG_VMAP_STACK) && !defined(CONFIG_ARM_LPAE) 117 + @ Before using the vmap'ed stack, we have to switch to swapper_pg_dir 118 + @ as the ID map does not cover the vmalloc region. 119 + mrc p15, 0, ip, c2, c0, 1 @ read TTBR1 120 + mcr p15, 0, ip, c2, c0, 0 @ set TTBR0 121 + instr_sync 122 + #endif 122 123 bl cpu_init @ restore the und/abt/irq banked regs 123 124 mov r0, #0 @ return zero on success 124 125 ldmfd sp!, {r4 - r11, pc}
+6 -5
arch/arm/kernel/smp.c
··· 400 400 check_cpu_icache_size(cpuid); 401 401 } 402 402 403 + static void set_current(struct task_struct *cur) 404 + { 405 + /* Set TPIDRURO */ 406 + asm("mcr p15, 0, %0, c13, c0, 3" :: "r"(cur) : "memory"); 407 + } 408 + 403 409 /* 404 410 * This is the secondary CPU boot entry. We're using this CPUs 405 411 * idle thread stack, but a set of temporary page tables. ··· 634 628 /* 635 629 * Main handler for inter-processor interrupts 636 630 */ 637 - asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) 638 - { 639 - handle_IPI(ipinr, regs); 640 - } 641 - 642 631 static void do_handle_IPI(int ipinr) 643 632 { 644 633 unsigned int cpu = smp_processor_id();
+2 -1
arch/arm/kernel/stacktrace.c
··· 160 160 frame.fp = (unsigned long)__builtin_frame_address(0); 161 161 frame.sp = current_stack_pointer; 162 162 frame.lr = (unsigned long)__builtin_return_address(0); 163 - frame.pc = (unsigned long)__save_stack_trace; 163 + here: 164 + frame.pc = (unsigned long)&&here; 164 165 } 165 166 #ifdef CONFIG_KRETPROBES 166 167 frame.kr_cur = NULL;
+87 -6
arch/arm/kernel/traps.c
··· 36 36 #include <asm/ptrace.h> 37 37 #include <asm/unwind.h> 38 38 #include <asm/tls.h> 39 + #include <asm/stacktrace.h> 39 40 #include <asm/system_misc.h> 40 41 #include <asm/opcodes.h> 41 42 ··· 62 61 __setup("user_debug=", user_debug_setup); 63 62 #endif 64 63 65 - static void dump_mem(const char *, const char *, unsigned long, unsigned long); 66 - 67 64 void dump_backtrace_entry(unsigned long where, unsigned long from, 68 65 unsigned long frame, const char *loglvl) 69 66 { 70 67 unsigned long end = frame + 4 + sizeof(struct pt_regs); 68 + 69 + if (IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER) && 70 + IS_ENABLED(CONFIG_CC_IS_GCC) && 71 + end > ALIGN(frame, THREAD_SIZE)) { 72 + /* 73 + * If we are walking past the end of the stack, it may be due 74 + * to the fact that we are on an IRQ or overflow stack. In this 75 + * case, we can load the address of the other stack from the 76 + * frame record. 77 + */ 78 + frame = ((unsigned long *)frame)[-2] - 4; 79 + end = frame + 4 + sizeof(struct pt_regs); 80 + } 71 81 72 82 #ifndef CONFIG_KALLSYMS 73 83 printk("%sFunction entered at [<%08lx>] from [<%08lx>]\n", ··· 123 111 static int verify_stack(unsigned long sp) 124 112 { 125 113 if (sp < PAGE_OFFSET || 126 - (sp > (unsigned long)high_memory && high_memory != NULL)) 114 + (!IS_ENABLED(CONFIG_VMAP_STACK) && 115 + sp > (unsigned long)high_memory && high_memory != NULL)) 127 116 return -EFAULT; 128 117 129 118 return 0; ··· 134 121 /* 135 122 * Dump out the contents of some memory nicely... 136 123 */ 137 - static void dump_mem(const char *lvl, const char *str, unsigned long bottom, 138 - unsigned long top) 124 + void dump_mem(const char *lvl, const char *str, unsigned long bottom, 125 + unsigned long top) 139 126 { 140 127 unsigned long first; 141 128 int i; ··· 294 281 295 282 if (!user_mode(regs) || in_interrupt()) { 296 283 dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp, 297 - THREAD_SIZE + (unsigned long)task_stack_page(tsk)); 284 + ALIGN(regs->ARM_sp - THREAD_SIZE, THREAD_ALIGN) 285 + + THREAD_SIZE); 298 286 dump_backtrace(regs, tsk, KERN_EMERG); 299 287 dump_instr(KERN_EMERG, regs); 300 288 } ··· 893 879 * image can be used. 894 880 */ 895 881 } 882 + #endif 883 + 884 + #ifdef CONFIG_VMAP_STACK 885 + 886 + DECLARE_PER_CPU(u8 *, irq_stack_ptr); 887 + 888 + asmlinkage DEFINE_PER_CPU(u8 *, overflow_stack_ptr); 889 + 890 + static int __init allocate_overflow_stacks(void) 891 + { 892 + u8 *stack; 893 + int cpu; 894 + 895 + for_each_possible_cpu(cpu) { 896 + stack = (u8 *)__get_free_page(GFP_KERNEL); 897 + if (WARN_ON(!stack)) 898 + return -ENOMEM; 899 + per_cpu(overflow_stack_ptr, cpu) = &stack[OVERFLOW_STACK_SIZE]; 900 + } 901 + return 0; 902 + } 903 + early_initcall(allocate_overflow_stacks); 904 + 905 + asmlinkage void handle_bad_stack(struct pt_regs *regs) 906 + { 907 + unsigned long tsk_stk = (unsigned long)current->stack; 908 + #ifdef CONFIG_IRQSTACKS 909 + unsigned long irq_stk = (unsigned long)this_cpu_read(irq_stack_ptr); 910 + #endif 911 + unsigned long ovf_stk = (unsigned long)this_cpu_read(overflow_stack_ptr); 912 + 913 + console_verbose(); 914 + pr_emerg("Insufficient stack space to handle exception!"); 915 + 916 + pr_emerg("Task stack: [0x%08lx..0x%08lx]\n", 917 + tsk_stk, tsk_stk + THREAD_SIZE); 918 + #ifdef CONFIG_IRQSTACKS 919 + pr_emerg("IRQ stack: [0x%08lx..0x%08lx]\n", 920 + irq_stk - THREAD_SIZE, irq_stk); 921 + #endif 922 + pr_emerg("Overflow stack: [0x%08lx..0x%08lx]\n", 923 + ovf_stk - OVERFLOW_STACK_SIZE, ovf_stk); 924 + 925 + die("kernel stack overflow", regs, 0); 926 + } 927 + 928 + #ifndef CONFIG_ARM_LPAE 929 + /* 930 + * Normally, we rely on the logic in do_translation_fault() to update stale PMD 931 + * entries covering the vmalloc space in a task's page tables when it first 932 + * accesses the region in question. Unfortunately, this is not sufficient when 933 + * the task stack resides in the vmalloc region, as do_translation_fault() is a 934 + * C function that needs a stack to run. 935 + * 936 + * So we need to ensure that these PMD entries are up to date *before* the MM 937 + * switch. As we already have some logic in the MM switch path that takes care 938 + * of this, let's trigger it by bumping the counter every time the core vmalloc 939 + * code modifies a PMD entry in the vmalloc region. Use release semantics on 940 + * the store so that other CPUs observing the counter's new value are 941 + * guaranteed to see the updated page table entries as well. 942 + */ 943 + void arch_sync_kernel_mappings(unsigned long start, unsigned long end) 944 + { 945 + if (start < VMALLOC_END && end > VMALLOC_START) 946 + atomic_inc_return_release(&init_mm.context.vmalloc_seq); 947 + } 948 + #endif 896 949 #endif
+49 -15
arch/arm/kernel/unwind.c
··· 33 33 #include <asm/traps.h> 34 34 #include <asm/unwind.h> 35 35 36 + #include "reboot.h" 37 + 36 38 /* Dummy functions to avoid linker complaints */ 37 39 void __aeabi_unwind_cpp_pr0(void) 38 40 { ··· 55 53 unsigned long vrs[16]; /* virtual register set */ 56 54 const unsigned long *insn; /* pointer to the current instructions word */ 57 55 unsigned long sp_high; /* highest value of sp allowed */ 56 + unsigned long *lr_addr; /* address of LR value on the stack */ 58 57 /* 59 58 * 1 : check for stack overflow for each register pop. 60 59 * 0 : save overhead if there is plenty of stack remaining. ··· 240 237 * from being tracked by KASAN. 241 238 */ 242 239 ctrl->vrs[reg] = READ_ONCE_NOCHECK(*(*vsp)); 240 + if (reg == 14) 241 + ctrl->lr_addr = *vsp; 243 242 (*vsp)++; 244 243 return URC_OK; 245 244 } ··· 261 256 mask >>= 1; 262 257 reg++; 263 258 } 264 - if (!load_sp) 259 + if (!load_sp) { 265 260 ctrl->vrs[SP] = (unsigned long)vsp; 261 + } 266 262 267 263 return URC_OK; 268 264 } ··· 319 313 320 314 if ((insn & 0xc0) == 0x00) 321 315 ctrl->vrs[SP] += ((insn & 0x3f) << 2) + 4; 322 - else if ((insn & 0xc0) == 0x40) 316 + else if ((insn & 0xc0) == 0x40) { 323 317 ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4; 324 - else if ((insn & 0xf0) == 0x80) { 318 + } else if ((insn & 0xf0) == 0x80) { 325 319 unsigned long mask; 326 320 327 321 insn = (insn << 8) | unwind_get_byte(ctrl); ··· 336 330 if (ret) 337 331 goto error; 338 332 } else if ((insn & 0xf0) == 0x90 && 339 - (insn & 0x0d) != 0x0d) 333 + (insn & 0x0d) != 0x0d) { 340 334 ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f]; 341 - else if ((insn & 0xf0) == 0xa0) { 335 + } else if ((insn & 0xf0) == 0xa0) { 342 336 ret = unwind_exec_pop_r4_to_rN(ctrl, insn); 343 337 if (ret) 344 338 goto error; ··· 381 375 */ 382 376 int unwind_frame(struct stackframe *frame) 383 377 { 384 - unsigned long low; 385 378 const struct unwind_idx *idx; 386 379 struct unwind_ctrl_block ctrl; 380 + unsigned long sp_low; 387 381 388 382 /* store the highest address on the stack to avoid crossing it*/ 389 - low = frame->sp; 390 - ctrl.sp_high = ALIGN(low, THREAD_SIZE); 383 + sp_low = frame->sp; 384 + ctrl.sp_high = ALIGN(sp_low - THREAD_SIZE, THREAD_ALIGN) 385 + + THREAD_SIZE; 391 386 392 387 pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__, 393 388 frame->pc, frame->lr, frame->sp); 394 389 395 - if (!kernel_text_address(frame->pc)) 396 - return -URC_FAILURE; 397 - 398 390 idx = unwind_find_idx(frame->pc); 399 391 if (!idx) { 400 - pr_warn("unwind: Index not found %08lx\n", frame->pc); 392 + if (frame->pc && kernel_text_address(frame->pc)) 393 + pr_warn("unwind: Index not found %08lx\n", frame->pc); 401 394 return -URC_FAILURE; 402 395 } 403 396 ··· 408 403 if (idx->insn == 1) 409 404 /* can't unwind */ 410 405 return -URC_FAILURE; 411 - else if ((idx->insn & 0x80000000) == 0) 406 + else if (frame->pc == prel31_to_addr(&idx->addr_offset)) { 407 + /* 408 + * Unwinding is tricky when we're halfway through the prologue, 409 + * since the stack frame that the unwinder expects may not be 410 + * fully set up yet. However, one thing we do know for sure is 411 + * that if we are unwinding from the very first instruction of 412 + * a function, we are still effectively in the stack frame of 413 + * the caller, and the unwind info has no relevance yet. 414 + */ 415 + if (frame->pc == frame->lr) 416 + return -URC_FAILURE; 417 + frame->pc = frame->lr; 418 + return URC_OK; 419 + } else if ((idx->insn & 0x80000000) == 0) 412 420 /* prel31 to the unwind table */ 413 421 ctrl.insn = (unsigned long *)prel31_to_addr(&idx->insn); 414 422 else if ((idx->insn & 0xff000000) == 0x80000000) ··· 448 430 449 431 ctrl.check_each_pop = 0; 450 432 433 + if (prel31_to_addr(&idx->addr_offset) == (u32)&call_with_stack) { 434 + /* 435 + * call_with_stack() is the only place where we permit SP to 436 + * jump from one stack to another, and since we know it is 437 + * guaranteed to happen, set up the SP bounds accordingly. 438 + */ 439 + sp_low = frame->fp; 440 + ctrl.sp_high = ALIGN(frame->fp, THREAD_SIZE); 441 + } 442 + 451 443 while (ctrl.entries > 0) { 452 444 int urc; 453 445 if ((ctrl.sp_high - ctrl.vrs[SP]) < sizeof(ctrl.vrs)) ··· 465 437 urc = unwind_exec_insn(&ctrl); 466 438 if (urc < 0) 467 439 return urc; 468 - if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= ctrl.sp_high) 440 + if (ctrl.vrs[SP] < sp_low || ctrl.vrs[SP] > ctrl.sp_high) 469 441 return -URC_FAILURE; 470 442 } 471 443 ··· 480 452 frame->sp = ctrl.vrs[SP]; 481 453 frame->lr = ctrl.vrs[LR]; 482 454 frame->pc = ctrl.vrs[PC]; 455 + frame->lr_addr = ctrl.lr_addr; 483 456 484 457 return URC_OK; 485 458 } ··· 504 475 frame.fp = (unsigned long)__builtin_frame_address(0); 505 476 frame.sp = current_stack_pointer; 506 477 frame.lr = (unsigned long)__builtin_return_address(0); 507 - frame.pc = (unsigned long)unwind_backtrace; 478 + /* We are saving the stack and execution state at this 479 + * point, so we should ensure that frame.pc is within 480 + * this block of code. 481 + */ 482 + here: 483 + frame.pc = (unsigned long)&&here; 508 484 } else { 509 485 /* task blocked in __switch_to */ 510 486 frame.fp = thread_saved_fp(tsk);
+2 -2
arch/arm/kernel/vmlinux.lds.S
··· 138 138 #ifdef CONFIG_STRICT_KERNEL_RWX 139 139 . = ALIGN(1<<SECTION_SHIFT); 140 140 #else 141 - . = ALIGN(THREAD_SIZE); 141 + . = ALIGN(THREAD_ALIGN); 142 142 #endif 143 143 __init_end = .; 144 144 145 145 _sdata = .; 146 - RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) 146 + RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_ALIGN) 147 147 _edata = .; 148 148 149 149 BSS_SECTION(0, 0, 0)
+11 -3
arch/arm/lib/backtrace-clang.S
··· 144 144 */ 145 145 1003: ldr sv_lr, [sv_fp, #4] @ get saved lr from next frame 146 146 147 - ldr r0, [sv_lr, #-4] @ get call instruction 147 + 1004: ldr r0, [sv_lr, #-4] @ get call instruction 148 148 ldr r3, .Lopcode+4 149 149 and r2, r3, r0 @ is this a bl call 150 150 teq r2, r3 ··· 164 164 /* 165 165 * Print the function (sv_pc) and where it was called from (sv_lr). 166 166 */ 167 - 1004: mov r0, sv_pc 167 + mov r0, sv_pc 168 168 169 169 mov r1, sv_lr 170 170 mov r2, frame ··· 197 197 198 198 cmp sv_fp, frame @ next frame must be 199 199 mov frame, sv_fp @ above the current frame 200 + #ifdef CONFIG_IRQSTACKS 201 + @ 202 + @ Kernel stacks may be discontiguous in memory. If the next 203 + @ frame is below the previous frame, accept it as long as it 204 + @ lives in kernel memory. 205 + @ 206 + cmpls sv_fp, #PAGE_OFFSET 207 + #endif 200 208 bhi for_each_frame 201 209 202 210 1006: adr r0, .Lbad ··· 218 210 .long 1001b, 1006b 219 211 .long 1002b, 1006b 220 212 .long 1003b, 1006b 221 - .long 1004b, 1006b 213 + .long 1004b, finished_setup 222 214 .long 1005b, 1006b 223 215 .popsection 224 216
+8
arch/arm/lib/backtrace.S
··· 98 98 99 99 cmp sv_fp, frame @ next frame must be 100 100 mov frame, sv_fp @ above the current frame 101 + #ifdef CONFIG_IRQSTACKS 102 + @ 103 + @ Kernel stacks may be discontiguous in memory. If the next 104 + @ frame is below the previous frame, accept it as long as it 105 + @ lives in kernel memory. 106 + @ 107 + cmpls sv_fp, #PAGE_OFFSET 108 + #endif 101 109 bhi for_each_frame 102 110 103 111 1006: adr r0, .Lbad
+25 -8
arch/arm/lib/call_with_stack.S
··· 8 8 9 9 #include <linux/linkage.h> 10 10 #include <asm/assembler.h> 11 + #include <asm/unwind.h> 11 12 12 13 /* 13 14 * void call_with_stack(void (*fn)(void *), void *arg, void *sp) 14 15 * 15 16 * Change the stack to that pointed at by sp, then invoke fn(arg) with 16 17 * the new stack. 18 + * 19 + * The sequence below follows the APCS frame convention for frame pointer 20 + * unwinding, and implements the unwinder annotations needed by the EABI 21 + * unwinder. 17 22 */ 18 - ENTRY(call_with_stack) 19 - str sp, [r2, #-4]! 20 - str lr, [r2, #-4]! 21 23 24 + ENTRY(call_with_stack) 25 + #if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC) 26 + mov ip, sp 27 + push {fp, ip, lr, pc} 28 + sub fp, ip, #4 29 + #else 30 + UNWIND( .fnstart ) 31 + UNWIND( .save {fpreg, lr} ) 32 + push {fpreg, lr} 33 + UNWIND( .setfp fpreg, sp ) 34 + mov fpreg, sp 35 + #endif 22 36 mov sp, r2 23 37 mov r2, r0 24 38 mov r0, r1 25 39 26 - badr lr, 1f 27 - ret r2 40 + bl_r r2 28 41 29 - 1: ldr lr, [sp] 30 - ldr sp, [sp, #4] 31 - ret lr 42 + #if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC) 43 + ldmdb fp, {fp, sp, pc} 44 + #else 45 + mov sp, fpreg 46 + pop {fpreg, pc} 47 + UNWIND( .fnend ) 48 + #endif 32 49 ENDPROC(call_with_stack)
+5 -8
arch/arm/lib/copy_from_user.S
··· 91 91 strb\cond \reg, [\ptr], #1 92 92 .endm 93 93 94 - .macro enter reg1 reg2 94 + .macro enter regs:vararg 95 95 mov r3, #0 96 - stmdb sp!, {r0, r2, r3, \reg1, \reg2} 96 + UNWIND( .save {r0, r2, r3, \regs} ) 97 + stmdb sp!, {r0, r2, r3, \regs} 97 98 .endm 98 99 99 - .macro usave reg1 reg2 100 - UNWIND( .save {r0, r2, r3, \reg1, \reg2} ) 101 - .endm 102 - 103 - .macro exit reg1 reg2 100 + .macro exit regs:vararg 104 101 add sp, sp, #8 105 - ldmfd sp!, {r0, \reg1, \reg2} 102 + ldmfd sp!, {r0, \regs} 106 103 .endm 107 104 108 105 .text
+23 -44
arch/arm/lib/copy_template.S
··· 69 69 * than one 32bit instruction in Thumb-2) 70 70 */ 71 71 72 - 73 72 UNWIND( .fnstart ) 74 - enter r4, lr 75 - UNWIND( .fnend ) 76 - 77 - UNWIND( .fnstart ) 78 - usave r4, lr @ in first stmdb block 73 + enter r4, UNWIND(fpreg,) lr 74 + UNWIND( .setfp fpreg, sp ) 75 + UNWIND( mov fpreg, sp ) 79 76 80 77 subs r2, r2, #4 81 78 blt 8f ··· 83 86 bne 10f 84 87 85 88 1: subs r2, r2, #(28) 86 - stmfd sp!, {r5 - r8} 87 - UNWIND( .fnend ) 88 - 89 - UNWIND( .fnstart ) 90 - usave r4, lr 91 - UNWIND( .save {r5 - r8} ) @ in second stmfd block 89 + stmfd sp!, {r5, r6, r8, r9} 92 90 blt 5f 93 91 94 92 CALGN( ands ip, r0, #31 ) ··· 102 110 PLD( pld [r1, #92] ) 103 111 104 112 3: PLD( pld [r1, #124] ) 105 - 4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f 113 + 4: ldr8w r1, r3, r4, r5, r6, r8, r9, ip, lr, abort=20f 106 114 subs r2, r2, #32 107 - str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f 115 + str8w r0, r3, r4, r5, r6, r8, r9, ip, lr, abort=20f 108 116 bge 3b 109 117 PLD( cmn r2, #96 ) 110 118 PLD( bge 4b ) ··· 124 132 ldr1w r1, r4, abort=20f 125 133 ldr1w r1, r5, abort=20f 126 134 ldr1w r1, r6, abort=20f 127 - ldr1w r1, r7, abort=20f 128 135 ldr1w r1, r8, abort=20f 136 + ldr1w r1, r9, abort=20f 129 137 ldr1w r1, lr, abort=20f 130 138 131 139 #if LDR1W_SHIFT < STR1W_SHIFT ··· 142 150 str1w r0, r4, abort=20f 143 151 str1w r0, r5, abort=20f 144 152 str1w r0, r6, abort=20f 145 - str1w r0, r7, abort=20f 146 153 str1w r0, r8, abort=20f 154 + str1w r0, r9, abort=20f 147 155 str1w r0, lr, abort=20f 148 156 149 157 CALGN( bcs 2b ) 150 158 151 - 7: ldmfd sp!, {r5 - r8} 152 - UNWIND( .fnend ) @ end of second stmfd block 159 + 7: ldmfd sp!, {r5, r6, r8, r9} 153 160 154 - UNWIND( .fnstart ) 155 - usave r4, lr @ still in first stmdb block 156 161 8: movs r2, r2, lsl #31 157 162 ldr1b r1, r3, ne, abort=21f 158 163 ldr1b r1, r4, cs, abort=21f ··· 158 169 str1b r0, r4, cs, abort=21f 159 170 str1b r0, ip, cs, abort=21f 160 171 161 - exit r4, pc 172 + exit r4, UNWIND(fpreg,) pc 162 173 163 174 9: rsb ip, ip, #4 164 175 cmp ip, #2 ··· 178 189 ldr1w r1, lr, abort=21f 179 190 beq 17f 180 191 bgt 18f 181 - UNWIND( .fnend ) 182 192 183 193 184 194 .macro forward_copy_shift pull push 185 195 186 - UNWIND( .fnstart ) 187 - usave r4, lr @ still in first stmdb block 188 196 subs r2, r2, #28 189 197 blt 14f 190 198 ··· 191 205 CALGN( subcc r2, r2, ip ) 192 206 CALGN( bcc 15f ) 193 207 194 - 11: stmfd sp!, {r5 - r9} 195 - UNWIND( .fnend ) 208 + 11: stmfd sp!, {r5, r6, r8 - r10} 196 209 197 - UNWIND( .fnstart ) 198 - usave r4, lr 199 - UNWIND( .save {r5 - r9} ) @ in new second stmfd block 200 210 PLD( pld [r1, #0] ) 201 211 PLD( subs r2, r2, #96 ) 202 212 PLD( pld [r1, #28] ) ··· 201 219 PLD( pld [r1, #92] ) 202 220 203 221 12: PLD( pld [r1, #124] ) 204 - 13: ldr4w r1, r4, r5, r6, r7, abort=19f 222 + 13: ldr4w r1, r4, r5, r6, r8, abort=19f 205 223 mov r3, lr, lspull #\pull 206 224 subs r2, r2, #32 207 - ldr4w r1, r8, r9, ip, lr, abort=19f 225 + ldr4w r1, r9, r10, ip, lr, abort=19f 208 226 orr r3, r3, r4, lspush #\push 209 227 mov r4, r4, lspull #\pull 210 228 orr r4, r4, r5, lspush #\push 211 229 mov r5, r5, lspull #\pull 212 230 orr r5, r5, r6, lspush #\push 213 231 mov r6, r6, lspull #\pull 214 - orr r6, r6, r7, lspush #\push 215 - mov r7, r7, lspull #\pull 216 - orr r7, r7, r8, lspush #\push 232 + orr r6, r6, r8, lspush #\push 217 233 mov r8, r8, lspull #\pull 218 234 orr r8, r8, r9, lspush #\push 219 235 mov r9, r9, lspull #\pull 220 - orr r9, r9, ip, lspush #\push 236 + orr r9, r9, r10, lspush #\push 237 + mov r10, r10, lspull #\pull 238 + orr r10, r10, ip, lspush #\push 221 239 mov ip, ip, lspull #\pull 222 240 orr ip, ip, lr, lspush #\push 223 - str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, abort=19f 241 + str8w r0, r3, r4, r5, r6, r8, r9, r10, ip, abort=19f 224 242 bge 12b 225 243 PLD( cmn r2, #96 ) 226 244 PLD( bge 13b ) 227 245 228 - ldmfd sp!, {r5 - r9} 229 - UNWIND( .fnend ) @ end of the second stmfd block 246 + ldmfd sp!, {r5, r6, r8 - r10} 230 247 231 - UNWIND( .fnstart ) 232 - usave r4, lr @ still in first stmdb block 233 248 14: ands ip, r2, #28 234 249 beq 16f 235 250 ··· 241 262 242 263 16: sub r1, r1, #(\push / 8) 243 264 b 8b 244 - UNWIND( .fnend ) 245 265 246 266 .endm 247 267 ··· 251 273 252 274 18: forward_copy_shift pull=24 push=8 253 275 276 + UNWIND( .fnend ) 254 277 255 278 /* 256 279 * Abort preamble and completion macros. ··· 261 282 */ 262 283 263 284 .macro copy_abort_preamble 264 - 19: ldmfd sp!, {r5 - r9} 285 + 19: ldmfd sp!, {r5, r6, r8 - r10} 265 286 b 21f 266 - 20: ldmfd sp!, {r5 - r8} 287 + 20: ldmfd sp!, {r5, r6, r8, r9} 267 288 21: 268 289 .endm 269 290 270 291 .macro copy_abort_end 271 - ldmfd sp!, {r4, pc} 292 + ldmfd sp!, {r4, UNWIND(fpreg,) pc} 272 293 .endm 273 294
+5 -8
arch/arm/lib/copy_to_user.S
··· 90 90 strusr \reg, \ptr, 1, \cond, abort=\abort 91 91 .endm 92 92 93 - .macro enter reg1 reg2 93 + .macro enter regs:vararg 94 94 mov r3, #0 95 - stmdb sp!, {r0, r2, r3, \reg1, \reg2} 95 + UNWIND( .save {r0, r2, r3, \regs} ) 96 + stmdb sp!, {r0, r2, r3, \regs} 96 97 .endm 97 98 98 - .macro usave reg1 reg2 99 - UNWIND( .save {r0, r2, r3, \reg1, \reg2} ) 100 - .endm 101 - 102 - .macro exit reg1 reg2 99 + .macro exit regs:vararg 103 100 add sp, sp, #8 104 - ldmfd sp!, {r0, \reg1, \reg2} 101 + ldmfd sp!, {r0, \regs} 105 102 .endm 106 103 107 104 .text
+5 -8
arch/arm/lib/memcpy.S
··· 42 42 strb\cond \reg, [\ptr], #1 43 43 .endm 44 44 45 - .macro enter reg1 reg2 46 - stmdb sp!, {r0, \reg1, \reg2} 45 + .macro enter regs:vararg 46 + UNWIND( .save {r0, \regs} ) 47 + stmdb sp!, {r0, \regs} 47 48 .endm 48 49 49 - .macro usave reg1 reg2 50 - UNWIND( .save {r0, \reg1, \reg2} ) 51 - .endm 52 - 53 - .macro exit reg1 reg2 54 - ldmfd sp!, {r0, \reg1, \reg2} 50 + .macro exit regs:vararg 51 + ldmfd sp!, {r0, \regs} 55 52 .endm 56 53 57 54 .text
+20 -40
arch/arm/lib/memmove.S
··· 31 31 subs ip, r0, r1 32 32 cmphi r2, ip 33 33 bls __memcpy 34 - 35 - stmfd sp!, {r0, r4, lr} 36 34 UNWIND( .fnend ) 37 35 38 36 UNWIND( .fnstart ) 39 - UNWIND( .save {r0, r4, lr} ) @ in first stmfd block 37 + UNWIND( .save {r0, r4, fpreg, lr} ) 38 + stmfd sp!, {r0, r4, UNWIND(fpreg,) lr} 39 + UNWIND( .setfp fpreg, sp ) 40 + UNWIND( mov fpreg, sp ) 40 41 add r1, r1, r2 41 42 add r0, r0, r2 42 43 subs r2, r2, #4 ··· 49 48 bne 10f 50 49 51 50 1: subs r2, r2, #(28) 52 - stmfd sp!, {r5 - r8} 53 - UNWIND( .fnend ) 54 - 55 - UNWIND( .fnstart ) 56 - UNWIND( .save {r0, r4, lr} ) 57 - UNWIND( .save {r5 - r8} ) @ in second stmfd block 51 + stmfd sp!, {r5, r6, r8, r9} 58 52 blt 5f 59 53 60 54 CALGN( ands ip, r0, #31 ) ··· 68 72 PLD( pld [r1, #-96] ) 69 73 70 74 3: PLD( pld [r1, #-128] ) 71 - 4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr} 75 + 4: ldmdb r1!, {r3, r4, r5, r6, r8, r9, ip, lr} 72 76 subs r2, r2, #32 73 - stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr} 77 + stmdb r0!, {r3, r4, r5, r6, r8, r9, ip, lr} 74 78 bge 3b 75 79 PLD( cmn r2, #96 ) 76 80 PLD( bge 4b ) ··· 84 88 W(ldr) r4, [r1, #-4]! 85 89 W(ldr) r5, [r1, #-4]! 86 90 W(ldr) r6, [r1, #-4]! 87 - W(ldr) r7, [r1, #-4]! 88 91 W(ldr) r8, [r1, #-4]! 92 + W(ldr) r9, [r1, #-4]! 89 93 W(ldr) lr, [r1, #-4]! 90 94 91 95 add pc, pc, ip ··· 95 99 W(str) r4, [r0, #-4]! 96 100 W(str) r5, [r0, #-4]! 97 101 W(str) r6, [r0, #-4]! 98 - W(str) r7, [r0, #-4]! 99 102 W(str) r8, [r0, #-4]! 103 + W(str) r9, [r0, #-4]! 100 104 W(str) lr, [r0, #-4]! 101 105 102 106 CALGN( bcs 2b ) 103 107 104 - 7: ldmfd sp!, {r5 - r8} 105 - UNWIND( .fnend ) @ end of second stmfd block 106 - 107 - UNWIND( .fnstart ) 108 - UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 108 + 7: ldmfd sp!, {r5, r6, r8, r9} 109 109 110 110 8: movs r2, r2, lsl #31 111 111 ldrbne r3, [r1, #-1]! ··· 110 118 strbne r3, [r0, #-1]! 111 119 strbcs r4, [r0, #-1]! 112 120 strbcs ip, [r0, #-1] 113 - ldmfd sp!, {r0, r4, pc} 121 + ldmfd sp!, {r0, r4, UNWIND(fpreg,) pc} 114 122 115 123 9: cmp ip, #2 116 124 ldrbgt r3, [r1, #-1]! ··· 129 137 ldr r3, [r1, #0] 130 138 beq 17f 131 139 blt 18f 132 - UNWIND( .fnend ) 133 140 134 141 135 142 .macro backward_copy_shift push pull 136 143 137 - UNWIND( .fnstart ) 138 - UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 139 144 subs r2, r2, #28 140 145 blt 14f 141 146 ··· 141 152 CALGN( subcc r2, r2, ip ) 142 153 CALGN( bcc 15f ) 143 154 144 - 11: stmfd sp!, {r5 - r9} 145 - UNWIND( .fnend ) 146 - 147 - UNWIND( .fnstart ) 148 - UNWIND( .save {r0, r4, lr} ) 149 - UNWIND( .save {r5 - r9} ) @ in new second stmfd block 155 + 11: stmfd sp!, {r5, r6, r8 - r10} 150 156 151 157 PLD( pld [r1, #-4] ) 152 158 PLD( subs r2, r2, #96 ) ··· 151 167 PLD( pld [r1, #-96] ) 152 168 153 169 12: PLD( pld [r1, #-128] ) 154 - 13: ldmdb r1!, {r7, r8, r9, ip} 170 + 13: ldmdb r1!, {r8, r9, r10, ip} 155 171 mov lr, r3, lspush #\push 156 172 subs r2, r2, #32 157 173 ldmdb r1!, {r3, r4, r5, r6} 158 174 orr lr, lr, ip, lspull #\pull 159 175 mov ip, ip, lspush #\push 160 - orr ip, ip, r9, lspull #\pull 176 + orr ip, ip, r10, lspull #\pull 177 + mov r10, r10, lspush #\push 178 + orr r10, r10, r9, lspull #\pull 161 179 mov r9, r9, lspush #\push 162 180 orr r9, r9, r8, lspull #\pull 163 181 mov r8, r8, lspush #\push 164 - orr r8, r8, r7, lspull #\pull 165 - mov r7, r7, lspush #\push 166 - orr r7, r7, r6, lspull #\pull 182 + orr r8, r8, r6, lspull #\pull 167 183 mov r6, r6, lspush #\push 168 184 orr r6, r6, r5, lspull #\pull 169 185 mov r5, r5, lspush #\push 170 186 orr r5, r5, r4, lspull #\pull 171 187 mov r4, r4, lspush #\push 172 188 orr r4, r4, r3, lspull #\pull 173 - stmdb r0!, {r4 - r9, ip, lr} 189 + stmdb r0!, {r4 - r6, r8 - r10, ip, lr} 174 190 bge 12b 175 191 PLD( cmn r2, #96 ) 176 192 PLD( bge 13b ) 177 193 178 - ldmfd sp!, {r5 - r9} 179 - UNWIND( .fnend ) @ end of the second stmfd block 180 - 181 - UNWIND( .fnstart ) 182 - UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 194 + ldmfd sp!, {r5, r6, r8 - r10} 183 195 184 196 14: ands ip, r2, #28 185 197 beq 16f ··· 191 211 192 212 16: add r1, r1, #(\pull / 8) 193 213 b 8b 194 - UNWIND( .fnend ) 195 214 196 215 .endm 197 216 ··· 201 222 202 223 18: backward_copy_shift push=24 pull=8 203 224 225 + UNWIND( .fnend ) 204 226 ENDPROC(memmove) 205 227 ENDPROC(__memmove)
+3 -4
arch/arm/lib/memset.S
··· 28 28 mov r3, r1 29 29 7: cmp r2, #16 30 30 blt 4f 31 + UNWIND( .fnend ) 31 32 32 33 #if ! CALGN(1)+0 33 34 34 35 /* 35 36 * We need 2 extra registers for this loop - use r8 and the LR 36 37 */ 37 - stmfd sp!, {r8, lr} 38 - UNWIND( .fnend ) 39 38 UNWIND( .fnstart ) 40 39 UNWIND( .save {r8, lr} ) 40 + stmfd sp!, {r8, lr} 41 41 mov r8, r1 42 42 mov lr, r3 43 43 ··· 66 66 * whole cache lines at once. 67 67 */ 68 68 69 - stmfd sp!, {r4-r8, lr} 70 - UNWIND( .fnend ) 71 69 UNWIND( .fnstart ) 72 70 UNWIND( .save {r4-r8, lr} ) 71 + stmfd sp!, {r4-r8, lr} 73 72 mov r4, r1 74 73 mov r5, r3 75 74 mov r6, r1
+1
arch/arm/mach-bcm/Makefile
··· 40 40 41 41 # Support for secure monitor traps 42 42 obj-$(CONFIG_ARCH_BCM_MOBILE_SMC) += bcm_kona_smc.o 43 + CFLAGS_REMOVE_bcm_kona_smc.o += $(CC_FLAGS_FTRACE) 43 44 44 45 # BCM2835 45 46 ifeq ($(CONFIG_ARCH_BCM2835),y)
+2 -4
arch/arm/mach-exynos/mcpm-exynos.c
··· 35 35 */ 36 36 #define exynos_v7_exit_coherency_flush(level) \ 37 37 asm volatile( \ 38 - "stmfd sp!, {fp, ip}\n\t"\ 39 38 "mrc p15, 0, r0, c1, c0, 0 @ get SCTLR\n\t" \ 40 39 "bic r0, r0, #"__stringify(CR_C)"\n\t" \ 41 40 "mcr p15, 0, r0, c1, c0, 0 @ set SCTLR\n\t" \ ··· 49 50 "mcr p15, 0, r0, c1, c0, 1 @ set ACTLR\n\t" \ 50 51 "isb\n\t" \ 51 52 "dsb\n\t" \ 52 - "ldmfd sp!, {fp, ip}" \ 53 53 : \ 54 54 : "Ir" (pmu_base_addr + S5P_INFORM0) \ 55 - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ 56 - "r9", "r10", "lr", "memory") 55 + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", \ 56 + "r9", "r10", "ip", "lr", "memory") 57 57 58 58 static int exynos_cpu_powerup(unsigned int cpu, unsigned int cluster) 59 59 {
+87
arch/arm/mach-footbridge/common.c
··· 27 27 28 28 #include "common.h" 29 29 30 + #include <mach/hardware.h> 31 + #include <mach/irqs.h> 32 + #include <asm/hardware/dec21285.h> 33 + 34 + static int dc21285_get_irq(void) 35 + { 36 + void __iomem *irqstatus = (void __iomem *)CSR_IRQ_STATUS; 37 + u32 mask = readl(irqstatus); 38 + 39 + if (mask & IRQ_MASK_SDRAMPARITY) 40 + return IRQ_SDRAMPARITY; 41 + 42 + if (mask & IRQ_MASK_UART_RX) 43 + return IRQ_CONRX; 44 + 45 + if (mask & IRQ_MASK_DMA1) 46 + return IRQ_DMA1; 47 + 48 + if (mask & IRQ_MASK_DMA2) 49 + return IRQ_DMA2; 50 + 51 + if (mask & IRQ_MASK_IN0) 52 + return IRQ_IN0; 53 + 54 + if (mask & IRQ_MASK_IN1) 55 + return IRQ_IN1; 56 + 57 + if (mask & IRQ_MASK_IN2) 58 + return IRQ_IN2; 59 + 60 + if (mask & IRQ_MASK_IN3) 61 + return IRQ_IN3; 62 + 63 + if (mask & IRQ_MASK_PCI) 64 + return IRQ_PCI; 65 + 66 + if (mask & IRQ_MASK_DOORBELLHOST) 67 + return IRQ_DOORBELLHOST; 68 + 69 + if (mask & IRQ_MASK_I2OINPOST) 70 + return IRQ_I2OINPOST; 71 + 72 + if (mask & IRQ_MASK_TIMER1) 73 + return IRQ_TIMER1; 74 + 75 + if (mask & IRQ_MASK_TIMER2) 76 + return IRQ_TIMER2; 77 + 78 + if (mask & IRQ_MASK_TIMER3) 79 + return IRQ_TIMER3; 80 + 81 + if (mask & IRQ_MASK_UART_TX) 82 + return IRQ_CONTX; 83 + 84 + if (mask & IRQ_MASK_PCI_ABORT) 85 + return IRQ_PCI_ABORT; 86 + 87 + if (mask & IRQ_MASK_PCI_SERR) 88 + return IRQ_PCI_SERR; 89 + 90 + if (mask & IRQ_MASK_DISCARD_TIMER) 91 + return IRQ_DISCARD_TIMER; 92 + 93 + if (mask & IRQ_MASK_PCI_DPERR) 94 + return IRQ_PCI_DPERR; 95 + 96 + if (mask & IRQ_MASK_PCI_PERR) 97 + return IRQ_PCI_PERR; 98 + 99 + return 0; 100 + } 101 + 102 + static void dc21285_handle_irq(struct pt_regs *regs) 103 + { 104 + int irq; 105 + do { 106 + irq = dc21285_get_irq(); 107 + if (!irq) 108 + break; 109 + 110 + generic_handle_irq(irq); 111 + } while (1); 112 + } 113 + 114 + 30 115 unsigned int mem_fclk_21285 = 50000000; 31 116 32 117 EXPORT_SYMBOL(mem_fclk_21285); ··· 193 108 194 109 void __init footbridge_init_irq(void) 195 110 { 111 + set_handle_irq(dc21285_handle_irq); 112 + 196 113 __fb_init_irq(); 197 114 198 115 if (!footbridge_cfn_mode())
-107
arch/arm/mach-footbridge/include/mach/entry-macro.S
··· 1 - /* 2 - * arch/arm/mach-footbridge/include/mach/entry-macro.S 3 - * 4 - * Low-level IRQ helper macros for footbridge-based platforms 5 - * 6 - * This file is licensed under the terms of the GNU General Public 7 - * License version 2. This program is licensed "as is" without any 8 - * warranty of any kind, whether express or implied. 9 - */ 10 - #include <mach/hardware.h> 11 - #include <mach/irqs.h> 12 - #include <asm/hardware/dec21285.h> 13 - 14 - .equ dc21285_high, ARMCSR_BASE & 0xff000000 15 - .equ dc21285_low, ARMCSR_BASE & 0x00ffffff 16 - 17 - .macro get_irqnr_preamble, base, tmp 18 - mov \base, #dc21285_high 19 - .if dc21285_low 20 - orr \base, \base, #dc21285_low 21 - .endif 22 - .endm 23 - 24 - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp 25 - ldr \irqstat, [\base, #0x180] @ get interrupts 26 - 27 - mov \irqnr, #IRQ_SDRAMPARITY 28 - tst \irqstat, #IRQ_MASK_SDRAMPARITY 29 - bne 1001f 30 - 31 - tst \irqstat, #IRQ_MASK_UART_RX 32 - movne \irqnr, #IRQ_CONRX 33 - bne 1001f 34 - 35 - tst \irqstat, #IRQ_MASK_DMA1 36 - movne \irqnr, #IRQ_DMA1 37 - bne 1001f 38 - 39 - tst \irqstat, #IRQ_MASK_DMA2 40 - movne \irqnr, #IRQ_DMA2 41 - bne 1001f 42 - 43 - tst \irqstat, #IRQ_MASK_IN0 44 - movne \irqnr, #IRQ_IN0 45 - bne 1001f 46 - 47 - tst \irqstat, #IRQ_MASK_IN1 48 - movne \irqnr, #IRQ_IN1 49 - bne 1001f 50 - 51 - tst \irqstat, #IRQ_MASK_IN2 52 - movne \irqnr, #IRQ_IN2 53 - bne 1001f 54 - 55 - tst \irqstat, #IRQ_MASK_IN3 56 - movne \irqnr, #IRQ_IN3 57 - bne 1001f 58 - 59 - tst \irqstat, #IRQ_MASK_PCI 60 - movne \irqnr, #IRQ_PCI 61 - bne 1001f 62 - 63 - tst \irqstat, #IRQ_MASK_DOORBELLHOST 64 - movne \irqnr, #IRQ_DOORBELLHOST 65 - bne 1001f 66 - 67 - tst \irqstat, #IRQ_MASK_I2OINPOST 68 - movne \irqnr, #IRQ_I2OINPOST 69 - bne 1001f 70 - 71 - tst \irqstat, #IRQ_MASK_TIMER1 72 - movne \irqnr, #IRQ_TIMER1 73 - bne 1001f 74 - 75 - tst \irqstat, #IRQ_MASK_TIMER2 76 - movne \irqnr, #IRQ_TIMER2 77 - bne 1001f 78 - 79 - tst \irqstat, #IRQ_MASK_TIMER3 80 - movne \irqnr, #IRQ_TIMER3 81 - bne 1001f 82 - 83 - tst \irqstat, #IRQ_MASK_UART_TX 84 - movne \irqnr, #IRQ_CONTX 85 - bne 1001f 86 - 87 - tst \irqstat, #IRQ_MASK_PCI_ABORT 88 - movne \irqnr, #IRQ_PCI_ABORT 89 - bne 1001f 90 - 91 - tst \irqstat, #IRQ_MASK_PCI_SERR 92 - movne \irqnr, #IRQ_PCI_SERR 93 - bne 1001f 94 - 95 - tst \irqstat, #IRQ_MASK_DISCARD_TIMER 96 - movne \irqnr, #IRQ_DISCARD_TIMER 97 - bne 1001f 98 - 99 - tst \irqstat, #IRQ_MASK_PCI_DPERR 100 - movne \irqnr, #IRQ_PCI_DPERR 101 - bne 1001f 102 - 103 - tst \irqstat, #IRQ_MASK_PCI_PERR 104 - movne \irqnr, #IRQ_PCI_PERR 105 - 1001: 106 - .endm 107 -
+9 -1
arch/arm/mach-iop32x/cp6.c
··· 7 7 #include <asm/traps.h> 8 8 #include <asm/ptrace.h> 9 9 10 - static int cp6_trap(struct pt_regs *regs, unsigned int instr) 10 + void iop_enable_cp6(void) 11 11 { 12 12 u32 temp; 13 13 ··· 16 16 "mrc p15, 0, %0, c15, c1, 0\n\t" 17 17 "orr %0, %0, #(1 << 6)\n\t" 18 18 "mcr p15, 0, %0, c15, c1, 0\n\t" 19 + "mrc p15, 0, %0, c15, c1, 0\n\t" 20 + "mov %0, %0\n\t" 21 + "sub pc, pc, #4 @ cp_wait\n\t" 19 22 : "=r"(temp)); 23 + } 24 + 25 + static int cp6_trap(struct pt_regs *regs, unsigned int instr) 26 + { 27 + iop_enable_cp6(); 20 28 21 29 return 0; 22 30 }
-31
arch/arm/mach-iop32x/include/mach/entry-macro.S
··· 1 - /* 2 - * arch/arm/mach-iop32x/include/mach/entry-macro.S 3 - * 4 - * Low-level IRQ helper macros for IOP32x-based platforms 5 - * 6 - * This file is licensed under the terms of the GNU General Public 7 - * License version 2. This program is licensed "as is" without any 8 - * warranty of any kind, whether express or implied. 9 - */ 10 - .macro get_irqnr_preamble, base, tmp 11 - mrc p15, 0, \tmp, c15, c1, 0 12 - orr \tmp, \tmp, #(1 << 6) 13 - mcr p15, 0, \tmp, c15, c1, 0 @ Enable cp6 access 14 - mrc p15, 0, \tmp, c15, c1, 0 15 - mov \tmp, \tmp 16 - sub pc, pc, #4 @ cp_wait 17 - .endm 18 - 19 - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp 20 - mrc p6, 0, \irqstat, c8, c0, 0 @ Read IINTSRC 21 - cmp \irqstat, #0 22 - clzne \irqnr, \irqstat 23 - rsbne \irqnr, \irqnr, #31 24 - .endm 25 - 26 - .macro arch_ret_to_user, tmp1, tmp2 27 - mrc p15, 0, \tmp1, c15, c1, 0 28 - ands \tmp2, \tmp1, #(1 << 6) 29 - bicne \tmp1, \tmp1, #(1 << 6) 30 - mcrne p15, 0, \tmp1, c15, c1, 0 @ Disable cp6 access 31 - .endm
+1 -1
arch/arm/mach-iop32x/include/mach/irqs.h
··· 9 9 #ifndef __IRQS_H 10 10 #define __IRQS_H 11 11 12 - #define NR_IRQS 32 12 + #define NR_IRQS 33 13 13 14 14 #endif
+1
arch/arm/mach-iop32x/iop3xx.h
··· 225 225 #include <linux/reboot.h> 226 226 227 227 void iop3xx_map_io(void); 228 + void iop_enable_cp6(void); 228 229 void iop_init_cp6_handler(void); 229 230 void iop_init_time(unsigned long tickrate); 230 231 void iop3xx_restart(enum reboot_mode, const char *);
+26 -3
arch/arm/mach-iop32x/irq.c
··· 29 29 asm volatile("mcr p6, 0, %0, c4, c0, 0" : : "r" (val)); 30 30 } 31 31 32 + static u32 iintsrc_read(void) 33 + { 34 + int irq; 35 + 36 + asm volatile("mrc p6, 0, %0, c8, c0, 0" : "=r" (irq)); 37 + 38 + return irq; 39 + } 40 + 32 41 static void 33 42 iop32x_irq_mask(struct irq_data *d) 34 43 { 35 - iop32x_mask &= ~(1 << d->irq); 44 + iop32x_mask &= ~(1 << (d->irq - 1)); 36 45 intctl_write(iop32x_mask); 37 46 } 38 47 39 48 static void 40 49 iop32x_irq_unmask(struct irq_data *d) 41 50 { 42 - iop32x_mask |= 1 << d->irq; 51 + iop32x_mask |= 1 << (d->irq - 1); 43 52 intctl_write(iop32x_mask); 44 53 } 45 54 ··· 59 50 .irq_unmask = iop32x_irq_unmask, 60 51 }; 61 52 53 + static void iop_handle_irq(struct pt_regs *regs) 54 + { 55 + u32 mask; 56 + 57 + iop_enable_cp6(); 58 + 59 + do { 60 + mask = iintsrc_read(); 61 + if (mask) 62 + generic_handle_irq(fls(mask)); 63 + } while (mask); 64 + } 65 + 62 66 void __init iop32x_init_irq(void) 63 67 { 64 68 int i; 65 69 66 70 iop_init_cp6_handler(); 71 + set_handle_irq(iop_handle_irq); 67 72 68 73 intctl_write(0); 69 74 intstr_write(0); ··· 88 65 machine_is_em7210()) 89 66 *IOP3XX_PCIIRSR = 0x0f; 90 67 91 - for (i = 0; i < NR_IRQS; i++) { 68 + for (i = 1; i < NR_IRQS; i++) { 92 69 irq_set_chip_and_handler(i, &ext_chip, handle_level_irq); 93 70 irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); 94 71 }
+32 -28
arch/arm/mach-iop32x/irqs.h
··· 7 7 #ifndef __IOP32X_IRQS_H 8 8 #define __IOP32X_IRQS_H 9 9 10 + /* Interrupts in Linux start at 1, hardware starts at 0 */ 11 + 12 + #define IOP_IRQ(x) ((x) + 1) 13 + 10 14 /* 11 15 * IOP80321 chipset interrupts 12 16 */ 13 - #define IRQ_IOP32X_DMA0_EOT 0 14 - #define IRQ_IOP32X_DMA0_EOC 1 15 - #define IRQ_IOP32X_DMA1_EOT 2 16 - #define IRQ_IOP32X_DMA1_EOC 3 17 - #define IRQ_IOP32X_AA_EOT 6 18 - #define IRQ_IOP32X_AA_EOC 7 19 - #define IRQ_IOP32X_CORE_PMON 8 20 - #define IRQ_IOP32X_TIMER0 9 21 - #define IRQ_IOP32X_TIMER1 10 22 - #define IRQ_IOP32X_I2C_0 11 23 - #define IRQ_IOP32X_I2C_1 12 24 - #define IRQ_IOP32X_MESSAGING 13 25 - #define IRQ_IOP32X_ATU_BIST 14 26 - #define IRQ_IOP32X_PERFMON 15 27 - #define IRQ_IOP32X_CORE_PMU 16 28 - #define IRQ_IOP32X_BIU_ERR 17 29 - #define IRQ_IOP32X_ATU_ERR 18 30 - #define IRQ_IOP32X_MCU_ERR 19 31 - #define IRQ_IOP32X_DMA0_ERR 20 32 - #define IRQ_IOP32X_DMA1_ERR 21 33 - #define IRQ_IOP32X_AA_ERR 23 34 - #define IRQ_IOP32X_MSG_ERR 24 35 - #define IRQ_IOP32X_SSP 25 36 - #define IRQ_IOP32X_XINT0 27 37 - #define IRQ_IOP32X_XINT1 28 38 - #define IRQ_IOP32X_XINT2 29 39 - #define IRQ_IOP32X_XINT3 30 40 - #define IRQ_IOP32X_HPI 31 17 + #define IRQ_IOP32X_DMA0_EOT IOP_IRQ(0) 18 + #define IRQ_IOP32X_DMA0_EOC IOP_IRQ(1) 19 + #define IRQ_IOP32X_DMA1_EOT IOP_IRQ(2) 20 + #define IRQ_IOP32X_DMA1_EOC IOP_IRQ(3) 21 + #define IRQ_IOP32X_AA_EOT IOP_IRQ(6) 22 + #define IRQ_IOP32X_AA_EOC IOP_IRQ(7) 23 + #define IRQ_IOP32X_CORE_PMON IOP_IRQ(8) 24 + #define IRQ_IOP32X_TIMER0 IOP_IRQ(9) 25 + #define IRQ_IOP32X_TIMER1 IOP_IRQ(10) 26 + #define IRQ_IOP32X_I2C_0 IOP_IRQ(11) 27 + #define IRQ_IOP32X_I2C_1 IOP_IRQ(12) 28 + #define IRQ_IOP32X_MESSAGING IOP_IRQ(13) 29 + #define IRQ_IOP32X_ATU_BIST IOP_IRQ(14) 30 + #define IRQ_IOP32X_PERFMON IOP_IRQ(15) 31 + #define IRQ_IOP32X_CORE_PMU IOP_IRQ(16) 32 + #define IRQ_IOP32X_BIU_ERR IOP_IRQ(17) 33 + #define IRQ_IOP32X_ATU_ERR IOP_IRQ(18) 34 + #define IRQ_IOP32X_MCU_ERR IOP_IRQ(19) 35 + #define IRQ_IOP32X_DMA0_ERR IOP_IRQ(20) 36 + #define IRQ_IOP32X_DMA1_ERR IOP_IRQ(21) 37 + #define IRQ_IOP32X_AA_ERR IOP_IRQ(23) 38 + #define IRQ_IOP32X_MSG_ERR IOP_IRQ(24) 39 + #define IRQ_IOP32X_SSP IOP_IRQ(25) 40 + #define IRQ_IOP32X_XINT0 IOP_IRQ(27) 41 + #define IRQ_IOP32X_XINT1 IOP_IRQ(28) 42 + #define IRQ_IOP32X_XINT2 IOP_IRQ(29) 43 + #define IRQ_IOP32X_XINT3 IOP_IRQ(30) 44 + #define IRQ_IOP32X_HPI IOP_IRQ(31) 41 45 42 46 #endif
+3 -2
arch/arm/mach-rpc/fiq.S
··· 2 2 #include <linux/linkage.h> 3 3 #include <asm/assembler.h> 4 4 #include <mach/hardware.h> 5 - #include <mach/entry-macro.S> 5 + 6 + .equ ioc_base_high, IOC_BASE & 0xff000000 7 + .equ ioc_base_low, IOC_BASE & 0x00ff0000 6 8 7 9 .text 8 - 9 10 .global rpc_default_fiq_end 10 11 ENTRY(rpc_default_fiq_start) 11 12 mov r12, #ioc_base_high
-13
arch/arm/mach-rpc/include/mach/entry-macro.S
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #include <mach/hardware.h> 3 - #include <asm/hardware/entry-macro-iomd.S> 4 - 5 - .equ ioc_base_high, IOC_BASE & 0xff000000 6 - .equ ioc_base_low, IOC_BASE & 0x00ff0000 7 - 8 - .macro get_irqnr_preamble, base, tmp 9 - mov \base, #ioc_base_high @ point at IOC 10 - .if ioc_base_low 11 - orr \base, \base, #ioc_base_low 12 - .endif 13 - .endm
+95
arch/arm/mach-rpc/irq.c
··· 14 14 #define CLR 0x04 15 15 #define MASK 0x08 16 16 17 + static const u8 irq_prio_h[256] = { 18 + 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10, 19 + 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10, 20 + 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 21 + 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 22 + 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10, 23 + 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10, 24 + 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 25 + 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 26 + 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10, 27 + 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10, 28 + 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 29 + 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 30 + 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10, 31 + 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10, 32 + 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 33 + 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 34 + }; 35 + 36 + static const u8 irq_prio_d[256] = { 37 + 0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 38 + 20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 39 + 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 40 + 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 41 + 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 42 + 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 43 + 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 44 + 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 45 + 23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 46 + 23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 47 + 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 48 + 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 49 + 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 50 + 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 51 + 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 52 + 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 53 + }; 54 + 55 + static const u8 irq_prio_l[256] = { 56 + 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 57 + 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 58 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 59 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 60 + 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 61 + 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 62 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 63 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 64 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 65 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 66 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 67 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 68 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 69 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 70 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 71 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 72 + }; 73 + 74 + static int iomd_get_irq_nr(void) 75 + { 76 + int irq; 77 + u8 reg; 78 + 79 + /* get highest priority first */ 80 + reg = readb(IOC_BASE + IOMD_IRQREQB); 81 + irq = irq_prio_h[reg]; 82 + if (irq) 83 + return irq; 84 + 85 + /* get DMA */ 86 + reg = readb(IOC_BASE + IOMD_DMAREQ); 87 + irq = irq_prio_d[reg]; 88 + if (irq) 89 + return irq; 90 + 91 + /* get low priority */ 92 + reg = readb(IOC_BASE + IOMD_IRQREQA); 93 + irq = irq_prio_l[reg]; 94 + if (irq) 95 + return irq; 96 + return 0; 97 + } 98 + 99 + static void iomd_handle_irq(struct pt_regs *regs) 100 + { 101 + int irq; 102 + 103 + do { 104 + irq = iomd_get_irq_nr(); 105 + if (irq) 106 + generic_handle_irq(irq); 107 + } while (irq); 108 + } 109 + 17 110 static void __iomem *iomd_get_base(struct irq_data *d) 18 111 { 19 112 void *cd = irq_data_get_irq_chip_data(d); ··· 174 81 175 82 set_fiq_handler(&rpc_default_fiq_start, 176 83 &rpc_default_fiq_end - &rpc_default_fiq_start); 84 + 85 + set_handle_irq(iomd_handle_irq); 177 86 178 87 for (irq = 0; irq < NR_IRQS; irq++) { 179 88 clr = IRQ_NOREQUEST;
+1
arch/arm/mm/Kconfig
··· 386 386 select CPU_PABRT_V6 387 387 select CPU_THUMB_CAPABLE 388 388 select CPU_TLB_V6 if MMU 389 + select SMP_ON_UP if SMP 389 390 390 391 # ARMv6k 391 392 config CPU_V6K
+18 -22
arch/arm/mm/cache-v7.S
··· 90 90 * 91 91 * Flush the D-cache up to the Level of Unification Inner Shareable 92 92 * 93 - * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) 93 + * Corrupted registers: r0-r6, r9-r10 94 94 */ 95 95 96 96 ENTRY(v7_flush_dcache_louis) ··· 117 117 * 118 118 * Flush the whole D-cache. 119 119 * 120 - * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) 120 + * Corrupted registers: r0-r6, r9-r10 121 121 * 122 122 * - mm - mm_struct describing address space 123 123 */ ··· 149 149 movw r4, #0x3ff 150 150 ands r4, r4, r1, lsr #3 @ find maximum number on the way size 151 151 clz r5, r4 @ find bit position of way size increment 152 - movw r7, #0x7fff 153 - ands r7, r7, r1, lsr #13 @ extract max number of the index size 152 + movw r6, #0x7fff 153 + and r1, r6, r1, lsr #13 @ extract max number of the index size 154 + mov r6, #1 155 + movne r4, r4, lsl r5 @ # of ways shifted into bits [31:...] 156 + movne r6, r6, lsl r5 @ 1 shifted left by same amount 154 157 loop1: 155 - mov r9, r7 @ create working copy of max index 158 + mov r9, r1 @ create working copy of max index 156 159 loop2: 157 - ARM( orr r11, r10, r4, lsl r5 ) @ factor way and cache number into r11 158 - THUMB( lsl r6, r4, r5 ) 159 - THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11 160 - ARM( orr r11, r11, r9, lsl r2 ) @ factor index number into r11 161 - THUMB( lsl r6, r9, r2 ) 162 - THUMB( orr r11, r11, r6 ) @ factor index number into r11 163 - mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way 160 + mov r5, r9, lsl r2 @ factor set number into r5 161 + orr r5, r5, r4 @ factor way number into r5 162 + orr r5, r5, r10 @ factor cache level into r5 163 + mcr p15, 0, r5, c7, c14, 2 @ clean & invalidate by set/way 164 164 subs r9, r9, #1 @ decrement the index 165 165 bge loop2 166 - subs r4, r4, #1 @ decrement the way 167 - bge loop1 166 + subs r4, r4, r6 @ decrement the way 167 + bcs loop1 168 168 skip: 169 169 add r10, r10, #2 @ increment cache number 170 170 cmp r3, r10 ··· 192 192 * 193 193 */ 194 194 ENTRY(v7_flush_kern_cache_all) 195 - ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} ) 196 - THUMB( stmfd sp!, {r4-r7, r9-r11, lr} ) 195 + stmfd sp!, {r4-r6, r9-r10, lr} 197 196 bl v7_flush_dcache_all 198 197 mov r0, #0 199 198 ALT_SMP(mcr p15, 0, r0, c7, c1, 0) @ invalidate I-cache inner shareable 200 199 ALT_UP(mcr p15, 0, r0, c7, c5, 0) @ I+BTB cache invalidate 201 - ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} ) 202 - THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} ) 200 + ldmfd sp!, {r4-r6, r9-r10, lr} 203 201 ret lr 204 202 ENDPROC(v7_flush_kern_cache_all) 205 203 ··· 208 210 * Invalidate the I-cache to the point of unification. 209 211 */ 210 212 ENTRY(v7_flush_kern_cache_louis) 211 - ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} ) 212 - THUMB( stmfd sp!, {r4-r7, r9-r11, lr} ) 213 + stmfd sp!, {r4-r6, r9-r10, lr} 213 214 bl v7_flush_dcache_louis 214 215 mov r0, #0 215 216 ALT_SMP(mcr p15, 0, r0, c7, c1, 0) @ invalidate I-cache inner shareable 216 217 ALT_UP(mcr p15, 0, r0, c7, c5, 0) @ I+BTB cache invalidate 217 - ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} ) 218 - THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} ) 218 + ldmfd sp!, {r4-r6, r9-r10, lr} 219 219 ret lr 220 220 ENDPROC(v7_flush_kern_cache_louis) 221 221
+1 -2
arch/arm/mm/context.c
··· 240 240 unsigned int cpu = smp_processor_id(); 241 241 u64 asid; 242 242 243 - if (unlikely(mm->context.vmalloc_seq != init_mm.context.vmalloc_seq)) 244 - __check_vmalloc_seq(mm); 243 + check_vmalloc_seq(mm); 245 244 246 245 /* 247 246 * We cannot update the pgd and the ASID atomicly with classic
+11 -7
arch/arm/mm/ioremap.c
··· 117 117 118 118 void __check_vmalloc_seq(struct mm_struct *mm) 119 119 { 120 - unsigned int seq; 120 + int seq; 121 121 122 122 do { 123 - seq = init_mm.context.vmalloc_seq; 123 + seq = atomic_read(&init_mm.context.vmalloc_seq); 124 124 memcpy(pgd_offset(mm, VMALLOC_START), 125 125 pgd_offset_k(VMALLOC_START), 126 126 sizeof(pgd_t) * (pgd_index(VMALLOC_END) - 127 127 pgd_index(VMALLOC_START))); 128 - mm->context.vmalloc_seq = seq; 129 - } while (seq != init_mm.context.vmalloc_seq); 128 + /* 129 + * Use a store-release so that other CPUs that observe the 130 + * counter's new value are guaranteed to see the results of the 131 + * memcpy as well. 132 + */ 133 + atomic_set_release(&mm->context.vmalloc_seq, seq); 134 + } while (seq != atomic_read(&init_mm.context.vmalloc_seq)); 130 135 } 131 136 132 137 #if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE) ··· 162 157 * Note: this is still racy on SMP machines. 163 158 */ 164 159 pmd_clear(pmdp); 165 - init_mm.context.vmalloc_seq++; 160 + atomic_inc_return_release(&init_mm.context.vmalloc_seq); 166 161 167 162 /* 168 163 * Free the page table, if there was one. ··· 179 174 * Ensure that the active_mm is up to date - we want to 180 175 * catch any use-after-iounmap cases. 181 176 */ 182 - if (current->active_mm->context.vmalloc_seq != init_mm.context.vmalloc_seq) 183 - __check_vmalloc_seq(current->active_mm); 177 + check_vmalloc_seq(current->active_mm); 184 178 185 179 flush_tlb_kernel_range(virt, end); 186 180 }
+5 -3
arch/arm/probes/kprobes/actions-common.c
··· 84 84 register void *rfn asm("lr") = asi->insn_fn; 85 85 86 86 __asm__ __volatile__ ( 87 - "stmdb sp!, {%[regs], r11} \n\t" 87 + ARM( "stmdb sp!, {%[regs], r11} \n\t" ) 88 + THUMB( "stmdb sp!, {%[regs], r7} \n\t" ) 88 89 "ldmia %[regs], {r0-r12} \n\t" 89 90 #if __LINUX_ARM_ARCH__ >= 6 90 91 "blx %[fn] \n\t" ··· 97 96 #endif 98 97 "ldr lr, [sp], #4 \n\t" /* lr = regs */ 99 98 "stmia lr, {r0-r12} \n\t" 100 - "ldr r11, [sp], #4 \n\t" 99 + ARM( "ldr r11, [sp], #4 \n\t" ) 100 + THUMB( "ldr r7, [sp], #4 \n\t" ) 101 101 : [regs] "=r" (rregs), [fn] "=r" (rfn) 102 102 : "0" (rregs), "1" (rfn) 103 - : "r0", "r2", "r3", "r4", "r5", "r6", "r7", 103 + : "r0", "r2", "r3", "r4", "r5", "r6", ARM("r7") THUMB("r11"), 104 104 "r8", "r9", "r10", "r12", "memory", "cc" 105 105 ); 106 106 }
+12 -4
arch/arm/probes/kprobes/actions-thumb.c
··· 447 447 448 448 __asm__ __volatile__ ( 449 449 "msr cpsr_fs, %[oldcpsr] \n\t" 450 + "mov r11, r7 \n\t" 450 451 "ldmia %[regs], {r0-r7} \n\t" 451 452 "blx %[fn] \n\t" 452 453 "stmia %[regs], {r0-r7} \n\t" 454 + "mov r7, r11 \n\t" 453 455 "mrs %[newcpsr], cpsr \n\t" 454 456 : [newcpsr] "=r" (newcpsr) 455 457 : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs), 456 458 [fn] "r" (asi->insn_fn) 457 - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 459 + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r11", 458 460 "lr", "memory", "cc" 459 461 ); 460 462 ··· 526 524 struct arch_probes_insn *asi, struct pt_regs *regs) 527 525 { 528 526 __asm__ __volatile__ ( 527 + "mov r11, r7 \n\t" 529 528 "ldr r9, [%[regs], #13*4] \n\t" 530 529 "ldr r8, [%[regs], #14*4] \n\t" 531 530 "ldmia %[regs], {r0-r7} \n\t" 532 531 "blx %[fn] \n\t" 533 532 "str r9, [%[regs], #13*4] \n\t" 533 + "mov r7, r11 \n\t" 534 534 : 535 535 : [regs] "r" (regs), [fn] "r" (asi->insn_fn) 536 - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", 536 + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r8", "r9", "r11", 537 537 "lr", "memory", "cc" 538 538 ); 539 539 } ··· 562 558 struct arch_probes_insn *asi, struct pt_regs *regs) 563 559 { 564 560 __asm__ __volatile__ ( 561 + "mov r11, r7 \n\t" 565 562 "ldr r9, [%[regs], #13*4] \n\t" 566 563 "ldmia %[regs], {r0-r7} \n\t" 567 564 "blx %[fn] \n\t" 568 565 "stmia %[regs], {r0-r7} \n\t" 569 566 "str r9, [%[regs], #13*4] \n\t" 567 + "mov r7, r11 \n\t" 570 568 : 571 569 : [regs] "r" (regs), [fn] "r" (asi->insn_fn) 572 - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", 570 + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r9", "r11", 573 571 "lr", "memory", "cc" 574 572 ); 575 573 } ··· 583 577 register unsigned long pc asm("r8"); 584 578 585 579 __asm__ __volatile__ ( 580 + "mov r11, r7 \n\t" 586 581 "ldr r9, [%[regs], #13*4] \n\t" 587 582 "ldmia %[regs], {r0-r7} \n\t" 588 583 "blx %[fn] \n\t" 589 584 "stmia %[regs], {r0-r7} \n\t" 590 585 "str r9, [%[regs], #13*4] \n\t" 586 + "mov r7, r11 \n\t" 591 587 : "=r" (pc) 592 588 : [regs] "r" (regs), [fn] "r" (asi->insn_fn) 593 - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", 589 + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r9", "r11", 594 590 "lr", "memory", "cc" 595 591 ); 596 592
+5 -17
drivers/irqchip/irq-nvic.c
··· 37 37 38 38 static struct irq_domain *nvic_irq_domain; 39 39 40 - static void __nvic_handle_irq(irq_hw_number_t hwirq) 40 + static void __irq_entry nvic_handle_irq(struct pt_regs *regs) 41 41 { 42 + unsigned long icsr = readl_relaxed(BASEADDR_V7M_SCB + V7M_SCB_ICSR); 43 + irq_hw_number_t hwirq = (icsr & V7M_SCB_ICSR_VECTACTIVE) - 16; 44 + 42 45 generic_handle_domain_irq(nvic_irq_domain, hwirq); 43 - } 44 - 45 - /* 46 - * TODO: restructure the ARMv7M entry logic so that this entry logic can live 47 - * in arch code. 48 - */ 49 - asmlinkage void __exception_irq_entry 50 - nvic_handle_irq(irq_hw_number_t hwirq, struct pt_regs *regs) 51 - { 52 - struct pt_regs *old_regs; 53 - 54 - irq_enter(); 55 - old_regs = set_irq_regs(regs); 56 - __nvic_handle_irq(hwirq); 57 - set_irq_regs(old_regs); 58 - irq_exit(); 59 46 } 60 47 61 48 static int nvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, ··· 130 143 for (i = 0; i < irqs; i += 4) 131 144 writel_relaxed(0, nvic_base + NVIC_IPR + i); 132 145 146 + set_handle_irq(nvic_handle_irq); 133 147 return 0; 134 148 } 135 149 IRQCHIP_DECLARE(armv7m_nvic, "arm,armv7m-nvic", nvic_of_init);