X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fum%2Fkernel%2Fskas%2Fprocess.c;h=ae4fa71d3b8b6540d4071712a1f5404ea5436eb9;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=cb91f8cd11390c38d52f90ccc80e8048e7194a49;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index cb91f8cd1..ae4fa71d3 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -1,395 +1,217 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "user.h" -#include "ptrace_user.h" -#include "time_user.h" -#include "sysdep/ptrace.h" -#include "user_util.h" +#include "linux/sched.h" +#include "linux/slab.h" +#include "linux/ptrace.h" +#include "linux/proc_fs.h" +#include "linux/file.h" +#include "linux/errno.h" +#include "linux/init.h" +#include "asm/uaccess.h" +#include "asm/atomic.h" #include "kern_util.h" #include "skas.h" -#include "sysdep/sigcontext.h" #include "os.h" -#include "proc_mm.h" -#include "skas_ptrace.h" - -unsigned long exec_regs[FRAME_SIZE]; -unsigned long exec_fp_regs[HOST_FP_SIZE]; -unsigned long exec_fpx_regs[HOST_XFP_SIZE]; -int have_fpx_regs = 1; +#include "user_util.h" +#include "tlb.h" +#include "kern.h" +#include "mode.h" +#include "registers.h" -static void handle_segv(int pid) +void switch_to_skas(void *prev, void *next) { - struct ptrace_faultinfo fault; - int err; + struct task_struct *from, *to; - err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault); - if(err) - panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n", - errno); + from = prev; + to = next; - segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL); -} - -static void handle_trap(int pid, union uml_pt_regs *regs) -{ - int err, syscall_nr, status; - - syscall_nr = PT_SYSCALL_NR(regs->skas.regs); - if(syscall_nr < 1){ - relay_signal(SIGTRAP, regs); - return; - } - UPT_SYSCALL_NR(regs) = syscall_nr; + /* XXX need to check runqueues[cpu].idle */ + if(current->pid == 0) + switch_timers(0); - err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); - if(err < 0) - panic("handle_trap - nullifying syscall failed errno = %d\n", - errno); + switch_threads(&from->thread.mode.skas.switch_buf, + &to->thread.mode.skas.switch_buf); - err = ptrace(PTRACE_SYSCALL, pid, 0, 0); - if(err < 0) - panic("handle_trap - continuing to end of syscall failed, " - "errno = %d\n", errno); + arch_switch_to_skas(current->thread.prev_sched, current); - err = waitpid(pid, &status, WUNTRACED); - if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) - panic("handle_trap - failed to wait at end of syscall, " - "errno = %d, status = %d\n", errno, status); - - handle_syscall(regs); + if(current->pid == 0) + switch_timers(1); } -int userspace_pid; +extern void schedule_tail(struct task_struct *prev); -static int userspace_tramp(void *arg) -{ - init_new_thread_signals(0); - enable_timer(); - ptrace(PTRACE_TRACEME, 0, 0, 0); - os_stop_process(os_getpid()); - return(0); +/* This is called magically, by its address being stuffed in a jmp_buf + * and being longjmp-d to. + */ +void new_thread_handler(void) +{ + int (*fn)(void *), n; + void *arg; + + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); + current->thread.prev_sched = NULL; + + fn = current->thread.request.u.thread.proc; + arg = current->thread.request.u.thread.arg; + + /* The return value is 1 if the kernel thread execs a process, + * 0 if it just exits + */ + n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); + if(n == 1){ + /* Handle any immediate reschedules or signals */ + interrupt_end(); + userspace(¤t->thread.regs.regs); + } + else do_exit(0); } -void start_userspace(void) +void release_thread_skas(struct task_struct *task) { - void *stack; - unsigned long sp; - int pid, status, n; - - stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if(stack == MAP_FAILED) - panic("start_userspace : mmap failed, errno = %d", errno); - sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); - - pid = clone(userspace_tramp, (void *) sp, - CLONE_FILES | CLONE_VM | SIGCHLD, NULL); - if(pid < 0) - panic("start_userspace : clone failed, errno = %d", errno); - - do { - n = waitpid(pid, &status, WUNTRACED); - if(n < 0) - panic("start_userspace : wait failed, errno = %d", - errno); - } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); - - if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) - panic("start_userspace : expected SIGSTOP, got status = %d", - status); - - if(munmap(stack, PAGE_SIZE) < 0) - panic("start_userspace : munmap failed, errno = %d\n", errno); - - userspace_pid = pid; } -void userspace(union uml_pt_regs *regs) +/* Called magically, see new_thread_handler above */ +void fork_handler(void) { - int err, status, op; - - restore_registers(regs); - - err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0); - if(err) - panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", - errno); - while(1){ - err = waitpid(userspace_pid, &status, WUNTRACED); - if(err < 0) - panic("userspace - waitpid failed, errno = %d\n", - errno); - - regs->skas.is_user = 1; - save_registers(regs); - - if(WIFSTOPPED(status)){ - switch(WSTOPSIG(status)){ - case SIGSEGV: - handle_segv(userspace_pid); - break; - case SIGTRAP: - handle_trap(userspace_pid, regs); - break; - case SIGIO: - case SIGVTALRM: - case SIGILL: - case SIGBUS: - case SIGFPE: - user_signal(WSTOPSIG(status), regs); - break; - default: - printk("userspace - child stopped with signal " - "%d\n", WSTOPSIG(status)); - } - interrupt_end(); - } + force_flush_all(); + if(current->thread.prev_sched == NULL) + panic("blech"); - restore_registers(regs); + schedule_tail(current->thread.prev_sched); - op = singlestepping_skas() ? PTRACE_SINGLESTEP : - PTRACE_SYSCALL; - err = ptrace(op, userspace_pid, 0, 0); - if(err) - panic("userspace - PTRACE_SYSCALL failed, " - "errno = %d\n", errno); - } -} + /* XXX: if interrupt_end() calls schedule, this call to + * arch_switch_to_skas isn't needed. We could want to apply this to + * improve performance. -bb */ + arch_switch_to_skas(current->thread.prev_sched, current); -void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, - void (*handler)(int)) -{ - jmp_buf switch_buf, fork_buf; - - *switch_buf_ptr = &switch_buf; - *fork_buf_ptr = &fork_buf; + current->thread.prev_sched = NULL; - if(setjmp(fork_buf) == 0) - new_thread_proc(stack, handler); +/* Handle any immediate reschedules or signals */ + interrupt_end(); - remove_sigstack(); + userspace(¤t->thread.regs.regs); } -void thread_wait(void *sw, void *fb) +int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long stack_top, struct task_struct * p, + struct pt_regs *regs) { - jmp_buf buf, **switch_buf = sw, *fork_buf; - - *switch_buf = &buf; - fork_buf = fb; - if(setjmp(buf) == 0) - longjmp(*fork_buf, 1); -} + void (*handler)(void); -static int move_registers(int int_op, int fp_op, union uml_pt_regs *regs, - unsigned long *fp_regs) -{ - if(ptrace(int_op, userspace_pid, 0, regs->skas.regs) < 0) - return(-errno); - if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0) - return(-errno); - return(0); -} + if(current->thread.forking){ + memcpy(&p->thread.regs.regs.skas, ®s->regs.skas, + sizeof(p->thread.regs.regs.skas)); + REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0); + if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp; -void save_registers(union uml_pt_regs *regs) -{ - unsigned long *fp_regs; - int err, fp_op; + handler = fork_handler; - if(have_fpx_regs){ - fp_op = PTRACE_GETFPXREGS; - fp_regs = regs->skas.xfp; + arch_copy_thread(¤t->thread.arch, &p->thread.arch); } else { - fp_op = PTRACE_GETFPREGS; - fp_regs = regs->skas.fp; + init_thread_registers(&p->thread.regs.regs); + p->thread.request.u.thread = current->thread.request.u.thread; + handler = new_thread_handler; } - err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs); - if(err) - panic("save_registers - saving registers failed, errno = %d\n", - err); + new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf, + handler); + return(0); } -void restore_registers(union uml_pt_regs *regs) +int new_mm(unsigned long stack) { - unsigned long *fp_regs; - int err, fp_op; + int fd; - if(have_fpx_regs){ - fp_op = PTRACE_SETFPXREGS; - fp_regs = regs->skas.xfp; - } - else { - fp_op = PTRACE_SETFPREGS; - fp_regs = regs->skas.fp; - } + fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); + if(fd < 0) + return(fd); - err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs); - if(err) - panic("restore_registers - saving registers failed, " - "errno = %d\n", err); -} + if(skas_needs_stub) + map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack); -void switch_threads(void *me, void *next) -{ - jmp_buf my_buf, **me_ptr = me, *next_buf = next; - - *me_ptr = &my_buf; - if(setjmp(my_buf) == 0) - longjmp(*next_buf, 1); + return(fd); } -static jmp_buf initial_jmpbuf; - -/* XXX Make these percpu */ -static void (*cb_proc)(void *arg); -static void *cb_arg; -static jmp_buf *cb_back; - -int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) +void init_idle_skas(void) { - jmp_buf **switch_buf = switch_buf_ptr; - int n; - - *fork_buf_ptr = &initial_jmpbuf; - n = setjmp(initial_jmpbuf); - if(n == 0) - new_thread_proc((void *) stack, new_thread_handler); - else if(n == 1) - remove_sigstack(); - else if(n == 2){ - (*cb_proc)(cb_arg); - longjmp(*cb_back, 1); - } - else if(n == 3){ - kmalloc_ok = 0; - return(0); - } - else if(n == 4){ - kmalloc_ok = 0; - return(1); - } - longjmp(**switch_buf, 1); + cpu_tasks[current_thread->cpu].pid = os_getpid(); + default_idle(); } -void remove_sigstack(void) -{ - stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE, - .ss_sp = NULL, - .ss_size = 0 }); - - if(sigaltstack(&stack, NULL) != 0) - panic("disabling signal stack failed, errno = %d\n", errno); -} +extern void start_kernel(void); -void initial_thread_cb_skas(void (*proc)(void *), void *arg) +static int start_kernel_proc(void *unused) { - jmp_buf here; - - cb_proc = proc; - cb_arg = arg; - cb_back = &here; + int pid; block_signals(); - if(setjmp(here) == 0) - longjmp(initial_jmpbuf, 2); - unblock_signals(); - - cb_proc = NULL; - cb_arg = NULL; - cb_back = NULL; + pid = os_getpid(); + + cpu_tasks[0].pid = pid; + cpu_tasks[0].task = current; +#ifdef CONFIG_SMP + cpu_online_map = cpumask_of_cpu(0); +#endif + start_kernel(); + return(0); } -void halt_skas(void) -{ - block_signals(); - longjmp(initial_jmpbuf, 3); -} +extern int userspace_pid[]; -void reboot_skas(void) +int start_uml_skas(void) { - block_signals(); - longjmp(initial_jmpbuf, 4); -} + if(proc_mm) + userspace_pid[0] = start_userspace(0); -int new_mm(int from) -{ - struct proc_mm_op copy; - int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0); + init_new_thread_signals(); - if(fd < 0) - return(-errno); - - if(from != -1){ - copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, - .u = - { .copy_segments = from } } ); - n = os_write_file(fd, ©, sizeof(copy)); - if(n != sizeof(copy)) - printk("new_mm : /proc/mm copy_segments failed, " - "errno = %d\n", errno); - } - return(fd); + init_task.thread.request.u.thread.proc = start_kernel_proc; + init_task.thread.request.u.thread.arg = NULL; + return(start_idle_thread(task_stack_page(&init_task), + &init_task.thread.mode.skas.switch_buf)); } -void switch_mm_skas(int mm_fd) +int external_pid_skas(struct task_struct *task) { - int err; - - err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd); - if(err) - panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", - errno); +#warning Need to look up userspace_pid by cpu + return(userspace_pid[0]); } -void kill_off_processes_skas(void) +int thread_pid_skas(struct task_struct *task) { - os_kill_process(userspace_pid, 1); +#warning Need to look up userspace_pid by cpu + return(userspace_pid[0]); } -void init_registers(int pid) +void kill_off_processes_skas(void) { - int err; + if(proc_mm) +#warning need to loop over userspace_pids in kill_off_processes_skas + os_kill_ptraced_process(userspace_pid[0], 1); + else { + struct task_struct *p; + int pid, me; - if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0) - panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", - errno); + me = os_getpid(); + for_each_process(p){ + if(p->mm == NULL) + continue; - err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs); - if(!err) - return; + pid = p->mm->context.skas.id.u.pid; + os_kill_ptraced_process(pid, 1); + } + } +} - have_fpx_regs = 0; - if(errno != EIO) - panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", - errno); +unsigned long current_stub_stack(void) +{ + if(current->mm == NULL) + return(0); - err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs); - if(err) - panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d", - errno); + return(current->mm->context.skas.id.stack); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */