diff options
Diffstat (limited to 'arch/alpha/kernel/process.c')
| -rw-r--r-- | arch/alpha/kernel/process.c | 264 |
1 files changed, 71 insertions, 193 deletions
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index eb20c3afff5..1941a07b581 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -8,33 +8,30 @@ * This file handles the architecture-dependent parts of process handling. */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/slab.h> #include <linux/user.h> -#include <linux/a.out.h> -#include <linux/utsname.h> #include <linux/time.h> #include <linux/major.h> #include <linux/stat.h> +#include <linux/vt.h> #include <linux/mman.h> #include <linux/elfcore.h> #include <linux/reboot.h> #include <linux/tty.h> #include <linux/console.h> +#include <linux/slab.h> +#include <linux/rcupdate.h> #include <asm/reg.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/hwrpb.h> @@ -43,25 +40,28 @@ #include "proto.h" #include "pci_impl.h" -void default_idle(void) +/* + * Power off function, if any + */ +void (*pm_power_off)(void) = machine_power_off; +EXPORT_SYMBOL(pm_power_off); + +#ifdef CONFIG_ALPHA_WTINT +/* + * Sleep the CPU. + * EV6, LCA45 and QEMU know how to power down, skipping N timer interrupts. + */ +void arch_cpu_idle(void) { - barrier(); + wtint(0); + local_irq_enable(); } -void -cpu_idle(void) +void arch_cpu_idle_dead(void) { - while (1) { - void (*idle)(void) = default_idle; - /* FIXME -- EV6 and LCA45 know how to power down - the CPU. */ - - while (!need_resched()) - idle(); - schedule(); - } + wtint(INT_MAX); } - +#endif /* ALPHA_WTINT */ struct halt_info { int mode; @@ -93,7 +93,8 @@ common_shutdown_1(void *generic_ptr) if (cpuid != boot_cpuid) { flags |= 0x00040000UL; /* "remain halted" */ *pflags = flags; - clear_bit(cpuid, &cpu_present_mask); + set_cpu_present(cpuid, false); + set_cpu_possible(cpuid, false); halt(); } #endif @@ -119,8 +120,9 @@ common_shutdown_1(void *generic_ptr) #ifdef CONFIG_SMP /* Wait for the secondaries to halt. */ - cpu_clear(boot_cpuid, cpu_possible_map); - while (cpus_weight(cpu_possible_map)) + set_cpu_present(boot_cpuid, false); + set_cpu_possible(boot_cpuid, false); + while (cpumask_weight(cpu_present_mask)) barrier(); #endif @@ -132,7 +134,9 @@ common_shutdown_1(void *generic_ptr) if (in_interrupt()) irq_exit(); /* This has the effect of resetting the VGA video origin. */ - take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1); + console_lock(); + do_take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1); + console_unlock(); #endif pci_restore_srm_config(); set_hae(srm_hae); @@ -160,7 +164,7 @@ common_shutdown(int mode, char *restart_cmd) struct halt_info args; args.mode = mode; args.restart_cmd = restart_cmd; - on_each_cpu(common_shutdown_1, &args, 1, 0); + on_each_cpu(common_shutdown_1, &args, 0); } void @@ -190,6 +194,7 @@ machine_power_off(void) void show_regs(struct pt_regs *regs) { + show_regs_print_info(KERN_DEFAULT); dik_show_regs(regs, NULL); } @@ -199,11 +204,11 @@ show_regs(struct pt_regs *regs) void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) { - set_fs(USER_DS); regs->pc = pc; regs->ps = 8; wrusp(sp); } +EXPORT_SYMBOL(start_thread); /* * Free current thread data structures etc.. @@ -231,152 +236,57 @@ release_thread(struct task_struct *dead_task) } /* - * "alpha_clone()".. By the time we get here, the - * non-volatile registers have also been saved on the - * stack. We do some ugly pointer stuff here.. (see - * also copy_thread) - * - * Notice that "fork()" is implemented in terms of clone, - * with parameters (SIGCHLD, 0). - */ -int -alpha_clone(unsigned long clone_flags, unsigned long usp, - int __user *parent_tid, int __user *child_tid, - unsigned long tls_value, struct pt_regs *regs) -{ - if (!usp) - usp = rdusp(); - - return do_fork(clone_flags, usp, regs, 0, parent_tid, child_tid); -} - -int -alpha_vfork(struct pt_regs *regs) -{ - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), - regs, 0, NULL, NULL); -} - -/* * Copy an alpha thread.. - * - * Note the "stack_offset" stuff: when returning to kernel mode, we need - * to have some extra stack-space for the kernel stack that still exists - * after the "ret_from_fork". When returning to user mode, we only want - * the space needed by the syscall stack frame (ie "struct pt_regs"). - * Use the passed "regs" pointer to determine how much space we need - * for a kernel fork(). */ int -copy_thread(int nr, unsigned long clone_flags, unsigned long usp, - unsigned long unused, - struct task_struct * p, struct pt_regs * regs) +copy_thread(unsigned long clone_flags, unsigned long usp, + unsigned long arg, + struct task_struct *p) { extern void ret_from_fork(void); + extern void ret_from_kernel_thread(void); + + struct thread_info *childti = task_thread_info(p); + struct pt_regs *childregs = task_pt_regs(p); + struct pt_regs *regs = current_pt_regs(); + struct switch_stack *childstack, *stack; - struct thread_info *childti = p->thread_info; - struct pt_regs * childregs; - struct switch_stack * childstack, *stack; - unsigned long stack_offset, settls; - - stack_offset = PAGE_SIZE - sizeof(struct pt_regs); - if (!(regs->ps & 8)) - stack_offset = (PAGE_SIZE-1) & (unsigned long) regs; - childregs = (struct pt_regs *) - (stack_offset + PAGE_SIZE + (long) childti); - - *childregs = *regs; - settls = regs->r20; - childregs->r0 = 0; - childregs->r19 = 0; - childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ - regs->r20 = 0; - stack = ((struct switch_stack *) regs) - 1; childstack = ((struct switch_stack *) childregs) - 1; - *childstack = *stack; - childstack->r26 = (unsigned long) ret_from_fork; - childti->pcb.usp = usp; childti->pcb.ksp = (unsigned long) childstack; childti->pcb.flags = 1; /* set FEN, clear everything else */ - /* Set a new TLS for the child thread? Peek back into the - syscall arguments that we saved on syscall entry. Oops, - except we'd have clobbered it with the parent/child set - of r20. Read the saved copy. */ + if (unlikely(p->flags & PF_KTHREAD)) { + /* kernel thread */ + memset(childstack, 0, + sizeof(struct switch_stack) + sizeof(struct pt_regs)); + childstack->r26 = (unsigned long) ret_from_kernel_thread; + childstack->r9 = usp; /* function */ + childstack->r10 = arg; + childregs->hae = alpha_mv.hae_cache, + childti->pcb.usp = 0; + return 0; + } /* Note: if CLONE_SETTLS is not set, then we must inherit the value from the parent, which will have been set by the block copy in dup_task_struct. This is non-intuitive, but is required for proper operation in the case of a threaded application calling fork. */ if (clone_flags & CLONE_SETTLS) - childti->pcb.unique = settls; - + childti->pcb.unique = regs->r20; + childti->pcb.usp = usp ?: rdusp(); + *childregs = *regs; + childregs->r0 = 0; + childregs->r19 = 0; + childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ + regs->r20 = 0; + stack = ((struct switch_stack *) regs) - 1; + *childstack = *stack; + childstack->r26 = (unsigned long) ret_from_fork; return 0; } /* - * Fill in the user structure for an ECOFF core dump. - */ -void -dump_thread(struct pt_regs * pt, struct user * dump) -{ - /* switch stack follows right below pt_regs: */ - struct switch_stack * sw = ((struct switch_stack *) pt) - 1; - - dump->magic = CMAGIC; - dump->start_code = current->mm->start_code; - dump->start_data = current->mm->start_data; - dump->start_stack = rdusp() & ~(PAGE_SIZE - 1); - dump->u_tsize = ((current->mm->end_code - dump->start_code) - >> PAGE_SHIFT); - dump->u_dsize = ((current->mm->brk + PAGE_SIZE-1 - dump->start_data) - >> PAGE_SHIFT); - dump->u_ssize = (current->mm->start_stack - dump->start_stack - + PAGE_SIZE-1) >> PAGE_SHIFT; - - /* - * We store the registers in an order/format that is - * compatible with DEC Unix/OSF/1 as this makes life easier - * for gdb. - */ - dump->regs[EF_V0] = pt->r0; - dump->regs[EF_T0] = pt->r1; - dump->regs[EF_T1] = pt->r2; - dump->regs[EF_T2] = pt->r3; - dump->regs[EF_T3] = pt->r4; - dump->regs[EF_T4] = pt->r5; - dump->regs[EF_T5] = pt->r6; - dump->regs[EF_T6] = pt->r7; - dump->regs[EF_T7] = pt->r8; - dump->regs[EF_S0] = sw->r9; - dump->regs[EF_S1] = sw->r10; - dump->regs[EF_S2] = sw->r11; - dump->regs[EF_S3] = sw->r12; - dump->regs[EF_S4] = sw->r13; - dump->regs[EF_S5] = sw->r14; - dump->regs[EF_S6] = sw->r15; - dump->regs[EF_A3] = pt->r19; - dump->regs[EF_A4] = pt->r20; - dump->regs[EF_A5] = pt->r21; - dump->regs[EF_T8] = pt->r22; - dump->regs[EF_T9] = pt->r23; - dump->regs[EF_T10] = pt->r24; - dump->regs[EF_T11] = pt->r25; - dump->regs[EF_RA] = pt->r26; - dump->regs[EF_T12] = pt->r27; - dump->regs[EF_AT] = pt->r28; - dump->regs[EF_SP] = rdusp(); - dump->regs[EF_PS] = pt->ps; - dump->regs[EF_PC] = pt->pc; - dump->regs[EF_GP] = pt->gp; - dump->regs[EF_A0] = pt->r16; - dump->regs[EF_A1] = pt->r17; - dump->regs[EF_A2] = pt->r18; - memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8); -} - -/* * Fill in the user structure for a ELF core dump. */ void @@ -415,7 +325,7 @@ dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt, struct thread_info *ti) dest[27] = pt->r27; dest[28] = pt->r28; dest[29] = pt->gp; - dest[30] = rdusp(); + dest[30] = ti == current_thread_info() ? rdusp() : ti->pcb.usp; dest[31] = pt->pc; /* Once upon a time this was the PS value. Which is stupid @@ -423,56 +333,24 @@ dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt, struct thread_info *ti) useful value of the thread's UNIQUE field. */ dest[32] = ti->pcb.unique; } +EXPORT_SYMBOL(dump_elf_thread); int dump_elf_task(elf_greg_t *dest, struct task_struct *task) { - struct thread_info *ti; - struct pt_regs *pt; - - ti = task->thread_info; - pt = (struct pt_regs *)((unsigned long)ti + 2*PAGE_SIZE) - 1; - - dump_elf_thread(dest, pt, ti); - + dump_elf_thread(dest, task_pt_regs(task), task_thread_info(task)); return 1; } +EXPORT_SYMBOL(dump_elf_task); int dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task) { - struct thread_info *ti; - struct pt_regs *pt; - struct switch_stack *sw; - - ti = task->thread_info; - pt = (struct pt_regs *)((unsigned long)ti + 2*PAGE_SIZE) - 1; - sw = (struct switch_stack *)pt - 1; - + struct switch_stack *sw = (struct switch_stack *)task_pt_regs(task) - 1; memcpy(dest, sw->fp, 32 * 8); - return 1; } - -/* - * sys_execve() executes a new program. - */ -asmlinkage int -do_sys_execve(char __user *ufilename, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs) -{ - int error; - char *filename; - - filename = getname(ufilename); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - error = do_execve(filename, argv, envp, regs); - putname(filename); -out: - return error; -} +EXPORT_SYMBOL(dump_elf_task_fp); /* * Return saved PC of a blocked thread. This assumes the frame @@ -489,10 +367,10 @@ out: */ unsigned long -thread_saved_pc(task_t *t) +thread_saved_pc(struct task_struct *t) { - unsigned long base = (unsigned long)t->thread_info; - unsigned long fp, sp = t->thread_info->pcb.ksp; + unsigned long base = (unsigned long)task_stack_page(t); + unsigned long fp, sp = task_thread_info(t)->pcb.ksp; if (sp > base && sp+6*8 < base + 16*1024) { fp = ((unsigned long*)sp)[6]; @@ -522,7 +400,7 @@ get_wchan(struct task_struct *p) pc = thread_saved_pc(p); if (in_sched_functions(pc)) { - schedule_frame = ((unsigned long *)p->thread_info->pcb.ksp)[6]; + schedule_frame = ((unsigned long *)task_thread_info(p)->pcb.ksp)[6]; return ((unsigned long *)schedule_frame)[12]; } return pc; |
