diff options
-rw-r--r-- | arch/arm64/include/asm/elf.h | 13 | ||||
-rw-r--r-- | arch/arm64/include/asm/processor.h | 5 | ||||
-rw-r--r-- | arch/arm64/include/uapi/asm/auxvec.h | 3 | ||||
-rw-r--r-- | arch/arm64/kernel/cpufeature.c | 1 | ||||
-rw-r--r-- | arch/arm64/kernel/signal.c | 52 |
5 files changed, 66 insertions, 8 deletions
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index fac1c4de7898..433b9554c6a1 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h | |||
@@ -121,6 +121,9 @@ | |||
121 | 121 | ||
122 | #ifndef __ASSEMBLY__ | 122 | #ifndef __ASSEMBLY__ |
123 | 123 | ||
124 | #include <linux/bug.h> | ||
125 | #include <asm/processor.h> /* for signal_minsigstksz, used by ARCH_DLINFO */ | ||
126 | |||
124 | typedef unsigned long elf_greg_t; | 127 | typedef unsigned long elf_greg_t; |
125 | 128 | ||
126 | #define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) | 129 | #define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) |
@@ -148,6 +151,16 @@ typedef struct user_fpsimd_state elf_fpregset_t; | |||
148 | do { \ | 151 | do { \ |
149 | NEW_AUX_ENT(AT_SYSINFO_EHDR, \ | 152 | NEW_AUX_ENT(AT_SYSINFO_EHDR, \ |
150 | (elf_addr_t)current->mm->context.vdso); \ | 153 | (elf_addr_t)current->mm->context.vdso); \ |
154 | \ | ||
155 | /* \ | ||
156 | * Should always be nonzero unless there's a kernel bug. \ | ||
157 | * If we haven't determined a sensible value to give to \ | ||
158 | * userspace, omit the entry: \ | ||
159 | */ \ | ||
160 | if (likely(signal_minsigstksz)) \ | ||
161 | NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz); \ | ||
162 | else \ | ||
163 | NEW_AUX_ENT(AT_IGNORE, 0); \ | ||
151 | } while (0) | 164 | } while (0) |
152 | 165 | ||
153 | #define ARCH_HAS_SETUP_ADDITIONAL_PAGES | 166 | #define ARCH_HAS_SETUP_ADDITIONAL_PAGES |
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 767598932549..65ab83e8926e 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h | |||
@@ -35,6 +35,8 @@ | |||
35 | #ifdef __KERNEL__ | 35 | #ifdef __KERNEL__ |
36 | 36 | ||
37 | #include <linux/build_bug.h> | 37 | #include <linux/build_bug.h> |
38 | #include <linux/cache.h> | ||
39 | #include <linux/init.h> | ||
38 | #include <linux/stddef.h> | 40 | #include <linux/stddef.h> |
39 | #include <linux/string.h> | 41 | #include <linux/string.h> |
40 | 42 | ||
@@ -244,6 +246,9 @@ void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused); | |||
244 | void cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused); | 246 | void cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused); |
245 | void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused); | 247 | void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused); |
246 | 248 | ||
249 | extern unsigned long __ro_after_init signal_minsigstksz; /* sigframe size */ | ||
250 | extern void __init minsigstksz_setup(void); | ||
251 | |||
247 | /* Userspace interface for PR_SVE_{SET,GET}_VL prctl()s: */ | 252 | /* Userspace interface for PR_SVE_{SET,GET}_VL prctl()s: */ |
248 | #define SVE_SET_VL(arg) sve_set_current_vl(arg) | 253 | #define SVE_SET_VL(arg) sve_set_current_vl(arg) |
249 | #define SVE_GET_VL() sve_get_current_vl() | 254 | #define SVE_GET_VL() sve_get_current_vl() |
diff --git a/arch/arm64/include/uapi/asm/auxvec.h b/arch/arm64/include/uapi/asm/auxvec.h index ec0a86d484e1..743c0b84fd30 100644 --- a/arch/arm64/include/uapi/asm/auxvec.h +++ b/arch/arm64/include/uapi/asm/auxvec.h | |||
@@ -19,7 +19,8 @@ | |||
19 | 19 | ||
20 | /* vDSO location */ | 20 | /* vDSO location */ |
21 | #define AT_SYSINFO_EHDR 33 | 21 | #define AT_SYSINFO_EHDR 33 |
22 | #define AT_MINSIGSTKSZ 51 /* stack needed for signal delivery */ | ||
22 | 23 | ||
23 | #define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */ | 24 | #define AT_VECTOR_SIZE_ARCH 2 /* entries in ARCH_DLINFO */ |
24 | 25 | ||
25 | #endif | 26 | #endif |
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index fbee8c17a4e6..d2856b129097 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c | |||
@@ -1618,6 +1618,7 @@ void __init setup_cpu_features(void) | |||
1618 | pr_info("emulated: Privileged Access Never (PAN) using TTBR0_EL1 switching\n"); | 1618 | pr_info("emulated: Privileged Access Never (PAN) using TTBR0_EL1 switching\n"); |
1619 | 1619 | ||
1620 | sve_setup(); | 1620 | sve_setup(); |
1621 | minsigstksz_setup(); | ||
1621 | 1622 | ||
1622 | /* Advertise that we have computed the system capabilities */ | 1623 | /* Advertise that we have computed the system capabilities */ |
1623 | set_sys_caps_initialised(); | 1624 | set_sys_caps_initialised(); |
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 154b7d30145d..e7da5dba7ba8 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/cache.h> | ||
20 | #include <linux/compat.h> | 21 | #include <linux/compat.h> |
21 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
22 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
@@ -570,8 +571,15 @@ badframe: | |||
570 | return 0; | 571 | return 0; |
571 | } | 572 | } |
572 | 573 | ||
573 | /* Determine the layout of optional records in the signal frame */ | 574 | /* |
574 | static int setup_sigframe_layout(struct rt_sigframe_user_layout *user) | 575 | * Determine the layout of optional records in the signal frame |
576 | * | ||
577 | * add_all: if true, lays out the biggest possible signal frame for | ||
578 | * this task; otherwise, generates a layout for the current state | ||
579 | * of the task. | ||
580 | */ | ||
581 | static int setup_sigframe_layout(struct rt_sigframe_user_layout *user, | ||
582 | bool add_all) | ||
575 | { | 583 | { |
576 | int err; | 584 | int err; |
577 | 585 | ||
@@ -581,7 +589,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user) | |||
581 | return err; | 589 | return err; |
582 | 590 | ||
583 | /* fault information, if valid */ | 591 | /* fault information, if valid */ |
584 | if (current->thread.fault_code) { | 592 | if (add_all || current->thread.fault_code) { |
585 | err = sigframe_alloc(user, &user->esr_offset, | 593 | err = sigframe_alloc(user, &user->esr_offset, |
586 | sizeof(struct esr_context)); | 594 | sizeof(struct esr_context)); |
587 | if (err) | 595 | if (err) |
@@ -591,8 +599,14 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user) | |||
591 | if (system_supports_sve()) { | 599 | if (system_supports_sve()) { |
592 | unsigned int vq = 0; | 600 | unsigned int vq = 0; |
593 | 601 | ||
594 | if (test_thread_flag(TIF_SVE)) | 602 | if (add_all || test_thread_flag(TIF_SVE)) { |
595 | vq = sve_vq_from_vl(current->thread.sve_vl); | 603 | int vl = sve_max_vl; |
604 | |||
605 | if (!add_all) | ||
606 | vl = current->thread.sve_vl; | ||
607 | |||
608 | vq = sve_vq_from_vl(vl); | ||
609 | } | ||
596 | 610 | ||
597 | err = sigframe_alloc(user, &user->sve_offset, | 611 | err = sigframe_alloc(user, &user->sve_offset, |
598 | SVE_SIG_CONTEXT_SIZE(vq)); | 612 | SVE_SIG_CONTEXT_SIZE(vq)); |
@@ -603,7 +617,6 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user) | |||
603 | return sigframe_alloc_end(user); | 617 | return sigframe_alloc_end(user); |
604 | } | 618 | } |
605 | 619 | ||
606 | |||
607 | static int setup_sigframe(struct rt_sigframe_user_layout *user, | 620 | static int setup_sigframe(struct rt_sigframe_user_layout *user, |
608 | struct pt_regs *regs, sigset_t *set) | 621 | struct pt_regs *regs, sigset_t *set) |
609 | { | 622 | { |
@@ -701,7 +714,7 @@ static int get_sigframe(struct rt_sigframe_user_layout *user, | |||
701 | int err; | 714 | int err; |
702 | 715 | ||
703 | init_user_layout(user); | 716 | init_user_layout(user); |
704 | err = setup_sigframe_layout(user); | 717 | err = setup_sigframe_layout(user, false); |
705 | if (err) | 718 | if (err) |
706 | return err; | 719 | return err; |
707 | 720 | ||
@@ -936,3 +949,28 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, | |||
936 | thread_flags = READ_ONCE(current_thread_info()->flags); | 949 | thread_flags = READ_ONCE(current_thread_info()->flags); |
937 | } while (thread_flags & _TIF_WORK_MASK); | 950 | } while (thread_flags & _TIF_WORK_MASK); |
938 | } | 951 | } |
952 | |||
953 | unsigned long __ro_after_init signal_minsigstksz; | ||
954 | |||
955 | /* | ||
956 | * Determine the stack space required for guaranteed signal devliery. | ||
957 | * This function is used to populate AT_MINSIGSTKSZ at process startup. | ||
958 | * cpufeatures setup is assumed to be complete. | ||
959 | */ | ||
960 | void __init minsigstksz_setup(void) | ||
961 | { | ||
962 | struct rt_sigframe_user_layout user; | ||
963 | |||
964 | init_user_layout(&user); | ||
965 | |||
966 | /* | ||
967 | * If this fails, SIGFRAME_MAXSZ needs to be enlarged. It won't | ||
968 | * be big enough, but it's our best guess: | ||
969 | */ | ||
970 | if (WARN_ON(setup_sigframe_layout(&user, true))) | ||
971 | return; | ||
972 | |||
973 | signal_minsigstksz = sigframe_size(&user) + | ||
974 | round_up(sizeof(struct frame_record), 16) + | ||
975 | 16; /* max alignment padding */ | ||
976 | } | ||