diff options
Diffstat (limited to 'arch/um/kernel')
35 files changed, 686 insertions, 1066 deletions
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index fe08971b64c..6fa63a2a89e 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -6,16 +6,14 @@ extra-y := vmlinux.lds clean-files := -obj-y = config.o exec_kern.o exitcode.o \ - init_task.o irq.o ksyms.o mem.o physmem.o \ - process_kern.o ptrace.o reboot.o resource.o sigio_kern.o \ - signal_kern.o smp.o syscall_kern.o sysrq.o \ - time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o +obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \ + physmem.o process.o ptrace.o reboot.o resource.o sigio.o \ + signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \ + um_arch.o umid.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o -obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o obj-$(CONFIG_MODE_TT) += tt/ obj-$(CONFIG_MODE_SKAS) += skas/ diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index 2517ecb8bf2..68ed24df5c8 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -26,6 +26,7 @@ SECTIONS /* Read-only sections, merged into text segment: */ .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec.c index c0cb627bf59..0561c43b468 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -31,18 +31,29 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); } +#ifdef CONFIG_TTY_LOG +extern void log_exec(char **argv, void *tty); +#endif + static long execve1(char *file, char __user * __user *argv, char __user *__user *env) { long error; #ifdef CONFIG_TTY_LOG - log_exec(argv, current->tty); + mutex_lock(&tty_mutex); + task_lock(current); /* FIXME: is this needed ? */ + log_exec(argv, current->signal->tty); + task_unlock(current); + mutex_unlock(&tty_mutex); #endif error = do_execve(file, argv, env, ¤t->thread.regs); if (error == 0){ task_lock(current); current->ptrace &= ~PT_DTRACE; +#ifdef SUBARCH_EXECVE1 + SUBARCH_EXECVE1(¤t->thread.regs.regs); +#endif task_unlock(current); set_cmdline(current_cmd()); } diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index d21ebad666b..8b7f2cdedf9 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -16,9 +16,13 @@ int uml_exitcode = 0; static int read_proc_exitcode(char *page, char **start, off_t off, int count, int *eof, void *data) { - int len; + int len, val; - len = sprintf(page, "%d\n", uml_exitcode); + /* Save uml_exitcode in a local so that we don't need to guarantee + * that sprintf accesses it atomically. + */ + val = uml_exitcode; + len = sprintf(page, "%d\n", val); len -= off; if(len <= off+count) *eof = 1; *start = page + off; diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c index 2c86e7fdb01..13aa115cd1b 100644 --- a/arch/um/kernel/gmon_syms.c +++ b/arch/um/kernel/gmon_syms.c @@ -5,7 +5,7 @@ #include "linux/module.h" -extern void __bb_init_func(void *); +extern void __bb_init_func(void *) __attribute__((weak)); EXPORT_SYMBOL(__bb_init_func); /* This is defined (and referred to in profiling stub code) only by some GCC @@ -21,14 +21,3 @@ EXPORT_SYMBOL(__gcov_init); extern void __gcov_merge_add(void *) __attribute__((weak)); EXPORT_SYMBOL(__gcov_merge_add); - -/* - * 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: - */ diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 2ffda012385..ce7f233fc49 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -63,7 +63,7 @@ int show_interrupts(struct seq_file *p, void *v) for_each_online_cpu(j) seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif - seq_printf(p, " %14s", irq_desc[i].handler->typename); + seq_printf(p, " %14s", irq_desc[i].chip->typename); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) @@ -110,18 +110,7 @@ void sigio_handler(int sig, union uml_pt_regs *regs) free_irqs(); } -static void maybe_sigio_broken(int fd, int type) -{ - if (os_isatty(fd)) { - if ((type == IRQ_WRITE) && !pty_output_sigio) { - write_sigio_workaround(); - add_sigio_fd(fd, 0); - } else if ((type == IRQ_READ) && !pty_close_sigio) { - write_sigio_workaround(); - add_sigio_fd(fd, 1); - } - } -} +static DEFINE_SPINLOCK(irq_lock); int activate_fd(int irq, int fd, int type, void *dev_id) { @@ -153,20 +142,7 @@ int activate_fd(int irq, int fd, int type, void *dev_id) .events = events, .current_events = 0 } ); - /* Critical section - locked by a spinlock because this stuff can - * be changed from interrupt handlers. The stuff above is done - * outside the lock because it allocates memory. - */ - - /* Actually, it only looks like it can be called from interrupt - * context. The culprit is reactivate_fd, which calls - * maybe_sigio_broken, which calls write_sigio_workaround, - * which calls activate_fd. However, write_sigio_workaround should - * only be called once, at boot time. That would make it clear that - * this is called only from process context, and can be locked with - * a semaphore. - */ - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); for (irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next) { if ((irq_fd->fd == fd) && (irq_fd->type == type)) { printk("Registering fd %d twice\n", fd); @@ -176,7 +152,6 @@ int activate_fd(int irq, int fd, int type, void *dev_id) } } - /*-------------*/ if (type == IRQ_WRITE) fd = -1; @@ -199,7 +174,7 @@ int activate_fd(int irq, int fd, int type, void *dev_id) * so we will not be able to put new pollfd struct to pollfds * then we free the buffer tmp_fds and try again. */ - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); kfree(tmp_pfd); tmp_pfd = NULL; @@ -207,37 +182,36 @@ int activate_fd(int irq, int fd, int type, void *dev_id) if (tmp_pfd == NULL) goto out_kfree; - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); } - /*-------------*/ *last_irq_ptr = new_fd; last_irq_ptr = &new_fd->next; - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); /* This calls activate_fd, so it has to be outside the critical * section. */ - maybe_sigio_broken(fd, type); + maybe_sigio_broken(fd, (type == IRQ_READ)); - return(0); + return 0; out_unlock: - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); out_kfree: kfree(new_fd); out: - return(err); + return err; } static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) { unsigned long flags; - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr); - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); } struct irq_and_dev { @@ -304,19 +278,16 @@ void reactivate_fd(int fd, int irqnum) unsigned long flags; int i; - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); irq = find_irq_by_fd(fd, irqnum, &i); if (irq == NULL) { - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); return; } os_set_pollfd(i, irq->fd); - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); - /* This calls activate_fd, so it has to be outside the critical - * section. - */ - maybe_sigio_broken(fd, irq->type); + add_sigio_fd(fd); } void deactivate_fd(int fd, int irqnum) @@ -325,13 +296,17 @@ void deactivate_fd(int fd, int irqnum) unsigned long flags; int i; - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); irq = find_irq_by_fd(fd, irqnum, &i); - if (irq == NULL) - goto out; + if(irq == NULL){ + spin_unlock_irqrestore(&irq_lock, flags); + return; + } + os_set_pollfd(i, -1); - out: - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); + + ignore_sigio_fd(fd); } int deactivate_all_fds(void) @@ -350,13 +325,14 @@ int deactivate_all_fds(void) return 0; } +#ifdef CONFIG_MODE_TT void forward_interrupts(int pid) { struct irq_fd *irq; unsigned long flags; int err; - flags = irq_lock(); + spin_lock_irqsave(&irq_lock, flags); for (irq = active_fds; irq != NULL; irq = irq->next) { err = os_set_owner(irq->fd, pid); if (err < 0) { @@ -369,8 +345,9 @@ void forward_interrupts(int pid) irq->pid = pid; } - irq_unlock(flags); + spin_unlock_irqrestore(&irq_lock, flags); } +#endif /* * do_IRQ handles all normal device IRQ's (the special @@ -403,21 +380,6 @@ int um_request_irq(unsigned int irq, int fd, int type, EXPORT_SYMBOL(um_request_irq); EXPORT_SYMBOL(reactivate_fd); -static DEFINE_SPINLOCK(irq_spinlock); - -unsigned long irq_lock(void) -{ - unsigned long flags; - - spin_lock_irqsave(&irq_spinlock, flags); - return flags; -} - -void irq_unlock(unsigned long flags) -{ - spin_unlock_irqrestore(&irq_spinlock, flags); -} - /* hw_interrupt_type must define (startup || enable) && * (shutdown || disable) && end */ static void dummy(unsigned int irq) @@ -451,13 +413,13 @@ void __init init_IRQ(void) irq_desc[TIMER_IRQ].status = IRQ_DISABLED; irq_desc[TIMER_IRQ].action = NULL; irq_desc[TIMER_IRQ].depth = 1; - irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type; + irq_desc[TIMER_IRQ].chip = &SIGVTALRM_irq_type; enable_irq(TIMER_IRQ); for (i = 1; i < NR_IRQS; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = NULL; irq_desc[i].depth = 1; - irq_desc[i].handler = &normal_irq_type; + irq_desc[i].chip = &normal_irq_type; enable_irq(i); } } @@ -474,7 +436,7 @@ int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *, } err = um_request_irq(irq, fds[0], IRQ_READ, handler, - SA_INTERRUPT | SA_SAMPLE_RANDOM, name, + IRQF_DISABLED | IRQF_SAMPLE_RANDOM, name, (void *) (long) fds[0]); if (err) { printk("init_aio_irq - : um_request_irq failed, err = %d\n", diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 432cf0b97a1..f030e44262b 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -21,7 +21,6 @@ #include "mem_user.h" #include "os.h" -EXPORT_SYMBOL(stop); EXPORT_SYMBOL(uml_physmem); EXPORT_SYMBOL(set_signals); EXPORT_SYMBOL(get_signals); @@ -41,12 +40,14 @@ EXPORT_SYMBOL(handle_page_fault); EXPORT_SYMBOL(find_iomem); #ifdef CONFIG_MODE_TT +EXPORT_SYMBOL(stop); EXPORT_SYMBOL(strncpy_from_user_tt); EXPORT_SYMBOL(copy_from_user_tt); EXPORT_SYMBOL(copy_to_user_tt); #endif #ifdef CONFIG_MODE_SKAS +EXPORT_SYMBOL(strnlen_user_skas); EXPORT_SYMBOL(strncpy_from_user_skas); EXPORT_SYMBOL(copy_to_user_skas); EXPORT_SYMBOL(copy_from_user_skas); @@ -88,12 +89,6 @@ EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(do_gettimeofday); EXPORT_SYMBOL(do_settimeofday); -/* This is here because UML expands lseek to sys_lseek, not to a system - * call instruction. - */ -EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_wait4); - #ifdef CONFIG_SMP /* required for SMP */ diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 44e41a35f00..c95855ba6ab 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -24,8 +24,6 @@ #include "init.h" #include "kern_constants.h" -extern char __binary_start; - /* Changed during early boot */ unsigned long *empty_zero_page = NULL; unsigned long *empty_bad_page = NULL; @@ -65,8 +63,6 @@ static void setup_highmem(unsigned long highmem_start, void mem_init(void) { - unsigned long start; - max_low_pfn = (high_physmem - uml_physmem) >> PAGE_SHIFT; /* clear the zero-page */ @@ -81,17 +77,12 @@ void mem_init(void) free_bootmem(__pa(brk_end), uml_reserved - brk_end); uml_reserved = brk_end; - /* Fill in any hole at the start of the binary */ - start = (unsigned long) &__binary_start & PAGE_MASK; - if(uml_physmem != start){ - map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem, - 1, 1, 0); - } - /* this will put all low memory onto the freelists */ totalram_pages = free_all_bootmem(); +#ifdef CONFIG_HIGHMEM totalhigh_pages = highmem >> PAGE_SHIFT; totalram_pages += totalhigh_pages; +#endif num_physpages = totalram_pages; max_pfn = totalram_pages; printk(KERN_INFO "Memory: %luk available\n", @@ -232,10 +223,14 @@ void paging_init(void) empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); - for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) + for(i = 0; i < ARRAY_SIZE(zones_size); i++) zones_size[i] = 0; - zones_size[ZONE_DMA] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); + + zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) - + (uml_physmem >> PAGE_SHIFT); +#ifdef CONFIG_HIGHMEM zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT; +#endif free_area_init(zones_size); /* diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index 166cb09cae4..abafa64b872 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -317,7 +317,7 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, } } -extern int __syscall_stub_start, __binary_start; +extern int __syscall_stub_start; void setup_physmem(unsigned long start, unsigned long reserve_end, unsigned long len, unsigned long long highmem) diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process.c index f6a5a502120..fe6c64abda5 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process.c @@ -1,10 +1,9 @@ -/* +/* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Copyright 2003 PathScale, Inc. * Licensed under the GPL */ -#include "linux/config.h" #include "linux/kernel.h" #include "linux/sched.h" #include "linux/interrupt.h" @@ -23,6 +22,7 @@ #include "linux/proc_fs.h" #include "linux/ptrace.h" #include "linux/random.h" +#include "linux/personality.h" #include "asm/unistd.h" #include "asm/mman.h" #include "asm/segment.h" @@ -112,11 +112,11 @@ void set_current(void *t) void *_switch_to(void *prev, void *next, void *last) { - struct task_struct *from = prev; - struct task_struct *to= next; + struct task_struct *from = prev; + struct task_struct *to= next; - to->thread.prev_sched = from; - set_current(to); + to->thread.prev_sched = from; + set_current(to); do { current->thread.saved_task = NULL ; @@ -127,7 +127,7 @@ void *_switch_to(void *prev, void *next, void *last) prev= current; } while(current->thread.saved_task); - return(current->thread.prev_sched); + return(current->thread.prev_sched); } @@ -141,19 +141,19 @@ void release_thread(struct task_struct *task) { CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task)); } - + void exit_thread(void) { unprotect_stack((unsigned long) current_thread); } - + void *get_current(void) { return(current); } int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, - unsigned long stack_top, struct task_struct * p, + unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { int ret; @@ -182,11 +182,11 @@ void initial_thread_cb(void (*proc)(void *), void *arg) int save_kmalloc_ok = kmalloc_ok; kmalloc_ok = 0; - CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, + CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, arg); kmalloc_ok = save_kmalloc_ok; } - + unsigned long stack_sp(unsigned long page) { return(page + PAGE_SIZE - sizeof(void *)); @@ -210,7 +210,7 @@ void default_idle(void) */ if(need_resched()) schedule(); - + idle_sleep(10); } } @@ -225,7 +225,7 @@ int page_size(void) return(PAGE_SIZE); } -void *um_virt_to_phys(struct task_struct *task, unsigned long addr, +void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t *pte_out) { pgd_t *pgd; @@ -234,7 +234,7 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t *pte; pte_t ptent; - if(task->mm == NULL) + if(task->mm == NULL) return(ERR_PTR(-EINVAL)); pgd = pgd_offset(task->mm, addr); if(!pgd_present(*pgd)) @@ -245,7 +245,7 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr, return(ERR_PTR(-EINVAL)); pmd = pmd_offset(pud, addr); - if(!pmd_present(*pmd)) + if(!pmd_present(*pmd)) return(ERR_PTR(-EINVAL)); pte = pte_offset_kernel(pmd, addr); @@ -270,7 +270,7 @@ char *current_cmd(void) void force_sigbus(void) { - printk(KERN_ERR "Killing pid %d because of a lack of memory\n", + printk(KERN_ERR "Killing pid %d because of a lack of memory\n", current->pid); lock_kernel(); sigaddset(¤t->pending.signal, SIGBUS); @@ -476,7 +476,7 @@ int singlestepping(void * t) #ifndef arch_align_stack unsigned long arch_align_stack(unsigned long sp) { - if (randomize_va_space) + if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) sp -= get_random_int() % 8192; return sp & ~0xf; } diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 3ef73bf2e78..f602623644a 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -22,7 +22,7 @@ static void kill_idlers(int me) struct task_struct *p; int i; - for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){ + for(i = 0; i < ARRAY_SIZE(idle_threads); i++){ p = idle_threads[i]; if((p != NULL) && (p->thread.mode.tt.extern_pid != me)) os_kill_process(p->thread.mode.tt.extern_pid, 0); @@ -62,14 +62,3 @@ void machine_halt(void) { machine_power_off(); } - -/* - * 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: - */ diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio.c index 1c1300fb1e9..0ad755ceb21 100644 --- a/arch/um/kernel/sigio_kern.c +++ b/arch/um/kernel/sigio.c @@ -31,7 +31,7 @@ int write_sigio_irq(int fd) int err; err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, - SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", + IRQF_DISABLED|IRQF_SAMPLE_RANDOM, "write sigio", NULL); if(err){ printk("write_sigio_irq : um_request_irq failed, err = %d\n", @@ -53,17 +53,3 @@ void sigio_unlock(void) { spin_unlock(&sigio_spinlock); } - -extern void sigio_cleanup(void); -__uml_exitcall(sigio_cleanup); - -/* - * 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: - */ diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal.c index da17b7541e0..4aa9808ba26 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -36,7 +36,7 @@ EXPORT_SYMBOL(unblock_signals); /* * OK, we're invoking a handler - */ + */ static int handle_signal(struct pt_regs *regs, unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset) @@ -88,7 +88,7 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, force_sigsegv(signr, current); } else { spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); if(!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked, signr); @@ -136,7 +136,7 @@ static int kern_do_signal(struct pt_regs *regs) PT_REGS_RESTART_SYSCALL(regs); break; case -ERESTART_RESTARTBLOCK: - PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall; + PT_REGS_ORIG_SYSCALL(regs) = __NR_restart_syscall; PT_REGS_RESTART_SYSCALL(regs); break; } @@ -146,7 +146,7 @@ static int kern_do_signal(struct pt_regs *regs) * you set a breakpoint on a system call instruction and singlestep * from it, the tracing thread used to PTRACE_SINGLESTEP the process * rather than PTRACE_SYSCALL it, allowing the system call to execute - * on the host. The tracing thread will check this flag and + * on the host. The tracing thread will check this flag and * PTRACE_SYSCALL if necessary. */ if(current->ptrace & PT_DTRACE) diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index ea3a8e409a6..3e3fa7e7e3c 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -3,8 +3,7 @@ # Licensed under the GPL # -obj-y := clone.o exec_kern.o mem.o mmu.o process_kern.o \ - syscall.o tlb.o uaccess.o +obj-y := clone.o exec.o mem.o mmu.o process.o syscall.o tlb.o uaccess.o # clone.o is in the stub, so it can't be built with profiling # GCC hardened also auto-enables -fpic, but we need %ebx so it can't work -> diff --git a/arch/um/kernel/skas/exec.c b/arch/um/kernel/skas/exec.c new file mode 100644 index 00000000000..54b79595137 --- /dev/null +++ b/arch/um/kernel/skas/exec.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/kernel.h" +#include "asm/current.h" +#include "asm/page.h" +#include "asm/signal.h" +#include "asm/ptrace.h" +#include "asm/uaccess.h" +#include "asm/mmu_context.h" +#include "tlb.h" +#include "skas.h" +#include "um_mmu.h" +#include "os.h" + +void flush_thread_skas(void) +{ + force_flush_all(); + switch_mm_skas(¤t->mm->context.skas.id); +} + +void start_thread_skas(struct pt_regs *regs, unsigned long eip, + unsigned long esp) +{ + set_fs(USER_DS); + PT_REGS_IP(regs) = eip; + PT_REGS_SP(regs) = esp; +} diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c deleted file mode 100644 index 77ed7bbab21..00000000000 --- a/arch/um/kernel/skas/exec_kern.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/kernel.h" -#include "asm/current.h" -#include "asm/page.h" -#include "asm/signal.h" -#include "asm/ptrace.h" -#include "asm/uaccess.h" -#include "asm/mmu_context.h" -#include "tlb.h" -#include "skas.h" -#include "um_mmu.h" -#include "os.h" - -void flush_thread_skas(void) -{ - force_flush_all(); - switch_mm_skas(¤t->mm->context.skas.id); -} - -void start_thread_skas(struct pt_regs *regs, unsigned long eip, - unsigned long esp) -{ - set_fs(USER_DS); - PT_REGS_IP(regs) = eip; - PT_REGS_SP(regs) = esp; -} - -/* - * 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: - */ diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c index 88ab96c609c..27bbf54b1e5 100644 --- a/arch/um/kernel/skas/mem.c +++ b/arch/um/kernel/skas/mem.c @@ -9,31 +9,19 @@ #include "mem_user.h" #include "skas.h" -unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, - unsigned long *task_size_out) +unsigned long set_task_sizes_skas(unsigned long *task_size_out) { /* Round up to the nearest 4M */ - unsigned long top = ROUND_4M((unsigned long) &arg); + unsigned long host_task_size = ROUND_4M((unsigned long) + &host_task_size); #ifdef CONFIG_HOST_TASK_SIZE - *host_size_out = CONFIG_HOST_TASK_SIZE; + *host_size_out = ROUND_4M(CONFIG_HOST_TASK_SIZE); *task_size_out = CONFIG_HOST_TASK_SIZE; #else - *host_size_out = top; if (!skas_needs_stub) - *task_size_out = top; + *task_size_out = host_task_size; else *task_size_out = CONFIG_STUB_START & PGDIR_MASK; #endif - return(((unsigned long) set_task_sizes_skas) & ~0xffffff); + return host_task_size; } - -/* - * 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: - */ diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index c5c9885a829..4cd2ff546ef 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -55,14 +55,16 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc, * destroy_context_skas. */ - mm->context.skas.last_page_table = pmd_page_kernel(*pmd); + mm->context.skas.last_page_table = pmd_page_vaddr(*pmd); #ifdef CONFIG_3_LEVEL_PGTABLES mm->context.skas.last_pmd = (unsigned long) __va(pud_val(*pud)); #endif *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT)); - *pte = pte_mkexec(*pte); - *pte = pte_wrprotect(*pte); + /* This is wrong for the code page, but it doesn't matter since the + * stub is mapped by hand with the correct permissions. + */ + *pte = pte_mkwrite(*pte); return(0); out_pmd: @@ -152,7 +154,7 @@ void destroy_context_skas(struct mm_struct *mm) free_page(mmu->id.stack); pte_lock_deinit(virt_to_page(mmu->last_page_table)); pte_free_kernel((pte_t *) mmu->last_page_table); - dec_page_state(nr_page_table_pages); + dec_zone_page_state(virt_to_page(mmu->last_page_table), NR_PAGETABLE); #ifdef CONFIG_3_LEVEL_PGTABLES pmd_free((pmd_t *) mmu->last_pmd); #endif diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process.c index 2135eaf98a9..ae4fa71d3b8 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process.c @@ -33,7 +33,7 @@ void switch_to_skas(void *prev, void *next) switch_timers(0); switch_threads(&from->thread.mode.skas.switch_buf, - to->thread.mode.skas.switch_buf); + &to->thread.mode.skas.switch_buf); arch_switch_to_skas(current->thread.prev_sched, current); @@ -43,21 +43,21 @@ void switch_to_skas(void *prev, void *next) extern void schedule_tail(struct task_struct *prev); -void new_thread_handler(int sig) +/* 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; - fn = current->thread.request.u.thread.proc; - arg = current->thread.request.u.thread.arg; - os_usr1_signal(1); - thread_wait(¤t->thread.mode.skas.switch_buf, - current->thread.mode.skas.fork_buf); - 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 */ @@ -70,22 +70,13 @@ void new_thread_handler(int sig) else do_exit(0); } -void new_thread_proc(void *stack, void (*handler)(int sig)) -{ - init_new_thread_stack(stack, handler); - os_usr1_process(os_getpid()); -} - void release_thread_skas(struct task_struct *task) { } -void fork_handler(int sig) +/* Called magically, see new_thread_handler above */ +void fork_handler(void) { - os_usr1_signal(1); - thread_wait(¤t->thread.mode.skas.switch_buf, - current->thread.mode.skas.fork_buf); - force_flush_all(); if(current->thread.prev_sched == NULL) panic("blech"); @@ -109,7 +100,7 @@ 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) { - void (*handler)(int); + void (*handler)(void); if(current->thread.forking){ memcpy(&p->thread.regs.regs.skas, ®s->regs.skas, @@ -123,12 +114,12 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, } else { init_thread_registers(&p->thread.regs.regs); - p->thread.request.u.thread = current->thread.request.u.thread; + p->thread.request.u.thread = current->thread.request.u.thread; handler = new_thread_handler; } new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf, - &p->thread.mode.skas.fork_buf, handler); + handler); return(0); } @@ -164,7 +155,7 @@ static int start_kernel_proc(void *unused) cpu_tasks[0].pid = pid; cpu_tasks[0].task = current; #ifdef CONFIG_SMP - cpu_online_map = cpumask_of_cpu(0); + cpu_online_map = cpumask_of_cpu(0); #endif start_kernel(); return(0); @@ -177,13 +168,12 @@ int start_uml_skas(void) if(proc_mm) userspace_pid[0] = start_userspace(0); - init_new_thread_signals(1); + init_new_thread_signals(); 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, - &init_task.thread.mode.skas.fork_buf)); + &init_task.thread.mode.skas.switch_buf)); } int external_pid_skas(struct task_struct *task) diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index 51fb94076fc..0ae4eea21be 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -18,11 +18,7 @@ void handle_syscall(union uml_pt_regs *r) struct pt_regs *regs = container_of(r, struct pt_regs, regs); long result; int syscall; -#ifdef UML_CONFIG_SYSCALL_DEBUG - int index; - index = record_syscall_start(UPT_SYSCALL_NR(r)); -#endif syscall_trace(r, 0); current->thread.nsyscalls++; @@ -44,7 +40,4 @@ void handle_syscall(union uml_pt_regs *r) REGS_SET_SYSCALL_RETURN(r->skas.regs, result); syscall_trace(r, 1); -#ifdef UML_CONFIG_SYSCALL_DEBUG - record_syscall_end(index, result); -#endif } diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 5992c325716..8912cec0fe4 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -8,6 +8,7 @@ #include "linux/kernel.h" #include "linux/string.h" #include "linux/fs.h" +#include "linux/hardirq.h" #include "linux/highmem.h" #include "asm/page.h" #include "asm/pgtable.h" @@ -38,7 +39,7 @@ static unsigned long maybe_map(unsigned long virt, int is_write) return((unsigned long) phys); } -static int do_op(unsigned long addr, int len, int is_write, +static int do_op_one_page(unsigned long addr, int len, int is_write, int (*op)(unsigned long addr, int len, void *arg), void *arg) { struct page *page; @@ -49,9 +50,11 @@ static int do_op(unsigned long addr, int len, int is_write, return(-1); page = phys_to_page(addr); - addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK); + addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) + (addr & ~PAGE_MASK); + n = (*op)(addr, len, arg); - kunmap(page); + + kunmap_atomic(page, KM_UML_USERCOPY); return(n); } @@ -77,7 +80,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) remain = len; current->thread.fault_catcher = jmpbuf; - n = do_op(addr, size, is_write, op, arg); + n = do_op_one_page(addr, size, is_write, op, arg); if(n != 0){ *res = (n < 0 ? remain : 0); goto out; @@ -91,7 +94,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) } while(addr < ((addr + remain) & PAGE_MASK)){ - n = do_op(addr, PAGE_SIZE, is_write, op, arg); + n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg); if(n != 0){ *res = (n < 0 ? remain : 0); goto out; @@ -105,7 +108,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) goto out; } - n = do_op(addr, remain, is_write, op, arg); + n = do_op_one_page(addr, remain, is_write, op, arg); if(n != 0) *res = (n < 0 ? remain : 0); else *res = 0; diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index 1731d90e685..48cf88dd02d 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -1,36 +1,166 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ +#include "linux/sched.h" +#include "linux/file.h" +#include "linux/smp_lock.h" +#include "linux/mm.h" +#include "linux/utsname.h" +#include "linux/msg.h" +#include "linux/shm.h" +#include "linux/sys.h" +#include "linux/syscalls.h" +#include "linux/unistd.h" +#include "linux/slab.h" +#include "linux/utime.h" +#include "asm/mman.h" +#include "asm/uaccess.h" #include "kern_util.h" -#include "syscall.h" -#include "os.h" +#include "user_util.h" +#include "sysdep/syscalls.h" +#include "mode_kern.h" +#include "choose-mode.h" -struct { - int syscall; - int pid; - long result; - unsigned long long start; - unsigned long long end; -} syscall_record[1024]; +/* Unlocked, I don't care if this is a bit off */ +int nsyscalls = 0; -int record_syscall_start(int syscall) +long sys_fork(void) { - int max, index; + long ret; - max = sizeof(syscall_record)/sizeof(syscall_record[0]); - index = next_syscall_index(max); + current->thread.forking = 1; + ret = do_fork(SIGCHLD, UPT_SP(¤t->thread.regs.regs), + ¤t->thread.regs, 0, NULL, NULL); + current->thread.forking = 0; + return(ret); +} + +long sys_vfork(void) +{ + long ret; + + current->thread.forking = 1; + ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, + UPT_SP(¤t->thread.regs.regs), + ¤t->thread.regs, 0, NULL, NULL); + current->thread.forking = 0; + return(ret); +} + +/* common code for old and new mmaps */ +long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + long error = -EBADF; + struct file * file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); + out: + return error; +} + +long old_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long offset) +{ + long err = -EINVAL; + if (offset & ~PAGE_MASK) + goto out; + + err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + out: + return err; +} +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +long sys_pipe(unsigned long __user * fildes) +{ + int fd[2]; + long error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(fildes, fd, sizeof(fd))) + error = -EFAULT; + } + return error; +} - syscall_record[index].syscall = syscall; - syscall_record[index].pid = current_pid(); - syscall_record[index].result = 0xdeadbeef; - syscall_record[index].start = os_nsecs(); - return(index); + +long sys_uname(struct old_utsname __user * name) +{ + long err; + if (!name) + return -EFAULT; + down_read(&uts_sem); + err = copy_to_user(name, &system_utsname, sizeof (*name)); + up_read(&uts_sem); + return err?-EFAULT:0; } -void record_syscall_end(int index, long result) +long sys_olduname(struct oldold_utsname __user * name) { - syscall_record[index].result = result; - syscall_record[index].end = os_nsecs(); + long error; + + if (!name) + return -EFAULT; + if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) + return -EFAULT; + + down_read(&uts_sem); + + error = __copy_to_user(&name->sysname,&system_utsname.sysname, + __OLD_UTS_LEN); + error |= __put_user(0,name->sysname+__OLD_UTS_LEN); + error |= __copy_to_user(&name->nodename,&system_utsname.nodename, + __OLD_UTS_LEN); + error |= __put_user(0,name->nodename+__OLD_UTS_LEN); + error |= __copy_to_user(&name->release,&system_utsname.release, + __OLD_UTS_LEN); + error |= __put_user(0,name->release+__OLD_UTS_LEN); + error |= __copy_to_user(&name->version,&system_utsname.version, + __OLD_UTS_LEN); + error |= __put_user(0,name->version+__OLD_UTS_LEN); + error |= __copy_to_user(&name->machine,&system_utsname.machine, + __OLD_UTS_LEN); + error |= __put_user(0,name->machine+__OLD_UTS_LEN); + + up_read(&uts_sem); + + error = error ? -EFAULT : 0; + + return error; +} + +DEFINE_SPINLOCK(syscall_lock); + +static int syscall_index = 0; + +int next_syscall_index(int limit) +{ + int ret; + + spin_lock(&syscall_lock); + ret = syscall_index; + if(++syscall_index == limit) + syscall_index = 0; + spin_unlock(&syscall_lock); + return(ret); } diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c deleted file mode 100644 index 37d3978337d..00000000000 --- a/arch/um/kernel/syscall_kern.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "linux/file.h" -#include "linux/smp_lock.h" -#include "linux/mm.h" -#include "linux/utsname.h" -#include "linux/msg.h" -#include "linux/shm.h" -#include "linux/sys.h" -#include "linux/syscalls.h" -#include "linux/unistd.h" -#include "linux/slab.h" -#include "linux/utime.h" -#include "asm/mman.h" -#include "asm/uaccess.h" -#include "kern_util.h" -#include "user_util.h" -#include "sysdep/syscalls.h" -#include "mode_kern.h" -#include "choose-mode.h" - -/* Unlocked, I don't care if this is a bit off */ -int nsyscalls = 0; - -long sys_fork(void) -{ - long ret; - - current->thread.forking = 1; - ret = do_fork(SIGCHLD, UPT_SP(¤t->thread.regs.regs), - ¤t->thread.regs, 0, NULL, NULL); - current->thread.forking = 0; - return(ret); -} - -long sys_vfork(void) -{ - long ret; - - current->thread.forking = 1; - ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, - UPT_SP(¤t->thread.regs.regs), - ¤t->thread.regs, 0, NULL, NULL); - current->thread.forking = 0; - return(ret); -} - -/* common code for old and new mmaps */ -long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - long error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); - out: - return error; -} - -long old_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long offset) -{ - long err = -EINVAL; - if (offset & ~PAGE_MASK) - goto out; - - err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); - out: - return err; -} -/* - * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way unix traditionally does this, though. - */ -long sys_pipe(unsigned long __user * fildes) -{ - int fd[2]; - long error; - - error = do_pipe(fd); - if (!error) { - if (copy_to_user(fildes, fd, sizeof(fd))) - error = -EFAULT; - } - return error; -} - - -long sys_uname(struct old_utsname __user * name) -{ - long err; - if (!name) - return -EFAULT; - down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); - up_read(&uts_sem); - return err?-EFAULT:0; -} - -long sys_olduname(struct oldold_utsname __user * name) -{ - long error; - - if (!name) - return -EFAULT; - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) - return -EFAULT; - - down_read(&uts_sem); - - error = __copy_to_user(&name->sysname,&system_utsname.sysname, - __OLD_UTS_LEN); - error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename, - __OLD_UTS_LEN); - error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release, - __OLD_UTS_LEN); - error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version, - __OLD_UTS_LEN); - error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine, - __OLD_UTS_LEN); - error |= __put_user(0,name->machine+__OLD_UTS_LEN); - - up_read(&uts_sem); - - error = error ? -EFAULT : 0; - - return error; -} - -DEFINE_SPINLOCK(syscall_lock); - -static int syscall_index = 0; - -int next_syscall_index(int limit) -{ - int ret; - - spin_lock(&syscall_lock); - ret = syscall_index; - if(++syscall_index == limit) - syscall_index = 0; - spin_unlock(&syscall_lock); - return(ret); -} diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 8fa2ae7f302..a92965f8f9c 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -1,172 +1,180 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <time.h> -#include <sys/time.h> -#include <signal.h> -#include <errno.h> -#include "user_util.h" +#include "linux/kernel.h" +#include "linux/module.h" +#include "linux/unistd.h" +#include "linux/stddef.h" +#include "linux/spinlock.h" +#include "linux/time.h" +#include "linux/sched.h" +#include "linux/interrupt.h" +#include "linux/init.h" +#include "linux/delay.h" +#include "linux/hrtimer.h" +#include "asm/irq.h" +#include "asm/param.h" +#include "asm/current.h" #include "kern_util.h" -#include "user.h" -#include "process.h" -#include "time_user.h" -#include "kern_constants.h" +#include "user_util.h" +#include "mode.h" #include "os.h" -/* XXX This really needs to be declared and initialized in a kernel file since - * it's in <linux/time.h> - */ -extern struct timespec wall_to_monotonic; - -extern struct timeval xtime; - -struct timeval local_offset = { 0, 0 }; - -void timer(void) +int hz(void) { - gettimeofday(&xtime, NULL); - timeradd(&xtime, &local_offset, &xtime); + return(HZ); } -static void set_interval(int timer_type) +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) { - int usec = 1000000/hz(); - struct itimerval interval = ((struct itimerval) { { 0, usec }, - { 0, usec } }); - - if(setitimer(timer_type, &interval, NULL) == -1) - panic("setitimer failed - errno = %d\n", errno); + return (unsigned long long)jiffies_64 * (1000000000 / HZ); } -void enable_timer(void) -{ - set_interval(ITIMER_VIRTUAL); -} +static unsigned long long prev_nsecs; +#ifdef CONFIG_UML_REAL_TIME_CLOCK +static long long delta; /* Deviation per interval */ +#endif -void prepare_timer(void * ptr) +void timer_irq(union uml_pt_regs *regs) { - int usec = 1000000/hz(); - *(struct itimerval *)ptr = ((struct itimerval) { { 0, usec }, - { 0, usec }}); + unsigned long long ticks = 0; + +#ifdef CONFIG_UML_REAL_TIME_CLOCK + if(prev_nsecs){ + /* We've had 1 tick */ + unsigned long long nsecs = os_nsecs(); + + delta += nsecs - prev_nsecs; + prev_nsecs = nsecs; + + /* Protect against the host clock being set backwards */ + if(delta < 0) + delta = 0; + + ticks += (delta * HZ) / BILLION; + delta -= (ticks * BILLION) / HZ; + } + else prev_nsecs = os_nsecs(); +#else + ticks = 1; +#endif + while(ticks > 0){ + do_IRQ(TIMER_IRQ, regs); + ticks--; + } } -void disable_timer(void) +static DEFINE_SPINLOCK(timer_spinlock); + +static unsigned long long local_offset = 0; + +static inline unsigned long long get_time(void) { - struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); - if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) || - (setitimer(ITIMER_REAL, &disable, NULL) < 0)) - printk("disnable_timer - setitimer failed, errno = %d\n", - errno); - /* If there are signals already queued, after unblocking ignore them */ - set_handler(SIGALRM, SIG_IGN, 0, -1); - set_handler(SIGVTALRM, SIG_IGN, 0, -1); + unsigned long long nsecs; + unsigned long flags; + + spin_lock_irqsave(&timer_spinlock, flags); + nsecs = os_nsecs(); + nsecs += local_offset; + spin_unlock_irqrestore(&timer_spinlock, flags); + + return nsecs; } -void switch_timers(int to_real) +irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) { - struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); - struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() }, - { 0, 1000000/hz() }}); - int old, new; - - if(to_real){ - old = ITIMER_VIRTUAL; - new = ITIMER_REAL; - } - else { - old = ITIMER_REAL; - new = ITIMER_VIRTUAL; - } + unsigned long long nsecs; + unsigned long flags; + + write_seqlock_irqsave(&xtime_lock, flags); + + do_timer(1); - if((setitimer(old, &disable, NULL) < 0) || - (setitimer(new, &enable, NULL))) - printk("switch_timers - setitimer failed, errno = %d\n", - errno); + nsecs = get_time(); + xtime.tv_sec = nsecs / NSEC_PER_SEC; + xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC; + + write_sequnlock_irqrestore(&xtime_lock, flags); + + return IRQ_HANDLED; } -void uml_idle_timer(void) +static void register_timer(void) { - if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) - panic("Couldn't unset SIGVTALRM handler"); - - set_handler(SIGALRM, (__sighandler_t) alarm_handler, - SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_interval(ITIMER_REAL); + int err; + + err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL); + if(err != 0) + printk(KERN_ERR "register_timer : request_irq failed - " + "errno = %d\n", -err); + + err = set_interval(1); + if(err != 0) + printk(KERN_ERR "register_timer : set_interval failed - " + "errno = %d\n", -err); } -extern void ktime_get_ts(struct timespec *ts); -#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts) +extern void (*late_time_init)(void); void time_init(void) { - struct timespec now; - - if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) - panic("Couldn't set SIGVTALRM handler"); - set_interval(ITIMER_VIRTUAL); + long long nsecs; - do_posix_clock_monotonic_gettime(&now); - wall_to_monotonic.tv_sec = -now.tv_sec; - wall_to_monotonic.tv_nsec = -now.tv_nsec; + nsecs = os_nsecs(); + set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION, + -nsecs % BILLION); + late_time_init = register_timer; } -/* Defined in linux/ktimer.h, which can't be included here */ -#define clock_was_set() do { } while (0) - void do_gettimeofday(struct timeval *tv) { - unsigned long flags; - - flags = time_lock(); - gettimeofday(tv, NULL); - timeradd(tv, &local_offset, tv); - time_unlock(flags); - clock_was_set(); + unsigned long long nsecs = get_time(); + + tv->tv_sec = nsecs / NSEC_PER_SEC; + /* Careful about calculations here - this was originally done as + * (nsecs - tv->tv_sec * NSEC_PER_SEC) / NSEC_PER_USEC + * which gave bogus (> 1000000) values. Dunno why, suspect gcc + * (4.0.0) miscompiled it, or there's a subtle 64/32-bit conversion + * problem that I missed. + */ + nsecs -= tv->tv_sec * NSEC_PER_SEC; + tv->tv_usec = (unsigned long) nsecs / NSEC_PER_USEC; } -int do_settimeofday(struct timespec *tv) +static inline void set_time(unsigned long long nsecs) { - struct timeval now; + unsigned long long now; unsigned long flags; - struct timeval tv_in; - if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC) - return -EINVAL; + spin_lock_irqsave(&timer_spinlock, flags); + now = os_nsecs(); + local_offset = nsecs - now; + spin_unlock_irqrestore(&timer_spinlock, flags); - tv_in.tv_sec = tv->tv_sec; - tv_in.tv_usec = tv->tv_nsec / 1000; - - flags = time_lock(); - gettimeofday(&now, NULL); - timersub(&tv_in, &now, &local_offset); - time_unlock(flags); - - return(0); + clock_was_set(); } -void idle_sleep(int secs) +int do_settimeofday(struct timespec *tv) { - struct timespec ts; + set_time((unsigned long long) tv->tv_sec * NSEC_PER_SEC + tv->tv_nsec); - ts.tv_sec = secs; - ts.tv_nsec = 0; - nanosleep(&ts, NULL); + return 0; } -/* XXX This partly duplicates init_irq_signals */ - -void user_time_init(void) +void timer_handler(int sig, union uml_pt_regs *regs) { - set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, - SIGALRM, SIGUSR2, -1); - set_handler(SIGALRM, (__sighandler_t) alarm_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, - SIGVTALRM, SIGUSR2, -1); - set_interval(ITIMER_VIRTUAL); + local_irq_disable(); + irq_enter(); + update_process_times(CHOOSE_MODE( + (UPT_SC(regs) && user_context(UPT_SP(regs))), + (regs)->skas.is_user)); + irq_exit(); + local_irq_enable(); + if(current_thread->cpu == 0) + timer_irq(regs); } diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c deleted file mode 100644 index 87cdbc560d3..00000000000 --- a/arch/um/kernel/time_kern.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/kernel.h" -#include "linux/module.h" -#include "linux/unistd.h" -#include "linux/stddef.h" -#include "linux/spinlock.h" -#include "linux/time.h" -#include "linux/sched.h" -#include "linux/interrupt.h" -#include "linux/init.h" -#include "linux/delay.h" -#include "linux/hrtimer.h" -#include "asm/irq.h" -#include "asm/param.h" -#include "asm/current.h" -#include "kern_util.h" -#include "user_util.h" -#include "mode.h" -#include "os.h" - -int hz(void) -{ - return(HZ); -} - -/* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies_64 * (1000000000 / HZ); -} - -/* Changed at early boot */ -int timer_irq_inited = 0; - -static int first_tick; -static unsigned long long prev_nsecs; -#ifdef CONFIG_UML_REAL_TIME_CLOCK -static long long delta; /* Deviation per interval */ -#endif - -void timer_irq(union uml_pt_regs *regs) -{ - unsigned long long ticks = 0; - - if(!timer_irq_inited){ - /* This is to ensure that ticks don't pile up when - * the timer handler is suspended */ - first_tick = 0; - return; - } - - if(first_tick){ -#ifdef CONFIG_UML_REAL_TIME_CLOCK - /* We've had 1 tick */ - unsigned long long nsecs = os_nsecs(); - - delta += nsecs - prev_nsecs; - prev_nsecs = nsecs; - - /* Protect against the host clock being set backwards */ - if(delta < 0) - delta = 0; - - ticks += (delta * HZ) / BILLION; - delta -= (ticks * BILLION) / HZ; -#else - ticks = 1; -#endif - } - else { - prev_nsecs = os_nsecs(); - first_tick = 1; - } - - while(ticks > 0){ - do_IRQ(TIMER_IRQ, regs); - ticks--; - } -} - - -void time_init_kern(void) -{ - long long nsecs; - - nsecs = os_nsecs(); - set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION, - -nsecs % BILLION); -} - -void do_boot_timer_handler(struct sigcontext * sc) -{ - struct pt_regs regs; - - CHOOSE_MODE((void) (UPT_SC(®s.regs) = sc), - (void) (regs.regs.skas.is_user = 0)); - do_timer(®s); -} - -static DEFINE_SPINLOCK(timer_spinlock); - -static unsigned long long local_offset = 0; - -static inline unsigned long long get_time(void) -{ - unsigned long long nsecs; - unsigned long flags; - - spin_lock_irqsave(&timer_spinlock, flags); - nsecs = os_nsecs(); - nsecs += local_offset; - spin_unlock_irqrestore(&timer_spinlock, flags); - - return nsecs; -} - -irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) -{ - unsigned long long nsecs; - unsigned long flags; - - do_timer(regs); - - write_seqlock_irqsave(&xtime_lock, flags); - nsecs = get_time() + local_offset; - xtime.tv_sec = nsecs / NSEC_PER_SEC; - xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC; - write_sequnlock_irqrestore(&xtime_lock, flags); - - return(IRQ_HANDLED); -} - -long um_time(int __user *tloc) -{ - long ret = get_time() / NSEC_PER_SEC; - - if((tloc != NULL) && put_user(ret, tloc)) - return -EFAULT; - - return ret; -} - -void do_gettimeofday(struct timeval *tv) -{ - unsigned long long nsecs = get_time(); - - tv->tv_sec = nsecs / NSEC_PER_SEC; - /* Careful about calculations here - this was originally done as - * (nsecs - tv->tv_sec * NSEC_PER_SEC) / NSEC_PER_USEC - * which gave bogus (> 1000000) values. Dunno why, suspect gcc - * (4.0.0) miscompiled it, or there's a subtle 64/32-bit conversion - * problem that I missed. - */ - nsecs -= tv->tv_sec * NSEC_PER_SEC; - tv->tv_usec = (unsigned long) nsecs / NSEC_PER_USEC; -} - -static inline void set_time(unsigned long long nsecs) -{ - unsigned long long now; - unsigned long flags; - - spin_lock_irqsave(&timer_spinlock, flags); - now = os_nsecs(); - local_offset = nsecs - now; - spin_unlock_irqrestore(&timer_spinlock, flags); - - clock_was_set(); -} - -long um_stime(int __user *tptr) -{ - int value; - - if (get_user(value, tptr)) - return -EFAULT; - - set_time((unsigned long long) value * NSEC_PER_SEC); - - return 0; -} - -int do_settimeofday(struct timespec *tv) -{ - set_time((unsigned long long) tv->tv_sec * NSEC_PER_SEC + tv->tv_nsec); - - return 0; -} - -void timer_handler(int sig, union uml_pt_regs *regs) -{ - local_irq_disable(); - irq_enter(); - update_process_times(CHOOSE_MODE( - (UPT_SC(regs) && user_context(UPT_SP(regs))), - (regs)->skas.is_user)); - irq_exit(); - local_irq_enable(); - if(current_thread->cpu == 0) - timer_irq(regs); -} - -int __init timer_init(void) -{ - int err; - - user_time_init(); - err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL); - if(err != 0) - printk(KERN_ERR "timer_init : request_irq failed - " - "errno = %d\n", -err); - timer_irq_inited = 1; - return(0); -} - -arch_initcall(timer_init); diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index f5b0636f9ad..54a5ff25645 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -16,12 +16,12 @@ #include "os.h" static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x, struct host_vm_op *ops, int *index, + int r, int w, int x, struct host_vm_op *ops, int *index, int last_filled, union mm_context *mmu, void **flush, int (*do_ops)(union mm_context *, struct host_vm_op *, int, int, void **)) { - __u64 offset; + __u64 offset; struct host_vm_op *last; int fd, ret = 0; @@ -89,7 +89,7 @@ static int add_munmap(unsigned long addr, unsigned long len, static int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, struct host_vm_op *ops, int *index, int last_filled, union mm_context *mmu, void **flush, - int (*do_ops)(union mm_context *, struct host_vm_op *, + int (*do_ops)(union mm_context *, struct host_vm_op *, int, int, void **)) { struct host_vm_op *last; @@ -124,105 +124,105 @@ static int add_mprotect(unsigned long addr, unsigned long len, int r, int w, #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) void fix_range_common(struct mm_struct *mm, unsigned long start_addr, - unsigned long end_addr, int force, + unsigned long end_addr, int force, int (*do_ops)(union mm_context *, struct host_vm_op *, int, int, void **)) { - pgd_t *npgd; - pud_t *npud; - pmd_t *npmd; - pte_t *npte; - union mm_context *mmu = &mm->context; - unsigned long addr, end; - int r, w, x; - struct host_vm_op ops[1]; - void *flush = NULL; - int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1; - int ret = 0; - - if(mm == NULL) return; - - ops[0].type = NONE; - for(addr = start_addr; addr < end_addr && !ret;){ - npgd = pgd_offset(mm, addr); - if(!pgd_present(*npgd)){ - end = ADD_ROUND(addr, PGDIR_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pgd_newpage(*npgd)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pgd_mkuptodate(*npgd); - } - addr = end; - continue; - } - - npud = pud_offset(npgd, addr); - if(!pud_present(*npud)){ - end = ADD_ROUND(addr, PUD_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pud_newpage(*npud)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pud_mkuptodate(*npud); - } - addr = end; - continue; - } - - npmd = pmd_offset(npud, addr); - if(!pmd_present(*npmd)){ - end = ADD_ROUND(addr, PMD_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pmd_newpage(*npmd)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pmd_mkuptodate(*npmd); - } - addr = end; - continue; - } - - npte = pte_offset_kernel(npmd, addr); - r = pte_read(*npte); - w = pte_write(*npte); - x = pte_exec(*npte); + pgd_t *npgd; + pud_t *npud; + pmd_t *npmd; + pte_t *npte; + union mm_context *mmu = &mm->context; + unsigned long addr, end; + int r, w, x; + struct host_vm_op ops[1]; + void *flush = NULL; + int op_index = -1, last_op = ARRAY_SIZE(ops) - 1; + int ret = 0; + + if(mm == NULL) + return; + + ops[0].type = NONE; + for(addr = start_addr; addr < end_addr && !ret;){ + npgd = pgd_offset(mm, addr); + if(!pgd_present(*npgd)){ + end = ADD_ROUND(addr, PGDIR_SIZE); + if(end > end_addr) + end = end_addr; + if(force || pgd_newpage(*npgd)){ + ret = add_munmap(addr, end - addr, ops, + &op_index, last_op, mmu, + &flush, do_ops); + pgd_mkuptodate(*npgd); + } + addr = end; + continue; + } + + npud = pud_offset(npgd, addr); + if(!pud_present(*npud)){ + end = ADD_ROUND(addr, PUD_SIZE); + if(end > end_addr) + end = end_addr; + if(force || pud_newpage(*npud)){ + ret = add_munmap(addr, end - addr, ops, + &op_index, last_op, mmu, + &flush, do_ops); + pud_mkuptodate(*npud); + } + addr = end; + continue; + } + + npmd = pmd_offset(npud, addr); + if(!pmd_present(*npmd)){ + end = ADD_ROUND(addr, PMD_SIZE); + if(end > end_addr) + end = end_addr; + if(force || pmd_newpage(*npmd)){ + ret = add_munmap(addr, end - addr, ops, + &op_index, last_op, mmu, + &flush, do_ops); + pmd_mkuptodate(*npmd); + } + addr = end; + continue; + } + + npte = pte_offset_kernel(npmd, addr); + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); if (!pte_young(*npte)) { r = 0; w = 0; } else if (!pte_dirty(*npte)) { w = 0; } - if(force || pte_newpage(*npte)){ - if(pte_present(*npte)) - ret = add_mmap(addr, - pte_val(*npte) & PAGE_MASK, - PAGE_SIZE, r, w, x, ops, - &op_index, last_op, mmu, - &flush, do_ops); + if(force || pte_newpage(*npte)){ + if(pte_present(*npte)) + ret = add_mmap(addr, + pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x, ops, + &op_index, last_op, mmu, + &flush, do_ops); else ret = add_munmap(addr, PAGE_SIZE, ops, &op_index, last_op, mmu, &flush, do_ops); - } - else if(pte_newprot(*npte)) + } + else if(pte_newprot(*npte)) ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops, &op_index, last_op, mmu, &flush, do_ops); - *npte = pte_mkuptodate(*npte); - addr += PAGE_SIZE; - } - + *npte = pte_mkuptodate(*npte); + addr += PAGE_SIZE; + } if(!ret) ret = (*do_ops)(mmu, ops, op_index, 1, &flush); - /* This is not an else because ret is modified above */ +/* This is not an else because ret is modified above */ if(ret) { printk("fix_range_common: failed, killing current process\n"); force_sig(SIGKILL, current); @@ -231,160 +231,160 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) { - struct mm_struct *mm; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - unsigned long addr, last; - int updated = 0, err; - - mm = &init_mm; - for(addr = start; addr < end;){ - pgd = pgd_offset(mm, addr); - if(!pgd_present(*pgd)){ - last = ADD_ROUND(addr, PGDIR_SIZE); - if(last > end) - last = end; - if(pgd_newpage(*pgd)){ - updated = 1; - err = os_unmap_memory((void *) addr, - last - addr); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr = last; - continue; - } - - pud = pud_offset(pgd, addr); - if(!pud_present(*pud)){ - last = ADD_ROUND(addr, PUD_SIZE); - if(last > end) - last = end; - if(pud_newpage(*pud)){ - updated = 1; - err = os_unmap_memory((void *) addr, - last - addr); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr = last; - continue; - } - - pmd = pmd_offset(pud, addr); - if(!pmd_present(*pmd)){ - last = ADD_ROUND(addr, PMD_SIZE); - if(last > end) - last = end; - if(pmd_newpage(*pmd)){ - updated = 1; - err = os_unmap_memory((void *) addr, - last - addr); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr = last; - continue; - } - - pte = pte_offset_kernel(pmd, addr); - if(!pte_present(*pte) || pte_newpage(*pte)){ - updated = 1; - err = os_unmap_memory((void *) addr, - PAGE_SIZE); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - if(pte_present(*pte)) - map_memory(addr, - pte_val(*pte) & PAGE_MASK, - PAGE_SIZE, 1, 1, 1); - } - else if(pte_newprot(*pte)){ - updated = 1; - os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1); - } - addr += PAGE_SIZE; - } - return(updated); + struct mm_struct *mm; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + unsigned long addr, last; + int updated = 0, err; + + mm = &init_mm; + for(addr = start; addr < end;){ + pgd = pgd_offset(mm, addr); + if(!pgd_present(*pgd)){ + last = ADD_ROUND(addr, PGDIR_SIZE); + if(last > end) + last = end; + if(pgd_newpage(*pgd)){ + updated = 1; + err = os_unmap_memory((void *) addr, + last - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr = last; + continue; + } + + pud = pud_offset(pgd, addr); + if(!pud_present(*pud)){ + last = ADD_ROUND(addr, PUD_SIZE); + if(last > end) + last = end; + if(pud_newpage(*pud)){ + updated = 1; + err = os_unmap_memory((void *) addr, + last - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr = last; + continue; + } + + pmd = pmd_offset(pud, addr); + if(!pmd_present(*pmd)){ + last = ADD_ROUND(addr, PMD_SIZE); + if(last > end) + last = end; + if(pmd_newpage(*pmd)){ + updated = 1; + err = os_unmap_memory((void *) addr, + last - addr); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr = last; + continue; + } + + pte = pte_offset_kernel(pmd, addr); + if(!pte_present(*pte) || pte_newpage(*pte)){ + updated = 1; + err = os_unmap_memory((void *) addr, + PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + if(pte_present(*pte)) + map_memory(addr, + pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, 1, 1, 1); + } + else if(pte_newprot(*pte)){ + updated = 1; + os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1); + } + addr += PAGE_SIZE; + } + return(updated); } pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) { - return(pgd_offset(mm, address)); + return(pgd_offset(mm, address)); } pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address) { - return(pud_offset(pgd, address)); + return(pud_offset(pgd, address)); } pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address) { - return(pmd_offset(pud, address)); + return(pmd_offset(pud, address)); } pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address) { - return(pte_offset_kernel(pmd, address)); + return(pte_offset_kernel(pmd, address)); } pte_t *addr_pte(struct task_struct *task, unsigned long addr) { - pgd_t *pgd = pgd_offset(task->mm, addr); - pud_t *pud = pud_offset(pgd, addr); - pmd_t *pmd = pmd_offset(pud, addr); + pgd_t *pgd = pgd_offset(task->mm, addr); + pud_t *pud = pud_offset(pgd, addr); + pmd_t *pmd = pmd_offset(pud, addr); - return(pte_offset_map(pmd, addr)); + return(pte_offset_map(pmd, addr)); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) { - address &= PAGE_MASK; - flush_tlb_range(vma, address, address + PAGE_SIZE); + address &= PAGE_MASK; + flush_tlb_range(vma, address, address + PAGE_SIZE); } void flush_tlb_all(void) { - flush_tlb_mm(current->mm); + flush_tlb_mm(current->mm); } void flush_tlb_kernel_range(unsigned long start, unsigned long end) { - CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt, - flush_tlb_kernel_range_common, start, end); + CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt, + flush_tlb_kernel_range_common, start, end); } void flush_tlb_kernel_vm(void) { - CHOOSE_MODE(flush_tlb_kernel_vm_tt(), - flush_tlb_kernel_range_common(start_vm, end_vm)); + CHOOSE_MODE(flush_tlb_kernel_vm_tt(), + flush_tlb_kernel_range_common(start_vm, end_vm)); } void __flush_tlb_one(unsigned long addr) { - CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); + CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); } void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start, - end); + CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start, + end); } void flush_tlb_mm(struct mm_struct *mm) { - CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); + CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); } void force_flush_all(void) { - CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); + CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); } diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap.c index 02f6d4d8dc3..c7b195c7e51 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap.c @@ -35,7 +35,7 @@ #include "os.h" /* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */ -int handle_page_fault(unsigned long address, unsigned long ip, +int handle_page_fault(unsigned long address, unsigned long ip, int is_write, int is_user, int *code_out) { struct mm_struct *mm = current->mm; @@ -55,20 +55,20 @@ int handle_page_fault(unsigned long address, unsigned long ip, down_read(&mm->mmap_sem); vma = find_vma(mm, address); - if(!vma) + if(!vma) goto out; - else if(vma->vm_start <= address) + else if(vma->vm_start <= address) goto good_area; - else if(!(vma->vm_flags & VM_GROWSDOWN)) + else if(!(vma->vm_flags & VM_GROWSDOWN)) goto out; else if(is_user && !ARCH_IS_STACKGROW(address)) goto out; - else if(expand_stack(vma, address)) + else if(expand_stack(vma, address)) goto out; good_area: *code_out = SEGV_ACCERR; - if(is_write && !(vma->vm_flags & VM_WRITE)) + if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; /* Don't require VM_READ|VM_EXEC for write faults! */ @@ -120,7 +120,7 @@ out_nosemaphore: * us unable to handle the page fault gracefully. */ out_of_memory: - if (current->pid == 1) { + if (is_init(current)) { up_read(&mm->mmap_sem); yield(); down_read(&mm->mmap_sem); @@ -140,14 +140,6 @@ void segv_handler(int sig, union uml_pt_regs *regs) segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); } -struct kern_handlers handlinfo_kern = { - .relay_signal = relay_signal, - .winch = winch, - .bus_handler = relay_signal, - .page_fault = segv_handler, - .sigio_handler = sigio_handler, - .timer_handler = timer_handler -}; /* * We give a *copy* of the faultinfo in the regs to segv. * This must be done, since nesting SEGVs could overwrite @@ -184,14 +176,14 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) else if(catcher != NULL){ current->thread.fault_addr = (void *) address; do_longjmp(catcher, 1); - } + } else if(current->thread.fault_addr != NULL) panic("fault_addr set but no fault catcher"); else if(!is_user && arch_fixup(ip, sc)) return(0); - if(!is_user) - panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", + if(!is_user) + panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", address, ip); if (err == -EACCES) { @@ -227,9 +219,16 @@ void bad_segv(struct faultinfo fi, unsigned long ip) void relay_signal(int sig, union uml_pt_regs *regs) { - if(arch_handle_signal(sig, regs)) return; - if(!UPT_IS_USER(regs)) + if(arch_handle_signal(sig, regs)) + return; + + if(!UPT_IS_USER(regs)){ + if(sig == SIGBUS) + printk("Bus error - the /dev/shm or /tmp mount likely " + "just ran out of space\n"); panic("Kernel mode signal %d", sig); + } + current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); force_sig(sig, current); } @@ -246,6 +245,15 @@ void winch(int sig, union uml_pt_regs *regs) do_IRQ(WINCH_IRQ, regs); } +const struct kern_handlers handlinfo_kern = { + .relay_signal = relay_signal, + .winch = winch, + .bus_handler = bus_handler, + .page_fault = segv_handler, + .sigio_handler = sigio_handler, + .timer_handler = timer_handler +}; + void trap_init(void) { } diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c index 5c1e4cc1c04..ad66df17d9d 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c @@ -21,7 +21,7 @@ static int exec_tramp(void *sig_stack) { init_new_thread_stack(sig_stack, NULL); - init_new_thread_signals(1); + init_new_thread_signals(); os_stop_process(os_getpid()); return(0); } diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c index bcb8796c3cb..84a23b14f77 100644 --- a/arch/um/kernel/tt/mem.c +++ b/arch/um/kernel/tt/mem.c @@ -24,22 +24,13 @@ void before_mem_tt(unsigned long brk_start) #define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) #define START (CONFIG_TOP_ADDR - SIZE) -unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, - unsigned long *task_size_out) +unsigned long set_task_sizes_tt(unsigned long *task_size_out) { + unsigned long host_task_size; + /* Round up to the nearest 4M */ - *host_size_out = ROUND_4M((unsigned long) &arg); + host_task_size = ROUND_4M((unsigned long) &host_task_size); *task_size_out = START; - return(START); -} -/* - * 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: - */ + return host_task_size; +} diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index a9c1443fc54..1e86f0bfef7 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -119,7 +119,7 @@ void suspend_new_thread(int fd) panic("read failed in suspend_new_thread, err = %d", -err); } -void schedule_tail(task_t *prev); +void schedule_tail(struct task_struct *prev); static void new_thread_handler(int sig) { @@ -142,7 +142,7 @@ static void new_thread_handler(int sig) schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; - init_new_thread_signals(1); + init_new_thread_signals(); enable_timer(); free_page(current->thread.temp_stack); set_cmdline("(kernel thread)"); diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c index 3fda9a03c59..293caa6d0c2 100644 --- a/arch/um/kernel/tt/syscall_kern.c +++ b/arch/um/kernel/tt/syscall_kern.c @@ -21,18 +21,11 @@ void syscall_handler_tt(int sig, struct pt_regs *regs) void *sc; long result; int syscall; -#ifdef CONFIG_SYSCALL_DEBUG - int index; -#endif + sc = UPT_SC(®s->regs); SC_START_SYSCALL(sc); syscall = UPT_SYSCALL_NR(®s->regs); - -#ifdef CONFIG_SYSCALL_DEBUG - index = record_syscall_start(syscall); -#endif - syscall_trace(®s->regs, 0); current->thread.nsyscalls++; @@ -50,7 +43,4 @@ void syscall_handler_tt(int sig, struct pt_regs *regs) SC_SET_SYSCALL_RETURN(sc, result); syscall_trace(®s->regs, 1); -#ifdef CONFIG_SYSCALL_DEBUG - record_syscall_end(index, result); -#endif } diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c index 71daae24e48..9882342206e 100644 --- a/arch/um/kernel/tt/tracer.c +++ b/arch/um/kernel/tt/tracer.c @@ -188,10 +188,7 @@ int tracer(int (*init_proc)(void *), void *sp) int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; int proc_id = 0, n, err, old_tracing = 0, strace = 0; int local_using_sysemu = 0; -#ifdef UML_CONFIG_SYSCALL_DEBUG - unsigned long eip = 0; - int last_index; -#endif + signal(SIGPIPE, SIG_IGN); setup_tracer_winch(); tracing_pid = os_getpid(); @@ -282,23 +279,6 @@ int tracer(int (*init_proc)(void *), void *sp) else if(WIFSTOPPED(status)){ proc_id = pid_to_processor_id(pid); sig = WSTOPSIG(status); -#ifdef UML_CONFIG_SYSCALL_DEBUG - if(signal_index[proc_id] == 1024){ - signal_index[proc_id] = 0; - last_index = 1023; - } - else last_index = signal_index[proc_id] - 1; - if(((sig == SIGPROF) || (sig == SIGVTALRM) || - (sig == SIGALRM)) && - (signal_record[proc_id][last_index].signal == sig)&& - (signal_record[proc_id][last_index].pid == pid)) - signal_index[proc_id] = last_index; - signal_record[proc_id][signal_index[proc_id]].pid = pid; - gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL); - eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0); - signal_record[proc_id][signal_index[proc_id]].addr = eip; - signal_record[proc_id][signal_index[proc_id]++].signal = sig; -#endif if(proc_id == -1){ sleeping_process_signal(pid, sig); continue; diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 7d51dd7201c..55005710dcb 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -106,7 +106,7 @@ static void c_stop(struct seq_file *m, void *v) { } -struct seq_operations cpuinfo_op = { +const struct seq_operations cpuinfo_op = { .start = c_start, .next = c_next, .stop = c_stop, @@ -330,6 +330,8 @@ EXPORT_SYMBOL(end_iomem); #define MIN_VMALLOC (32 * 1024 * 1024) +extern char __binary_start; + int linux_main(int argc, char **argv) { unsigned long avail, diff; @@ -374,8 +376,9 @@ int linux_main(int argc, char **argv) printf("UML running in %s mode\n", mode); - uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, - &host_task_size, &task_size); + uml_start = (unsigned long) &__binary_start; + host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt, + set_task_sizes_skas, &task_size); /* * Setting up handlers to 'sig_info' struct @@ -395,7 +398,7 @@ int linux_main(int argc, char **argv) physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); } - uml_physmem = uml_start; + uml_physmem = uml_start & PAGE_MASK; /* Reserve up to 4M after the current brk */ uml_reserved = ROUND_4M(brk_start) + (1 << 22); @@ -495,6 +498,7 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end) { } +#ifdef CONFIG_SMP void alternatives_smp_module_add(struct module *mod, char *name, void *locks, void *locks_end, void *text, void *text_end) @@ -504,3 +508,4 @@ void alternatives_smp_module_add(struct module *mod, char *name, void alternatives_smp_module_del(struct module *mod) { } +#endif diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index af11915ce0a..8eca47a6ff0 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -7,13 +7,16 @@ jiffies = jiffies_64; SECTIONS { - /*This must contain the right address - not quite the default ELF one.*/ + /* This must contain the right address - not quite the default ELF one.*/ PROVIDE (__executable_start = START); - . = START + SIZEOF_HEADERS; + /* Static binaries stick stuff here, like the sigreturn trampoline, + * invisibly to objdump. So, just make __binary_start equal to the very + * beginning of the executable, and if there are unmapped pages after this, + * they are forever unusable. + */ + __binary_start = START; - /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start - * is remapped.*/ - __binary_start = .; + . = START + SIZEOF_HEADERS; #ifdef MODE_TT .remap_data : { UNMAP_PATH (.data .bss) } diff --git a/arch/um/kernel/vmlinux.lds.S b/arch/um/kernel/vmlinux.lds.S index 1660a769674..f8aeb448aab 100644 --- a/arch/um/kernel/vmlinux.lds.S +++ b/arch/um/kernel/vmlinux.lds.S @@ -1,4 +1,3 @@ -#include <linux/config.h> #ifdef CONFIG_LD_SCRIPT_STATIC #include "uml.lds.S" #else |