1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/arch/arm/kernel/process.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 1996-2000 Russell King - Converted to ARM.
61da177e4SLinus Torvalds * Original Copyright (C) 1995 Linus Torvalds
71da177e4SLinus Torvalds */
8ecea4ab6SPaul Gortmaker #include <linux/export.h>
91da177e4SLinus Torvalds #include <linux/sched.h>
10b17b0153SIngo Molnar #include <linux/sched/debug.h>
1129930025SIngo Molnar #include <linux/sched/task.h>
1268db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
131da177e4SLinus Torvalds #include <linux/kernel.h>
141da177e4SLinus Torvalds #include <linux/mm.h>
151da177e4SLinus Torvalds #include <linux/stddef.h>
161da177e4SLinus Torvalds #include <linux/unistd.h>
171da177e4SLinus Torvalds #include <linux/user.h>
181da177e4SLinus Torvalds #include <linux/interrupt.h>
191da177e4SLinus Torvalds #include <linux/init.h>
2084dff1a7SBen Dooks #include <linux/elfcore.h>
2174617fb6SRichard Purdie #include <linux/pm.h>
229e4559ddSKevin Hilman #include <linux/tick.h>
23154c772eSRussell King #include <linux/utsname.h>
2433fa9b13SRussell King #include <linux/uaccess.h>
25990cb8acSNicolas Pitre #include <linux/random.h>
26864232faSWill Deacon #include <linux/hw_breakpoint.h>
27fa8bbb13SBryan Wu #include <linux/leds.h>
281da177e4SLinus Torvalds
291da177e4SLinus Torvalds #include <asm/processor.h>
30d6551e88SRussell King #include <asm/thread_notify.h>
312d7c11bfSCatalin Marinas #include <asm/stacktrace.h>
32779dd959SRussell King #include <asm/system_misc.h>
332ea83398SRussell King #include <asm/mach/time.h>
34a4780adeSAndré Hentschel #include <asm/tls.h>
35045ab94eSRussell King #include <asm/vdso.h>
361da177e4SLinus Torvalds
3783dc1d99SBen Dooks (Codethink) #include "signal.h"
3883dc1d99SBen Dooks (Codethink)
399c46929eSArd Biesheuvel #if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP)
4050596b75SArd Biesheuvel DEFINE_PER_CPU(struct task_struct *, __entry_task);
4150596b75SArd Biesheuvel #endif
4250596b75SArd Biesheuvel
43189af465SArd Biesheuvel #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK)
44c743f380SNicolas Pitre #include <linux/stackprotector.h>
45c743f380SNicolas Pitre unsigned long __stack_chk_guard __read_mostly;
46c743f380SNicolas Pitre EXPORT_SYMBOL(__stack_chk_guard);
47c743f380SNicolas Pitre #endif
48c743f380SNicolas Pitre
499c46929eSArd Biesheuvel #ifndef CONFIG_CURRENT_POINTER_IN_TPIDRURO
509c46929eSArd Biesheuvel asmlinkage struct task_struct *__current;
519c46929eSArd Biesheuvel EXPORT_SYMBOL(__current);
529c46929eSArd Biesheuvel #endif
539c46929eSArd Biesheuvel
54e2e55fdeSUwe Kleine-König static const char *processor_modes[] __maybe_unused = {
55ae0a846eSRussell King "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
56ae0a846eSRussell King "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
57f3a04202SStephen Boyd "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "MON_32" , "ABT_32" ,
58f3a04202SStephen Boyd "UK8_32" , "UK9_32" , "HYP_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
59ae0a846eSRussell King };
60ae0a846eSRussell King
61e2e55fdeSUwe Kleine-König static const char *isa_modes[] __maybe_unused = {
62909d6c6cSGeorge G. Davis "ARM" , "Thumb" , "Jazelle", "ThumbEE"
63909d6c6cSGeorge G. Davis };
64909d6c6cSGeorge G. Davis
651da177e4SLinus Torvalds /*
664fa20439SNicolas Pitre * This is our default idle handler.
671da177e4SLinus Torvalds */
684fa20439SNicolas Pitre
694fa20439SNicolas Pitre void (*arm_pm_idle)(void);
704fa20439SNicolas Pitre
71ad68cc7aSNicolas Pitre /*
72ad68cc7aSNicolas Pitre * Called from the core idle loop.
73ad68cc7aSNicolas Pitre */
74ad68cc7aSNicolas Pitre
arch_cpu_idle(void)75ad68cc7aSNicolas Pitre void arch_cpu_idle(void)
761da177e4SLinus Torvalds {
774fa20439SNicolas Pitre if (arm_pm_idle)
784fa20439SNicolas Pitre arm_pm_idle();
794fa20439SNicolas Pitre else
80ae940913SNicolas Pitre cpu_do_idle();
811da177e4SLinus Torvalds }
829ccdac36SRussell King
arch_cpu_idle_prepare(void)83f7b861b7SThomas Gleixner void arch_cpu_idle_prepare(void)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds local_fiq_enable();
86f7b861b7SThomas Gleixner }
871da177e4SLinus Torvalds
arch_cpu_idle_enter(void)88f7b861b7SThomas Gleixner void arch_cpu_idle_enter(void)
89f7b861b7SThomas Gleixner {
90fa8bbb13SBryan Wu ledtrig_cpu(CPU_LED_IDLE_START);
9111ed0ba1SWill Deacon #ifdef CONFIG_PL310_ERRATA_769419
9211ed0ba1SWill Deacon wmb();
9311ed0ba1SWill Deacon #endif
94f7b861b7SThomas Gleixner }
95f7b861b7SThomas Gleixner
arch_cpu_idle_exit(void)96f7b861b7SThomas Gleixner void arch_cpu_idle_exit(void)
97f7b861b7SThomas Gleixner {
98f7b861b7SThomas Gleixner ledtrig_cpu(CPU_LED_IDLE_END);
99f7b861b7SThomas Gleixner }
100f7b861b7SThomas Gleixner
__show_regs_alloc_free(struct pt_regs * regs)1015aa6b70eSManinder Singh void __show_regs_alloc_free(struct pt_regs *regs)
1025aa6b70eSManinder Singh {
1035aa6b70eSManinder Singh int i;
1045aa6b70eSManinder Singh
1055aa6b70eSManinder Singh /* check for r0 - r12 only */
1065aa6b70eSManinder Singh for (i = 0; i < 13; i++) {
1075aa6b70eSManinder Singh pr_alert("Register r%d information:", i);
1085aa6b70eSManinder Singh mem_dump_obj((void *)regs->uregs[i]);
1095aa6b70eSManinder Singh }
1105aa6b70eSManinder Singh }
1115aa6b70eSManinder Singh
__show_regs(struct pt_regs * regs)112652a12efSRussell King void __show_regs(struct pt_regs *regs)
1131da177e4SLinus Torvalds {
114154c772eSRussell King unsigned long flags;
115154c772eSRussell King char buf[64];
11677f1b959SRussell King #ifndef CONFIG_CPU_V7M
1178ac6f5d7SArnd Bergmann unsigned int domain;
11877f1b959SRussell King #ifdef CONFIG_CPU_SW_DOMAIN_PAN
11977f1b959SRussell King /*
12077f1b959SRussell King * Get the domain register for the parent context. In user
12177f1b959SRussell King * mode, we don't save the DACR, so lets use what it should
12277f1b959SRussell King * be. For other modes, we place it after the pt_regs struct.
12377f1b959SRussell King */
124e6978e4bSRussell King if (user_mode(regs)) {
12577f1b959SRussell King domain = DACR_UACCESS_ENABLE;
126e6978e4bSRussell King } else {
1275fa9da50SRussell King domain = to_svc_pt_regs(regs)->dacr;
128e6978e4bSRussell King }
12977f1b959SRussell King #else
13077f1b959SRussell King domain = get_domain();
13177f1b959SRussell King #endif
13277f1b959SRussell King #endif
1331da177e4SLinus Torvalds
134a43cb95dSTejun Heo show_regs_print_info(KERN_DEFAULT);
135a43cb95dSTejun Heo
1363ea70d7dSSergey Senozhatsky printk("PC is at %pS\n", (void *)instruction_pointer(regs));
1373ea70d7dSSergey Senozhatsky printk("LR is at %pS\n", (void *)regs->ARM_lr);
138801f19b9SJoe Perches printk("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n",
139801f19b9SJoe Perches regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr);
140801f19b9SJoe Perches printk("sp : %08lx ip : %08lx fp : %08lx\n",
141154c772eSRussell King regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
1421da177e4SLinus Torvalds printk("r10: %08lx r9 : %08lx r8 : %08lx\n",
1431da177e4SLinus Torvalds regs->ARM_r10, regs->ARM_r9,
1441da177e4SLinus Torvalds regs->ARM_r8);
1451da177e4SLinus Torvalds printk("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
1461da177e4SLinus Torvalds regs->ARM_r7, regs->ARM_r6,
1471da177e4SLinus Torvalds regs->ARM_r5, regs->ARM_r4);
1481da177e4SLinus Torvalds printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
1491da177e4SLinus Torvalds regs->ARM_r3, regs->ARM_r2,
1501da177e4SLinus Torvalds regs->ARM_r1, regs->ARM_r0);
151154c772eSRussell King
152154c772eSRussell King flags = regs->ARM_cpsr;
153154c772eSRussell King buf[0] = flags & PSR_N_BIT ? 'N' : 'n';
154154c772eSRussell King buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';
155154c772eSRussell King buf[2] = flags & PSR_C_BIT ? 'C' : 'c';
156154c772eSRussell King buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
157154c772eSRussell King buf[4] = '\0';
158154c772eSRussell King
159e2e55fdeSUwe Kleine-König #ifndef CONFIG_CPU_V7M
160a5e090acSRussell King {
161a5e090acSRussell King const char *segment;
162a5e090acSRussell King
163a5e090acSRussell King if ((domain & domain_mask(DOMAIN_USER)) ==
164a5e090acSRussell King domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
165a5e090acSRussell King segment = "none";
166a5e090acSRussell King else
167a5e090acSRussell King segment = "user";
168a5e090acSRussell King
169909d6c6cSGeorge G. Davis printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n",
170154c772eSRussell King buf, interrupts_enabled(regs) ? "n" : "ff",
1711da177e4SLinus Torvalds fast_interrupts_enabled(regs) ? "n" : "ff",
1721da177e4SLinus Torvalds processor_modes[processor_mode(regs)],
173a5e090acSRussell King isa_modes[isa_mode(regs)], segment);
174a5e090acSRussell King }
175e2e55fdeSUwe Kleine-König #else
176e2e55fdeSUwe Kleine-König printk("xPSR: %08lx\n", regs->ARM_cpsr);
177e2e55fdeSUwe Kleine-König #endif
178e2e55fdeSUwe Kleine-König
179154c772eSRussell King #ifdef CONFIG_CPU_CP15
1801da177e4SLinus Torvalds {
181f12d0d7cSHyok S. Choi unsigned int ctrl;
182154c772eSRussell King
183154c772eSRussell King buf[0] = '\0';
184f12d0d7cSHyok S. Choi #ifdef CONFIG_CPU_CP15_MMU
185f12d0d7cSHyok S. Choi {
18677f1b959SRussell King unsigned int transbase;
187154c772eSRussell King asm("mrc p15, 0, %0, c2, c0\n\t"
1881eef5d2fSRussell King : "=r" (transbase));
189154c772eSRussell King snprintf(buf, sizeof(buf), " Table: %08x DAC: %08x",
19077f1b959SRussell King transbase, domain);
191f12d0d7cSHyok S. Choi }
192f12d0d7cSHyok S. Choi #endif
193154c772eSRussell King asm("mrc p15, 0, %0, c1, c0\n" : "=r" (ctrl));
194154c772eSRussell King
195154c772eSRussell King printk("Control: %08x%s\n", ctrl, buf);
196154c772eSRussell King }
197f12d0d7cSHyok S. Choi #endif
1981da177e4SLinus Torvalds }
1991da177e4SLinus Torvalds
show_regs(struct pt_regs * regs)200652a12efSRussell King void show_regs(struct pt_regs * regs)
201652a12efSRussell King {
202652a12efSRussell King __show_regs(regs);
20309cffecaSZhen Lei dump_backtrace(regs, NULL, KERN_DEFAULT);
204652a12efSRussell King }
205652a12efSRussell King
206797245f5SRussell King ATOMIC_NOTIFIER_HEAD(thread_notify_head);
207797245f5SRussell King
208797245f5SRussell King EXPORT_SYMBOL_GPL(thread_notify_head);
209797245f5SRussell King
2101da177e4SLinus Torvalds /*
2111da177e4SLinus Torvalds * Free current thread data structures etc..
2121da177e4SLinus Torvalds */
exit_thread(struct task_struct * tsk)213e6464694SJiri Slaby void exit_thread(struct task_struct *tsk)
2141da177e4SLinus Torvalds {
215e6464694SJiri Slaby thread_notify(THREAD_NOTIFY_EXIT, task_thread_info(tsk));
2161da177e4SLinus Torvalds }
2171da177e4SLinus Torvalds
flush_thread(void)2181da177e4SLinus Torvalds void flush_thread(void)
2191da177e4SLinus Torvalds {
2201da177e4SLinus Torvalds struct thread_info *thread = current_thread_info();
2211da177e4SLinus Torvalds struct task_struct *tsk = current;
2221da177e4SLinus Torvalds
223864232faSWill Deacon flush_ptrace_hw_breakpoint(tsk);
224864232faSWill Deacon
2251da177e4SLinus Torvalds memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
226d6551e88SRussell King memset(&thread->fpstate, 0, sizeof(union fp_state));
227d6551e88SRussell King
228fbfb872fSNathan Lynch flush_tls();
229fbfb872fSNathan Lynch
230d6551e88SRussell King thread_notify(THREAD_NOTIFY_FLUSH, thread);
2311da177e4SLinus Torvalds }
2321da177e4SLinus Torvalds
2331da177e4SLinus Torvalds asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
2341da177e4SLinus Torvalds
copy_thread(struct task_struct * p,const struct kernel_clone_args * args)235c5febea0SEric W. Biederman int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
2361da177e4SLinus Torvalds {
237c5febea0SEric W. Biederman unsigned long clone_flags = args->flags;
238c5febea0SEric W. Biederman unsigned long stack_start = args->stack;
239c5febea0SEric W. Biederman unsigned long tls = args->tls;
240815d5ec8SAl Viro struct thread_info *thread = task_thread_info(p);
241815d5ec8SAl Viro struct pt_regs *childregs = task_pt_regs(p);
2421da177e4SLinus Torvalds
2439e14f828SAl Viro memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
2449e14f828SAl Viro
245af4cb25dSRussell King #ifdef CONFIG_CPU_USE_DOMAINS
2461eef5d2fSRussell King /*
2471eef5d2fSRussell King * Copy the initial value of the domain access control register
2481eef5d2fSRussell King * from the current thread: thread->addr_limit will have been
2491eef5d2fSRussell King * copied from the current thread via setup_thread_stack() in
2501eef5d2fSRussell King * kernel/fork.c
2511eef5d2fSRussell King */
2521eef5d2fSRussell King thread->cpu_domain = get_domain();
253af4cb25dSRussell King #endif
2541eef5d2fSRussell King
2555bd2e97cSEric W. Biederman if (likely(!args->fn)) {
25638a61b6bSAl Viro *childregs = *current_pt_regs();
2571da177e4SLinus Torvalds childregs->ARM_r0 = 0;
25838a61b6bSAl Viro if (stack_start)
2591da177e4SLinus Torvalds childregs->ARM_sp = stack_start;
2609e14f828SAl Viro } else {
2619fff2fa0SAl Viro memset(childregs, 0, sizeof(struct pt_regs));
2625bd2e97cSEric W. Biederman thread->cpu_context.r4 = (unsigned long)args->fn_arg;
2635bd2e97cSEric W. Biederman thread->cpu_context.r5 = (unsigned long)args->fn;
2649e14f828SAl Viro childregs->ARM_cpsr = SVC_MODE;
2659e14f828SAl Viro }
2669fff2fa0SAl Viro thread->cpu_context.pc = (unsigned long)ret_from_fork;
2679e14f828SAl Viro thread->cpu_context.sp = (unsigned long)childregs;
2681da177e4SLinus Torvalds
269864232faSWill Deacon clear_ptrace_hw_breakpoint(p);
270864232faSWill Deacon
2711da177e4SLinus Torvalds if (clone_flags & CLONE_SETTLS)
272167ee0b8SAmanieu d'Antras thread->tp_value[0] = tls;
273a4780adeSAndré Hentschel thread->tp_value[1] = get_tpuser();
2741da177e4SLinus Torvalds
2752e82669aSCatalin Marinas thread_notify(THREAD_NOTIFY_COPY, thread);
2762e82669aSCatalin Marinas
2771da177e4SLinus Torvalds return 0;
2781da177e4SLinus Torvalds }
2791da177e4SLinus Torvalds
__get_wchan(struct task_struct * p)28042a20f86SKees Cook unsigned long __get_wchan(struct task_struct *p)
2811da177e4SLinus Torvalds {
2822d7c11bfSCatalin Marinas struct stackframe frame;
2831b15ec7aSKonstantin Khlebnikov unsigned long stack_page;
2841da177e4SLinus Torvalds int count = 0;
2851da177e4SLinus Torvalds
2862d7c11bfSCatalin Marinas frame.fp = thread_saved_fp(p);
2872d7c11bfSCatalin Marinas frame.sp = thread_saved_sp(p);
2882d7c11bfSCatalin Marinas frame.lr = 0; /* recovered from the stack */
2892d7c11bfSCatalin Marinas frame.pc = thread_saved_pc(p);
2901b15ec7aSKonstantin Khlebnikov stack_page = (unsigned long)task_stack_page(p);
2911da177e4SLinus Torvalds do {
2921b15ec7aSKonstantin Khlebnikov if (frame.sp < stack_page ||
2931b15ec7aSKonstantin Khlebnikov frame.sp >= stack_page + THREAD_SIZE ||
2941b15ec7aSKonstantin Khlebnikov unwind_frame(&frame) < 0)
2951da177e4SLinus Torvalds return 0;
2962d7c11bfSCatalin Marinas if (!in_sched_functions(frame.pc))
2972d7c11bfSCatalin Marinas return frame.pc;
2981da177e4SLinus Torvalds } while (count ++ < 16);
2991da177e4SLinus Torvalds return 0;
3001da177e4SLinus Torvalds }
301990cb8acSNicolas Pitre
3026cde6d42SWill Deacon #ifdef CONFIG_MMU
303a5463cd3SRussell King #ifdef CONFIG_KUSER_HELPERS
304ec706dabSNicolas Pitre /*
305ec706dabSNicolas Pitre * The vectors page is always readable from user space for the
30648be69a0SRussell King * atomic helpers. Insert it into the gate_vma so that it is visible
30748be69a0SRussell King * through ptrace and /proc/<pid>/mem.
308ec706dabSNicolas Pitre */
309a670468fSAndrew Morton static struct vm_area_struct gate_vma;
310ec706dabSNicolas Pitre
gate_vma_init(void)311f9d4861fSWill Deacon static int __init gate_vma_init(void)
312ec706dabSNicolas Pitre {
3132c4541e2SKirill A. Shutemov vma_init(&gate_vma, NULL);
314f9d4861fSWill Deacon gate_vma.vm_page_prot = PAGE_READONLY_EXEC;
315a670468fSAndrew Morton gate_vma.vm_start = 0xffff0000;
316a670468fSAndrew Morton gate_vma.vm_end = 0xffff0000 + PAGE_SIZE;
317*1c71222eSSuren Baghdasaryan vm_flags_init(&gate_vma, VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC);
318f9d4861fSWill Deacon return 0;
319f9d4861fSWill Deacon }
320f9d4861fSWill Deacon arch_initcall(gate_vma_init);
321f9d4861fSWill Deacon
get_gate_vma(struct mm_struct * mm)322f9d4861fSWill Deacon struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
323f9d4861fSWill Deacon {
324f9d4861fSWill Deacon return &gate_vma;
325f9d4861fSWill Deacon }
326f9d4861fSWill Deacon
in_gate_area(struct mm_struct * mm,unsigned long addr)327f9d4861fSWill Deacon int in_gate_area(struct mm_struct *mm, unsigned long addr)
328f9d4861fSWill Deacon {
329f9d4861fSWill Deacon return (addr >= gate_vma.vm_start) && (addr < gate_vma.vm_end);
330f9d4861fSWill Deacon }
331f9d4861fSWill Deacon
in_gate_area_no_mm(unsigned long addr)332f9d4861fSWill Deacon int in_gate_area_no_mm(unsigned long addr)
333f9d4861fSWill Deacon {
334f9d4861fSWill Deacon return in_gate_area(NULL, addr);
335ec706dabSNicolas Pitre }
3361d0bbf42SRussell King #define is_gate_vma(vma) ((vma) == &gate_vma)
337a5463cd3SRussell King #else
338a5463cd3SRussell King #define is_gate_vma(vma) 0
339a5463cd3SRussell King #endif
340ec706dabSNicolas Pitre
arch_vma_name(struct vm_area_struct * vma)341ec706dabSNicolas Pitre const char *arch_vma_name(struct vm_area_struct *vma)
342ec706dabSNicolas Pitre {
34302e0409aSNathan Lynch return is_gate_vma(vma) ? "[vectors]" : NULL;
34448be69a0SRussell King }
34548be69a0SRussell King
346389522b0SNathan Lynch /* If possible, provide a placement hint at a random offset from the
347ecf99a43SNathan Lynch * stack for the sigpage and vdso pages.
348389522b0SNathan Lynch */
sigpage_addr(const struct mm_struct * mm,unsigned int npages)349389522b0SNathan Lynch static unsigned long sigpage_addr(const struct mm_struct *mm,
350389522b0SNathan Lynch unsigned int npages)
351389522b0SNathan Lynch {
352389522b0SNathan Lynch unsigned long offset;
353389522b0SNathan Lynch unsigned long first;
354389522b0SNathan Lynch unsigned long last;
355389522b0SNathan Lynch unsigned long addr;
356389522b0SNathan Lynch unsigned int slots;
357389522b0SNathan Lynch
358389522b0SNathan Lynch first = PAGE_ALIGN(mm->start_stack);
359389522b0SNathan Lynch
360389522b0SNathan Lynch last = TASK_SIZE - (npages << PAGE_SHIFT);
361389522b0SNathan Lynch
362389522b0SNathan Lynch /* No room after stack? */
363389522b0SNathan Lynch if (first > last)
364389522b0SNathan Lynch return 0;
365389522b0SNathan Lynch
366389522b0SNathan Lynch /* Just enough room? */
367389522b0SNathan Lynch if (first == last)
368389522b0SNathan Lynch return first;
369389522b0SNathan Lynch
370389522b0SNathan Lynch slots = ((last - first) >> PAGE_SHIFT) + 1;
371389522b0SNathan Lynch
3728032bf12SJason A. Donenfeld offset = get_random_u32_below(slots);
373389522b0SNathan Lynch
374389522b0SNathan Lynch addr = first + (offset << PAGE_SHIFT);
375389522b0SNathan Lynch
376389522b0SNathan Lynch return addr;
37748be69a0SRussell King }
37848be69a0SRussell King
379e0d40756SRussell King static struct page *signal_page;
38048be69a0SRussell King extern struct page *get_signal_page(void);
38148be69a0SRussell King
sigpage_mremap(const struct vm_special_mapping * sm,struct vm_area_struct * new_vma)382280e87e9SDmitry Safonov static int sigpage_mremap(const struct vm_special_mapping *sm,
383280e87e9SDmitry Safonov struct vm_area_struct *new_vma)
384280e87e9SDmitry Safonov {
385280e87e9SDmitry Safonov current->mm->context.sigpage = new_vma->vm_start;
386280e87e9SDmitry Safonov return 0;
387280e87e9SDmitry Safonov }
388280e87e9SDmitry Safonov
38902e0409aSNathan Lynch static const struct vm_special_mapping sigpage_mapping = {
39002e0409aSNathan Lynch .name = "[sigpage]",
39102e0409aSNathan Lynch .pages = &signal_page,
392280e87e9SDmitry Safonov .mremap = sigpage_mremap,
39302e0409aSNathan Lynch };
39402e0409aSNathan Lynch
arch_setup_additional_pages(struct linux_binprm * bprm,int uses_interp)39548be69a0SRussell King int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
39648be69a0SRussell King {
39748be69a0SRussell King struct mm_struct *mm = current->mm;
39802e0409aSNathan Lynch struct vm_area_struct *vma;
399ecf99a43SNathan Lynch unsigned long npages;
40048be69a0SRussell King unsigned long addr;
401389522b0SNathan Lynch unsigned long hint;
40202e0409aSNathan Lynch int ret = 0;
40348be69a0SRussell King
404e0d40756SRussell King if (!signal_page)
405e0d40756SRussell King signal_page = get_signal_page();
406e0d40756SRussell King if (!signal_page)
40748be69a0SRussell King return -ENOMEM;
40848be69a0SRussell King
409ecf99a43SNathan Lynch npages = 1; /* for sigpage */
410ecf99a43SNathan Lynch npages += vdso_total_pages;
411ecf99a43SNathan Lynch
412d8ed45c5SMichel Lespinasse if (mmap_write_lock_killable(mm))
41369048176SMichal Hocko return -EINTR;
414ecf99a43SNathan Lynch hint = sigpage_addr(mm, npages);
415ecf99a43SNathan Lynch addr = get_unmapped_area(NULL, hint, npages << PAGE_SHIFT, 0, 0);
41648be69a0SRussell King if (IS_ERR_VALUE(addr)) {
41748be69a0SRussell King ret = addr;
41848be69a0SRussell King goto up_fail;
41948be69a0SRussell King }
42048be69a0SRussell King
42102e0409aSNathan Lynch vma = _install_special_mapping(mm, addr, PAGE_SIZE,
42248be69a0SRussell King VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
42302e0409aSNathan Lynch &sigpage_mapping);
42448be69a0SRussell King
42502e0409aSNathan Lynch if (IS_ERR(vma)) {
42602e0409aSNathan Lynch ret = PTR_ERR(vma);
42702e0409aSNathan Lynch goto up_fail;
42802e0409aSNathan Lynch }
42902e0409aSNathan Lynch
43048be69a0SRussell King mm->context.sigpage = addr;
43148be69a0SRussell King
432ecf99a43SNathan Lynch /* Unlike the sigpage, failure to install the vdso is unlikely
433ecf99a43SNathan Lynch * to be fatal to the process, so no error check needed
434ecf99a43SNathan Lynch * here.
435ecf99a43SNathan Lynch */
436ecf99a43SNathan Lynch arm_install_vdso(mm, addr + PAGE_SIZE);
437ecf99a43SNathan Lynch
43848be69a0SRussell King up_fail:
439d8ed45c5SMichel Lespinasse mmap_write_unlock(mm);
44048be69a0SRussell King return ret;
441ec706dabSNicolas Pitre }
4426cde6d42SWill Deacon #endif
443