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

arm64: Emulate SETEND for AArch32 tasks

Emulate deprecated 'setend' instruction for AArch32 bit tasks.

setend [le/be] - Sets the endianness of EL0

On systems with CPUs which support mixed endian at EL0, the hardware
support for the instruction can be enabled by setting the SCTLR_EL1.SED
bit. Like the other emulated instructions it is controlled by an entry in
/proc/sys/abi/. For more information see :
Documentation/arm64/legacy_instructions.txt

The instruction is emulated by setting/clearing the SPSR_EL1.E bit, which
will be reflected in the PSTATE.E in AArch32 context.

This patch also restores the native endianness for the execution of signal
handlers, since the process could have changed the endianness.

Note: All CPUs on the system must have mixed endian support at EL0. Once the
handler is registered, hotplugging a CPU which doesn't support mixed endian,
could lead to unexpected results/behavior in applications.

Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Punit Agrawal <punit.agrawal@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Suzuki K. Poulose and committed by
Catalin Marinas
2d888f48 736d474f

+119 -1
+12
Documentation/arm64/legacy_instructions.txt
··· 32 32 architecture. Deprecated instructions should default to emulation 33 33 while obsolete instructions must be undefined by default. 34 34 35 + Note: Instruction emulation may not be possible in all cases. See 36 + individual instruction notes for further information. 37 + 35 38 Supported legacy instructions 36 39 ----------------------------- 37 40 * SWP{B} ··· 46 43 Node: /proc/sys/abi/cp15_barrier 47 44 Status: Deprecated 48 45 Default: Emulate (1) 46 + 47 + * SETEND 48 + Node: /proc/sys/abi/setend 49 + Status: Deprecated 50 + Default: Emulate (1)* 51 + Note: All the cpus on the system must have mixed endian support at EL0 52 + for this feature to be enabled. If a new CPU - which doesn't support mixed 53 + endian - is hotplugged in after this feature has been enabled, there could 54 + be unexpected results in the application.
+15
arch/arm64/Kconfig
··· 540 540 541 541 If unsure, say Y 542 542 543 + config SETEND_EMULATION 544 + bool "Emulate SETEND instruction" 545 + help 546 + The SETEND instruction alters the data-endianness of the 547 + AArch32 EL0, and is deprecated in ARMv8. 548 + 549 + Say Y here to enable software emulation of the instruction 550 + for AArch32 userspace code. 551 + 552 + Note: All the cpus on the system must have mixed endian support at EL0 553 + for this feature to be enabled. If a new CPU - which doesn't support mixed 554 + endian - is hotplugged in after this feature has been enabled, there could 555 + be unexpected results in the applications. 556 + 557 + If unsure, say Y 543 558 endif 544 559 545 560 endmenu
+1
arch/arm64/include/asm/cputype.h
··· 82 82 (((mmfr0) & ID_AA64MMFR0_BIGEND_MASK) >> ID_AA64MMFR0_BIGEND_SHIFT) 83 83 84 84 #define SCTLR_EL1_CP15BEN (0x1 << 5) 85 + #define SCTLR_EL1_SED (0x1 << 8) 85 86 86 87 #ifndef __ASSEMBLY__ 87 88
+7
arch/arm64/include/asm/ptrace.h
··· 58 58 #define COMPAT_PSR_Z_BIT 0x40000000 59 59 #define COMPAT_PSR_N_BIT 0x80000000 60 60 #define COMPAT_PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ 61 + 62 + #ifdef CONFIG_CPU_BIG_ENDIAN 63 + #define COMPAT_PSR_ENDSTATE COMPAT_PSR_E_BIT 64 + #else 65 + #define COMPAT_PSR_ENDSTATE 0 66 + #endif 67 + 61 68 /* 62 69 * These are 'magic' values for PTRACE_PEEKUSR that return info about where a 63 70 * process is located in memory.
+80
arch/arm64/kernel/armv8_deprecated.c
··· 548 548 .set_hw_mode = cp15_barrier_set_hw_mode, 549 549 }; 550 550 551 + static int setend_set_hw_mode(bool enable) 552 + { 553 + if (!cpu_supports_mixed_endian_el0()) 554 + return -EINVAL; 555 + 556 + if (enable) 557 + config_sctlr_el1(SCTLR_EL1_SED, 0); 558 + else 559 + config_sctlr_el1(0, SCTLR_EL1_SED); 560 + return 0; 561 + } 562 + 563 + static int compat_setend_handler(struct pt_regs *regs, u32 big_endian) 564 + { 565 + char *insn; 566 + 567 + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); 568 + 569 + if (big_endian) { 570 + insn = "setend be"; 571 + regs->pstate |= COMPAT_PSR_E_BIT; 572 + } else { 573 + insn = "setend le"; 574 + regs->pstate &= ~COMPAT_PSR_E_BIT; 575 + } 576 + 577 + trace_instruction_emulation(insn, regs->pc); 578 + pr_warn_ratelimited("\"%s\" (%ld) uses deprecated setend instruction at 0x%llx\n", 579 + current->comm, (unsigned long)current->pid, regs->pc); 580 + 581 + return 0; 582 + } 583 + 584 + static int a32_setend_handler(struct pt_regs *regs, u32 instr) 585 + { 586 + int rc = compat_setend_handler(regs, (instr >> 9) & 1); 587 + regs->pc += 4; 588 + return rc; 589 + } 590 + 591 + static int t16_setend_handler(struct pt_regs *regs, u32 instr) 592 + { 593 + int rc = compat_setend_handler(regs, (instr >> 3) & 1); 594 + regs->pc += 2; 595 + return rc; 596 + } 597 + 598 + static struct undef_hook setend_hooks[] = { 599 + { 600 + .instr_mask = 0xfffffdff, 601 + .instr_val = 0xf1010000, 602 + .pstate_mask = COMPAT_PSR_MODE_MASK, 603 + .pstate_val = COMPAT_PSR_MODE_USR, 604 + .fn = a32_setend_handler, 605 + }, 606 + { 607 + /* Thumb mode */ 608 + .instr_mask = 0x0000fff7, 609 + .instr_val = 0x0000b650, 610 + .pstate_mask = (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK), 611 + .pstate_val = (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR), 612 + .fn = t16_setend_handler, 613 + }, 614 + {} 615 + }; 616 + 617 + static struct insn_emulation_ops setend_ops = { 618 + .name = "setend", 619 + .status = INSN_DEPRECATED, 620 + .hooks = setend_hooks, 621 + .set_hw_mode = setend_set_hw_mode, 622 + }; 623 + 551 624 static int insn_cpu_hotplug_notify(struct notifier_block *b, 552 625 unsigned long action, void *hcpu) 553 626 { ··· 645 572 646 573 if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION)) 647 574 register_insn_emulation(&cp15_barrier_ops); 575 + 576 + if (IS_ENABLED(CONFIG_SETEND_EMULATION)) { 577 + if(system_supports_mixed_endian_el0()) 578 + register_insn_emulation(&setend_ops); 579 + else 580 + pr_info("setend instruction emulation is not supported on the system"); 581 + } 648 582 649 583 register_cpu_notifier(&insn_cpu_hotplug_notifier); 650 584 register_insn_emulation_sysctl(ctl_abi);
+4 -1
arch/arm64/kernel/signal32.c
··· 440 440 { 441 441 compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler); 442 442 compat_ulong_t retcode; 443 - compat_ulong_t spsr = regs->pstate & ~PSR_f; 443 + compat_ulong_t spsr = regs->pstate & ~(PSR_f | COMPAT_PSR_E_BIT); 444 444 int thumb; 445 445 446 446 /* Check if the handler is written for ARM or Thumb */ ··· 453 453 454 454 /* The IT state must be cleared for both ARM and Thumb-2 */ 455 455 spsr &= ~COMPAT_PSR_IT_MASK; 456 + 457 + /* Restore the original endianness */ 458 + spsr |= COMPAT_PSR_ENDSTATE; 456 459 457 460 if (ka->sa.sa_flags & SA_RESTORER) { 458 461 retcode = ptr_to_compat(ka->sa.sa_restorer);