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/Makefile17
-rw-r--r--arch/um/kernel/skas/clone.c58
-rw-r--r--arch/um/kernel/skas/exec_kern.c41
-rw-r--r--arch/um/kernel/skas/include/mm_id.h17
-rw-r--r--arch/um/kernel/skas/include/mmu-skas.h29
-rw-r--r--arch/um/kernel/skas/include/mode-skas.h33
-rw-r--r--arch/um/kernel/skas/include/mode_kern-skas.h52
-rw-r--r--arch/um/kernel/skas/include/proc_mm.h55
-rw-r--r--arch/um/kernel/skas/include/skas.h51
-rw-r--r--arch/um/kernel/skas/include/stub-data.h18
-rw-r--r--arch/um/kernel/skas/include/uaccess-skas.h45
-rw-r--r--arch/um/kernel/skas/mem.c39
-rw-r--r--arch/um/kernel/skas/mem_user.c173
-rw-r--r--arch/um/kernel/skas/mmu.c211
-rw-r--r--arch/um/kernel/skas/process.c534
-rw-r--r--arch/um/kernel/skas/process_kern.c232
-rw-r--r--arch/um/kernel/skas/syscall.c40
-rw-r--r--arch/um/kernel/skas/syscall_kern.c43
-rw-r--r--arch/um/kernel/skas/syscall_user.c44
-rw-r--r--arch/um/kernel/skas/tlb.c92
-rw-r--r--arch/um/kernel/skas/trap_user.c78
-rw-r--r--arch/um/kernel/skas/uaccess.c275
-rw-r--r--arch/um/kernel/skas/util/Makefile5
-rw-r--r--arch/um/kernel/skas/util/mk_ptregs-i386.c49
-rw-r--r--arch/um/kernel/skas/util/mk_ptregs-x86_64.c66
25 files changed, 392 insertions, 1905 deletions
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index d296d55ade4..0b76d8869c9 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -1,16 +1,15 @@
-#
-# 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 mem_user.o mmu.o process.o process_kern.o \
- syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \
+obj-y := clone.o mmu.o process.o syscall.o uaccess.o
-subdir- := util
+# 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 ->
+# disable it
-USER_OBJS := process.o clone.o
+CFLAGS_clone.o := $(CFLAGS_NO_HARDENING)
+UNPROFILE_OBJS := clone.o
include arch/um/scripts/Makefile.rules
-
-# clone.o is in the stub, so it can't be built with profiling
-$(obj)/clone.o : c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
index 4dc55f10cd1..289771dadf8 100644
--- a/arch/um/kernel/skas/clone.c
+++ b/arch/um/kernel/skas/clone.c
@@ -1,44 +1,56 @@
-#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"
-
-/* 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
+ * on some systems.
*/
+
void __attribute__ ((__section__ (".__syscall_stub")))
stub_clone_handler(void)
{
+ struct stub_data *data = (struct stub_data *) STUB_DATA;
long err;
- struct stub_data *from = (struct stub_data *) UML_CONFIG_STUB_DATA;
err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
- UML_CONFIG_STUB_DATA + 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,
- (long) &from->timer, 0);
- if(err)
+ (long) &data->timer, 0);
+ if (err)
goto out;
- err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA, PAGE_SIZE,
- PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
- from->fd, from->offset);
+ remap_stack(data->fd, data->offset);
+ goto done;
+
out:
- /* save current result. Parent: pid; child: retcode of mmap */
- from->err = err;
+ /*
+ * save current result.
+ * Parent: pid;
+ * child: retcode of mmap already saved and it jumps around this
+ * assignment
+ */
+ data->err = err;
+ done:
trap_myself();
}
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/include/mm_id.h b/arch/um/kernel/skas/include/mm_id.h
deleted file mode 100644
index 48dd0989dda..00000000000
--- a/arch/um/kernel/skas/include/mm_id.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __MM_ID_H
-#define __MM_ID_H
-
-struct mm_id {
- union {
- int mm_fd;
- int pid;
- } u;
- unsigned long stack;
-};
-
-#endif
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
deleted file mode 100644
index 278b72f1d9a..00000000000
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SKAS_MMU_H
-#define __SKAS_MMU_H
-
-#include "mm_id.h"
-
-struct mmu_context_skas {
- struct mm_id id;
- unsigned long last_page_table;
-};
-
-extern void switch_mm_skas(struct mm_id * mm_idp);
-
-#endif
-
-/*
- * 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/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h
deleted file mode 100644
index bcd26a6a388..00000000000
--- a/arch/um/kernel/skas/include/mode-skas.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __MODE_SKAS_H__
-#define __MODE_SKAS_H__
-
-#include <sysdep/ptrace.h>
-
-extern unsigned long exec_regs[];
-extern unsigned long exec_fp_regs[];
-extern unsigned long exec_fpx_regs[];
-extern int have_fpx_regs;
-
-extern void sig_handler_common_skas(int sig, void *sc_ptr);
-extern void halt_skas(void);
-extern void reboot_skas(void);
-extern void kill_off_processes_skas(void);
-extern int is_skas_winch(int pid, int fd, void *data);
-
-#endif
-
-/*
- * 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/include/mode_kern-skas.h b/arch/um/kernel/skas/include/mode_kern-skas.h
deleted file mode 100644
index e4849002811..00000000000
--- a/arch/um/kernel/skas/include/mode_kern-skas.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SKAS_MODE_KERN_H__
-#define __SKAS_MODE_KERN_H__
-
-#include "linux/sched.h"
-#include "asm/page.h"
-#include "asm/ptrace.h"
-
-extern void flush_thread_skas(void);
-extern void *switch_to_skas(void *prev, void *next);
-extern void start_thread_skas(struct pt_regs *regs, unsigned long eip,
- unsigned long esp);
-extern 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);
-extern void release_thread_skas(struct task_struct *task);
-extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
-extern void init_idle_skas(void);
-extern void flush_tlb_kernel_range_skas(unsigned long start,
- unsigned long end);
-extern void flush_tlb_kernel_vm_skas(void);
-extern void __flush_tlb_one_skas(unsigned long addr);
-extern void flush_tlb_range_skas(struct vm_area_struct *vma,
- unsigned long start, unsigned long end);
-extern void flush_tlb_mm_skas(struct mm_struct *mm);
-extern void force_flush_all_skas(void);
-extern long execute_syscall_skas(void *r);
-extern void before_mem_skas(unsigned long unused);
-extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
- unsigned long *task_size_out);
-extern int start_uml_skas(void);
-extern int external_pid_skas(struct task_struct *task);
-extern int thread_pid_skas(struct task_struct *task);
-
-#define kmem_end_skas (host_task_size - 1024 * 1024)
-
-#endif
-
-/*
- * 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/include/proc_mm.h b/arch/um/kernel/skas/include/proc_mm.h
deleted file mode 100644
index cce61a67905..00000000000
--- a/arch/um/kernel/skas/include/proc_mm.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SKAS_PROC_MM_H
-#define __SKAS_PROC_MM_H
-
-#define MM_MMAP 54
-#define MM_MUNMAP 55
-#define MM_MPROTECT 56
-#define MM_COPY_SEGMENTS 57
-
-struct mm_mmap {
- unsigned long addr;
- unsigned long len;
- unsigned long prot;
- unsigned long flags;
- unsigned long fd;
- unsigned long offset;
-};
-
-struct mm_munmap {
- unsigned long addr;
- unsigned long len;
-};
-
-struct mm_mprotect {
- unsigned long addr;
- unsigned long len;
- unsigned int prot;
-};
-
-struct proc_mm_op {
- int op;
- union {
- struct mm_mmap mmap;
- struct mm_munmap munmap;
- struct mm_mprotect mprotect;
- int copy_segments;
- } u;
-};
-
-#endif
-
-/*
- * 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/include/skas.h b/arch/um/kernel/skas/include/skas.h
deleted file mode 100644
index d983ea84254..00000000000
--- a/arch/um/kernel/skas/include/skas.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SKAS_H
-#define __SKAS_H
-
-#include "mm_id.h"
-#include "sysdep/ptrace.h"
-
-extern int userspace_pid[];
-extern int proc_mm, ptrace_faultinfo;
-
-extern void switch_threads(void *me, void *next);
-extern void thread_wait(void *sw, void *fb);
-extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
- void (*handler)(int));
-extern int start_idle_thread(void *stack, void *switch_buf_ptr,
- void **fork_buf_ptr);
-extern int user_thread(unsigned long stack, int flags);
-extern void userspace(union uml_pt_regs *regs);
-extern void new_thread_proc(void *stack, void (*handler)(int sig));
-extern void remove_sigstack(void);
-extern void new_thread_handler(int sig);
-extern void handle_syscall(union uml_pt_regs *regs);
-extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
- int r, int w, int x, int phys_fd, unsigned long long offset);
-extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
-extern int protect(struct mm_id * mm_idp, unsigned long addr,
- unsigned long len, int r, int w, int x);
-extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
-extern int new_mm(int from);
-extern int start_userspace(unsigned long stub_stack);
-extern int copy_context_skas0(unsigned long stack, int pid);
-extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
-extern long execute_syscall_skas(void *r);
-extern unsigned long current_stub_stack(void);
-
-#endif
-
-/*
- * 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/include/stub-data.h b/arch/um/kernel/skas/include/stub-data.h
deleted file mode 100644
index f6ed92c3727..00000000000
--- a/arch/um/kernel/skas/include/stub-data.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __STUB_DATA_H
-#define __STUB_DATA_H
-
-#include <sys/time.h>
-
-struct stub_data {
- long offset;
- int fd;
- struct itimerval timer;
- long err;
-};
-
-#endif
diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h
deleted file mode 100644
index cd6c280482c..00000000000
--- a/arch/um/kernel/skas/include/uaccess-skas.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SKAS_UACCESS_H
-#define __SKAS_UACCESS_H
-
-#include "asm/errno.h"
-#include "asm/fixmap.h"
-
-#define access_ok_skas(type, addr, size) \
- ((segment_eq(get_fs(), KERNEL_DS)) || \
- (((unsigned long) (addr) < TASK_SIZE) && \
- ((unsigned long) (addr) + (size) <= TASK_SIZE)) || \
- ((type == VERIFY_READ ) && \
- ((unsigned long) (addr) >= FIXADDR_USER_START) && \
- ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
- ((unsigned long) (addr) + (size) >= (unsigned long)(addr))))
-
-static inline int verify_area_skas(int type, const void * addr,
- unsigned long size)
-{
- return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
-}
-
-extern int copy_from_user_skas(void *to, const void *from, int n);
-extern int copy_to_user_skas(void *to, const void *from, int n);
-extern int strncpy_from_user_skas(char *dst, const char *src, int count);
-extern int __clear_user_skas(void *mem, int len);
-extern int clear_user_skas(void *mem, int len);
-extern int strnlen_user_skas(const void *str, int len);
-
-#endif
-
-/*
- * 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 147466d7ff4..00000000000
--- a/arch/um/kernel/skas/mem.c
+++ /dev/null
@@ -1,39 +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(int arg, unsigned long *host_size_out,
- unsigned long *task_size_out)
-{
- /* Round up to the nearest 4M */
- unsigned long top = ROUND_4M((unsigned long) &arg);
-
-#ifdef CONFIG_HOST_TASK_SIZE
- *host_size_out = CONFIG_HOST_TASK_SIZE;
- *task_size_out = CONFIG_HOST_TASK_SIZE;
-#else
- *host_size_out = top;
- if (proc_mm && ptrace_faultinfo)
- *task_size_out = top;
- else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
-#endif
- return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
-}
-
-/*
- * 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_user.c b/arch/um/kernel/skas/mem_user.c
deleted file mode 100644
index b0980ff3bd9..00000000000
--- a/arch/um/kernel/skas/mem_user.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <signal.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-#include <asm/page.h>
-#include <asm/unistd.h>
-#include "mem_user.h"
-#include "mem.h"
-#include "mm_id.h"
-#include "user.h"
-#include "os.h"
-#include "proc_mm.h"
-#include "ptrace_user.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "task.h"
-#include "registers.h"
-#include "uml-config.h"
-#include "sysdep/ptrace.h"
-#include "sysdep/stub.h"
-#include "skas.h"
-
-extern unsigned long syscall_stub, __syscall_stub_start;
-
-extern void wait_stub_done(int pid, int sig, char * fname);
-
-static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
- unsigned long *args)
-{
- int n, pid = mm_idp->u.pid;
- unsigned long regs[MAX_REG_NR];
-
- get_safe_registers(regs);
- regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
- ((unsigned long) &syscall_stub -
- (unsigned long) &__syscall_stub_start);
- /* XXX Don't have a define for starting a syscall */
- regs[REGS_SYSCALL_NR] = syscall;
- regs[REGS_SYSCALL_ARG1] = args[0];
- regs[REGS_SYSCALL_ARG2] = args[1];
- regs[REGS_SYSCALL_ARG3] = args[2];
- regs[REGS_SYSCALL_ARG4] = args[3];
- regs[REGS_SYSCALL_ARG5] = args[4];
- regs[REGS_SYSCALL_ARG6] = args[5];
- n = ptrace_setregs(pid, regs);
- if(n < 0){
- printk("run_syscall_stub : PTRACE_SETREGS failed, "
- "errno = %d\n", n);
- return(n);
- }
-
- wait_stub_done(pid, 0, "run_syscall_stub");
-
- return(*((unsigned long *) mm_idp->stack));
-}
-
-int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
- int r, int w, int x, int phys_fd, unsigned long long offset)
-{
- int prot, n;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
-
- if(proc_mm){
- struct proc_mm_op map;
- int fd = mm_idp->u.mm_fd;
- map = ((struct proc_mm_op) { .op = MM_MMAP,
- .u =
- { .mmap =
- { .addr = virt,
- .len = len,
- .prot = prot,
- .flags = MAP_SHARED |
- MAP_FIXED,
- .fd = phys_fd,
- .offset= offset
- } } } );
- n = os_write_file(fd, &map, sizeof(map));
- if(n != sizeof(map))
- printk("map : /proc/mm map failed, err = %d\n", -n);
- }
- else {
- long res;
- unsigned long args[] = { virt, len, prot,
- MAP_SHARED | MAP_FIXED, phys_fd,
- MMAP_OFFSET(offset) };
-
- res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
- if((void *) res == MAP_FAILED)
- printk("mmap stub failed, errno = %d\n", res);
- }
-
- return 0;
-}
-
-int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
-{
- int n;
-
- if(proc_mm){
- struct proc_mm_op unmap;
- int fd = mm_idp->u.mm_fd;
- unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
- .u =
- { .munmap =
- { .addr =
- (unsigned long) addr,
- .len = len } } } );
- n = os_write_file(fd, &unmap, sizeof(unmap));
- if(n != sizeof(unmap)) {
- if(n < 0)
- return(n);
- else if(n > 0)
- return(-EIO);
- }
- }
- else {
- int res;
- unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
- 0 };
-
- res = run_syscall_stub(mm_idp, __NR_munmap, args);
- if(res < 0)
- printk("munmap stub failed, errno = %d\n", res);
- }
-
- return(0);
-}
-
-int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
- int r, int w, int x)
-{
- struct proc_mm_op protect;
- int prot, n;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
-
- if(proc_mm){
- int fd = mm_idp->u.mm_fd;
- protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
- .u =
- { .mprotect =
- { .addr =
- (unsigned long) addr,
- .len = len,
- .prot = prot } } } );
-
- n = os_write_file(fd, &protect, sizeof(protect));
- if(n != sizeof(protect))
- panic("protect failed, err = %d", -n);
- }
- else {
- int res;
- unsigned long args[] = { addr, len, prot, 0, 0, 0 };
-
- res = run_syscall_stub(mm_idp, __NR_mprotect, args);
- if(res < 0)
- panic("mprotect stub failed, errno = %d\n", res);
- }
-
- return(0);
-}
-
-void before_mem_skas(unsigned long unused)
-{
-}
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index d232daa42c3..007d5503f49 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -1,22 +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 "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;
@@ -28,7 +22,6 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
pmd_t *pmd;
pte_t *pte;
- spin_lock(&mm->page_table_lock);
pgd = pgd_offset(mm, proc);
pud = pud_alloc(mm, pgd, proc);
if (!pud)
@@ -38,108 +31,148 @@ 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_kernel(*pmd);
-
*pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
- *pte = pte_mkexec(*pte);
- *pte = pte_wrprotect(*pte);
- spin_unlock(&mm->page_table_lock);
- 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:
- spin_unlock(&mm->page_table_lock);
- 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 mm_struct *cur_mm = current->mm;
- struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
- struct mm_id *mm_id = &mm->context.skas.id;
- unsigned long stack;
- int from, ret;
-
- if(proc_mm){
- if((cur_mm != NULL) && (cur_mm != &init_mm))
- from = cur_mm->context.skas.id.u.mm_fd;
- else from = -1;
-
- ret = new_mm(from);
- if(ret < 0){
- printk("init_new_context_skas - new_mm failed, "
- "errno = %d\n", ret);
- return ret;
- }
- mm_id->u.mm_fd = ret;
- }
- else {
- /* 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);
+ struct mm_context *from_mm = NULL;
+ struct mm_context *to_mm = &mm->context;
+ unsigned long stack = 0;
+ int ret = -ENOMEM;
- ret = init_stub_pte(mm, CONFIG_STUB_CODE,
- (unsigned long) &__syscall_stub_start);
- if(ret)
- goto out;
-
- ret = -ENOMEM;
+ if (skas_needs_stub) {
stack = get_zeroed_page(GFP_KERNEL);
- if(stack == 0)
+ if (stack == 0)
goto out;
- mm_id->stack = stack;
+ }
- ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
- if(ret)
+ to_mm->id.stack = stack;
+ if (current->mm != NULL && current->mm != &init_mm)
+ from_mm = &current->mm->context;
+
+ if (proc_mm) {
+ ret = new_mm(stack);
+ 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)
+ to_mm->id.u.pid = copy_context_skas0(stack,
+ from_mm->id.u.pid);
+ else to_mm->id.u.pid = start_userspace(stack);
- mm->nr_ptes--;
+ if (to_mm->id.u.pid < 0) {
+ ret = to_mm->id.u.pid;
+ goto out_free;
+ }
+ }
- if((cur_mm != NULL) && (cur_mm != &init_mm))
- mm_id->u.pid = copy_context_skas0(stack,
- cur_mm_id->u.pid);
- else mm_id->u.pid = start_userspace(stack);
+ ret = init_new_ldt(to_mm, from_mm);
+ if (ret < 0) {
+ printk(KERN_ERR "init_new_context_skas - init_ldt"
+ " failed, errno = %d\n", ret);
+ goto out_free;
}
return 0;
out_free:
- free_page(mm_id->stack);
+ 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 {
+ /*
+ * 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);
- free_page(mmu->id.stack);
- free_page(mmu->last_page_table);
}
+
+ if (skas_needs_stub)
+ free_page(mmu->id.stack);
+
+ free_ldt(mmu);
}
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 6dd9e5bf18e..4da11b3c8dd 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -1,513 +1,81 @@
-/*
- * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com)
+/*
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <sched.h>
-#include <sys/wait.h>
-#include <sys/mman.h>
-#include <sys/user.h>
-#include <sys/time.h>
-#include <asm/unistd.h>
-#include <asm/types.h>
-#include "user.h"
-#include "ptrace_user.h"
-#include "time_user.h"
-#include "sysdep/ptrace.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "skas.h"
-#include "stub-data.h"
-#include "mm_id.h"
-#include "sysdep/sigcontext.h"
-#include "sysdep/stub.h"
-#include "os.h"
-#include "proc_mm.h"
-#include "skas_ptrace.h"
-#include "chan_user.h"
-#include "signal_user.h"
-#include "registers.h"
-#include "mem.h"
-#include "uml-config.h"
-#include "process.h"
-
-int is_skas_winch(int pid, int fd, void *data)
-{
- if(pid != os_getpgrp())
- return(0);
-
- register_winch_irq(-1, fd, -1, data);
- return(1);
-}
-
-void wait_stub_done(int pid, int sig, char * fname)
-{
- int n, status, err;
-
- do {
- if ( sig != -1 ) {
- err = ptrace(PTRACE_CONT, pid, 0, sig);
- if(err)
- panic("%s : continue failed, errno = %d\n",
- fname, errno);
- }
- sig = 0;
-
- CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
- } while((n >= 0) && WIFSTOPPED(status) &&
- (WSTOPSIG(status) == SIGVTALRM));
-
- if((n < 0) || !WIFSTOPPED(status) ||
- (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){
- panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
- "pid = %d, n = %d, errno = %d, status = 0x%x\n",
- fname, pid, n, errno, status);
- }
-}
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <as-layout.h>
+#include <kern.h>
+#include <os.h>
+#include <skas.h>
-void get_skas_faultinfo(int pid, struct faultinfo * fi)
+int new_mm(unsigned long stack)
{
- int err;
-
- if(ptrace_faultinfo){
- err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
- if(err)
- panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
- "errno = %d\n", errno);
-
- /* Special handling for i386, which has different structs */
- if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
- memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
- sizeof(struct faultinfo) -
- sizeof(struct ptrace_faultinfo));
- }
- else {
- wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
-
- /* faultinfo is prepared by the stub-segv-handler at start of
- * the stub stack page. We just have to copy it.
- */
- memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
- }
-}
-
-static void handle_segv(int pid, union uml_pt_regs * regs)
-{
- get_skas_faultinfo(pid, &regs->skas.faultinfo);
- segv(regs->skas.faultinfo, 0, 1, NULL);
-}
-
-/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
-static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu)
-{
- int err, status;
-
- /* Mark this as a syscall */
- UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs);
-
- if (!local_using_sysemu)
- {
- err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
- if(err < 0)
- panic("handle_trap - nullifying syscall failed errno = %d\n",
- errno);
-
- err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
- if(err < 0)
- panic("handle_trap - continuing to end of syscall failed, "
- "errno = %d\n", errno);
-
- CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
- if((err < 0) || !WIFSTOPPED(status) ||
- (WSTOPSIG(status) != SIGTRAP + 0x80))
- panic("handle_trap - failed to wait at end of syscall, "
- "errno = %d, status = %d\n", errno, status);
- }
-
- handle_syscall(regs);
-}
+ int fd, err;
-extern int __syscall_stub_start;
+ fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
+ if (fd < 0)
+ return fd;
-static int userspace_tramp(void *stack)
-{
- void *addr;
-
- ptrace(PTRACE_TRACEME, 0, 0, 0);
-
- init_new_thread_signals(1);
- enable_timer();
-
- if(!proc_mm){
- /* This has a pte, but it can't be mapped in with the usual
- * tlb_flush mechanism because this is part of that mechanism
- */
- int fd;
- __u64 offset;
-
- fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
- addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
- PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
- if(addr == MAP_FAILED){
- printk("mapping mmap stub failed, errno = %d\n",
- errno);
- exit(1);
+ if (skas_needs_stub) {
+ err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
+ if (err) {
+ os_close_file(fd);
+ return err;
}
-
- if(stack != NULL){
- fd = phys_mapping(to_phys(stack), &offset);
- addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
- PROT_READ | PROT_WRITE,
- MAP_FIXED | MAP_SHARED, fd, offset);
- if(addr == MAP_FAILED){
- printk("mapping segfault stack failed, "
- "errno = %d\n", errno);
- exit(1);
- }
- }
- }
- if(!ptrace_faultinfo && (stack != NULL)){
- unsigned long v = UML_CONFIG_STUB_CODE +
- (unsigned long) stub_segv_handler -
- (unsigned long) &__syscall_stub_start;
-
- set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
- set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
- SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
- SIGUSR1, -1);
}
- os_stop_process(os_getpid());
- return(0);
-}
-
-/* Each element set once, and only accessed by a single processor anyway */
-#undef NR_CPUS
-#define NR_CPUS 1
-int userspace_pid[NR_CPUS];
-
-int start_userspace(unsigned long stub_stack)
-{
- void *stack;
- unsigned long sp;
- int pid, status, n, flags;
-
- stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if(stack == MAP_FAILED)
- panic("start_userspace : mmap failed, errno = %d", errno);
- sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
-
- flags = CLONE_FILES | SIGCHLD;
- if(proc_mm) flags |= CLONE_VM;
- pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
- if(pid < 0)
- panic("start_userspace : clone failed, errno = %d", errno);
-
- do {
- CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
- if(n < 0)
- panic("start_userspace : wait failed, errno = %d",
- errno);
- } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
-
- if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
- panic("start_userspace : expected SIGSTOP, got status = %d",
- status);
-
- if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, (void *)PTRACE_O_TRACESYSGOOD) < 0)
- panic("start_userspace : PTRACE_SETOPTIONS failed, errno=%d\n",
- errno);
-
- if(munmap(stack, PAGE_SIZE) < 0)
- panic("start_userspace : munmap failed, errno = %d\n", errno);
-
- return(pid);
-}
-
-void userspace(union uml_pt_regs *regs)
-{
- int err, status, op, pid = userspace_pid[0];
- int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
-
- while(1){
- restore_registers(pid, regs);
-
- /* Now we set local_using_sysemu to be used for one loop */
- local_using_sysemu = get_using_sysemu();
-
- op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
-
- err = ptrace(op, pid, 0, 0);
- if(err)
- panic("userspace - could not resume userspace process, "
- "pid=%d, ptrace operation = %d, errno = %d\n",
- op, errno);
-
- CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
- if(err < 0)
- panic("userspace - waitpid failed, errno = %d\n",
- errno);
-
- regs->skas.is_user = 1;
- save_registers(pid, regs);
- UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
-
- if(WIFSTOPPED(status)){
- switch(WSTOPSIG(status)){
- case SIGSEGV:
- if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
- user_signal(SIGSEGV, regs, pid);
- else handle_segv(pid, regs);
- break;
- case SIGTRAP + 0x80:
- handle_trap(pid, regs, local_using_sysemu);
- break;
- case SIGTRAP:
- relay_signal(SIGTRAP, regs);
- break;
- case SIGIO:
- case SIGVTALRM:
- case SIGILL:
- case SIGBUS:
- case SIGFPE:
- case SIGWINCH:
- user_signal(WSTOPSIG(status), regs, pid);
- break;
- default:
- printk("userspace - child stopped with signal "
- "%d\n", WSTOPSIG(status));
- }
- pid = userspace_pid[0];
- interrupt_end();
-
- /* Avoid -ERESTARTSYS handling in host */
- PT_SYSCALL_NR(regs->skas.regs) = -1;
- }
- }
+ return fd;
}
-#define INIT_JMP_NEW_THREAD 0
-#define INIT_JMP_REMOVE_SIGSTACK 1
-#define INIT_JMP_CALLBACK 2
-#define INIT_JMP_HALT 3
-#define INIT_JMP_REBOOT 4
+extern void start_kernel(void);
-int copy_context_skas0(unsigned long new_stack, int pid)
+static int __init start_kernel_proc(void *unused)
{
- int err;
- unsigned long regs[MAX_REG_NR];
- unsigned long current_stack = current_stub_stack();
- struct stub_data *data = (struct stub_data *) current_stack;
- struct stub_data *child_data = (struct stub_data *) new_stack;
- __u64 new_offset;
- int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
-
- /* prepare offset and fd of child's stack as argument for parent's
- * and child's mmap2 calls
- */
- *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset),
- .fd = new_fd,
- .timer = ((struct itimerval)
- { { 0, 1000000 / hz() },
- { 0, 1000000 / hz() }})});
- get_safe_registers(regs);
-
- /* Set parent's instruction pointer to start of clone-stub */
- regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
- (unsigned long) stub_clone_handler -
- (unsigned long) &__syscall_stub_start;
- regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
- sizeof(void *);
- err = ptrace_setregs(pid, regs);
- if(err < 0)
- panic("copy_context_skas0 : PTRACE_SETREGS failed, "
- "pid = %d, errno = %d\n", pid, errno);
-
- /* set a well known return code for detection of child write failure */
- child_data->err = 12345678;
-
- /* Wait, until parent has finished its work: read child's pid from
- * parent's stack, and check, if bad result.
- */
- wait_stub_done(pid, 0, "copy_context_skas0");
-
- pid = data->err;
- if(pid < 0)
- panic("copy_context_skas0 - stub-parent reports error %d\n",
- pid);
-
- /* Wait, until child has finished too: read child's result from
- * child's stack and check it.
- */
- wait_stub_done(pid, -1, "copy_context_skas0");
- if (child_data->err != UML_CONFIG_STUB_DATA)
- panic("copy_context_skas0 - stub-child reports error %d\n",
- child_data->err);
+ int pid;
- if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
- (void *)PTRACE_O_TRACESYSGOOD) < 0)
- panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, "
- "errno = %d\n", errno);
-
- return pid;
-}
-
-void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
- void (*handler)(int))
-{
- unsigned long flags;
- sigjmp_buf switch_buf, fork_buf;
-
- *switch_buf_ptr = &switch_buf;
- *fork_buf_ptr = &fork_buf;
-
- /* Somewhat subtle - siglongjmp restores the signal mask before doing
- * the longjmp. This means that when jumping from one stack to another
- * when the target stack has interrupts enabled, an interrupt may occur
- * on the source stack. This is bad when starting up a process because
- * it's not supposed to get timer ticks until it has been scheduled.
- * So, we disable interrupts around the sigsetjmp to ensure that
- * they can't happen until we get back here where they are safe.
- */
- flags = get_signals();
block_signals();
- if(sigsetjmp(fork_buf, 1) == 0)
- new_thread_proc(stack, handler);
-
- remove_sigstack();
+ pid = os_getpid();
- set_signals(flags);
+ 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;
}
-void thread_wait(void *sw, void *fb)
-{
- sigjmp_buf buf, **switch_buf = sw, *fork_buf;
+extern int userspace_pid[];
- *switch_buf = &buf;
- fork_buf = fb;
- if(sigsetjmp(buf, 1) == 0)
- siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK);
-}
+extern char cpu0_irqstack[];
-void switch_threads(void *me, void *next)
+int __init start_uml(void)
{
- sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
-
- *me_ptr = &my_buf;
- if(sigsetjmp(my_buf, 1) == 0)
- siglongjmp(*next_buf, 1);
-}
-
-static sigjmp_buf initial_jmpbuf;
-
-/* XXX Make these percpu */
-static void (*cb_proc)(void *arg);
-static void *cb_arg;
-static sigjmp_buf *cb_back;
-
-int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
-{
- sigjmp_buf **switch_buf = switch_buf_ptr;
- int n;
-
- set_handler(SIGWINCH, (__sighandler_t) sig_handler,
- SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
- SIGVTALRM, -1);
-
- *fork_buf_ptr = &initial_jmpbuf;
- n = sigsetjmp(initial_jmpbuf, 1);
- switch(n){
- case INIT_JMP_NEW_THREAD:
- new_thread_proc((void *) stack, new_thread_handler);
- break;
- case INIT_JMP_REMOVE_SIGSTACK:
- remove_sigstack();
- break;
- case INIT_JMP_CALLBACK:
- (*cb_proc)(cb_arg);
- siglongjmp(*cb_back, 1);
- break;
- case INIT_JMP_HALT:
- kmalloc_ok = 0;
- return(0);
- case INIT_JMP_REBOOT:
- kmalloc_ok = 0;
- return(1);
- default:
- panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
+ 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);
+ }
}
- siglongjmp(**switch_buf, 1);
-}
-
-void remove_sigstack(void)
-{
- stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
- .ss_sp = NULL,
- .ss_size = 0 });
-
- if(sigaltstack(&stack, NULL) != 0)
- panic("disabling signal stack failed, errno = %d\n", errno);
-}
-
-void initial_thread_cb_skas(void (*proc)(void *), void *arg)
-{
- sigjmp_buf here;
-
- cb_proc = proc;
- cb_arg = arg;
- cb_back = &here;
- block_signals();
- if(sigsetjmp(here, 1) == 0)
- siglongjmp(initial_jmpbuf, INIT_JMP_CALLBACK);
- unblock_signals();
+ init_new_thread_signals();
- cb_proc = NULL;
- cb_arg = NULL;
- cb_back = NULL;
+ 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);
}
-void halt_skas(void)
+unsigned long current_stub_stack(void)
{
- block_signals();
- siglongjmp(initial_jmpbuf, INIT_JMP_HALT);
-}
+ if (current->mm == NULL)
+ return 0;
-void reboot_skas(void)
-{
- block_signals();
- siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
+ return current->mm->context.id.stack;
}
-
-void switch_mm_skas(struct mm_id *mm_idp)
-{
- int err;
-
-#warning need cpu pid in switch_mm_skas
- if(proc_mm){
- err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
- mm_idp->u.mm_fd);
- if(err)
- panic("switch_mm_skas - PTRACE_SWITCH_MM failed, "
- "errno = %d\n", errno);
- }
- else userspace_pid[0] = mm_idp->u.pid;
-}
-
-/*
- * 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/process_kern.c b/arch/um/kernel/skas/process_kern.c
deleted file mode 100644
index cbabab104ac..00000000000
--- a/arch/um/kernel/skas/process_kern.c
+++ /dev/null
@@ -1,232 +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 "time_user.h"
-#include "signal_user.h"
-#include "skas.h"
-#include "os.h"
-#include "user_util.h"
-#include "tlb.h"
-#include "kern.h"
-#include "mode.h"
-#include "proc_mm.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);
-
- to->thread.prev_sched = from;
- set_current(to);
-
- switch_threads(&from->thread.mode.skas.switch_buf,
- to->thread.mode.skas.switch_buf);
-
- if(current->pid == 0)
- switch_timers(1);
-
- return(current->thread.prev_sched);
-}
-
-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;
- change_sig(SIGUSR1, 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)
-{
- change_sig(SIGUSR1, 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);
- 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;
- }
- else {
- init_thread_registers(&p->thread.regs.regs);
- p->thread.request.u.thread = current->thread.request.u.thread;
- handler = new_thread_handler;
- }
-
- new_thread(p->thread_info, &p->thread.mode.skas.switch_buf,
- &p->thread.mode.skas.fork_buf, handler);
- return(0);
-}
-
-int new_mm(int from)
-{
- struct proc_mm_op copy;
- int n, fd;
-
- fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
- if(fd < 0)
- return(fd);
-
- if(from != -1){
- copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS,
- .u =
- { .copy_segments = from } } );
- n = os_write_file(fd, &copy, sizeof(copy));
- if(n != sizeof(copy))
- printk("new_mm : /proc/mm copy_segments failed, "
- "err = %d\n", -n);
- }
-
- 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(1);
-
- init_task.thread.request.u.thread.proc = start_kernel_proc;
- init_task.thread.request.u.thread.arg = NULL;
- return(start_idle_thread(init_task.thread_info,
- &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
new file mode 100644
index 00000000000..c0681e09743
--- /dev/null
+++ b/arch/um/kernel/skas/syscall.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <kern_util.h>
+#include <sysdep/ptrace.h>
+#include <sysdep/syscalls.h>
+
+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_enter(regs);
+
+ /*
+ * 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.
+ * The assembly looks functionally the same to me. This is
+ * gcc version 4.0.1 20050727 (Red Hat 4.0.1-5)
+ * in case it's a compiler bug.
+ */
+ syscall = UPT_SYSCALL_NR(r);
+ if ((syscall >= NR_SYSCALLS) || (syscall < 0))
+ result = -ENOSYS;
+ else result = EXECUTE_SYSCALL(syscall, regs);
+
+ PT_REGS_SET_SYSCALL_RETURN(regs, result);
+
+ syscall_trace_leave(regs);
+}
diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c
deleted file mode 100644
index bdf040ce5b8..00000000000
--- a/arch/um/kernel/skas/syscall_kern.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.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"
-
-extern syscall_handler_t *sys_call_table[];
-
-long execute_syscall_skas(void *r)
-{
- struct pt_regs *regs = r;
- long res;
- int syscall;
-
- current->thread.nsyscalls++;
- nsyscalls++;
- syscall = UPT_SYSCALL_NR(&regs->regs);
-
- if((syscall >= NR_syscalls) || (syscall < 0))
- res = -ENOSYS;
- else res = EXECUTE_SYSCALL(syscall, regs);
-
- return(res);
-}
-
-/*
- * 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/syscall_user.c b/arch/um/kernel/skas/syscall_user.c
deleted file mode 100644
index 6b066497014..00000000000
--- a/arch/um/kernel/skas/syscall_user.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <signal.h>
-#include "kern_util.h"
-#include "uml-config.h"
-#include "syscall_user.h"
-#include "sysdep/ptrace.h"
-#include "sysdep/sigcontext.h"
-#include "skas.h"
-
-void handle_syscall(union uml_pt_regs *regs)
-{
- long result;
-#ifdef UML_CONFIG_SYSCALL_DEBUG
- int index;
-
- index = record_syscall_start(UPT_SYSCALL_NR(regs));
-#endif
-
- syscall_trace(regs, 0);
- result = execute_syscall_skas(regs);
-
- REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
-
- syscall_trace(regs, 1);
-#ifdef UML_CONFIG_SYSCALL_DEBUG
- record_syscall_end(index, result);
-#endif
-}
-
-/*
- * 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/tlb.c b/arch/um/kernel/skas/tlb.c
deleted file mode 100644
index 6230999c672..00000000000
--- a/arch/um/kernel/skas/tlb.c
+++ /dev/null
@@ -1,92 +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 void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
-{
- struct host_vm_op *op;
- int i;
-
- for(i = 0; i <= last; i++){
- op = &ops[i];
- switch(op->type){
- case MMAP:
- 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);
- break;
- case MUNMAP:
- unmap(&mmu->skas.id, (void *) op->u.munmap.addr,
- op->u.munmap.len);
- break;
- case MPROTECT:
- protect(&mmu->skas.id, op->u.mprotect.addr,
- op->u.mprotect.len, op->u.mprotect.r,
- op->u.mprotect.w, op->u.mprotect.x);
- break;
- default:
- printk("Unknown op type %d in do_ops\n", op->type);
- break;
- }
- }
-}
-
-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/trap_user.c b/arch/um/kernel/skas/trap_user.c
deleted file mode 100644
index 9950a6716fe..00000000000
--- a/arch/um/kernel/skas/trap_user.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
- * Licensed under the GPL
- */
-
-#include <signal.h>
-#include <errno.h>
-#include "signal_user.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "task.h"
-#include "sigcontext.h"
-#include "skas.h"
-#include "ptrace_user.h"
-#include "sysdep/ptrace.h"
-#include "sysdep/ptrace_user.h"
-
-void sig_handler_common_skas(int sig, void *sc_ptr)
-{
- struct sigcontext *sc = sc_ptr;
- struct skas_regs *r;
- struct signal_info *info;
- int save_errno = errno;
- int save_user;
-
- /* This is done because to allow SIGSEGV to be delivered inside a SEGV
- * handler. This can happen in copy_user, and if SEGV is disabled,
- * the process will die.
- * XXX Figure out why this is better than SA_NODEFER
- */
- if(sig == SIGSEGV)
- change_sig(SIGSEGV, 1);
-
- r = &TASK_REGS(get_current())->skas;
- save_user = r->is_user;
- r->is_user = 0;
- if ( sig == SIGFPE || sig == SIGSEGV ||
- sig == SIGBUS || sig == SIGILL ||
- sig == SIGTRAP ) {
- GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
- }
-
- change_sig(SIGUSR1, 1);
- info = &sig_info[sig];
- if(!info->is_irq) unblock_signals();
-
- (*info->handler)(sig, (union uml_pt_regs *) r);
-
- errno = save_errno;
- r->is_user = save_user;
-}
-
-extern int ptrace_faultinfo;
-
-void user_signal(int sig, union uml_pt_regs *regs, int pid)
-{
- struct signal_info *info;
- int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
- (sig == SIGILL) || (sig == SIGTRAP));
-
- if (segv)
- get_skas_faultinfo(pid, &regs->skas.faultinfo);
- info = &sig_info[sig];
- (*info->handler)(sig, regs);
-
- unblock_signals();
-}
-
-/*
- * 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/uaccess.c b/arch/um/kernel/skas/uaccess.c
index 75195281081..4ffb644d6c0 100644
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -1,130 +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/highmem.h"
-#include "asm/page.h"
-#include "asm/pgtable.h"
-#include "asm/uaccess.h"
-#include "kern_util.h"
-#include "user_util.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(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)
{
+ 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(page) + (addr & ~PAGE_MASK);
- n = (*op)(addr, len, arg);
- kunmap(page);
+ current->thread.fault_catcher = &buf;
- return(n);
+ faulted = UML_SETJMP(&buf);
+ if (faulted == 0)
+ n = (*op)(addr, len, arg);
+ else
+ n = -1;
+
+ current->thread.fault_catcher = NULL;
+
+ kunmap_atomic((void *)addr);
+
+ 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(addr, size, is_write, op, arg);
- if(n != 0){
- *res = (n < 0 ? remain : 0);
+ n = do_op_one_page(addr, size, is_write, op, arg);
+ 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)){
- n = do_op(addr, PAGE_SIZE, is_write, op, arg);
- if(n != 0){
- *res = (n < 0 ? remain : 0);
+ while (addr < ((addr + remain) & PAGE_MASK)) {
+ n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg);
+ 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) {
+ remain = (n < 0 ? remain : 0);
goto out;
}
- n = do_op(addr, remain, is_write, op, arg);
- if(n != 0)
- *res = (n < 0 ? remain : 0);
- else *res = 0;
+ return 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);
-
- return(addr + len - (unsigned long) current->thread.fault_addr);
+ return remain;
}
static int copy_chunk_from_user(unsigned long from, int len, void *arg)
@@ -133,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_skas(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)
{
@@ -154,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_skas(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)
{
@@ -178,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_skas(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_skas(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)
{
@@ -232,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);
diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile
deleted file mode 100644
index f7b7eba8334..00000000000
--- a/arch/um/kernel/skas/util/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-hostprogs-y := mk_ptregs
-always := $(hostprogs-y)
-
-mk_ptregs-objs := mk_ptregs-$(SUBARCH).o
-HOSTCFLAGS_mk_ptregs-$(SUBARCH).o := -I$(objtree)/arch/um
diff --git a/arch/um/kernel/skas/util/mk_ptregs-i386.c b/arch/um/kernel/skas/util/mk_ptregs-i386.c
deleted file mode 100644
index 1f96e1eeb8a..00000000000
--- a/arch/um/kernel/skas/util/mk_ptregs-i386.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <stdio.h>
-#include <user-offsets.h>
-
-#define SHOW(name) printf("#define %s %d\n", #name, name)
-
-int main(int argc, char **argv)
-{
- printf("/* Automatically generated by "
- "arch/um/kernel/skas/util/mk_ptregs */\n");
- printf("\n");
- printf("#ifndef __SKAS_PT_REGS_\n");
- printf("#define __SKAS_PT_REGS_\n");
- printf("\n");
- SHOW(HOST_FRAME_SIZE);
- SHOW(HOST_FP_SIZE);
- SHOW(HOST_XFP_SIZE);
-
- SHOW(HOST_IP);
- SHOW(HOST_SP);
- SHOW(HOST_EFLAGS);
- SHOW(HOST_EAX);
- SHOW(HOST_EBX);
- SHOW(HOST_ECX);
- SHOW(HOST_EDX);
- SHOW(HOST_ESI);
- SHOW(HOST_EDI);
- SHOW(HOST_EBP);
- SHOW(HOST_CS);
- SHOW(HOST_SS);
- SHOW(HOST_DS);
- SHOW(HOST_FS);
- SHOW(HOST_ES);
- SHOW(HOST_GS);
-
- printf("\n");
- printf("#endif\n");
- 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:
- */
diff --git a/arch/um/kernel/skas/util/mk_ptregs-x86_64.c b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
deleted file mode 100644
index 5fccbfe35f7..00000000000
--- a/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2003 PathScale, Inc.
- *
- * Licensed under the GPL
- */
-
-#include <stdio.h>
-#include <user-offsets.h>
-
-#define SHOW(name) \
- printf("#define %s (%d / sizeof(unsigned long))\n", #name, name)
-
-int main(int argc, char **argv)
-{
- printf("/* Automatically generated by "
- "arch/um/kernel/skas/util/mk_ptregs */\n");
- printf("\n");
- printf("#ifndef __SKAS_PT_REGS_\n");
- printf("#define __SKAS_PT_REGS_\n");
- SHOW(HOST_FRAME_SIZE);
- SHOW(HOST_RBX);
- SHOW(HOST_RCX);
- SHOW(HOST_RDI);
- SHOW(HOST_RSI);
- SHOW(HOST_RDX);
- SHOW(HOST_RBP);
- SHOW(HOST_RAX);
- SHOW(HOST_R8);
- SHOW(HOST_R9);
- SHOW(HOST_R10);
- SHOW(HOST_R11);
- SHOW(HOST_R12);
- SHOW(HOST_R13);
- SHOW(HOST_R14);
- SHOW(HOST_R15);
- SHOW(HOST_ORIG_RAX);
- SHOW(HOST_CS);
- SHOW(HOST_SS);
- SHOW(HOST_EFLAGS);
-#if 0
- SHOW(HOST_FS);
- SHOW(HOST_GS);
- SHOW(HOST_DS);
- SHOW(HOST_ES);
-#endif
-
- SHOW(HOST_IP);
- SHOW(HOST_SP);
- printf("#define HOST_FP_SIZE 0\n");
- printf("#define HOST_XFP_SIZE 0\n");
- printf("\n");
- printf("\n");
- printf("#endif\n");
- 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:
- */