1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/arch/alpha/kernel/process.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 1995 Linus Torvalds
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds /*
91da177e4SLinus Torvalds * This file handles the architecture-dependent parts of process handling.
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
121e8a0be5SJosh Poimboeuf #include <linux/cpu.h>
131da177e4SLinus Torvalds #include <linux/errno.h>
141da177e4SLinus Torvalds #include <linux/module.h>
151da177e4SLinus Torvalds #include <linux/sched.h>
16b17b0153SIngo Molnar #include <linux/sched/debug.h>
1729930025SIngo Molnar #include <linux/sched/task.h>
1868db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
191da177e4SLinus Torvalds #include <linux/kernel.h>
201da177e4SLinus Torvalds #include <linux/mm.h>
211da177e4SLinus Torvalds #include <linux/smp.h>
221da177e4SLinus Torvalds #include <linux/stddef.h>
231da177e4SLinus Torvalds #include <linux/unistd.h>
241da177e4SLinus Torvalds #include <linux/ptrace.h>
251da177e4SLinus Torvalds #include <linux/user.h>
261da177e4SLinus Torvalds #include <linux/time.h>
271da177e4SLinus Torvalds #include <linux/major.h>
281da177e4SLinus Torvalds #include <linux/stat.h>
29a8f340e3SJon Smirl #include <linux/vt.h>
301da177e4SLinus Torvalds #include <linux/mman.h>
311da177e4SLinus Torvalds #include <linux/elfcore.h>
321da177e4SLinus Torvalds #include <linux/reboot.h>
331da177e4SLinus Torvalds #include <linux/tty.h>
341da177e4SLinus Torvalds #include <linux/console.h>
355a0e3ad6STejun Heo #include <linux/slab.h>
364c94cadaSFrederic Weisbecker #include <linux/rcupdate.h>
371da177e4SLinus Torvalds
381da177e4SLinus Torvalds #include <asm/reg.h>
397c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
401da177e4SLinus Torvalds #include <asm/io.h>
411da177e4SLinus Torvalds #include <asm/hwrpb.h>
421da177e4SLinus Torvalds #include <asm/fpu.h>
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds #include "proto.h"
451da177e4SLinus Torvalds #include "pci_impl.h"
461da177e4SLinus Torvalds
475e38291dSEric W. Biederman /*
485e38291dSEric W. Biederman * Power off function, if any
495e38291dSEric W. Biederman */
505e38291dSEric W. Biederman void (*pm_power_off)(void) = machine_power_off;
5189eb1693SAl Viro EXPORT_SYMBOL(pm_power_off);
525e38291dSEric W. Biederman
537f3bbb82SRichard Henderson #ifdef CONFIG_ALPHA_WTINT
547f3bbb82SRichard Henderson /*
557f3bbb82SRichard Henderson * Sleep the CPU.
567f3bbb82SRichard Henderson * EV6, LCA45 and QEMU know how to power down, skipping N timer interrupts.
577f3bbb82SRichard Henderson */
arch_cpu_idle(void)587f3bbb82SRichard Henderson void arch_cpu_idle(void)
597f3bbb82SRichard Henderson {
607f3bbb82SRichard Henderson wtint(0);
617f3bbb82SRichard Henderson }
627f3bbb82SRichard Henderson
arch_cpu_idle_dead(void)63*071c44e4SJosh Poimboeuf void __noreturn arch_cpu_idle_dead(void)
647f3bbb82SRichard Henderson {
657f3bbb82SRichard Henderson wtint(INT_MAX);
66550db679SJosh Poimboeuf BUG();
677f3bbb82SRichard Henderson }
687f3bbb82SRichard Henderson #endif /* ALPHA_WTINT */
697f3bbb82SRichard Henderson
701da177e4SLinus Torvalds struct halt_info {
711da177e4SLinus Torvalds int mode;
721da177e4SLinus Torvalds char *restart_cmd;
731da177e4SLinus Torvalds };
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds static void
common_shutdown_1(void * generic_ptr)761da177e4SLinus Torvalds common_shutdown_1(void *generic_ptr)
771da177e4SLinus Torvalds {
7889b25c0eSLi zeming struct halt_info *how = generic_ptr;
791da177e4SLinus Torvalds struct percpu_struct *cpup;
801da177e4SLinus Torvalds unsigned long *pflags, flags;
811da177e4SLinus Torvalds int cpuid = smp_processor_id();
821da177e4SLinus Torvalds
831da177e4SLinus Torvalds /* No point in taking interrupts anymore. */
841da177e4SLinus Torvalds local_irq_disable();
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds cpup = (struct percpu_struct *)
871da177e4SLinus Torvalds ((unsigned long)hwrpb + hwrpb->processor_offset
881da177e4SLinus Torvalds + hwrpb->processor_size * cpuid);
891da177e4SLinus Torvalds pflags = &cpup->flags;
901da177e4SLinus Torvalds flags = *pflags;
911da177e4SLinus Torvalds
921da177e4SLinus Torvalds /* Clear reason to "default"; clear "bootstrap in progress". */
931da177e4SLinus Torvalds flags &= ~0x00ff0001UL;
941da177e4SLinus Torvalds
951da177e4SLinus Torvalds #ifdef CONFIG_SMP
961da177e4SLinus Torvalds /* Secondaries halt here. */
971da177e4SLinus Torvalds if (cpuid != boot_cpuid) {
981da177e4SLinus Torvalds flags |= 0x00040000UL; /* "remain halted" */
991da177e4SLinus Torvalds *pflags = flags;
1001371be0fSRusty Russell set_cpu_present(cpuid, false);
1011371be0fSRusty Russell set_cpu_possible(cpuid, false);
1021da177e4SLinus Torvalds halt();
1031da177e4SLinus Torvalds }
1041da177e4SLinus Torvalds #endif
1051da177e4SLinus Torvalds
1061da177e4SLinus Torvalds if (how->mode == LINUX_REBOOT_CMD_RESTART) {
1071da177e4SLinus Torvalds if (!how->restart_cmd) {
1081da177e4SLinus Torvalds flags |= 0x00020000UL; /* "cold bootstrap" */
1091da177e4SLinus Torvalds } else {
1101da177e4SLinus Torvalds /* For SRM, we could probably set environment
1111da177e4SLinus Torvalds variables to get this to work. We'd have to
1121da177e4SLinus Torvalds delay this until after srm_paging_stop unless
1131da177e4SLinus Torvalds we ever got srm_fixup working.
1141da177e4SLinus Torvalds
1151da177e4SLinus Torvalds At the moment, SRM will use the last boot device,
1161da177e4SLinus Torvalds but the file and flags will be the defaults, when
1171da177e4SLinus Torvalds doing a "warm" bootstrap. */
1181da177e4SLinus Torvalds flags |= 0x00030000UL; /* "warm bootstrap" */
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds } else {
1211da177e4SLinus Torvalds flags |= 0x00040000UL; /* "remain halted" */
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds *pflags = flags;
1241da177e4SLinus Torvalds
1251da177e4SLinus Torvalds #ifdef CONFIG_SMP
1261da177e4SLinus Torvalds /* Wait for the secondaries to halt. */
1271371be0fSRusty Russell set_cpu_present(boot_cpuid, false);
1281371be0fSRusty Russell set_cpu_possible(boot_cpuid, false);
12971c1a517SYury Norov while (!cpumask_empty(cpu_present_mask))
1301da177e4SLinus Torvalds barrier();
1311da177e4SLinus Torvalds #endif
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds /* If booted from SRM, reset some of the original environment. */
1341da177e4SLinus Torvalds if (alpha_using_srm) {
1351da177e4SLinus Torvalds #ifdef CONFIG_DUMMY_CONSOLE
1364b3c86a7SIvan Kokshaysky /* If we've gotten here after SysRq-b, leave interrupt
1374b3c86a7SIvan Kokshaysky context before taking over the console. */
138290ec1d5SChangbin Du if (in_hardirq())
1394b3c86a7SIvan Kokshaysky irq_exit();
1401da177e4SLinus Torvalds /* This has the effect of resetting the VGA video origin. */
141155957f5SWang YanQing console_lock();
142155957f5SWang YanQing do_take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
143155957f5SWang YanQing console_unlock();
1441da177e4SLinus Torvalds #endif
1451da177e4SLinus Torvalds pci_restore_srm_config();
1461da177e4SLinus Torvalds set_hae(srm_hae);
1471da177e4SLinus Torvalds }
1481da177e4SLinus Torvalds
1491da177e4SLinus Torvalds if (alpha_mv.kill_arch)
1501da177e4SLinus Torvalds alpha_mv.kill_arch(how->mode);
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds if (! alpha_using_srm && how->mode != LINUX_REBOOT_CMD_RESTART) {
1531da177e4SLinus Torvalds /* Unfortunately, since MILO doesn't currently understand
1541da177e4SLinus Torvalds the hwrpb bits above, we can't reliably halt the
1551da177e4SLinus Torvalds processor and keep it halted. So just loop. */
1561da177e4SLinus Torvalds return;
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds
1591da177e4SLinus Torvalds if (alpha_using_srm)
1601da177e4SLinus Torvalds srm_paging_stop();
1611da177e4SLinus Torvalds
1621da177e4SLinus Torvalds halt();
1631da177e4SLinus Torvalds }
1641da177e4SLinus Torvalds
1651da177e4SLinus Torvalds static void
common_shutdown(int mode,char * restart_cmd)1661da177e4SLinus Torvalds common_shutdown(int mode, char *restart_cmd)
1671da177e4SLinus Torvalds {
1681da177e4SLinus Torvalds struct halt_info args;
1691da177e4SLinus Torvalds args.mode = mode;
1701da177e4SLinus Torvalds args.restart_cmd = restart_cmd;
17115c8b6c1SJens Axboe on_each_cpu(common_shutdown_1, &args, 0);
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds
1741da177e4SLinus Torvalds void
machine_restart(char * restart_cmd)1751da177e4SLinus Torvalds machine_restart(char *restart_cmd)
1761da177e4SLinus Torvalds {
1771da177e4SLinus Torvalds common_shutdown(LINUX_REBOOT_CMD_RESTART, restart_cmd);
1781da177e4SLinus Torvalds }
1791da177e4SLinus Torvalds
1801da177e4SLinus Torvalds
1811da177e4SLinus Torvalds void
machine_halt(void)1821da177e4SLinus Torvalds machine_halt(void)
1831da177e4SLinus Torvalds {
1841da177e4SLinus Torvalds common_shutdown(LINUX_REBOOT_CMD_HALT, NULL);
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds
1871da177e4SLinus Torvalds
1881da177e4SLinus Torvalds void
machine_power_off(void)1891da177e4SLinus Torvalds machine_power_off(void)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds common_shutdown(LINUX_REBOOT_CMD_POWER_OFF, NULL);
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds
1941da177e4SLinus Torvalds
1951da177e4SLinus Torvalds /* Used by sysrq-p, among others. I don't believe r9-r15 are ever
1961da177e4SLinus Torvalds saved in the context it's used. */
1971da177e4SLinus Torvalds
1981da177e4SLinus Torvalds void
show_regs(struct pt_regs * regs)1991da177e4SLinus Torvalds show_regs(struct pt_regs *regs)
2001da177e4SLinus Torvalds {
201a43cb95dSTejun Heo show_regs_print_info(KERN_DEFAULT);
2021da177e4SLinus Torvalds dik_show_regs(regs, NULL);
2031da177e4SLinus Torvalds }
2041da177e4SLinus Torvalds
2051da177e4SLinus Torvalds /*
2061da177e4SLinus Torvalds * Re-start a thread when doing execve()
2071da177e4SLinus Torvalds */
2081da177e4SLinus Torvalds void
start_thread(struct pt_regs * regs,unsigned long pc,unsigned long sp)2091da177e4SLinus Torvalds start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
2101da177e4SLinus Torvalds {
2111da177e4SLinus Torvalds regs->pc = pc;
2121da177e4SLinus Torvalds regs->ps = 8;
2131da177e4SLinus Torvalds wrusp(sp);
2141da177e4SLinus Torvalds }
215cff52dafSAl Viro EXPORT_SYMBOL(start_thread);
2161da177e4SLinus Torvalds
2171da177e4SLinus Torvalds void
flush_thread(void)2181da177e4SLinus Torvalds flush_thread(void)
2191da177e4SLinus Torvalds {
2201da177e4SLinus Torvalds /* Arrange for each exec'ed process to start off with a clean slate
2211da177e4SLinus Torvalds with respect to the FPU. This is all exceptions disabled. */
2221da177e4SLinus Torvalds current_thread_info()->ieee_state = 0;
2231da177e4SLinus Torvalds wrfpcr(FPCR_DYN_NORMAL | ieee_swcr_to_fpcr(0));
2241da177e4SLinus Torvalds
2251da177e4SLinus Torvalds /* Clean slate for TLS. */
2261da177e4SLinus Torvalds current_thread_info()->pcb.unique = 0;
2271da177e4SLinus Torvalds }
2281da177e4SLinus Torvalds
2291da177e4SLinus Torvalds /*
2309f7b2d1fSAlex Dowad * Copy architecture-specific thread state
2311da177e4SLinus Torvalds */
copy_thread(struct task_struct * p,const struct kernel_clone_args * args)232c5febea0SEric W. Biederman int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
2331da177e4SLinus Torvalds {
234c5febea0SEric W. Biederman unsigned long clone_flags = args->flags;
235c5febea0SEric W. Biederman unsigned long usp = args->stack;
236c5febea0SEric W. Biederman unsigned long tls = args->tls;
2371da177e4SLinus Torvalds extern void ret_from_fork(void);
238cba1ec7eSAl Viro extern void ret_from_kernel_thread(void);
2391da177e4SLinus Torvalds
24027f45130SAl Viro struct thread_info *childti = task_thread_info(p);
241cba1ec7eSAl Viro struct pt_regs *childregs = task_pt_regs(p);
24225906730SAl Viro struct pt_regs *regs = current_pt_regs();
2431da177e4SLinus Torvalds struct switch_stack *childstack, *stack;
2441da177e4SLinus Torvalds
245cba1ec7eSAl Viro childstack = ((struct switch_stack *) childregs) - 1;
24625906730SAl Viro childti->pcb.ksp = (unsigned long) childstack;
24725906730SAl Viro childti->pcb.flags = 1; /* set FEN, clear everything else */
24805096666SAl Viro childti->status |= TS_SAVED_FP | TS_RESTORE_FP;
24925906730SAl Viro
2505bd2e97cSEric W. Biederman if (unlikely(args->fn)) {
251cba1ec7eSAl Viro /* kernel thread */
252cba1ec7eSAl Viro memset(childstack, 0,
253cba1ec7eSAl Viro sizeof(struct switch_stack) + sizeof(struct pt_regs));
254cba1ec7eSAl Viro childstack->r26 = (unsigned long) ret_from_kernel_thread;
2555bd2e97cSEric W. Biederman childstack->r9 = (unsigned long) args->fn;
2565bd2e97cSEric W. Biederman childstack->r10 = (unsigned long) args->fn_arg;
257f0443da1SZheng Yongjun childregs->hae = alpha_mv.hae_cache;
25805096666SAl Viro memset(childti->fp, '\0', sizeof(childti->fp));
259cba1ec7eSAl Viro childti->pcb.usp = 0;
260cba1ec7eSAl Viro return 0;
261cba1ec7eSAl Viro }
26225906730SAl Viro /* Note: if CLONE_SETTLS is not set, then we must inherit the
26325906730SAl Viro value from the parent, which will have been set by the block
26425906730SAl Viro copy in dup_task_struct. This is non-intuitive, but is
26525906730SAl Viro required for proper operation in the case of a threaded
26625906730SAl Viro application calling fork. */
26725906730SAl Viro if (clone_flags & CLONE_SETTLS)
2680fdfc53fSChristian Brauner childti->pcb.unique = tls;
26921ffcedaSMikulas Patocka else
27021ffcedaSMikulas Patocka regs->r20 = 0; /* OSF/1 has some strange fork() semantics. */
27125906730SAl Viro childti->pcb.usp = usp ?: rdusp();
2721da177e4SLinus Torvalds *childregs = *regs;
2731da177e4SLinus Torvalds childregs->r0 = 0;
2741da177e4SLinus Torvalds childregs->r19 = 0;
2751da177e4SLinus Torvalds childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
2761da177e4SLinus Torvalds stack = ((struct switch_stack *) regs) - 1;
2771da177e4SLinus Torvalds *childstack = *stack;
2781da177e4SLinus Torvalds childstack->r26 = (unsigned long) ret_from_fork;
2791da177e4SLinus Torvalds return 0;
2801da177e4SLinus Torvalds }
2811da177e4SLinus Torvalds
2821da177e4SLinus Torvalds /*
2831da177e4SLinus Torvalds * Fill in the user structure for a ELF core dump.
2841da177e4SLinus Torvalds */
2851da177e4SLinus Torvalds void
dump_elf_thread(elf_greg_t * dest,struct pt_regs * pt,struct thread_info * ti)2861da177e4SLinus Torvalds dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt, struct thread_info *ti)
2871da177e4SLinus Torvalds {
2881da177e4SLinus Torvalds /* switch stack follows right below pt_regs: */
2891da177e4SLinus Torvalds struct switch_stack * sw = ((struct switch_stack *) pt) - 1;
2901da177e4SLinus Torvalds
2911da177e4SLinus Torvalds dest[ 0] = pt->r0;
2921da177e4SLinus Torvalds dest[ 1] = pt->r1;
2931da177e4SLinus Torvalds dest[ 2] = pt->r2;
2941da177e4SLinus Torvalds dest[ 3] = pt->r3;
2951da177e4SLinus Torvalds dest[ 4] = pt->r4;
2961da177e4SLinus Torvalds dest[ 5] = pt->r5;
2971da177e4SLinus Torvalds dest[ 6] = pt->r6;
2981da177e4SLinus Torvalds dest[ 7] = pt->r7;
2991da177e4SLinus Torvalds dest[ 8] = pt->r8;
3001da177e4SLinus Torvalds dest[ 9] = sw->r9;
3011da177e4SLinus Torvalds dest[10] = sw->r10;
3021da177e4SLinus Torvalds dest[11] = sw->r11;
3031da177e4SLinus Torvalds dest[12] = sw->r12;
3041da177e4SLinus Torvalds dest[13] = sw->r13;
3051da177e4SLinus Torvalds dest[14] = sw->r14;
3061da177e4SLinus Torvalds dest[15] = sw->r15;
3071da177e4SLinus Torvalds dest[16] = pt->r16;
3081da177e4SLinus Torvalds dest[17] = pt->r17;
3091da177e4SLinus Torvalds dest[18] = pt->r18;
3101da177e4SLinus Torvalds dest[19] = pt->r19;
3111da177e4SLinus Torvalds dest[20] = pt->r20;
3121da177e4SLinus Torvalds dest[21] = pt->r21;
3131da177e4SLinus Torvalds dest[22] = pt->r22;
3141da177e4SLinus Torvalds dest[23] = pt->r23;
3151da177e4SLinus Torvalds dest[24] = pt->r24;
3161da177e4SLinus Torvalds dest[25] = pt->r25;
3171da177e4SLinus Torvalds dest[26] = pt->r26;
3181da177e4SLinus Torvalds dest[27] = pt->r27;
3191da177e4SLinus Torvalds dest[28] = pt->r28;
3201da177e4SLinus Torvalds dest[29] = pt->gp;
32132163f4bSAl Viro dest[30] = ti == current_thread_info() ? rdusp() : ti->pcb.usp;
3221da177e4SLinus Torvalds dest[31] = pt->pc;
3231da177e4SLinus Torvalds
3241da177e4SLinus Torvalds /* Once upon a time this was the PS value. Which is stupid
3251da177e4SLinus Torvalds since that is always 8 for usermode. Usurped for the more
3261da177e4SLinus Torvalds useful value of the thread's UNIQUE field. */
3271da177e4SLinus Torvalds dest[32] = ti->pcb.unique;
3281da177e4SLinus Torvalds }
329cff52dafSAl Viro EXPORT_SYMBOL(dump_elf_thread);
3301da177e4SLinus Torvalds
3311da177e4SLinus Torvalds int
dump_elf_task(elf_greg_t * dest,struct task_struct * task)3321da177e4SLinus Torvalds dump_elf_task(elf_greg_t *dest, struct task_struct *task)
3331da177e4SLinus Torvalds {
334e52f4ca2Sakpm@osdl.org dump_elf_thread(dest, task_pt_regs(task), task_thread_info(task));
3351da177e4SLinus Torvalds return 1;
3361da177e4SLinus Torvalds }
337cff52dafSAl Viro EXPORT_SYMBOL(dump_elf_task);
3381da177e4SLinus Torvalds
elf_core_copy_task_fpregs(struct task_struct * t,elf_fpregset_t * fpu)339bdbadfccSAl Viro int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
3401da177e4SLinus Torvalds {
34105096666SAl Viro memcpy(fpu, task_thread_info(t)->fp, 32 * 8);
3421da177e4SLinus Torvalds return 1;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds
3451da177e4SLinus Torvalds /*
3461da177e4SLinus Torvalds * Return saved PC of a blocked thread. This assumes the frame
3471da177e4SLinus Torvalds * pointer is the 6th saved long on the kernel stack and that the
3481da177e4SLinus Torvalds * saved return address is the first long in the frame. This all
3491da177e4SLinus Torvalds * holds provided the thread blocked through a call to schedule() ($15
3501da177e4SLinus Torvalds * is the frame pointer in schedule() and $15 is saved at offset 48 by
3511da177e4SLinus Torvalds * entry.S:do_switch_stack).
3521da177e4SLinus Torvalds *
3531da177e4SLinus Torvalds * Under heavy swap load I've seen this lose in an ugly way. So do
3541da177e4SLinus Torvalds * some extra sanity checking on the ranges we expect these pointers
3551da177e4SLinus Torvalds * to be in so that we can fail gracefully. This is just for ps after
3561da177e4SLinus Torvalds * all. -- r~
3571da177e4SLinus Torvalds */
3581da177e4SLinus Torvalds
35916dc17eeSTobias Klauser static unsigned long
thread_saved_pc(struct task_struct * t)36036c8b586SIngo Molnar thread_saved_pc(struct task_struct *t)
3611da177e4SLinus Torvalds {
36227f45130SAl Viro unsigned long base = (unsigned long)task_stack_page(t);
36337bfbaf9SAl Viro unsigned long fp, sp = task_thread_info(t)->pcb.ksp;
3641da177e4SLinus Torvalds
3651da177e4SLinus Torvalds if (sp > base && sp+6*8 < base + 16*1024) {
3661da177e4SLinus Torvalds fp = ((unsigned long*)sp)[6];
3671da177e4SLinus Torvalds if (fp > sp && fp < base + 16*1024)
3681da177e4SLinus Torvalds return *(unsigned long *)fp;
3691da177e4SLinus Torvalds }
3701da177e4SLinus Torvalds
3711da177e4SLinus Torvalds return 0;
3721da177e4SLinus Torvalds }
3731da177e4SLinus Torvalds
3741da177e4SLinus Torvalds unsigned long
__get_wchan(struct task_struct * p)37542a20f86SKees Cook __get_wchan(struct task_struct *p)
3761da177e4SLinus Torvalds {
3771da177e4SLinus Torvalds unsigned long schedule_frame;
3781da177e4SLinus Torvalds unsigned long pc;
37942a20f86SKees Cook
3801da177e4SLinus Torvalds /*
3811da177e4SLinus Torvalds * This one depends on the frame size of schedule(). Do a
3821da177e4SLinus Torvalds * "disass schedule" in gdb to find the frame size. Also, the
3831da177e4SLinus Torvalds * code assumes that sleep_on() follows immediately after
3841da177e4SLinus Torvalds * interruptible_sleep_on() and that add_timer() follows
3851da177e4SLinus Torvalds * immediately after interruptible_sleep(). Ugly, isn't it?
3861da177e4SLinus Torvalds * Maybe adding a wchan field to task_struct would be better,
3871da177e4SLinus Torvalds * after all...
3881da177e4SLinus Torvalds */
3891da177e4SLinus Torvalds
3901da177e4SLinus Torvalds pc = thread_saved_pc(p);
3911da177e4SLinus Torvalds if (in_sched_functions(pc)) {
39237bfbaf9SAl Viro schedule_frame = ((unsigned long *)task_thread_info(p)->pcb.ksp)[6];
3931da177e4SLinus Torvalds return ((unsigned long *)schedule_frame)[12];
3941da177e4SLinus Torvalds }
3951da177e4SLinus Torvalds return pc;
3961da177e4SLinus Torvalds }
397