aboutsummaryrefslogtreecommitdiff
path: root/arch/um/kernel/skas
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel/skas')
-rw-r--r--arch/um/kernel/skas/Makefile5
-rw-r--r--arch/um/kernel/skas/clone.c46
-rw-r--r--arch/um/kernel/skas/exec_kern.c41
-rw-r--r--arch/um/kernel/skas/mem.c27
-rw-r--r--arch/um/kernel/skas/mmu.c192
-rw-r--r--arch/um/kernel/skas/process.c81
-rw-r--r--arch/um/kernel/skas/process_kern.c227
-rw-r--r--arch/um/kernel/skas/syscall.c35
-rw-r--r--arch/um/kernel/skas/tlb.c98
-rw-r--r--arch/um/kernel/skas/uaccess.c268
10 files changed, 359 insertions, 661 deletions
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index ea3a8e409a6..0b76d8869c9 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -1,10 +1,9 @@
#
-# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
+# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
# 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 mmu.o process.o syscall.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/clone.c b/arch/um/kernel/skas/clone.c
index 47b812b3bca..289771dadf8 100644
--- a/arch/um/kernel/skas/clone.c
+++ b/arch/um/kernel/skas/clone.c
@@ -1,17 +1,19 @@
-#include <sched.h>
+/*
+ * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
#include <signal.h>
-#include <sys/mman.h>
-#include <sys/time.h>
+#include <sched.h>
#include <asm/unistd.h>
-#include <asm/page.h>
-#include "ptrace_user.h"
-#include "skas.h"
-#include "stub-data.h"
-#include "uml-config.h"
-#include "sysdep/stub.h"
-#include "kern_constants.h"
-
-/* This is in a separate file because it needs to be compiled with any
+#include <sys/time.h>
+#include <as-layout.h>
+#include <ptrace_user.h>
+#include <stub-data.h>
+#include <sysdep/stub.h>
+
+/*
+ * This is in a separate file because it needs to be compiled with any
* extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled
*
* Use UM_KERN_PAGE_SIZE instead of PAGE_SIZE because that calls getpagesize
@@ -21,31 +23,31 @@
void __attribute__ ((__section__ (".__syscall_stub")))
stub_clone_handler(void)
{
- struct stub_data *data = (struct stub_data *) UML_CONFIG_STUB_DATA;
+ struct stub_data *data = (struct stub_data *) STUB_DATA;
long err;
err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
- UML_CONFIG_STUB_DATA + UM_KERN_PAGE_SIZE / 2 -
- sizeof(void *));
- if(err != 0)
+ STUB_DATA + UM_KERN_PAGE_SIZE / 2 - sizeof(void *));
+ if (err != 0)
goto out;
err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
- if(err)
+ if (err)
goto out;
- err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
+ err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
(long) &data->timer, 0);
- if(err)
+ if (err)
goto out;
remap_stack(data->fd, data->offset);
goto done;
out:
- /* save current result.
- * Parent: pid;
- * child: retcode of mmap already saved and it jumps around this
+ /*
+ * save current result.
+ * Parent: pid;
+ * child: retcode of mmap already saved and it jumps around this
* assignment
*/
data->err = err;
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(&current->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
deleted file mode 100644
index 27bbf54b1e5..00000000000
--- a/arch/um/kernel/skas/mem.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/config.h"
-#include "linux/mm.h"
-#include "asm/pgtable.h"
-#include "mem_user.h"
-#include "skas.h"
-
-unsigned long set_task_sizes_skas(unsigned long *task_size_out)
-{
- /* Round up to the nearest 4M */
- unsigned long host_task_size = ROUND_4M((unsigned long)
- &host_task_size);
-
-#ifdef CONFIG_HOST_TASK_SIZE
- *host_size_out = ROUND_4M(CONFIG_HOST_TASK_SIZE);
- *task_size_out = CONFIG_HOST_TASK_SIZE;
-#else
- if (!skas_needs_stub)
- *task_size_out = host_task_size;
- else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
-#endif
- return host_task_size;
-}
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 79c22707a63..007d5503f49 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -1,23 +1,16 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/config.h"
-#include "linux/sched.h"
-#include "linux/list.h"
-#include "linux/spinlock.h"
-#include "linux/slab.h"
-#include "linux/errno.h"
-#include "linux/mm.h"
-#include "asm/current.h"
-#include "asm/segment.h"
-#include "asm/mmu.h"
-#include "asm/pgalloc.h"
-#include "asm/pgtable.h"
-#include "asm/ldt.h"
-#include "os.h"
-#include "skas.h"
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <as-layout.h>
+#include <os.h>
+#include <skas.h>
extern int __syscall_stub_start;
@@ -38,94 +31,63 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
if (!pmd)
goto out_pmd;
- pte = pte_alloc_map(mm, pmd, proc);
+ pte = pte_alloc_map(mm, NULL, pmd, proc);
if (!pte)
goto out_pte;
- /* There's an interaction between the skas0 stub pages, stack
- * randomization, and the BUG at the end of exit_mmap. exit_mmap
- * checks that the number of page tables freed is the same as had
- * been allocated. If the stack is on the last page table page,
- * then the stack pte page will be freed, and if not, it won't. To
- * avoid having to know where the stack is, or if the process mapped
- * something at the top of its address space for some other reason,
- * we set TASK_SIZE to end at the start of the last page table.
- * This keeps exit_mmap off the last page, but introduces a leak
- * of that page. So, we hang onto it here and free it in
- * destroy_context_skas.
- */
-
- 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);
- return(0);
+ *pte = pte_mkread(*pte);
+ return 0;
- out_pmd:
- pud_free(pud);
out_pte:
- pmd_free(pmd);
+ pmd_free(mm, pmd);
+ out_pmd:
+ pud_free(mm, pud);
out:
- return(-ENOMEM);
+ return -ENOMEM;
}
-int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
+int init_new_context(struct task_struct *task, struct mm_struct *mm)
{
- struct mmu_context_skas *from_mm = NULL;
- struct mmu_context_skas *to_mm = &mm->context.skas;
+ struct mm_context *from_mm = NULL;
+ struct mm_context *to_mm = &mm->context;
unsigned long stack = 0;
int ret = -ENOMEM;
- if(skas_needs_stub){
+ if (skas_needs_stub) {
stack = get_zeroed_page(GFP_KERNEL);
- if(stack == 0)
+ if (stack == 0)
goto out;
-
- /* This zeros the entry that pgd_alloc didn't, needed since
- * we are about to reinitialize it, and want mm.nr_ptes to
- * be accurate.
- */
- mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
-
- ret = init_stub_pte(mm, CONFIG_STUB_CODE,
- (unsigned long) &__syscall_stub_start);
- if(ret)
- goto out_free;
-
- ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
- if(ret)
- goto out_free;
-
- mm->nr_ptes--;
}
to_mm->id.stack = stack;
- if(current->mm != NULL && current->mm != &init_mm)
- from_mm = &current->mm->context.skas;
+ if (current->mm != NULL && current->mm != &init_mm)
+ from_mm = &current->mm->context;
- if(proc_mm){
+ if (proc_mm) {
ret = new_mm(stack);
- if(ret < 0){
- printk("init_new_context_skas - new_mm failed, "
- "errno = %d\n", ret);
+ if (ret < 0) {
+ printk(KERN_ERR "init_new_context_skas - "
+ "new_mm failed, errno = %d\n", ret);
goto out_free;
}
to_mm->id.u.mm_fd = ret;
}
else {
- if(from_mm)
+ if (from_mm)
to_mm->id.u.pid = copy_context_skas0(stack,
from_mm->id.u.pid);
else to_mm->id.u.pid = start_userspace(stack);
+
+ if (to_mm->id.u.pid < 0) {
+ ret = to_mm->id.u.pid;
+ goto out_free;
+ }
}
ret = init_new_ldt(to_mm, from_mm);
- if(ret < 0){
- printk("init_new_context_skas - init_ldt"
+ if (ret < 0) {
+ printk(KERN_ERR "init_new_context_skas - init_ldt"
" failed, errno = %d\n", ret);
goto out_free;
}
@@ -133,28 +95,84 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
return 0;
out_free:
- if(to_mm->id.stack != 0)
+ if (to_mm->id.stack != 0)
free_page(to_mm->id.stack);
out:
return ret;
}
-void destroy_context_skas(struct mm_struct *mm)
+void uml_setup_stubs(struct mm_struct *mm)
+{
+ int err, ret;
+
+ if (!skas_needs_stub)
+ return;
+
+ ret = init_stub_pte(mm, STUB_CODE,
+ (unsigned long) &__syscall_stub_start);
+ if (ret)
+ goto out;
+
+ ret = init_stub_pte(mm, STUB_DATA, mm->context.id.stack);
+ if (ret)
+ goto out;
+
+ mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start);
+ mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack);
+
+ /* dup_mmap already holds mmap_sem */
+ err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START,
+ VM_READ | VM_MAYREAD | VM_EXEC |
+ VM_MAYEXEC | VM_DONTCOPY | VM_PFNMAP,
+ mm->context.stub_pages);
+ if (err) {
+ printk(KERN_ERR "install_special_mapping returned %d\n", err);
+ goto out;
+ }
+ return;
+
+out:
+ force_sigsegv(SIGSEGV, current);
+}
+
+void arch_exit_mmap(struct mm_struct *mm)
+{
+ pte_t *pte;
+
+ pte = virt_to_pte(mm, STUB_CODE);
+ if (pte != NULL)
+ pte_clear(mm, STUB_CODE, pte);
+
+ pte = virt_to_pte(mm, STUB_DATA);
+ if (pte == NULL)
+ return;
+
+ pte_clear(mm, STUB_DATA, pte);
+}
+
+void destroy_context(struct mm_struct *mm)
{
- struct mmu_context_skas *mmu = &mm->context.skas;
+ struct mm_context *mmu = &mm->context;
- if(proc_mm)
+ if (proc_mm)
os_close_file(mmu->id.u.mm_fd);
- else
+ else {
+ /*
+ * If init_new_context wasn't called, this will be
+ * zero, resulting in a kill(0), which will result in the
+ * whole UML suddenly dying. Also, cover negative and
+ * 1 cases, since they shouldn't happen either.
+ */
+ if (mmu->id.u.pid < 2) {
+ printk(KERN_ERR "corrupt mm_context - pid = %d\n",
+ mmu->id.u.pid);
+ return;
+ }
os_kill_ptraced_process(mmu->id.u.pid, 1);
+ }
- if(!proc_mm || !ptrace_faultinfo){
+ if (skas_needs_stub)
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_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
- }
+
+ free_ldt(mmu);
}
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
new file mode 100644
index 00000000000..4da11b3c8dd
--- /dev/null
+++ b/arch/um/kernel/skas/process.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <as-layout.h>
+#include <kern.h>
+#include <os.h>
+#include <skas.h>
+
+int new_mm(unsigned long stack)
+{
+ int fd, err;
+
+ fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
+ if (fd < 0)
+ return fd;
+
+ if (skas_needs_stub) {
+ err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
+ if (err) {
+ os_close_file(fd);
+ return err;
+ }
+ }
+
+ return fd;
+}
+
+extern void start_kernel(void);
+
+static int __init start_kernel_proc(void *unused)
+{
+ int pid;
+
+ block_signals();
+ pid = os_getpid();
+
+ cpu_tasks[0].pid = pid;
+ cpu_tasks[0].task = current;
+#ifdef CONFIG_SMP
+ init_cpu_online(get_cpu_mask(0));
+#endif
+ start_kernel();
+ return 0;
+}
+
+extern int userspace_pid[];
+
+extern char cpu0_irqstack[];
+
+int __init start_uml(void)
+{
+ stack_protections((unsigned long) &cpu0_irqstack);
+ set_sigstack(cpu0_irqstack, THREAD_SIZE);
+ if (proc_mm) {
+ userspace_pid[0] = start_userspace(0);
+ if (userspace_pid[0] < 0) {
+ printf("start_uml - start_userspace returned %d\n",
+ userspace_pid[0]);
+ exit(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.switch_buf);
+}
+
+unsigned long current_stub_stack(void)
+{
+ if (current->mm == NULL)
+ return 0;
+
+ return current->mm->context.id.stack;
+}
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
deleted file mode 100644
index 55caeec8b25..00000000000
--- a/arch/um/kernel/skas/process_kern.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#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 "os.h"
-#include "user_util.h"
-#include "tlb.h"
-#include "kern.h"
-#include "mode.h"
-#include "registers.h"
-
-void switch_to_skas(void *prev, void *next)
-{
- struct task_struct *from, *to;
-
- from = prev;
- to = next;
-
- /* XXX need to check runqueues[cpu].idle */
- if(current->pid == 0)
- switch_timers(0);
-
- switch_threads(&from->thread.mode.skas.switch_buf,
- to->thread.mode.skas.switch_buf);
-
- arch_switch_to_skas(current->thread.prev_sched, current);
-
- if(current->pid == 0)
- switch_timers(1);
-}
-
-extern void schedule_tail(struct task_struct *prev);
-
-void new_thread_handler(int sig)
-{
- 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(&current->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;
-
- /* The return value is 1 if the kernel thread execs a process,
- * 0 if it just exits
- */
- n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
- if(n == 1){
- /* Handle any immediate reschedules or signals */
- interrupt_end();
- userspace(&current->thread.regs.regs);
- }
- 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)
-{
- os_usr1_signal(1);
- thread_wait(&current->thread.mode.skas.switch_buf,
- current->thread.mode.skas.fork_buf);
-
- force_flush_all();
- if(current->thread.prev_sched == NULL)
- panic("blech");
-
- schedule_tail(current->thread.prev_sched);
-
- /* 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);
-
- current->thread.prev_sched = NULL;
-
-/* Handle any immediate reschedules or signals */
- interrupt_end();
-
- userspace(&current->thread.regs.regs);
-}
-
-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);
-
- if(current->thread.forking){
- memcpy(&p->thread.regs.regs.skas, &regs->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;
-
- handler = fork_handler;
-
- arch_copy_thread(&current->thread.arch, &p->thread.arch);
- }
- else {
- init_thread_registers(&p->thread.regs.regs);
- 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);
- return(0);
-}
-
-int new_mm(unsigned long stack)
-{
- int fd;
-
- fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
- if(fd < 0)
- return(fd);
-
- if(skas_needs_stub)
- map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack);
-
- return(fd);
-}
-
-void init_idle_skas(void)
-{
- cpu_tasks[current_thread->cpu].pid = os_getpid();
- default_idle();
-}
-
-extern void start_kernel(void);
-
-static int start_kernel_proc(void *unused)
-{
- int pid;
-
- block_signals();
- 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);
-}
-
-extern int userspace_pid[];
-
-int start_uml_skas(void)
-{
- if(proc_mm)
- userspace_pid[0] = start_userspace(0);
-
- 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));
-}
-
-int external_pid_skas(struct task_struct *task)
-{
-#warning Need to look up userspace_pid by cpu
- return(userspace_pid[0]);
-}
-
-int thread_pid_skas(struct task_struct *task)
-{
-#warning Need to look up userspace_pid by cpu
- return(userspace_pid[0]);
-}
-
-void kill_off_processes_skas(void)
-{
- 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;
-
- me = os_getpid();
- for_each_process(p){
- if(p->mm == NULL)
- continue;
-
- pid = p->mm->context.skas.id.u.pid;
- os_kill_ptraced_process(pid, 1);
- }
- }
-}
-
-unsigned long current_stub_stack(void)
-{
- if(current->mm == NULL)
- return(0);
-
- return(current->mm->context.skas.id.stack);
-}
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
index 0ae4eea21be..c0681e09743 100644
--- a/arch/um/kernel/skas/syscall.c
+++ b/arch/um/kernel/skas/syscall.c
@@ -1,30 +1,27 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/sys.h"
-#include "linux/ptrace.h"
-#include "asm/errno.h"
-#include "asm/unistd.h"
-#include "asm/ptrace.h"
-#include "asm/current.h"
-#include "sysdep/syscalls.h"
-#include "kern_util.h"
-#include "syscall.h"
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <kern_util.h>
+#include <sysdep/ptrace.h>
+#include <sysdep/syscalls.h>
-void handle_syscall(union uml_pt_regs *r)
+extern int syscall_table_size;
+#define NR_SYSCALLS (syscall_table_size / sizeof(void *))
+
+void handle_syscall(struct uml_pt_regs *r)
{
struct pt_regs *regs = container_of(r, struct pt_regs, regs);
long result;
int syscall;
- syscall_trace(r, 0);
-
- current->thread.nsyscalls++;
- nsyscalls++;
+ syscall_trace_enter(regs);
- /* This should go in the declaration of syscall, but when I do that,
+ /*
+ * This should go in the declaration of syscall, but when I do that,
* strace -f -c bash -c 'ls ; ls' breaks, sometimes not tracing
* children at all, sometimes hanging when bash doesn't see the first
* ls exit.
@@ -33,11 +30,11 @@ void handle_syscall(union uml_pt_regs *r)
* in case it's a compiler bug.
*/
syscall = UPT_SYSCALL_NR(r);
- if((syscall >= NR_syscalls) || (syscall < 0))
+ if ((syscall >= NR_SYSCALLS) || (syscall < 0))
result = -ENOSYS;
else result = EXECUTE_SYSCALL(syscall, regs);
- REGS_SET_SYSCALL_RETURN(r->skas.regs, result);
+ PT_REGS_SET_SYSCALL_RETURN(regs, result);
- syscall_trace(r, 1);
+ syscall_trace_leave(regs);
}
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
deleted file mode 100644
index 6e84963dfc2..00000000000
--- a/arch/um/kernel/skas/tlb.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Copyright 2003 PathScale, Inc.
- * Licensed under the GPL
- */
-
-#include "linux/stddef.h"
-#include "linux/sched.h"
-#include "linux/config.h"
-#include "linux/mm.h"
-#include "asm/page.h"
-#include "asm/pgtable.h"
-#include "asm/mmu.h"
-#include "user_util.h"
-#include "mem_user.h"
-#include "mem.h"
-#include "skas.h"
-#include "os.h"
-#include "tlb.h"
-
-static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
- int finished, void **flush)
-{
- struct host_vm_op *op;
- int i, ret = 0;
-
- for(i = 0; i <= last && !ret; i++){
- op = &ops[i];
- switch(op->type){
- case MMAP:
- ret = map(&mmu->skas.id, op->u.mmap.addr,
- op->u.mmap.len, op->u.mmap.r, op->u.mmap.w,
- op->u.mmap.x, op->u.mmap.fd,
- op->u.mmap.offset, finished, flush);
- break;
- case MUNMAP:
- ret = unmap(&mmu->skas.id,
- (void *) op->u.munmap.addr,
- op->u.munmap.len, finished, flush);
- break;
- case MPROTECT:
- ret = protect(&mmu->skas.id, op->u.mprotect.addr,
- op->u.mprotect.len, op->u.mprotect.r,
- op->u.mprotect.w, op->u.mprotect.x,
- finished, flush);
- break;
- default:
- printk("Unknown op type %d in do_ops\n", op->type);
- break;
- }
- }
-
- return ret;
-}
-
-extern int proc_mm;
-
-static void fix_range(struct mm_struct *mm, unsigned long start_addr,
- unsigned long end_addr, int force)
-{
- if(!proc_mm && (end_addr > CONFIG_STUB_START))
- end_addr = CONFIG_STUB_START;
-
- fix_range_common(mm, start_addr, end_addr, force, do_ops);
-}
-
-void __flush_tlb_one_skas(unsigned long addr)
-{
- flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE);
-}
-
-void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start,
- unsigned long end)
-{
- if(vma->vm_mm == NULL)
- flush_tlb_kernel_range_common(start, end);
- else fix_range(vma->vm_mm, start, end, 0);
-}
-
-void flush_tlb_mm_skas(struct mm_struct *mm)
-{
- unsigned long end;
-
- /* Don't bother flushing if this address space is about to be
- * destroyed.
- */
- if(atomic_read(&mm->mm_users) == 0)
- return;
-
- end = proc_mm ? task_size : CONFIG_STUB_START;
- fix_range(mm, 0, end, 0);
-}
-
-void force_flush_all_skas(void)
-{
- unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
- fix_range(current->mm, 0, end, 1);
-}
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
index 8912cec0fe4..4ffb644d6c0 100644
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -1,133 +1,133 @@
/*
- * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/compiler.h"
-#include "linux/stddef.h"
-#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"
-#include "asm/uaccess.h"
-#include "kern_util.h"
-#include "os.h"
-
-extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
- pte_t *pte_out);
-
-static unsigned long maybe_map(unsigned long virt, int is_write)
+#include <linux/err.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/current.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <kern_util.h>
+#include <os.h>
+
+pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr)
{
- pte_t pte;
- int err;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
- void *phys = um_virt_to_phys(current, virt, &pte);
- int dummy_code;
+ if (mm == NULL)
+ return NULL;
- if(IS_ERR(phys) || (is_write && !pte_write(pte))){
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_present(*pgd))
+ return NULL;
+
+ pud = pud_offset(pgd, addr);
+ if (!pud_present(*pud))
+ return NULL;
+
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_present(*pmd))
+ return NULL;
+
+ return pte_offset_kernel(pmd, addr);
+}
+
+static pte_t *maybe_map(unsigned long virt, int is_write)
+{
+ pte_t *pte = virt_to_pte(current->mm, virt);
+ int err, dummy_code;
+
+ if ((pte == NULL) || !pte_present(*pte) ||
+ (is_write && !pte_write(*pte))) {
err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
- if(err)
- return(-1UL);
- phys = um_virt_to_phys(current, virt, NULL);
+ if (err)
+ return NULL;
+ pte = virt_to_pte(current->mm, virt);
}
- if(IS_ERR(phys))
- phys = (void *) -1;
+ if (!pte_present(*pte))
+ pte = NULL;
- return((unsigned long) phys);
+ return pte;
}
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)
{
+ jmp_buf buf;
struct page *page;
- int n;
+ pte_t *pte;
+ int n, faulted;
+
+ pte = maybe_map(addr, is_write);
+ if (pte == NULL)
+ return -1;
- addr = maybe_map(addr, is_write);
- if(addr == -1UL)
- return(-1);
+ page = pte_page(*pte);
+ addr = (unsigned long) kmap_atomic(page) +
+ (addr & ~PAGE_MASK);
- page = phys_to_page(addr);
- addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) + (addr & ~PAGE_MASK);
+ current->thread.fault_catcher = &buf;
- n = (*op)(addr, len, arg);
+ faulted = UML_SETJMP(&buf);
+ if (faulted == 0)
+ n = (*op)(addr, len, arg);
+ else
+ n = -1;
+
+ current->thread.fault_catcher = NULL;
- kunmap_atomic(page, KM_UML_USERCOPY);
+ kunmap_atomic((void *)addr);
- return(n);
+ return n;
}
-static void do_buffer_op(void *jmpbuf, void *arg_ptr)
+static int buffer_op(unsigned long addr, int len, int is_write,
+ int (*op)(unsigned long, int, void *), void *arg)
{
- va_list args;
- unsigned long addr;
- int len, is_write, size, remain, n;
- int (*op)(unsigned long, int, void *);
- void *arg;
- int *res;
-
- va_copy(args, *(va_list *)arg_ptr);
- addr = va_arg(args, unsigned long);
- len = va_arg(args, int);
- is_write = va_arg(args, int);
- op = va_arg(args, void *);
- arg = va_arg(args, void *);
- res = va_arg(args, int *);
- va_end(args);
+ int size, remain, n;
+
size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
remain = len;
- current->thread.fault_catcher = jmpbuf;
n = do_op_one_page(addr, size, is_write, op, arg);
- if(n != 0){
- *res = (n < 0 ? remain : 0);
+ if (n != 0) {
+ remain = (n < 0 ? remain : 0);
goto out;
}
addr += size;
remain -= size;
- if(remain == 0){
- *res = 0;
+ if (remain == 0)
goto out;
- }
- while(addr < ((addr + remain) & PAGE_MASK)){
+ while (addr < ((addr + remain) & PAGE_MASK)) {
n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg);
- if(n != 0){
- *res = (n < 0 ? remain : 0);
+ if (n != 0) {
+ remain = (n < 0 ? remain : 0);
goto out;
}
addr += PAGE_SIZE;
remain -= PAGE_SIZE;
}
- if(remain == 0){
- *res = 0;
+ if (remain == 0)
goto out;
- }
n = do_op_one_page(addr, remain, is_write, op, arg);
- if(n != 0)
- *res = (n < 0 ? remain : 0);
- else *res = 0;
- out:
- current->thread.fault_catcher = NULL;
-}
-
-static int buffer_op(unsigned long addr, int len, int is_write,
- int (*op)(unsigned long addr, int len, void *arg),
- void *arg)
-{
- int faulted, res;
-
- faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg,
- &res);
- if(!faulted)
- return(res);
+ if (n != 0) {
+ remain = (n < 0 ? remain : 0);
+ goto out;
+ }
- return(addr + len - (unsigned long) current->thread.fault_addr);
+ return 0;
+ out:
+ return remain;
}
static int copy_chunk_from_user(unsigned long from, int len, void *arg)
@@ -136,20 +136,21 @@ static int copy_chunk_from_user(unsigned long from, int len, void *arg)
memcpy((void *) to, (void *) from, len);
*to_ptr += len;
- return(0);
+ return 0;
}
-int copy_from_user_skas(void *to, const void __user *from, int n)
+int copy_from_user(void *to, const void __user *from, int n)
{
- if(segment_eq(get_fs(), KERNEL_DS)){
+ if (segment_eq(get_fs(), KERNEL_DS)) {
memcpy(to, (__force void*)from, n);
- return(0);
+ return 0;
}
- return(access_ok(VERIFY_READ, from, n) ?
+ return access_ok(VERIFY_READ, from, n) ?
buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
- n);
+ n;
}
+EXPORT_SYMBOL(copy_from_user);
static int copy_chunk_to_user(unsigned long to, int len, void *arg)
{
@@ -157,20 +158,21 @@ static int copy_chunk_to_user(unsigned long to, int len, void *arg)
memcpy((void *) to, (void *) from, len);
*from_ptr += len;
- return(0);
+ return 0;
}
-int copy_to_user_skas(void __user *to, const void *from, int n)
+int copy_to_user(void __user *to, const void *from, int n)
{
- if(segment_eq(get_fs(), KERNEL_DS)){
- memcpy((__force void*)to, from, n);
- return(0);
+ if (segment_eq(get_fs(), KERNEL_DS)) {
+ memcpy((__force void *) to, from, n);
+ return 0;
}
- return(access_ok(VERIFY_WRITE, to, n) ?
+ return access_ok(VERIFY_WRITE, to, n) ?
buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
- n);
+ n;
}
+EXPORT_SYMBOL(copy_to_user);
static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
{
@@ -181,52 +183,54 @@ static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
n = strnlen(to, len);
*to_ptr += n;
- if(n < len)
- return(1);
- return(0);
+ if (n < len)
+ return 1;
+ return 0;
}
-int strncpy_from_user_skas(char *dst, const char __user *src, int count)
+int strncpy_from_user(char *dst, const char __user *src, int count)
{
int n;
char *ptr = dst;
- if(segment_eq(get_fs(), KERNEL_DS)){
- strncpy(dst, (__force void*)src, count);
- return(strnlen(dst, count));
+ if (segment_eq(get_fs(), KERNEL_DS)) {
+ strncpy(dst, (__force void *) src, count);
+ return strnlen(dst, count);
}
- if(!access_ok(VERIFY_READ, src, 1))
- return(-EFAULT);
+ if (!access_ok(VERIFY_READ, src, 1))
+ return -EFAULT;
n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
&ptr);
- if(n != 0)
- return(-EFAULT);
- return(strnlen(dst, count));
+ if (n != 0)
+ return -EFAULT;
+ return strnlen(dst, count);
}
+EXPORT_SYMBOL(strncpy_from_user);
static int clear_chunk(unsigned long addr, int len, void *unused)
{
memset((void *) addr, 0, len);
- return(0);
+ return 0;
}
-int __clear_user_skas(void __user *mem, int len)
+int __clear_user(void __user *mem, int len)
{
- return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL));
+ return buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL);
}
-int clear_user_skas(void __user *mem, int len)
+int clear_user(void __user *mem, int len)
{
- if(segment_eq(get_fs(), KERNEL_DS)){
+ if (segment_eq(get_fs(), KERNEL_DS)) {
memset((__force void*)mem, 0, len);
- return(0);
+ return 0;
}
- return(access_ok(VERIFY_WRITE, mem, len) ?
- buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
+ return access_ok(VERIFY_WRITE, mem, len) ?
+ buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len;
}
+EXPORT_SYMBOL(clear_user);
static int strnlen_chunk(unsigned long str, int len, void *arg)
{
@@ -235,31 +239,21 @@ static int strnlen_chunk(unsigned long str, int len, void *arg)
n = strnlen((void *) str, len);
*len_ptr += n;
- if(n < len)
- return(1);
- return(0);
+ if (n < len)
+ return 1;
+ return 0;
}
-int strnlen_user_skas(const void __user *str, int len)
+int strnlen_user(const void __user *str, int len)
{
int count = 0, n;
- if(segment_eq(get_fs(), KERNEL_DS))
- return(strnlen((__force char*)str, len) + 1);
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return strnlen((__force char*)str, len) + 1;
n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
- if(n == 0)
- return(count + 1);
- return(-EFAULT);
+ if (n == 0)
+ return count + 1;
+ return 0;
}
-
-/*
- * 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:
- */
+EXPORT_SYMBOL(strnlen_user);