aboutsummaryrefslogtreecommitdiff
path: root/arch/um/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel')
-rw-r--r--arch/um/kernel/Makefile32
-rw-r--r--arch/um/kernel/asm-offsets.c2
-rw-r--r--arch/um/kernel/config.c.in20
-rw-r--r--arch/um/kernel/dyn.lds.S63
-rw-r--r--arch/um/kernel/early_printk.c35
-rw-r--r--arch/um/kernel/exec.c50
-rw-r--r--arch/um/kernel/exec_kern.c90
-rw-r--r--arch/um/kernel/exitcode.c93
-rw-r--r--arch/um/kernel/gmon_syms.c33
-rw-r--r--arch/um/kernel/gprof_syms.c15
-rw-r--r--arch/um/kernel/init_task.c62
-rw-r--r--arch/um/kernel/initrd.c71
-rw-r--r--arch/um/kernel/irq.c553
-rw-r--r--arch/um/kernel/irq_user.c447
-rw-r--r--arch/um/kernel/ksyms.c84
-rw-r--r--arch/um/kernel/maccess.c24
-rw-r--r--arch/um/kernel/mem.c266
-rw-r--r--arch/um/kernel/physmem.c381
-rw-r--r--arch/um/kernel/process.c416
-rw-r--r--arch/um/kernel/process_kern.c472
-rw-r--r--arch/um/kernel/ptrace.c290
-rw-r--r--arch/um/kernel/reboot.c80
-rw-r--r--arch/um/kernel/resource.c23
-rw-r--r--arch/um/kernel/sigio.c49
-rw-r--r--arch/um/kernel/sigio_kern.c63
-rw-r--r--arch/um/kernel/sigio_user.c431
-rw-r--r--arch/um/kernel/signal.c124
-rw-r--r--arch/um/kernel/signal_kern.c213
-rw-r--r--arch/um/kernel/signal_user.c157
-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.h35
-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.h50
-rw-r--r--arch/um/kernel/skas/include/stub-data.h18
-rw-r--r--arch/um/kernel/skas/include/uaccess-skas.h39
-rw-r--r--arch/um/kernel/skas/mem.c39
-rw-r--r--arch/um/kernel/skas/mem_user.c281
-rw-r--r--arch/um/kernel/skas/mmu.c202
-rw-r--r--arch/um/kernel/skas/process.c602
-rw-r--r--arch/um/kernel/skas/process_kern.c232
-rw-r--r--arch/um/kernel/skas/syscall.c42
-rw-r--r--arch/um/kernel/skas/tlb.c98
-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/smp.c139
-rw-r--r--arch/um/kernel/syscall.c48
-rw-r--r--arch/um/kernel/syscall_kern.c166
-rw-r--r--arch/um/kernel/sysrq.c136
-rw-r--r--arch/um/kernel/time.c226
-rw-r--r--arch/um/kernel/time_kern.c184
-rw-r--r--arch/um/kernel/tlb.c700
-rw-r--r--arch/um/kernel/trap.c330
-rw-r--r--arch/um/kernel/trap_kern.c219
-rw-r--r--arch/um/kernel/trap_user.c98
-rw-r--r--arch/um/kernel/tt/Makefile14
-rw-r--r--arch/um/kernel/tt/exec_kern.c87
-rw-r--r--arch/um/kernel/tt/exec_user.c57
-rw-r--r--arch/um/kernel/tt/gdb.c278
-rw-r--r--arch/um/kernel/tt/gdb_kern.c40
-rw-r--r--arch/um/kernel/tt/include/debug.h18
-rw-r--r--arch/um/kernel/tt/include/mmu-tt.h23
-rw-r--r--arch/um/kernel/tt/include/mode-tt.h34
-rw-r--r--arch/um/kernel/tt/include/mode_kern-tt.h52
-rw-r--r--arch/um/kernel/tt/include/tt.h46
-rw-r--r--arch/um/kernel/tt/include/uaccess-tt.h65
-rw-r--r--arch/um/kernel/tt/ksyms.c29
-rw-r--r--arch/um/kernel/tt/mem.c45
-rw-r--r--arch/um/kernel/tt/mem_user.c50
-rw-r--r--arch/um/kernel/tt/process_kern.c457
-rw-r--r--arch/um/kernel/tt/ptproxy/Makefile10
-rw-r--r--arch/um/kernel/tt/ptproxy/proxy.c377
-rw-r--r--arch/um/kernel/tt/ptproxy/ptproxy.h61
-rw-r--r--arch/um/kernel/tt/ptproxy/ptrace.c237
-rw-r--r--arch/um/kernel/tt/ptproxy/sysdep.c70
-rw-r--r--arch/um/kernel/tt/ptproxy/sysdep.h25
-rw-r--r--arch/um/kernel/tt/ptproxy/wait.c86
-rw-r--r--arch/um/kernel/tt/ptproxy/wait.h15
-rw-r--r--arch/um/kernel/tt/syscall_kern.c52
-rw-r--r--arch/um/kernel/tt/syscall_user.c61
-rw-r--r--arch/um/kernel/tt/tlb.c121
-rw-r--r--arch/um/kernel/tt/tracer.c484
-rw-r--r--arch/um/kernel/tt/trap_user.c66
-rw-r--r--arch/um/kernel/tt/uaccess.c73
-rw-r--r--arch/um/kernel/tt/uaccess_user.c106
-rw-r--r--arch/um/kernel/tty_log.c230
-rw-r--r--arch/um/kernel/uaccess.c30
-rw-r--r--arch/um/kernel/um_arch.c412
-rw-r--r--arch/um/kernel/umid.c330
-rw-r--r--arch/um/kernel/uml.lds.S99
-rw-r--r--arch/um/kernel/user_util.c174
-rw-r--r--arch/um/kernel/vmlinux.lds.S4
96 files changed, 3159 insertions, 10408 deletions
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index 3de9d21e36b..d8b78a03855 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -1,30 +1,26 @@
#
-# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux,intel}.com)
# Licensed under the GPL
#
+CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START) \
+ -DELF_ARCH=$(LDS_ELF_ARCH) \
+ -DELF_FORMAT=$(LDS_ELF_FORMAT) \
+ $(LDS_EXTRA)
extra-y := vmlinux.lds
clean-files :=
-obj-y = config.o exec_kern.o exitcode.o \
- init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \
- process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \
- signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o time.o \
- time_kern.o tlb.o trap_kern.o trap_user.o uaccess.o um_arch.o \
- umid.o user_util.o
+obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \
+ physmem.o process.o ptrace.o reboot.o sigio.o \
+ signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o \
+ um_arch.o umid.o maccess.o skas/
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
obj-$(CONFIG_GPROF) += gprof_syms.o
obj-$(CONFIG_GCOV) += gmon_syms.o
-obj-$(CONFIG_TTY_LOG) += tty_log.o
-obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-obj-$(CONFIG_MODE_TT) += tt/
-obj-$(CONFIG_MODE_SKAS) += skas/
-
-user-objs-$(CONFIG_TTY_LOG) += tty_log.o
-
-USER_OBJS := $(user-objs-y) config.o time.o tty_log.o umid.o user_util.o
+USER_OBJS := config.o
include arch/um/scripts/Makefile.rules
@@ -37,7 +33,7 @@ $(obj)/config.tmp: $(objtree)/.config FORCE
$(call if_changed,quote1)
quiet_cmd_quote1 = QUOTE $@
- cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' \
+ cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n",/' \
$< > $@
$(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE
@@ -45,9 +41,9 @@ $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE
quiet_cmd_quote2 = QUOTE $@
cmd_quote2 = sed -e '/CONFIG/{' \
- -e 's/"CONFIG"\;/""/' \
+ -e 's/"CONFIG"//' \
-e 'r $(obj)/config.tmp' \
-e 'a \' \
- -e '""\;' \
+ -e '""' \
-e '}' \
$< > $@
diff --git a/arch/um/kernel/asm-offsets.c b/arch/um/kernel/asm-offsets.c
index c13a64a288f..1fb12235ab9 100644
--- a/arch/um/kernel/asm-offsets.c
+++ b/arch/um/kernel/asm-offsets.c
@@ -1 +1 @@
-/* Dummy file to make kbuild happy - unused! */
+#include <sysdep/kernel-offsets.h>
diff --git a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in
index c062cbfe386..972bf165956 100644
--- a/arch/um/kernel/config.c.in
+++ b/arch/um/kernel/config.c.in
@@ -5,13 +5,17 @@
#include <stdio.h>
#include <stdlib.h>
-#include "init.h"
+#include <init.h>
-static __initdata char *config = "CONFIG";
+static __initdata const char *config[] = {
+"CONFIG"
+};
static int __init print_config(char *line, int *add)
{
- printf("%s", config);
+ int i;
+ for (i = 0; i < sizeof(config)/sizeof(config[0]); i++)
+ printf("%s", config[i]);
exit(0);
}
@@ -20,13 +24,3 @@ __uml_setup("--showconfig", print_config,
" Prints the config file that this UML binary was generated from.\n\n"
);
-/*
- * 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/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 2517ecb8bf2..adde088aeef 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -1,4 +1,5 @@
#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
OUTPUT_FORMAT(ELF_FORMAT)
OUTPUT_ARCH(ELF_ARCH)
@@ -10,22 +11,16 @@ SECTIONS
PROVIDE (__executable_start = START);
. = START + SIZEOF_HEADERS;
.interp : { *(.interp) }
- /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
- * is remapped.*/
__binary_start = .;
. = ALIGN(4096); /* Init code and data */
- _stext = .;
- __init_begin = .;
- .init.text : {
- _sinittext = .;
- *(.init.text)
- _einittext = .;
- }
+ _text = .;
+ INIT_TEXT_SECTION(PAGE_SIZE)
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
/* Read-only sections, merged into text segment: */
.hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
@@ -53,14 +48,25 @@ SECTIONS
.rela.got : { *(.rela.got) }
.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
+ .rel.plt : {
+ *(.rel.plt)
+ PROVIDE_HIDDEN(__rel_iplt_start = .);
+ *(.rel.iplt)
+ PROVIDE_HIDDEN(__rel_iplt_end = .);
+ }
+ .rela.plt : {
+ *(.rela.plt)
+ PROVIDE_HIDDEN(__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN(__rela_iplt_end = .);
+ }
.init : {
KEEP (*(.init))
} =0x90909090
.plt : { *(.plt) }
.text : {
- *(.text)
+ _stext = .;
+ TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
*(.fixup)
@@ -68,21 +74,25 @@ SECTIONS
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
- . = ALIGN(4096);
- __syscall_stub_start = .;
- *(.__syscall_stub*)
- __syscall_stub_end = .;
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
} =0x90909090
+ . = ALIGN(PAGE_SIZE);
+ .syscall_stub : {
+ __syscall_stub_start = .;
+ *(.__syscall_stub*)
+ __syscall_stub_end = .;
+ }
.fini : {
KEEP (*(.fini))
} =0x90909090
.kstrtab : { *(.kstrtab) }
- #include "asm/common.lds.S"
+ #include <asm/common.lds.S>
- init.data : { *(.init.data) }
+ __init_begin = .;
+ init.data : { INIT_DATA }
+ __init_end = .;
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
@@ -93,9 +103,11 @@ SECTIONS
.init_array : { *(.init_array) }
.fini_array : { *(.fini_array) }
.data : {
- . = ALIGN(KERNEL_STACK_SIZE); /* init_task */
- *(.data.init_task)
- *(.data .data.* .gnu.linkonce.d.*)
+ INIT_TASK_DATA(KERNEL_STACK_SIZE)
+ . = ALIGN(KERNEL_STACK_SIZE);
+ *(.data..init_irqstack)
+ DATA_DATA
+ *(.data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
@@ -133,8 +145,8 @@ SECTIONS
.got : { *(.got.plt) *(.got) }
_edata = .;
PROVIDE (edata = .);
- __bss_start = .;
.bss : {
+ __bss_start = .;
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
@@ -144,10 +156,13 @@ SECTIONS
. = ALIGN(32 / 8);
. = ALIGN(32 / 8);
}
+ __bss_stop = .;
_end = .;
PROVIDE (end = .);
STABS_DEBUG
DWARF_DEBUG
+
+ DISCARDS
}
diff --git a/arch/um/kernel/early_printk.c b/arch/um/kernel/early_printk.c
new file mode 100644
index 00000000000..4a0800bc37b
--- /dev/null
+++ b/arch/um/kernel/early_printk.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 Richard Weinberger <richrd@nod.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <os.h>
+
+static void early_console_write(struct console *con, const char *s, unsigned int n)
+{
+ um_early_printk(s, n);
+}
+
+static struct console early_console_dev = {
+ .name = "earlycon",
+ .write = early_console_write,
+ .flags = CON_BOOT,
+ .index = -1,
+};
+
+static int __init setup_early_printk(char *buf)
+{
+ if (!early_console) {
+ early_console = &early_console_dev;
+ register_console(&early_console_dev);
+ }
+ return 0;
+}
+
+early_param("earlyprintk", setup_early_printk);
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
new file mode 100644
index 00000000000..0d7103c9eff
--- /dev/null
+++ b/arch/um/kernel/exec.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <asm/current.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <as-layout.h>
+#include <mem_user.h>
+#include <skas.h>
+#include <os.h>
+
+void flush_thread(void)
+{
+ void *data = NULL;
+ int ret;
+
+ arch_flush_thread(&current->thread.arch);
+
+ ret = unmap(&current->mm->context.id, 0, STUB_START, 0, &data);
+ ret = ret || unmap(&current->mm->context.id, STUB_END,
+ host_task_size - STUB_END, 1, &data);
+ if (ret) {
+ printk(KERN_ERR "flush_thread - clearing address space failed, "
+ "err = %d\n", ret);
+ force_sig(SIGKILL, current);
+ }
+ get_safe_registers(current_pt_regs()->regs.gp,
+ current_pt_regs()->regs.fp);
+
+ __switch_mm(&current->mm->context.id);
+}
+
+void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
+{
+ PT_REGS_IP(regs) = eip;
+ PT_REGS_SP(regs) = esp;
+ current->ptrace &= ~PT_DTRACE;
+#ifdef SUBARCH_EXECVE1
+ SUBARCH_EXECVE1(regs->regs);
+#endif
+}
+EXPORT_SYMBOL(start_thread);
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
deleted file mode 100644
index efd222ffe20..00000000000
--- a/arch/um/kernel/exec_kern.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/slab.h"
-#include "linux/smp_lock.h"
-#include "linux/ptrace.h"
-#include "asm/ptrace.h"
-#include "asm/pgtable.h"
-#include "asm/tlbflush.h"
-#include "asm/uaccess.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "mem_user.h"
-#include "kern.h"
-#include "irq_user.h"
-#include "tlb.h"
-#include "os.h"
-#include "time_user.h"
-#include "choose-mode.h"
-#include "mode_kern.h"
-
-void flush_thread(void)
-{
- CHOOSE_MODE(flush_thread_tt(), flush_thread_skas());
-}
-
-void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
-{
- CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp);
-}
-
-extern void log_exec(char **argv, void *tty);
-
-static long execve1(char *file, char __user * __user *argv,
- char *__user __user *env)
-{
- long error;
-
-#ifdef CONFIG_TTY_LOG
- log_exec(argv, current->tty);
-#endif
- error = do_execve(file, argv, env, &current->thread.regs);
- if (error == 0){
- task_lock(current);
- current->ptrace &= ~PT_DTRACE;
- task_unlock(current);
- set_cmdline(current_cmd());
- }
- return(error);
-}
-
-long um_execve(char *file, char __user *__user *argv, char __user *__user *env)
-{
- long err;
-
- err = execve1(file, argv, env);
- if(!err)
- do_longjmp(current->thread.exec_buf, 1);
- return(err);
-}
-
-long sys_execve(char *file, char __user *__user *argv,
- char __user *__user *env)
-{
- long error;
- char *filename;
-
- lock_kernel();
- filename = getname((char __user *) file);
- error = PTR_ERR(filename);
- if (IS_ERR(filename)) goto out;
- error = execve1(filename, argv, env);
- putname(filename);
- out:
- unlock_kernel();
- return(error);
-}
-
-/*
- * 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/exitcode.c b/arch/um/kernel/exitcode.c
index d21ebad666b..41ebbfebb33 100644
--- a/arch/um/kernel/exitcode.c
+++ b/arch/um/kernel/exitcode.c
@@ -1,73 +1,80 @@
-/*
- * 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/init.h"
-#include "linux/ctype.h"
-#include "linux/proc_fs.h"
-#include "asm/uaccess.h"
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
-/* If read and write race, the read will still atomically read a valid
+/*
+ * If read and write race, the read will still atomically read a valid
* value.
*/
int uml_exitcode = 0;
-static int read_proc_exitcode(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int exitcode_proc_show(struct seq_file *m, void *v)
{
- int len;
+ int val;
+
+ /*
+ * Save uml_exitcode in a local so that we don't need to guarantee
+ * that sprintf accesses it atomically.
+ */
+ val = uml_exitcode;
+ seq_printf(m, "%d\n", val);
+ return 0;
+}
- len = sprintf(page, "%d\n", uml_exitcode);
- len -= off;
- if(len <= off+count) *eof = 1;
- *start = page + off;
- if(len > count) len = count;
- if(len < 0) len = 0;
- return(len);
+static int exitcode_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, exitcode_proc_show, NULL);
}
-static int write_proc_exitcode(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static ssize_t exitcode_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *pos)
{
char *end, buf[sizeof("nnnnn\0")];
+ size_t size;
int tmp;
- if(copy_from_user(buf, buffer, count))
- return(-EFAULT);
+ size = min(count, sizeof(buf));
+ if (copy_from_user(buf, buffer, size))
+ return -EFAULT;
+
tmp = simple_strtol(buf, &end, 0);
- if((*end != '\0') && !isspace(*end))
- return(-EINVAL);
+ if ((*end != '\0') && !isspace(*end))
+ return -EINVAL;
+
uml_exitcode = tmp;
- return(count);
+ return count;
}
+static const struct file_operations exitcode_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = exitcode_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = exitcode_proc_write,
+};
+
static int make_proc_exitcode(void)
{
struct proc_dir_entry *ent;
- ent = create_proc_entry("exitcode", 0600, &proc_root);
- if(ent == NULL){
+ ent = proc_create("exitcode", 0600, NULL, &exitcode_proc_fops);
+ if (ent == NULL) {
printk(KERN_WARNING "make_proc_exitcode : Failed to register "
"/proc/exitcode\n");
- return(0);
+ return 0;
}
-
- ent->read_proc = read_proc_exitcode;
- ent->write_proc = write_proc_exitcode;
-
- return(0);
+ return 0;
}
__initcall(make_proc_exitcode);
-
-/*
- * 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/gmon_syms.c b/arch/um/kernel/gmon_syms.c
index 2c86e7fdb01..1bf61266da8 100644
--- a/arch/um/kernel/gmon_syms.c
+++ b/arch/um/kernel/gmon_syms.c
@@ -1,34 +1,9 @@
-/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/module.h"
+#include <linux/module.h>
-extern void __bb_init_func(void *);
+extern void __bb_init_func(void *) __attribute__((weak));
EXPORT_SYMBOL(__bb_init_func);
-
-/* This is defined (and referred to in profiling stub code) only by some GCC
- * versions in libgcov.
- *
- * Since SuSE backported the fix, we cannot handle it depending on GCC version.
- * So, unconditinally export it. But also give it a weak declaration, which will
- * be overriden by any other one.
- */
-
-extern void __gcov_init(void *) __attribute__((weak));
-EXPORT_SYMBOL(__gcov_init);
-
-extern void __gcov_merge_add(void *) __attribute__((weak));
-EXPORT_SYMBOL(__gcov_merge_add);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/gprof_syms.c b/arch/um/kernel/gprof_syms.c
index 9244f018d44..74ddb44288a 100644
--- a/arch/um/kernel/gprof_syms.c
+++ b/arch/um/kernel/gprof_syms.c
@@ -1,20 +1,9 @@
/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/module.h"
+#include <linux/module.h>
extern void mcount(void);
EXPORT_SYMBOL(mcount);
-
-/*
- * 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/init_task.c b/arch/um/kernel/init_task.c
deleted file mode 100644
index 49ed5ddf070..00000000000
--- a/arch/um/kernel/init_task.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/config.h"
-#include "linux/mm.h"
-#include "linux/module.h"
-#include "linux/sched.h"
-#include "linux/init_task.h"
-#include "linux/mqueue.h"
-#include "asm/uaccess.h"
-#include "asm/pgtable.h"
-#include "user_util.h"
-#include "mem_user.h"
-#include "os.h"
-
-static struct fs_struct init_fs = INIT_FS;
-struct mm_struct init_mm = INIT_MM(init_mm);
-static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
-static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-EXPORT_SYMBOL(init_mm);
-
-/*
- * Initial task structure.
- *
- * All other task structs will be allocated on slabs in fork.c
- */
-
-struct task_struct init_task = INIT_TASK(init_task);
-
-EXPORT_SYMBOL(init_task);
-
-/*
- * Initial thread structure.
- *
- * We need to make sure that this is 16384-byte aligned due to the
- * way process stacks are handled. This is done by having a special
- * "init_task" linker map entry..
- */
-
-union thread_union init_thread_union
-__attribute__((__section__(".data.init_task"))) =
-{ INIT_THREAD_INFO(init_task) };
-
-void unprotect_stack(unsigned long stack)
-{
- os_protect_memory((void *) stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE,
- 1, 1, 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/initrd.c b/arch/um/kernel/initrd.c
index 82ecf904b09..55cead809b1 100644
--- a/arch/um/kernel/initrd.c
+++ b/arch/um/kernel/initrd.c
@@ -1,20 +1,18 @@
/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/init.h"
-#include "linux/bootmem.h"
-#include "linux/initrd.h"
-#include "asm/types.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "initrd.h"
-#include "init.h"
-#include "os.h"
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/initrd.h>
+#include <asm/types.h>
+#include <init.h>
+#include <os.h>
/* Changed by uml_initrd_setup, which is a setup */
static char *initrd __initdata = NULL;
+static int load_initrd(char *filename, void *buf, int size);
static int __init read_initrd(void)
{
@@ -22,12 +20,29 @@ static int __init read_initrd(void)
long long size;
int err;
- if(initrd == NULL) return 0;
+ if (initrd == NULL)
+ return 0;
+
err = os_file_size(initrd, &size);
- if(err) return 0;
+ if (err)
+ return 0;
+
+ /*
+ * This is necessary because alloc_bootmem craps out if you
+ * ask for no memory.
+ */
+ if (size == 0) {
+ printk(KERN_ERR "\"%s\" is a zero-size initrd\n", initrd);
+ return 0;
+ }
+
area = alloc_bootmem(size);
- if(area == NULL) return 0;
- if(load_initrd(initrd, area, size) == -1) return 0;
+ if (area == NULL)
+ return 0;
+
+ if (load_initrd(initrd, area, size) == -1)
+ return 0;
+
initrd_start = (unsigned long) area;
initrd_end = initrd_start + size;
return 0;
@@ -47,32 +62,24 @@ __uml_setup("initrd=", uml_initrd_setup,
" name of the file containing the image.\n\n"
);
-int load_initrd(char *filename, void *buf, int size)
+static int load_initrd(char *filename, void *buf, int size)
{
int fd, n;
fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
- if(fd < 0){
- printk("Opening '%s' failed - err = %d\n", filename, -fd);
- return(-1);
+ if (fd < 0) {
+ printk(KERN_ERR "Opening '%s' failed - err = %d\n", filename,
+ -fd);
+ return -1;
}
n = os_read_file(fd, buf, size);
- if(n != size){
- printk("Read of %d bytes from '%s' failed, err = %d\n", size,
+ if (n != size) {
+ printk(KERN_ERR "Read of %d bytes from '%s' failed, "
+ "err = %d\n", size,
filename, -n);
- return(-1);
+ return -1;
}
os_close_file(fd);
- return(0);
+ 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/irq.c b/arch/um/kernel/irq.c
index bbf94bf2921..1d8505b1e29 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -1,198 +1,473 @@
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
* Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
*/
-#include "linux/config.h"
-#include "linux/kernel.h"
-#include "linux/module.h"
-#include "linux/smp.h"
-#include "linux/kernel_stat.h"
-#include "linux/interrupt.h"
-#include "linux/random.h"
-#include "linux/slab.h"
-#include "linux/file.h"
-#include "linux/proc_fs.h"
-#include "linux/init.h"
-#include "linux/seq_file.h"
-#include "linux/profile.h"
-#include "linux/hardirq.h"
-#include "asm/irq.h"
-#include "asm/hw_irq.h"
-#include "asm/atomic.h"
-#include "asm/signal.h"
-#include "asm/system.h"
-#include "asm/errno.h"
-#include "asm/uaccess.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "irq_user.h"
-#include "irq_kern.h"
-#include "os.h"
+#include <linux/cpumask.h>
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <as-layout.h>
+#include <kern_util.h>
+#include <os.h>
/*
- * Generic, controller-independent functions:
+ * This list is accessed under irq_lock, except in sigio_handler,
+ * where it is safe from being modified. IRQ handlers won't change it -
+ * if an IRQ source has vanished, it will be freed by free_irqs just
+ * before returning from sigio_handler. That will process a separate
+ * list of irqs to free, with its own locking, coming back here to
+ * remove list elements, taking the irq_lock to do so.
*/
+static struct irq_fd *active_fds = NULL;
+static struct irq_fd **last_irq_ptr = &active_fds;
+
+extern void free_irqs(void);
+
+void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
+{
+ struct irq_fd *irq_fd;
+ int n;
+
+ if (smp_sigio_handler())
+ return;
+
+ while (1) {
+ n = os_waiting_for_events(active_fds);
+ if (n <= 0) {
+ if (n == -EINTR)
+ continue;
+ else break;
+ }
+
+ for (irq_fd = active_fds; irq_fd != NULL;
+ irq_fd = irq_fd->next) {
+ if (irq_fd->current_events != 0) {
+ irq_fd->current_events = 0;
+ do_IRQ(irq_fd->irq, regs);
+ }
+ }
+ }
+
+ free_irqs();
+}
+
+static DEFINE_SPINLOCK(irq_lock);
+
+static int activate_fd(int irq, int fd, int type, void *dev_id)
+{
+ struct pollfd *tmp_pfd;
+ struct irq_fd *new_fd, *irq_fd;
+ unsigned long flags;
+ int events, err, n;
+
+ err = os_set_fd_async(fd);
+ if (err < 0)
+ goto out;
+
+ err = -ENOMEM;
+ new_fd = kmalloc(sizeof(struct irq_fd), GFP_KERNEL);
+ if (new_fd == NULL)
+ goto out;
+
+ if (type == IRQ_READ)
+ events = UM_POLLIN | UM_POLLPRI;
+ else events = UM_POLLOUT;
+ *new_fd = ((struct irq_fd) { .next = NULL,
+ .id = dev_id,
+ .fd = fd,
+ .type = type,
+ .irq = irq,
+ .events = events,
+ .current_events = 0 } );
+
+ err = -EBUSY;
+ spin_lock_irqsave(&irq_lock, flags);
+ for (irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next) {
+ if ((irq_fd->fd == fd) && (irq_fd->type == type)) {
+ printk(KERN_ERR "Registering fd %d twice\n", fd);
+ printk(KERN_ERR "Irqs : %d, %d\n", irq_fd->irq, irq);
+ printk(KERN_ERR "Ids : 0x%p, 0x%p\n", irq_fd->id,
+ dev_id);
+ goto out_unlock;
+ }
+ }
+
+ if (type == IRQ_WRITE)
+ fd = -1;
+
+ tmp_pfd = NULL;
+ n = 0;
+
+ while (1) {
+ n = os_create_pollfd(fd, events, tmp_pfd, n);
+ if (n == 0)
+ break;
+
+ /*
+ * n > 0
+ * It means we couldn't put new pollfd to current pollfds
+ * and tmp_fds is NULL or too small for new pollfds array.
+ * Needed size is equal to n as minimum.
+ *
+ * Here we have to drop the lock in order to call
+ * kmalloc, which might sleep.
+ * If something else came in and changed the pollfds array
+ * so we will not be able to put new pollfd struct to pollfds
+ * then we free the buffer tmp_fds and try again.
+ */
+ spin_unlock_irqrestore(&irq_lock, flags);
+ kfree(tmp_pfd);
+
+ tmp_pfd = kmalloc(n, GFP_KERNEL);
+ if (tmp_pfd == NULL)
+ goto out_kfree;
+
+ spin_lock_irqsave(&irq_lock, flags);
+ }
+
+ *last_irq_ptr = new_fd;
+ last_irq_ptr = &new_fd->next;
+
+ spin_unlock_irqrestore(&irq_lock, flags);
+
+ /*
+ * This calls activate_fd, so it has to be outside the critical
+ * section.
+ */
+ maybe_sigio_broken(fd, (type == IRQ_READ));
+
+ return 0;
+
+ out_unlock:
+ spin_unlock_irqrestore(&irq_lock, flags);
+ out_kfree:
+ kfree(new_fd);
+ out:
+ return err;
+}
+
+static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_lock, flags);
+ os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr);
+ spin_unlock_irqrestore(&irq_lock, flags);
+}
+
+struct irq_and_dev {
+ int irq;
+ void *dev;
+};
+
+static int same_irq_and_dev(struct irq_fd *irq, void *d)
+{
+ struct irq_and_dev *data = d;
+
+ return ((irq->irq == data->irq) && (irq->id == data->dev));
+}
+
+static void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
+{
+ struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq,
+ .dev = dev });
+
+ free_irq_by_cb(same_irq_and_dev, &data);
+}
+
+static int same_fd(struct irq_fd *irq, void *fd)
+{
+ return (irq->fd == *((int *)fd));
+}
+
+void free_irq_by_fd(int fd)
+{
+ free_irq_by_cb(same_fd, &fd);
+}
+
+/* Must be called with irq_lock held */
+static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
+{
+ struct irq_fd *irq;
+ int i = 0;
+ int fdi;
+
+ for (irq = active_fds; irq != NULL; irq = irq->next) {
+ if ((irq->fd == fd) && (irq->irq == irqnum))
+ break;
+ i++;
+ }
+ if (irq == NULL) {
+ printk(KERN_ERR "find_irq_by_fd doesn't have descriptor %d\n",
+ fd);
+ goto out;
+ }
+ fdi = os_get_pollfd(i);
+ if ((fdi != -1) && (fdi != fd)) {
+ printk(KERN_ERR "find_irq_by_fd - mismatch between active_fds "
+ "and pollfds, fd %d vs %d, need %d\n", irq->fd,
+ fdi, fd);
+ irq = NULL;
+ goto out;
+ }
+ *index_out = i;
+ out:
+ return irq;
+}
+
+void reactivate_fd(int fd, int irqnum)
+{
+ struct irq_fd *irq;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&irq_lock, flags);
+ irq = find_irq_by_fd(fd, irqnum, &i);
+ if (irq == NULL) {
+ spin_unlock_irqrestore(&irq_lock, flags);
+ return;
+ }
+ os_set_pollfd(i, irq->fd);
+ spin_unlock_irqrestore(&irq_lock, flags);
+
+ add_sigio_fd(fd);
+}
-int show_interrupts(struct seq_file *p, void *v)
+void deactivate_fd(int fd, int irqnum)
{
- int i = *(loff_t *) v, j;
- struct irqaction * action;
+ struct irq_fd *irq;
unsigned long flags;
+ int i;
- if (i == 0) {
- seq_printf(p, " ");
- for_each_online_cpu(j)
- seq_printf(p, "CPU%d ",j);
- seq_putc(p, '\n');
+ spin_lock_irqsave(&irq_lock, flags);
+ irq = find_irq_by_fd(fd, irqnum, &i);
+ if (irq == NULL) {
+ spin_unlock_irqrestore(&irq_lock, flags);
+ return;
}
- if (i < NR_IRQS) {
- spin_lock_irqsave(&irq_desc[i].lock, flags);
- action = irq_desc[i].action;
- if (!action)
- goto skip;
- seq_printf(p, "%3d: ",i);
-#ifndef CONFIG_SMP
- seq_printf(p, "%10u ", kstat_irqs(i));
-#else
- for_each_online_cpu(j)
- seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
-#endif
- seq_printf(p, " %14s", irq_desc[i].handler->typename);
- seq_printf(p, " %s", action->name);
-
- for (action=action->next; action; action = action->next)
- seq_printf(p, ", %s", action->name);
-
- seq_putc(p, '\n');
-skip:
- spin_unlock_irqrestore(&irq_desc[i].lock, flags);
- } else if (i == NR_IRQS) {
- seq_putc(p, '\n');
+ os_set_pollfd(i, -1);
+ spin_unlock_irqrestore(&irq_lock, flags);
+
+ ignore_sigio_fd(fd);
+}
+EXPORT_SYMBOL(deactivate_fd);
+
+/*
+ * Called just before shutdown in order to provide a clean exec
+ * environment in case the system is rebooting. No locking because
+ * that would cause a pointless shutdown hang if something hadn't
+ * released the lock.
+ */
+int deactivate_all_fds(void)
+{
+ struct irq_fd *irq;
+ int err;
+
+ for (irq = active_fds; irq != NULL; irq = irq->next) {
+ err = os_clear_fd_async(irq->fd);
+ if (err)
+ return err;
}
+ /* If there is a signal already queued, after unblocking ignore it */
+ os_set_ioignore();
return 0;
}
/*
- * do_IRQ handles all normal device IRQ's (the special
+ * do_IRQ handles all normal device IRQs (the special
* SMP cross-CPU interrupts have their own specific
* handlers).
*/
-unsigned int do_IRQ(int irq, union uml_pt_regs *regs)
+unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs);
+ irq_enter();
+ generic_handle_irq(irq);
+ irq_exit();
+ set_irq_regs(old_regs);
+ return 1;
+}
+
+void um_free_irq(unsigned int irq, void *dev)
{
- irq_enter();
- __do_IRQ(irq, (struct pt_regs *) regs);
- irq_exit();
- return 1;
+ free_irq_by_irq_and_dev(irq, dev);
+ free_irq(irq, dev);
}
+EXPORT_SYMBOL(um_free_irq);
int um_request_irq(unsigned int irq, int fd, int type,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
+ irq_handler_t handler,
unsigned long irqflags, const char * devname,
void *dev_id)
{
int err;
- err = request_irq(irq, handler, irqflags, devname, dev_id);
- if(err)
- return(err);
-
- if(fd != -1)
+ if (fd != -1) {
err = activate_fd(irq, fd, type, dev_id);
- return(err);
-}
-EXPORT_SYMBOL(um_request_irq);
-EXPORT_SYMBOL(reactivate_fd);
-
-static DEFINE_SPINLOCK(irq_spinlock);
-
-unsigned long irq_lock(void)
-{
- unsigned long flags;
+ if (err)
+ return err;
+ }
- spin_lock_irqsave(&irq_spinlock, flags);
- return(flags);
+ return request_irq(irq, handler, irqflags, devname, dev_id);
}
-void irq_unlock(unsigned long flags)
-{
- spin_unlock_irqrestore(&irq_spinlock, flags);
-}
+EXPORT_SYMBOL(um_request_irq);
+EXPORT_SYMBOL(reactivate_fd);
-/* hw_interrupt_type must define (startup || enable) &&
- * (shutdown || disable) && end */
-static void dummy(unsigned int irq)
+/*
+ * irq_chip must define at least enable/disable and ack when
+ * the edge handler is used.
+ */
+static void dummy(struct irq_data *d)
{
}
/* This is used for everything else than the timer. */
-static struct hw_interrupt_type normal_irq_type = {
- .typename = "SIGIO",
- .release = free_irq_by_irq_and_dev,
- .disable = dummy,
- .enable = dummy,
- .ack = dummy,
- .end = dummy
+static struct irq_chip normal_irq_type = {
+ .name = "SIGIO",
+ .irq_disable = dummy,
+ .irq_enable = dummy,
+ .irq_ack = dummy,
+ .irq_mask = dummy,
+ .irq_unmask = dummy,
};
-static struct hw_interrupt_type SIGVTALRM_irq_type = {
- .typename = "SIGVTALRM",
- .release = free_irq_by_irq_and_dev,
- .shutdown = dummy, /* never called */
- .disable = dummy,
- .enable = dummy,
- .ack = dummy,
- .end = dummy
+static struct irq_chip SIGVTALRM_irq_type = {
+ .name = "SIGVTALRM",
+ .irq_disable = dummy,
+ .irq_enable = dummy,
+ .irq_ack = dummy,
+ .irq_mask = dummy,
+ .irq_unmask = dummy,
};
void __init init_IRQ(void)
{
int i;
- irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
- irq_desc[TIMER_IRQ].action = NULL;
- irq_desc[TIMER_IRQ].depth = 1;
- irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;
- enable_irq(TIMER_IRQ);
- for(i=1;i<NR_IRQS;i++){
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].action = NULL;
- irq_desc[i].depth = 1;
- irq_desc[i].handler = &normal_irq_type;
- enable_irq(i);
- }
+ irq_set_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq);
+
+ for (i = 1; i < NR_IRQS; i++)
+ irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
}
-int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *,
- struct pt_regs *))
+/*
+ * IRQ stack entry and exit:
+ *
+ * Unlike i386, UML doesn't receive IRQs on the normal kernel stack
+ * and switch over to the IRQ stack after some preparation. We use
+ * sigaltstack to receive signals on a separate stack from the start.
+ * These two functions make sure the rest of the kernel won't be too
+ * upset by being on a different stack. The IRQ stack has a
+ * thread_info structure at the bottom so that current et al continue
+ * to work.
+ *
+ * to_irq_stack copies the current task's thread_info to the IRQ stack
+ * thread_info and sets the tasks's stack to point to the IRQ stack.
+ *
+ * from_irq_stack copies the thread_info struct back (flags may have
+ * been modified) and resets the task's stack pointer.
+ *
+ * Tricky bits -
+ *
+ * What happens when two signals race each other? UML doesn't block
+ * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal
+ * could arrive while a previous one is still setting up the
+ * thread_info.
+ *
+ * There are three cases -
+ * The first interrupt on the stack - sets up the thread_info and
+ * handles the interrupt
+ * A nested interrupt interrupting the copying of the thread_info -
+ * can't handle the interrupt, as the stack is in an unknown state
+ * A nested interrupt not interrupting the copying of the
+ * thread_info - doesn't do any setup, just handles the interrupt
+ *
+ * The first job is to figure out whether we interrupted stack setup.
+ * This is done by xchging the signal mask with thread_info->pending.
+ * If the value that comes back is zero, then there is no setup in
+ * progress, and the interrupt can be handled. If the value is
+ * non-zero, then there is stack setup in progress. In order to have
+ * the interrupt handled, we leave our signal in the mask, and it will
+ * be handled by the upper handler after it has set up the stack.
+ *
+ * Next is to figure out whether we are the outer handler or a nested
+ * one. As part of setting up the stack, thread_info->real_thread is
+ * set to non-NULL (and is reset to NULL on exit). This is the
+ * nesting indicator. If it is non-NULL, then the stack is already
+ * set up and the handler can run.
+ */
+
+static unsigned long pending_mask;
+
+unsigned long to_irq_stack(unsigned long *mask_out)
{
- int fds[2], err;
+ struct thread_info *ti;
+ unsigned long mask, old;
+ int nested;
- err = os_pipe(fds, 1, 1);
- if(err){
- printk("init_aio_irq - os_pipe failed, err = %d\n", -err);
- goto out;
+ mask = xchg(&pending_mask, *mask_out);
+ if (mask != 0) {
+ /*
+ * If any interrupts come in at this point, we want to
+ * make sure that their bits aren't lost by our
+ * putting our bit in. So, this loop accumulates bits
+ * until xchg returns the same value that we put in.
+ * When that happens, there were no new interrupts,
+ * and pending_mask contains a bit for each interrupt
+ * that came in.
+ */
+ old = *mask_out;
+ do {
+ old |= mask;
+ mask = xchg(&pending_mask, old);
+ } while (mask != old);
+ return 1;
}
- err = um_request_irq(irq, fds[0], IRQ_READ, handler,
- SA_INTERRUPT | SA_SAMPLE_RANDOM, name,
- (void *) (long) fds[0]);
- if(err){
- printk("init_aio_irq - : um_request_irq failed, err = %d\n",
- err);
- goto out_close;
+ ti = current_thread_info();
+ nested = (ti->real_thread != NULL);
+ if (!nested) {
+ struct task_struct *task;
+ struct thread_info *tti;
+
+ task = cpu_tasks[ti->cpu].task;
+ tti = task_thread_info(task);
+
+ *ti = *tti;
+ ti->real_thread = tti;
+ task->stack = ti;
}
- err = fds[1];
- goto out;
+ mask = xchg(&pending_mask, 0);
+ *mask_out |= mask | nested;
+ return 0;
+}
- out_close:
- os_close_file(fds[0]);
- os_close_file(fds[1]);
- out:
- return(err);
+unsigned long from_irq_stack(int nested)
+{
+ struct thread_info *ti, *to;
+ unsigned long mask;
+
+ ti = current_thread_info();
+
+ pending_mask = 1;
+
+ to = ti->real_thread;
+ current->stack = to;
+ ti->real_thread = NULL;
+ *to = *ti;
+
+ mask = xchg(&pending_mask, 0);
+ return mask & ~1;
}
+
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
deleted file mode 100644
index c3ccaf24f3e..00000000000
--- a/arch/um/kernel/irq_user.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/poll.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include "user_util.h"
-#include "kern_util.h"
-#include "user.h"
-#include "process.h"
-#include "signal_user.h"
-#include "sigio.h"
-#include "irq_user.h"
-#include "os.h"
-
-struct irq_fd {
- struct irq_fd *next;
- void *id;
- int fd;
- int type;
- int irq;
- int pid;
- int events;
- int current_events;
- int freed;
-};
-
-static struct irq_fd *active_fds = NULL;
-static struct irq_fd **last_irq_ptr = &active_fds;
-
-static struct pollfd *pollfds = NULL;
-static int pollfds_num = 0;
-static int pollfds_size = 0;
-
-extern int io_count, intr_count;
-
-void sigio_handler(int sig, union uml_pt_regs *regs)
-{
- struct irq_fd *irq_fd, *next;
- int i, n;
-
- if(smp_sigio_handler()) return;
- while(1){
- n = poll(pollfds, pollfds_num, 0);
- if(n < 0){
- if(errno == EINTR) continue;
- printk("sigio_handler : poll returned %d, "
- "errno = %d\n", n, errno);
- break;
- }
- if(n == 0) break;
-
- irq_fd = active_fds;
- for(i = 0; i < pollfds_num; i++){
- if(pollfds[i].revents != 0){
- irq_fd->current_events = pollfds[i].revents;
- pollfds[i].fd = -1;
- }
- irq_fd = irq_fd->next;
- }
-
- for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){
- next = irq_fd->next;
- if(irq_fd->current_events != 0){
- irq_fd->current_events = 0;
- do_IRQ(irq_fd->irq, regs);
-
- /* This is here because the next irq may be
- * freed in the handler. If a console goes
- * away, both the read and write irqs will be
- * freed. After do_IRQ, ->next will point to
- * a good IRQ.
- * Irqs can't be freed inside their handlers,
- * so the next best thing is to have them
- * marked as needing freeing, so that they
- * can be freed here.
- */
- next = irq_fd->next;
- if(irq_fd->freed){
- free_irq(irq_fd->irq, irq_fd->id);
- }
- }
- }
- }
-}
-
-int activate_ipi(int fd, int pid)
-{
- return(os_set_fd_async(fd, pid));
-}
-
-static void maybe_sigio_broken(int fd, int type)
-{
- if(isatty(fd)){
- if((type == IRQ_WRITE) && !pty_output_sigio){
- write_sigio_workaround();
- add_sigio_fd(fd, 0);
- }
- else if((type == IRQ_READ) && !pty_close_sigio){
- write_sigio_workaround();
- add_sigio_fd(fd, 1);
- }
- }
-}
-
-int activate_fd(int irq, int fd, int type, void *dev_id)
-{
- struct pollfd *tmp_pfd;
- struct irq_fd *new_fd, *irq_fd;
- unsigned long flags;
- int pid, events, err, n, size;
-
- pid = os_getpid();
- err = os_set_fd_async(fd, pid);
- if(err < 0)
- goto out;
-
- new_fd = um_kmalloc(sizeof(*new_fd));
- err = -ENOMEM;
- if(new_fd == NULL)
- goto out;
-
- if(type == IRQ_READ) events = POLLIN | POLLPRI;
- else events = POLLOUT;
- *new_fd = ((struct irq_fd) { .next = NULL,
- .id = dev_id,
- .fd = fd,
- .type = type,
- .irq = irq,
- .pid = pid,
- .events = events,
- .current_events = 0,
- .freed = 0 } );
-
- /* Critical section - locked by a spinlock because this stuff can
- * be changed from interrupt handlers. The stuff above is done
- * outside the lock because it allocates memory.
- */
-
- /* Actually, it only looks like it can be called from interrupt
- * context. The culprit is reactivate_fd, which calls
- * maybe_sigio_broken, which calls write_sigio_workaround,
- * which calls activate_fd. However, write_sigio_workaround should
- * only be called once, at boot time. That would make it clear that
- * this is called only from process context, and can be locked with
- * a semaphore.
- */
- flags = irq_lock();
- for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
- if((irq_fd->fd == fd) && (irq_fd->type == type)){
- printk("Registering fd %d twice\n", fd);
- printk("Irqs : %d, %d\n", irq_fd->irq, irq);
- printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id);
- goto out_unlock;
- }
- }
-
- n = pollfds_num;
- if(n == pollfds_size){
- while(1){
- /* Here we have to drop the lock in order to call
- * kmalloc, which might sleep. If something else
- * came in and changed the pollfds array, we free
- * the buffer and try again.
- */
- irq_unlock(flags);
- size = (pollfds_num + 1) * sizeof(pollfds[0]);
- tmp_pfd = um_kmalloc(size);
- flags = irq_lock();
- if(tmp_pfd == NULL)
- goto out_unlock;
- if(n == pollfds_size)
- break;
- kfree(tmp_pfd);
- }
- if(pollfds != NULL){
- memcpy(tmp_pfd, pollfds,
- sizeof(pollfds[0]) * pollfds_size);
- kfree(pollfds);
- }
- pollfds = tmp_pfd;
- pollfds_size++;
- }
-
- if(type == IRQ_WRITE)
- fd = -1;
-
- pollfds[pollfds_num] = ((struct pollfd) { .fd = fd,
- .events = events,
- .revents = 0 });
- pollfds_num++;
-
- *last_irq_ptr = new_fd;
- last_irq_ptr = &new_fd->next;
-
- irq_unlock(flags);
-
- /* This calls activate_fd, so it has to be outside the critical
- * section.
- */
- maybe_sigio_broken(fd, type);
-
- return(0);
-
- out_unlock:
- irq_unlock(flags);
- kfree(new_fd);
- out:
- return(err);
-}
-
-static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
-{
- struct irq_fd **prev;
- unsigned long flags;
- int i = 0;
-
- flags = irq_lock();
- prev = &active_fds;
- while(*prev != NULL){
- if((*test)(*prev, arg)){
- struct irq_fd *old_fd = *prev;
- if((pollfds[i].fd != -1) &&
- (pollfds[i].fd != (*prev)->fd)){
- printk("free_irq_by_cb - mismatch between "
- "active_fds and pollfds, fd %d vs %d\n",
- (*prev)->fd, pollfds[i].fd);
- goto out;
- }
-
- pollfds_num--;
-
- /* This moves the *whole* array after pollfds[i] (though
- * it doesn't spot as such)! */
-
- memmove(&pollfds[i], &pollfds[i + 1],
- (pollfds_num - i) * sizeof(pollfds[0]));
-
- if(last_irq_ptr == &old_fd->next)
- last_irq_ptr = prev;
- *prev = (*prev)->next;
- if(old_fd->type == IRQ_WRITE)
- ignore_sigio_fd(old_fd->fd);
- kfree(old_fd);
- continue;
- }
- prev = &(*prev)->next;
- i++;
- }
- out:
- irq_unlock(flags);
-}
-
-struct irq_and_dev {
- int irq;
- void *dev;
-};
-
-static int same_irq_and_dev(struct irq_fd *irq, void *d)
-{
- struct irq_and_dev *data = d;
-
- return((irq->irq == data->irq) && (irq->id == data->dev));
-}
-
-void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
-{
- struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq,
- .dev = dev });
-
- free_irq_by_cb(same_irq_and_dev, &data);
-}
-
-static int same_fd(struct irq_fd *irq, void *fd)
-{
- return(irq->fd == *((int *) fd));
-}
-
-void free_irq_by_fd(int fd)
-{
- free_irq_by_cb(same_fd, &fd);
-}
-
-static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
-{
- struct irq_fd *irq;
- int i = 0;
-
- for(irq=active_fds; irq != NULL; irq = irq->next){
- if((irq->fd == fd) && (irq->irq == irqnum)) break;
- i++;
- }
- if(irq == NULL){
- printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
- goto out;
- }
- if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){
- printk("find_irq_by_fd - mismatch between active_fds and "
- "pollfds, fd %d vs %d, need %d\n", irq->fd,
- pollfds[i].fd, fd);
- irq = NULL;
- goto out;
- }
- *index_out = i;
- out:
- return(irq);
-}
-
-void free_irq_later(int irq, void *dev_id)
-{
- struct irq_fd *irq_fd;
- unsigned long flags;
-
- flags = irq_lock();
- for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
- if((irq_fd->irq == irq) && (irq_fd->id == dev_id))
- break;
- }
- if(irq_fd == NULL){
- printk("free_irq_later found no irq, irq = %d, "
- "dev_id = 0x%p\n", irq, dev_id);
- goto out;
- }
- irq_fd->freed = 1;
- out:
- irq_unlock(flags);
-}
-
-void reactivate_fd(int fd, int irqnum)
-{
- struct irq_fd *irq;
- unsigned long flags;
- int i;
-
- flags = irq_lock();
- irq = find_irq_by_fd(fd, irqnum, &i);
- if(irq == NULL){
- irq_unlock(flags);
- return;
- }
-
- pollfds[i].fd = irq->fd;
-
- irq_unlock(flags);
-
- /* This calls activate_fd, so it has to be outside the critical
- * section.
- */
- maybe_sigio_broken(fd, irq->type);
-}
-
-void deactivate_fd(int fd, int irqnum)
-{
- struct irq_fd *irq;
- unsigned long flags;
- int i;
-
- flags = irq_lock();
- irq = find_irq_by_fd(fd, irqnum, &i);
- if(irq == NULL)
- goto out;
- pollfds[i].fd = -1;
- out:
- irq_unlock(flags);
-}
-
-int deactivate_all_fds(void)
-{
- struct irq_fd *irq;
- int err;
-
- for(irq=active_fds;irq != NULL;irq = irq->next){
- err = os_clear_fd_async(irq->fd);
- if(err)
- return(err);
- }
- /* If there is a signal already queued, after unblocking ignore it */
- set_handler(SIGIO, SIG_IGN, 0, -1);
-
- return(0);
-}
-
-void forward_ipi(int fd, int pid)
-{
- int err;
-
- err = os_set_owner(fd, pid);
- if(err < 0)
- printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
- "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
-}
-
-void forward_interrupts(int pid)
-{
- struct irq_fd *irq;
- unsigned long flags;
- int err;
-
- flags = irq_lock();
- for(irq=active_fds;irq != NULL;irq = irq->next){
- err = os_set_owner(irq->fd, pid);
- if(err < 0){
- /* XXX Just remove the irq rather than
- * print out an infinite stream of these
- */
- printk("Failed to forward %d to pid %d, err = %d\n",
- irq->fd, pid, -err);
- }
-
- irq->pid = pid;
- }
- irq_unlock(flags);
-}
-
-void init_irq_signals(int on_sigstack)
-{
- __sighandler_t h;
- int flags;
-
- flags = on_sigstack ? SA_ONSTACK : 0;
- if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
- else h = boot_timer_handler;
-
- set_handler(SIGVTALRM, h, flags | SA_RESTART,
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1);
- set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
- SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
- signal(SIGWINCH, SIG_IGN);
-}
-
-/*
- * 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/ksyms.c b/arch/um/kernel/ksyms.c
index 7713e7a6f47..543c0475693 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -1,65 +1,17 @@
/*
- * Copyright (C) 2001 - 2004 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/config.h"
-#include "linux/module.h"
-#include "linux/string.h"
-#include "linux/smp_lock.h"
-#include "linux/spinlock.h"
-#include "linux/highmem.h"
-#include "asm/current.h"
-#include "asm/processor.h"
-#include "asm/unistd.h"
-#include "asm/pgalloc.h"
-#include "asm/pgtable.h"
-#include "asm/page.h"
-#include "asm/tlbflush.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "mem_user.h"
-#include "os.h"
+#include <linux/module.h>
+#include <os.h>
-EXPORT_SYMBOL(stop);
-EXPORT_SYMBOL(uml_physmem);
EXPORT_SYMBOL(set_signals);
EXPORT_SYMBOL(get_signals);
-EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(sys_waitpid);
-EXPORT_SYMBOL(task_size);
-EXPORT_SYMBOL(flush_tlb_range);
-EXPORT_SYMBOL(host_task_size);
-EXPORT_SYMBOL(arch_validate);
-EXPORT_SYMBOL(get_kmem_end);
-
-EXPORT_SYMBOL(high_physmem);
-EXPORT_SYMBOL(empty_zero_page);
-EXPORT_SYMBOL(um_virt_to_phys);
-EXPORT_SYMBOL(mode_tt);
-EXPORT_SYMBOL(handle_page_fault);
-EXPORT_SYMBOL(find_iomem);
-EXPORT_SYMBOL(end_iomem);
-
-#ifdef CONFIG_MODE_TT
-EXPORT_SYMBOL(strncpy_from_user_tt);
-EXPORT_SYMBOL(copy_from_user_tt);
-EXPORT_SYMBOL(copy_to_user_tt);
-#endif
-
-#ifdef CONFIG_MODE_SKAS
-EXPORT_SYMBOL(strncpy_from_user_skas);
-EXPORT_SYMBOL(copy_to_user_skas);
-EXPORT_SYMBOL(copy_from_user_skas);
-EXPORT_SYMBOL(clear_user_skas);
-#endif
-EXPORT_SYMBOL(uml_strdup);
EXPORT_SYMBOL(os_stat_fd);
EXPORT_SYMBOL(os_stat_file);
EXPORT_SYMBOL(os_access);
-EXPORT_SYMBOL(os_print_error);
-EXPORT_SYMBOL(os_get_exec_close);
EXPORT_SYMBOL(os_set_exec_close);
EXPORT_SYMBOL(os_getpid);
EXPORT_SYMBOL(os_open_file);
@@ -83,28 +35,10 @@ EXPORT_SYMBOL(os_connect_socket);
EXPORT_SYMBOL(os_accept_connection);
EXPORT_SYMBOL(os_rcv_fd);
EXPORT_SYMBOL(run_helper);
-EXPORT_SYMBOL(start_thread);
-EXPORT_SYMBOL(dump_thread);
-
-EXPORT_SYMBOL(do_gettimeofday);
-EXPORT_SYMBOL(do_settimeofday);
-
-/* This is here because UML expands open to sys_open, not to a system
- * call instruction.
- */
-EXPORT_SYMBOL(sys_open);
-EXPORT_SYMBOL(sys_lseek);
-EXPORT_SYMBOL(sys_read);
-EXPORT_SYMBOL(sys_wait4);
-
-#ifdef CONFIG_SMP
-
-/* required for SMP */
-
-extern void FASTCALL( __write_lock_failed(rwlock_t *rw));
-EXPORT_SYMBOL(__write_lock_failed);
-
-extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
-EXPORT_SYMBOL(__read_lock_failed);
+EXPORT_SYMBOL(os_major);
+EXPORT_SYMBOL(os_minor);
+EXPORT_SYMBOL(os_makedev);
-#endif
+EXPORT_SYMBOL(add_sigio_fd);
+EXPORT_SYMBOL(ignore_sigio_fd);
+EXPORT_SYMBOL(sigio_broken);
diff --git a/arch/um/kernel/maccess.c b/arch/um/kernel/maccess.c
new file mode 100644
index 00000000000..1f3d5c4910d
--- /dev/null
+++ b/arch/um/kernel/maccess.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 Richard Weinberger <richrd@nod.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <os.h>
+
+long probe_kernel_read(void *dst, const void *src, size_t size)
+{
+ void *psrc = (void *)rounddown((unsigned long)src, PAGE_SIZE);
+
+ if ((unsigned long)src < PAGE_SIZE || size <= 0)
+ return -EFAULT;
+
+ if (os_mincore(psrc, size + src - psrc) <= 0)
+ return -EFAULT;
+
+ return __probe_kernel_read(dst, src, size);
+}
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index fa4f915be5c..8636e905426 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -1,106 +1,78 @@
/*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/stddef.h"
-#include "linux/kernel.h"
-#include "linux/mm.h"
-#include "linux/bootmem.h"
-#include "linux/swap.h"
-#include "linux/highmem.h"
-#include "linux/gfp.h"
-#include "asm/page.h"
-#include "asm/fixmap.h"
-#include "asm/pgalloc.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "kern.h"
-#include "mem_user.h"
-#include "uml_uaccess.h"
-#include "os.h"
-#include "linux/types.h"
-#include "linux/string.h"
-#include "init.h"
-#include "kern_constants.h"
-
-extern char __binary_start;
-
-/* Changed during early boot */
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <asm/fixmap.h>
+#include <asm/page.h>
+#include <as-layout.h>
+#include <init.h>
+#include <kern.h>
+#include <kern_util.h>
+#include <mem_user.h>
+#include <os.h>
+
+/* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */
unsigned long *empty_zero_page = NULL;
-unsigned long *empty_bad_page = NULL;
+EXPORT_SYMBOL(empty_zero_page);
+/* allocated in paging_init and unchanged thereafter */
+static unsigned long *empty_bad_page = NULL;
+
+/*
+ * Initialized during boot, and readonly for initializing page tables
+ * afterwards
+ */
pgd_t swapper_pg_dir[PTRS_PER_PGD];
-unsigned long highmem;
+
+/* Initialized at boot time, and readonly after that */
+unsigned long long highmem;
int kmalloc_ok = 0;
+/* Used during early boot */
static unsigned long brk_end;
-void unmap_physmem(void)
-{
- os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
-}
-
-static void map_cb(void *unused)
-{
- map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
-}
-
#ifdef CONFIG_HIGHMEM
static void setup_highmem(unsigned long highmem_start,
unsigned long highmem_len)
{
- struct page *page;
unsigned long highmem_pfn;
int i;
highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
- for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
- page = &mem_map[highmem_pfn + i];
- ClearPageReserved(page);
- set_page_count(page, 1);
- __free_page(page);
- }
+ for (i = 0; i < highmem_len >> PAGE_SHIFT; i++)
+ free_highmem_page(&mem_map[highmem_pfn + i]);
}
#endif
-void mem_init(void)
+void __init mem_init(void)
{
- unsigned long start;
-
- max_low_pfn = (high_physmem - uml_physmem) >> PAGE_SHIFT;
-
- /* clear the zero-page */
- memset((void *) empty_zero_page, 0, PAGE_SIZE);
+ /* clear the zero-page */
+ memset(empty_zero_page, 0, PAGE_SIZE);
/* Map in the area just after the brk now that kmalloc is about
* to be turned on.
*/
brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
- map_cb(NULL);
- initial_thread_cb(map_cb, NULL);
+ map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
free_bootmem(__pa(brk_end), uml_reserved - brk_end);
uml_reserved = brk_end;
- /* Fill in any hole at the start of the binary */
- start = (unsigned long) &__binary_start & PAGE_MASK;
- if(uml_physmem != start){
- map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem,
- 1, 1, 0);
- }
-
/* this will put all low memory onto the freelists */
- totalram_pages = free_all_bootmem();
- totalhigh_pages = highmem >> PAGE_SHIFT;
- totalram_pages += totalhigh_pages;
- num_physpages = totalram_pages;
- max_pfn = totalram_pages;
- printk(KERN_INFO "Memory: %luk available\n",
- (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
- kmalloc_ok = 1;
-
+ free_all_bootmem();
+ max_low_pfn = totalram_pages;
#ifdef CONFIG_HIGHMEM
setup_highmem(end_iomem, highmem);
#endif
+ max_pfn = totalram_pages;
+ mem_init_print_info(NULL);
+ kmalloc_ok = 1;
}
/*
@@ -128,7 +100,7 @@ static void __init one_md_table_init(pud_t *pud)
#endif
}
-static void __init fixrange_init(unsigned long start, unsigned long end,
+static void __init fixrange_init(unsigned long start, unsigned long end,
pgd_t *pgd_base)
{
pgd_t *pgd;
@@ -147,7 +119,7 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
if (pud_none(*pud))
one_md_table_init(pud);
pmd = pmd_offset(pud, vaddr);
- for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
+ for (; (j < PTRS_PER_PMD) && (vaddr < end); pmd++, j++) {
one_page_table_init(pmd);
vaddr += PMD_SIZE;
}
@@ -161,7 +133,7 @@ pgprot_t kmap_prot;
#define kmap_get_fixmap_pte(vaddr) \
pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\
- (vaddr)), (vaddr))
+ (vaddr)), (vaddr))
static void __init kmap_init(void)
{
@@ -174,7 +146,7 @@ static void __init kmap_init(void)
kmap_prot = PAGE_KERNEL;
}
-static void init_highmem(void)
+static void __init init_highmem(void)
{
pgd_t *pgd;
pud_t *pud;
@@ -206,36 +178,42 @@ static void __init fixaddr_user_init( void)
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
- unsigned long paddr, vaddr = FIXADDR_USER_START;
+ phys_t p;
+ unsigned long v, vaddr = FIXADDR_USER_START;
- if ( ! size )
+ if (!size)
return;
fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir);
- paddr = (unsigned long)alloc_bootmem_low_pages( size);
- memcpy( (void *)paddr, (void *)FIXADDR_USER_START, size);
- paddr = __pa(paddr);
- for ( ; size > 0; size-=PAGE_SIZE, vaddr+=PAGE_SIZE, paddr+=PAGE_SIZE){
+ v = (unsigned long) alloc_bootmem_low_pages(size);
+ memcpy((void *) v , (void *) FIXADDR_USER_START, size);
+ p = __pa(v);
+ for ( ; size > 0; size -= PAGE_SIZE, vaddr += PAGE_SIZE,
+ p += PAGE_SIZE) {
pgd = swapper_pg_dir + pgd_index(vaddr);
pud = pud_offset(pgd, vaddr);
pmd = pmd_offset(pud, vaddr);
pte = pte_offset_kernel(pmd, vaddr);
- pte_set_val( (*pte), paddr, PAGE_READONLY);
+ pte_set_val(*pte, p, PAGE_READONLY);
}
#endif
}
-void paging_init(void)
+void __init paging_init(void)
{
unsigned long zones_size[MAX_NR_ZONES], vaddr;
int i;
empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
- for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++)
+ for (i = 0; i < ARRAY_SIZE(zones_size); i++)
zones_size[i] = 0;
- zones_size[ZONE_DMA] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
+
+ zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) -
+ (uml_physmem >> PAGE_SHIFT);
+#ifdef CONFIG_HIGHMEM
zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT;
+#endif
free_area_init(zones_size);
/*
@@ -252,34 +230,8 @@ void paging_init(void)
#endif
}
-struct page *arch_validate(struct page *page, gfp_t mask, int order)
-{
- unsigned long addr, zero = 0;
- int i;
-
- again:
- if(page == NULL) return(page);
- if(PageHighMem(page)) return(page);
-
- addr = (unsigned long) page_address(page);
- for(i = 0; i < (1 << order); i++){
- current->thread.fault_addr = (void *) addr;
- if(__do_copy_to_user((void __user *) addr, &zero,
- sizeof(zero),
- &current->thread.fault_addr,
- &current->thread.fault_catcher)){
- if(!(mask & __GFP_WAIT)) return(NULL);
- else break;
- }
- addr += PAGE_SIZE;
- }
-
- if(i == (1 << order)) return(page);
- page = alloc_pages(mask, order);
- goto again;
-}
-
-/* This can't do anything because nothing in the kernel image can be freed
+/*
+ * This can't do anything because nothing in the kernel image can be freed
* since it's not in kernel physical memory.
*/
@@ -288,55 +240,13 @@ void free_initmem(void)
}
#ifdef CONFIG_BLK_DEV_INITRD
-
void free_initrd_mem(unsigned long start, unsigned long end)
{
- if (start < end)
- printk ("Freeing initrd memory: %ldk freed\n",
- (end - start) >> 10);
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- set_page_count(virt_to_page(start), 1);
- free_page(start);
- totalram_pages++;
- }
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
-
#endif
-void show_mem(void)
-{
- int pfn, total = 0, reserved = 0;
- int shared = 0, cached = 0;
- int highmem = 0;
- struct page *page;
-
- printk("Mem-info:\n");
- show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
- pfn = max_mapnr;
- while(pfn-- > 0) {
- page = pfn_to_page(pfn);
- total++;
- if(PageHighMem(page))
- highmem++;
- if(PageReserved(page))
- reserved++;
- else if(PageSwapCache(page))
- cached++;
- else if(page_count(page))
- shared += page_count(page) - 1;
- }
- printk("%d pages of RAM\n", total);
- printk("%d pages of HIGHMEM\n", highmem);
- printk("%d reserved pages\n", reserved);
- printk("%d pages shared\n", shared);
- printk("%d pages swap cached\n", cached);
-}
-
-/*
- * Allocate and free page tables.
- */
+/* Allocate and free page tables. */
pgd_t *pgd_alloc(struct mm_struct *mm)
{
@@ -344,14 +254,14 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
if (pgd) {
memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
- memcpy(pgd + USER_PTRS_PER_PGD,
- swapper_pg_dir + USER_PTRS_PER_PGD,
+ memcpy(pgd + USER_PTRS_PER_PGD,
+ swapper_pg_dir + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
}
return pgd;
}
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
free_page((unsigned long) pgd);
}
@@ -364,31 +274,33 @@ pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
return pte;
}
-struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
{
struct page *pte;
-
+
pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
+ if (!pte)
+ return NULL;
+ if (!pgtable_page_ctor(pte)) {
+ __free_page(pte);
+ return NULL;
+ }
return pte;
}
-struct iomem_region *iomem_regions = NULL;
-int iomem_size = 0;
+#ifdef CONFIG_3_LEVEL_PGTABLES
+pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
-extern int parse_iomem(char *str, int *add) __init;
+ if (pmd)
+ memset(pmd, 0, PAGE_SIZE);
-__uml_setup("iomem=", parse_iomem,
-"iomem=<name>,<file>\n"
-" Configure <file> as an IO memory region named <name>.\n\n"
-);
+ return pmd;
+}
+#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:
- */
+void *uml_kmalloc(int size, int flags)
+{
+ return kmalloc(size, flags);
+}
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index f3b583a878a..30fdd5d0067 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -1,254 +1,29 @@
/*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/mm.h"
-#include "linux/rbtree.h"
-#include "linux/slab.h"
-#include "linux/vmalloc.h"
-#include "linux/bootmem.h"
-#include "linux/module.h"
-#include "asm/types.h"
-#include "asm/pgtable.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "mode_kern.h"
-#include "mem.h"
-#include "mem_user.h"
-#include "os.h"
-#include "kern.h"
-#include "init.h"
-
-struct phys_desc {
- struct rb_node rb;
- int fd;
- __u64 offset;
- void *virt;
- unsigned long phys;
- struct list_head list;
-};
-
-static struct rb_root phys_mappings = RB_ROOT;
-
-static struct rb_node **find_rb(void *virt)
-{
- struct rb_node **n = &phys_mappings.rb_node;
- struct phys_desc *d;
-
- while(*n != NULL){
- d = rb_entry(*n, struct phys_desc, rb);
- if(d->virt == virt)
- return(n);
-
- if(d->virt > virt)
- n = &(*n)->rb_left;
- else
- n = &(*n)->rb_right;
- }
-
- return(n);
-}
-
-static struct phys_desc *find_phys_mapping(void *virt)
-{
- struct rb_node **n = find_rb(virt);
-
- if(*n == NULL)
- return(NULL);
-
- return(rb_entry(*n, struct phys_desc, rb));
-}
-
-static void insert_phys_mapping(struct phys_desc *desc)
-{
- struct rb_node **n = find_rb(desc->virt);
-
- if(*n != NULL)
- panic("Physical remapping for %p already present",
- desc->virt);
-
- rb_link_node(&desc->rb, (*n)->rb_parent, n);
- rb_insert_color(&desc->rb, &phys_mappings);
-}
-
-LIST_HEAD(descriptor_mappings);
-
-struct desc_mapping {
- int fd;
- struct list_head list;
- struct list_head pages;
-};
-
-static struct desc_mapping *find_mapping(int fd)
-{
- struct desc_mapping *desc;
- struct list_head *ele;
-
- list_for_each(ele, &descriptor_mappings){
- desc = list_entry(ele, struct desc_mapping, list);
- if(desc->fd == fd)
- return(desc);
- }
-
- return(NULL);
-}
-
-static struct desc_mapping *descriptor_mapping(int fd)
-{
- struct desc_mapping *desc;
-
- desc = find_mapping(fd);
- if(desc != NULL)
- return(desc);
-
- desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
- if(desc == NULL)
- return(NULL);
-
- *desc = ((struct desc_mapping)
- { .fd = fd,
- .list = LIST_HEAD_INIT(desc->list),
- .pages = LIST_HEAD_INIT(desc->pages) });
- list_add(&desc->list, &descriptor_mappings);
-
- return(desc);
-}
-
-int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
-{
- struct desc_mapping *fd_maps;
- struct phys_desc *desc;
- unsigned long phys;
- int err;
-
- fd_maps = descriptor_mapping(fd);
- if(fd_maps == NULL)
- return(-ENOMEM);
-
- phys = __pa(virt);
- desc = find_phys_mapping(virt);
- if(desc != NULL)
- panic("Address 0x%p is already substituted\n", virt);
-
- err = -ENOMEM;
- desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
- if(desc == NULL)
- goto out;
-
- *desc = ((struct phys_desc)
- { .fd = fd,
- .offset = offset,
- .virt = virt,
- .phys = __pa(virt),
- .list = LIST_HEAD_INIT(desc->list) });
- insert_phys_mapping(desc);
-
- list_add(&desc->list, &fd_maps->pages);
-
- virt = (void *) ((unsigned long) virt & PAGE_MASK);
- err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0);
- if(!err)
- goto out;
-
- rb_erase(&desc->rb, &phys_mappings);
- kfree(desc);
- out:
- return(err);
-}
+#include <linux/module.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+#include <linux/pfn.h>
+#include <asm/page.h>
+#include <as-layout.h>
+#include <init.h>
+#include <kern.h>
+#include <mem_user.h>
+#include <os.h>
static int physmem_fd = -1;
-static void remove_mapping(struct phys_desc *desc)
-{
- void *virt = desc->virt;
- int err;
-
- rb_erase(&desc->rb, &phys_mappings);
- list_del(&desc->list);
- kfree(desc);
-
- err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0);
- if(err)
- panic("Failed to unmap block device page from physical memory, "
- "errno = %d", -err);
-}
-
-int physmem_remove_mapping(void *virt)
-{
- struct phys_desc *desc;
-
- virt = (void *) ((unsigned long) virt & PAGE_MASK);
- desc = find_phys_mapping(virt);
- if(desc == NULL)
- return(0);
-
- remove_mapping(desc);
- return(1);
-}
-
-void physmem_forget_descriptor(int fd)
-{
- struct desc_mapping *desc;
- struct phys_desc *page;
- struct list_head *ele, *next;
- __u64 offset;
- void *addr;
- int err;
-
- desc = find_mapping(fd);
- if(desc == NULL)
- return;
-
- list_for_each_safe(ele, next, &desc->pages){
- page = list_entry(ele, struct phys_desc, list);
- offset = page->offset;
- addr = page->virt;
- remove_mapping(page);
- err = os_seek_file(fd, offset);
- if(err)
- panic("physmem_forget_descriptor - failed to seek "
- "to %lld in fd %d, error = %d\n",
- offset, fd, -err);
- err = os_read_file(fd, addr, PAGE_SIZE);
- if(err < 0)
- panic("physmem_forget_descriptor - failed to read "
- "from fd %d to 0x%p, error = %d\n",
- fd, addr, -err);
- }
-
- list_del(&desc->list);
- kfree(desc);
-}
-
-EXPORT_SYMBOL(physmem_forget_descriptor);
-EXPORT_SYMBOL(physmem_remove_mapping);
-EXPORT_SYMBOL(physmem_subst_mapping);
-
-void arch_free_page(struct page *page, int order)
-{
- void *virt;
- int i;
-
- for(i = 0; i < (1 << order); i++){
- virt = __va(page_to_phys(page + i));
- physmem_remove_mapping(virt);
- }
-}
-
-int is_remapped(void *virt)
-{
- struct phys_desc *desc = find_phys_mapping(virt);
-
- return(desc != NULL);
-}
-
/* Changed during early boot */
unsigned long high_physmem;
+EXPORT_SYMBOL(high_physmem);
extern unsigned long long physmem_size;
-int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
+int __init init_maps(unsigned long physmem, unsigned long iomem,
+ unsigned long highmem)
{
struct page *p, *map;
unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
@@ -265,37 +40,21 @@ int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
highmem_len = highmem_pages * sizeof(struct page);
total_pages = phys_pages + iomem_pages + highmem_pages;
- total_len = phys_len + iomem_pages + highmem_len;
-
- if(kmalloc_ok){
- map = kmalloc(total_len, GFP_KERNEL);
- if(map == NULL)
- map = vmalloc(total_len);
- }
- else map = alloc_bootmem_low_pages(total_len);
+ total_len = phys_len + iomem_len + highmem_len;
- if(map == NULL)
- return(-ENOMEM);
+ map = alloc_bootmem_low_pages(total_len);
+ if (map == NULL)
+ return -ENOMEM;
- for(i = 0; i < total_pages; i++){
+ for (i = 0; i < total_pages; i++) {
p = &map[i];
- set_page_count(p, 0);
+ memset(p, 0, sizeof(struct page));
SetPageReserved(p);
INIT_LIST_HEAD(&p->lru);
}
max_mapnr = total_pages;
- return(0);
-}
-
-/* Changed during early boot */
-static unsigned long kmem_top = 0;
-
-unsigned long get_kmem_end(void)
-{
- if(kmem_top == 0)
- kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
- return(kmem_top);
+ return 0;
}
void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
@@ -306,9 +65,9 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
fd = phys_mapping(phys, &offset);
err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
- if(err) {
- if(err == -ENOMEM)
- printk("try increasing the host's "
+ if (err) {
+ if (err == -ENOMEM)
+ printk(KERN_ERR "try increasing the host's "
"/proc/sys/vm/max_map_count to <physical "
"memory size>/4096\n");
panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
@@ -316,12 +75,10 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
}
}
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+extern int __syscall_stub_start;
-extern int __syscall_stub_start, __binary_start;
-
-void setup_physmem(unsigned long start, unsigned long reserve_end,
- unsigned long len, unsigned long long highmem)
+void __init setup_physmem(unsigned long start, unsigned long reserve_end,
+ unsigned long len, unsigned long long highmem)
{
unsigned long reserve = reserve_end - start;
int pfn = PFN_UP(__pa(reserve_end));
@@ -332,42 +89,41 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
offset = uml_reserved - uml_physmem;
err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
- len - offset, 1, 1, 0);
- if(err < 0){
- os_print_error(err, "Mapping memory");
+ len - offset, 1, 1, 1);
+ if (err < 0) {
+ printf("setup_physmem - mapping %ld bytes of memory at 0x%p "
+ "failed - errno = %d\n", len - offset,
+ (void *) uml_reserved, err);
exit(1);
}
- /* Special kludge - This page will be mapped in to userspace processes
+ /*
+ * Special kludge - This page will be mapped in to userspace processes
* from physmem_fd, so it needs to be written out there.
*/
os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
+ os_fsync_file(physmem_fd);
bootmap_size = init_bootmem(pfn, pfn + delta);
free_bootmem(__pa(reserve_end) + bootmap_size,
len - bootmap_size - reserve);
}
-int phys_mapping(unsigned long phys, __u64 *offset_out)
+int phys_mapping(unsigned long phys, unsigned long long *offset_out)
{
- struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK));
int fd = -1;
- if(desc != NULL){
- fd = desc->fd;
- *offset_out = desc->offset;
- }
- else if(phys < physmem_size){
+ if (phys < physmem_size) {
fd = physmem_fd;
*offset_out = phys;
}
- else if(phys < __pa(end_iomem)){
+ else if (phys < __pa(end_iomem)) {
struct iomem_region *region = iomem_regions;
- while(region != NULL){
- if((phys >= region->phys) &&
- (phys < region->phys + region->size)){
+ while (region != NULL) {
+ if ((phys >= region->phys) &&
+ (phys < region->phys + region->size)) {
fd = region->fd;
*offset_out = phys - region->phys;
break;
@@ -375,12 +131,12 @@ int phys_mapping(unsigned long phys, __u64 *offset_out)
region = region->next;
}
}
- else if(phys < __pa(end_iomem) + highmem){
+ else if (phys < __pa(end_iomem) + highmem) {
fd = physmem_fd;
*offset_out = phys - iomem_size;
}
- return(fd);
+ return fd;
}
static int __init uml_mem_setup(char *line, int *add)
@@ -399,32 +155,52 @@ __uml_setup("mem=", uml_mem_setup,
" Example: mem=64M\n\n"
);
+extern int __init parse_iomem(char *str, int *add);
+
+__uml_setup("iomem=", parse_iomem,
+"iomem=<name>,<file>\n"
+" Configure <file> as an IO memory region named <name>.\n\n"
+);
+
+/*
+ * This list is constructed in parse_iomem and addresses filled in in
+ * setup_iomem, both of which run during early boot. Afterwards, it's
+ * unchanged.
+ */
+struct iomem_region *iomem_regions;
+
+/* Initialized in parse_iomem and unchanged thereafter */
+int iomem_size;
+
unsigned long find_iomem(char *driver, unsigned long *len_out)
{
struct iomem_region *region = iomem_regions;
- while(region != NULL){
- if(!strcmp(region->driver, driver)){
+ while (region != NULL) {
+ if (!strcmp(region->driver, driver)) {
*len_out = region->size;
- return(region->virt);
+ return region->virt;
}
+
+ region = region->next;
}
- return(0);
+ return 0;
}
+EXPORT_SYMBOL(find_iomem);
-int setup_iomem(void)
+static int setup_iomem(void)
{
struct iomem_region *region = iomem_regions;
unsigned long iomem_start = high_physmem + PAGE_SIZE;
int err;
- while(region != NULL){
+ while (region != NULL) {
err = os_map_memory((void *) iomem_start, region->fd, 0,
region->size, 1, 1, 0);
- if(err)
- printk("Mapping iomem region for driver '%s' failed, "
- "errno = %d\n", region->driver, -err);
+ if (err)
+ printk(KERN_ERR "Mapping iomem region for driver '%s' "
+ "failed, errno = %d\n", region->driver, -err);
else {
region->virt = iomem_start;
region->phys = __pa(region->virt);
@@ -434,18 +210,7 @@ int setup_iomem(void)
region = region->next;
}
- return(0);
+ return 0;
}
__initcall(setup_iomem);
-
-/*
- * 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/process.c b/arch/um/kernel/process.c
new file mode 100644
index 00000000000..f17bca8ed2c
--- /dev/null
+++ b/arch/um/kernel/process.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright 2003 PathScale, Inc.
+ * Licensed under the GPL
+ */
+
+#include <linux/stddef.h>
+#include <linux/err.h>
+#include <linux/hardirq.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/personality.h>
+#include <linux/proc_fs.h>
+#include <linux/ptrace.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/tick.h>
+#include <linux/threads.h>
+#include <linux/tracehook.h>
+#include <asm/current.h>
+#include <asm/pgtable.h>
+#include <asm/mmu_context.h>
+#include <asm/uaccess.h>
+#include <as-layout.h>
+#include <kern_util.h>
+#include <os.h>
+#include <skas.h>
+
+/*
+ * This is a per-cpu array. A processor only modifies its entry and it only
+ * cares about its entry, so it's OK if another processor is modifying its
+ * entry.
+ */
+struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
+
+static inline int external_pid(void)
+{
+ /* FIXME: Need to look up userspace_pid by cpu */
+ return userspace_pid[0];
+}
+
+int pid_to_processor_id(int pid)
+{
+ int i;
+
+ for (i = 0; i < ncpus; i++) {
+ if (cpu_tasks[i].pid == pid)
+ return i;
+ }
+ return -1;
+}
+
+void free_stack(unsigned long stack, int order)
+{
+ free_pages(stack, order);
+}
+
+unsigned long alloc_stack(int order, int atomic)
+{
+ unsigned long page;
+ gfp_t flags = GFP_KERNEL;
+
+ if (atomic)
+ flags = GFP_ATOMIC;
+ page = __get_free_pages(flags, order);
+
+ return page;
+}
+
+static inline void set_current(struct task_struct *task)
+{
+ cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
+ { external_pid(), task });
+}
+
+extern void arch_switch_to(struct task_struct *to);
+
+void *__switch_to(struct task_struct *from, struct task_struct *to)
+{
+ to->thread.prev_sched = from;
+ set_current(to);
+
+ switch_threads(&from->thread.switch_buf, &to->thread.switch_buf);
+ arch_switch_to(current);
+
+ return current->thread.prev_sched;
+}
+
+void interrupt_end(void)
+{
+ if (need_resched())
+ schedule();
+ if (test_thread_flag(TIF_SIGPENDING))
+ do_signal();
+ if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME))
+ tracehook_notify_resume(&current->thread.regs);
+}
+
+void exit_thread(void)
+{
+}
+
+int get_current_pid(void)
+{
+ return task_pid_nr(current);
+}
+
+/*
+ * This is called magically, by its address being stuffed in a jmp_buf
+ * and being longjmp-d to.
+ */
+void new_thread_handler(void)
+{
+ int (*fn)(void *), n;
+ void *arg;
+
+ if (current->thread.prev_sched != NULL)
+ schedule_tail(current->thread.prev_sched);
+ current->thread.prev_sched = NULL;
+
+ fn = current->thread.request.u.thread.proc;
+ arg = current->thread.request.u.thread.arg;
+
+ /*
+ * callback returns only if the kernel thread execs a process
+ */
+ n = fn(arg);
+ userspace(&current->thread.regs.regs);
+}
+
+/* Called magically, see new_thread_handler above */
+void fork_handler(void)
+{
+ force_flush_all();
+
+ schedule_tail(current->thread.prev_sched);
+
+ /*
+ * XXX: if interrupt_end() calls schedule, this call to
+ * arch_switch_to isn't needed. We could want to apply this to
+ * improve performance. -bb
+ */
+ arch_switch_to(current);
+
+ current->thread.prev_sched = NULL;
+
+ userspace(&current->thread.regs.regs);
+}
+
+int copy_thread(unsigned long clone_flags, unsigned long sp,
+ unsigned long arg, struct task_struct * p)
+{
+ void (*handler)(void);
+ int kthread = current->flags & PF_KTHREAD;
+ int ret = 0;
+
+ p->thread = (struct thread_struct) INIT_THREAD;
+
+ if (!kthread) {
+ memcpy(&p->thread.regs.regs, current_pt_regs(),
+ sizeof(p->thread.regs.regs));
+ PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0);
+ if (sp != 0)
+ REGS_SP(p->thread.regs.regs.gp) = sp;
+
+ handler = fork_handler;
+
+ arch_copy_thread(&current->thread.arch, &p->thread.arch);
+ } else {
+ get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp);
+ p->thread.request.u.thread.proc = (int (*)(void *))sp;
+ p->thread.request.u.thread.arg = (void *)arg;
+ handler = new_thread_handler;
+ }
+
+ new_thread(task_stack_page(p), &p->thread.switch_buf, handler);
+
+ if (!kthread) {
+ clear_flushed_tls(p);
+
+ /*
+ * Set a new TLS for the child thread?
+ */
+ if (clone_flags & CLONE_SETTLS)
+ ret = arch_copy_tls(p);
+ }
+
+ return ret;
+}
+
+void initial_thread_cb(void (*proc)(void *), void *arg)
+{
+ int save_kmalloc_ok = kmalloc_ok;
+
+ kmalloc_ok = 0;
+ initial_thread_cb_skas(proc, arg);
+ kmalloc_ok = save_kmalloc_ok;
+}
+
+void arch_cpu_idle(void)
+{
+ unsigned long long nsecs;
+
+ cpu_tasks[current_thread_info()->cpu].pid = os_getpid();
+ nsecs = disable_timer();
+ idle_sleep(nsecs);
+ local_irq_enable();
+}
+
+int __cant_sleep(void) {
+ return in_atomic() || irqs_disabled() || in_interrupt();
+ /* Is in_interrupt() really needed? */
+}
+
+int user_context(unsigned long sp)
+{
+ unsigned long stack;
+
+ stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
+ return stack != (unsigned long) current_thread_info();
+}
+
+extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
+
+void do_uml_exitcalls(void)
+{
+ exitcall_t *call;
+
+ call = &__uml_exitcall_end;
+ while (--call >= &__uml_exitcall_begin)
+ (*call)();
+}
+
+char *uml_strdup(const char *string)
+{
+ return kstrdup(string, GFP_KERNEL);
+}
+EXPORT_SYMBOL(uml_strdup);
+
+int copy_to_user_proc(void __user *to, void *from, int size)
+{
+ return copy_to_user(to, from, size);
+}
+
+int copy_from_user_proc(void *to, void __user *from, int size)
+{
+ return copy_from_user(to, from, size);
+}
+
+int clear_user_proc(void __user *buf, int size)
+{
+ return clear_user(buf, size);
+}
+
+int strlen_user_proc(char __user *str)
+{
+ return strlen_user(str);
+}
+
+int smp_sigio_handler(void)
+{
+#ifdef CONFIG_SMP
+ int cpu = current_thread_info()->cpu;
+ IPI_handler(cpu);
+ if (cpu != 0)
+ return 1;
+#endif
+ return 0;
+}
+
+int cpu(void)
+{
+ return current_thread_info()->cpu;
+}
+
+static atomic_t using_sysemu = ATOMIC_INIT(0);
+int sysemu_supported;
+
+void set_using_sysemu(int value)
+{
+ if (value > sysemu_supported)
+ return;
+ atomic_set(&using_sysemu, value);
+}
+
+int get_using_sysemu(void)
+{
+ return atomic_read(&using_sysemu);
+}
+
+static int sysemu_proc_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%d\n", get_using_sysemu());
+ return 0;
+}
+
+static int sysemu_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, sysemu_proc_show, NULL);
+}
+
+static ssize_t sysemu_proc_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ char tmp[2];
+
+ if (copy_from_user(tmp, buf, 1))
+ return -EFAULT;
+
+ if (tmp[0] >= '0' && tmp[0] <= '2')
+ set_using_sysemu(tmp[0] - '0');
+ /* We use the first char, but pretend to write everything */
+ return count;
+}
+
+static const struct file_operations sysemu_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = sysemu_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = sysemu_proc_write,
+};
+
+int __init make_proc_sysemu(void)
+{
+ struct proc_dir_entry *ent;
+ if (!sysemu_supported)
+ return 0;
+
+ ent = proc_create("sysemu", 0600, NULL, &sysemu_proc_fops);
+
+ if (ent == NULL)
+ {
+ printk(KERN_WARNING "Failed to register /proc/sysemu\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+late_initcall(make_proc_sysemu);
+
+int singlestepping(void * t)
+{
+ struct task_struct *task = t ? t : current;
+
+ if (!(task->ptrace & PT_DTRACE))
+ return 0;
+
+ if (task->thread.singlestep_syscall)
+ return 1;
+
+ return 2;
+}
+
+/*
+ * Only x86 and x86_64 have an arch_align_stack().
+ * All other arches have "#define arch_align_stack(x) (x)"
+ * in their asm/exec.h
+ * As this is included in UML from asm-um/system-generic.h,
+ * we can use it to behave as the subarch does.
+ */
+#ifndef arch_align_stack
+unsigned long arch_align_stack(unsigned long sp)
+{
+ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+ sp -= get_random_int() % 8192;
+ return sp & ~0xf;
+}
+#endif
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long stack_page, sp, ip;
+ bool seen_sched = 0;
+
+ if ((p == NULL) || (p == current) || (p->state == TASK_RUNNING))
+ return 0;
+
+ stack_page = (unsigned long) task_stack_page(p);
+ /* Bail if the process has no kernel stack for some reason */
+ if (stack_page == 0)
+ return 0;
+
+ sp = p->thread.switch_buf->JB_SP;
+ /*
+ * Bail if the stack pointer is below the bottom of the kernel
+ * stack for some reason
+ */
+ if (sp < stack_page)
+ return 0;
+
+ while (sp < stack_page + THREAD_SIZE) {
+ ip = *((unsigned long *) sp);
+ if (in_sched_functions(ip))
+ /* Ignore everything until we're above the scheduler */
+ seen_sched = 1;
+ else if (kernel_text_address(ip) && seen_sched)
+ return ip;
+
+ sp += sizeof(unsigned long);
+ }
+
+ return 0;
+}
+
+int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
+{
+ int cpu = current_thread_info()->cpu;
+
+ return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu);
+}
+
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
deleted file mode 100644
index 34b54a3e213..00000000000
--- a/arch/um/kernel/process_kern.c
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Copyright 2003 PathScale, Inc.
- * Licensed under the GPL
- */
-
-#include "linux/config.h"
-#include "linux/kernel.h"
-#include "linux/sched.h"
-#include "linux/interrupt.h"
-#include "linux/string.h"
-#include "linux/mm.h"
-#include "linux/slab.h"
-#include "linux/utsname.h"
-#include "linux/fs.h"
-#include "linux/utime.h"
-#include "linux/smp_lock.h"
-#include "linux/module.h"
-#include "linux/init.h"
-#include "linux/capability.h"
-#include "linux/vmalloc.h"
-#include "linux/spinlock.h"
-#include "linux/proc_fs.h"
-#include "linux/ptrace.h"
-#include "linux/random.h"
-#include "asm/unistd.h"
-#include "asm/mman.h"
-#include "asm/segment.h"
-#include "asm/stat.h"
-#include "asm/pgtable.h"
-#include "asm/processor.h"
-#include "asm/tlbflush.h"
-#include "asm/uaccess.h"
-#include "asm/user.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "kern.h"
-#include "signal_kern.h"
-#include "signal_user.h"
-#include "init.h"
-#include "irq_user.h"
-#include "mem_user.h"
-#include "time_user.h"
-#include "tlb.h"
-#include "frame_kern.h"
-#include "sigcontext.h"
-#include "os.h"
-#include "mode.h"
-#include "mode_kern.h"
-#include "choose-mode.h"
-
-/* This is a per-cpu array. A processor only modifies its entry and it only
- * cares about its entry, so it's OK if another processor is modifying its
- * entry.
- */
-struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
-
-int external_pid(void *t)
-{
- struct task_struct *task = t ? t : current;
-
- return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
-}
-
-int pid_to_processor_id(int pid)
-{
- int i;
-
- for(i = 0; i < ncpus; i++){
- if(cpu_tasks[i].pid == pid) return(i);
- }
- return(-1);
-}
-
-void free_stack(unsigned long stack, int order)
-{
- free_pages(stack, order);
-}
-
-unsigned long alloc_stack(int order, int atomic)
-{
- unsigned long page;
- gfp_t flags = GFP_KERNEL;
-
- if (atomic)
- flags = GFP_ATOMIC;
- page = __get_free_pages(flags, order);
- if(page == 0)
- return(0);
- stack_protections(page);
- return(page);
-}
-
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- int pid;
-
- current->thread.request.u.thread.proc = fn;
- current->thread.request.u.thread.arg = arg;
- pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0,
- &current->thread.regs, 0, NULL, NULL);
- if(pid < 0)
- panic("do_fork failed in kernel_thread, errno = %d", pid);
- return(pid);
-}
-
-void set_current(void *t)
-{
- struct task_struct *task = t;
-
- cpu_tasks[task->thread_info->cpu] = ((struct cpu_task)
- { external_pid(task), task });
-}
-
-void *_switch_to(void *prev, void *next, void *last)
-{
- struct task_struct *from = prev;
- struct task_struct *to= next;
-
- to->thread.prev_sched = from;
- set_current(to);
-
- do {
- current->thread.saved_task = NULL ;
- CHOOSE_MODE_PROC(switch_to_tt, switch_to_skas, prev, next);
- if(current->thread.saved_task)
- show_regs(&(current->thread.regs));
- next= current->thread.saved_task;
- prev= current;
- } while(current->thread.saved_task);
-
- return(current->thread.prev_sched);
-
-}
-
-void interrupt_end(void)
-{
- if(need_resched()) schedule();
- if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal();
-}
-
-void release_thread(struct task_struct *task)
-{
- CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
-}
-
-void exit_thread(void)
-{
- unprotect_stack((unsigned long) current_thread);
-}
-
-void *get_current(void)
-{
- return(current);
-}
-
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
- unsigned long stack_top, struct task_struct * p,
- struct pt_regs *regs)
-{
- p->thread = (struct thread_struct) INIT_THREAD;
- return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
- clone_flags, sp, stack_top, p, regs));
-}
-
-void initial_thread_cb(void (*proc)(void *), void *arg)
-{
- int save_kmalloc_ok = kmalloc_ok;
-
- kmalloc_ok = 0;
- CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc,
- arg);
- kmalloc_ok = save_kmalloc_ok;
-}
-
-unsigned long stack_sp(unsigned long page)
-{
- return(page + PAGE_SIZE - sizeof(void *));
-}
-
-int current_pid(void)
-{
- return(current->pid);
-}
-
-void default_idle(void)
-{
- CHOOSE_MODE(uml_idle_timer(), (void) 0);
-
- atomic_inc(&init_mm.mm_count);
- current->mm = &init_mm;
- current->active_mm = &init_mm;
-
- while(1){
- /* endless idle loop with no priority at all */
-
- /*
- * although we are an idle CPU, we do not want to
- * get into the scheduler unnecessarily.
- */
- if(need_resched())
- schedule();
-
- idle_sleep(10);
- }
-}
-
-void cpu_idle(void)
-{
- CHOOSE_MODE(init_idle_tt(), init_idle_skas());
-}
-
-int page_size(void)
-{
- return(PAGE_SIZE);
-}
-
-void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
- pte_t *pte_out)
-{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- pte_t ptent;
-
- if(task->mm == NULL)
- return(ERR_PTR(-EINVAL));
- pgd = pgd_offset(task->mm, addr);
- if(!pgd_present(*pgd))
- return(ERR_PTR(-EINVAL));
-
- pud = pud_offset(pgd, addr);
- if(!pud_present(*pud))
- return(ERR_PTR(-EINVAL));
-
- pmd = pmd_offset(pud, addr);
- if(!pmd_present(*pmd))
- return(ERR_PTR(-EINVAL));
-
- pte = pte_offset_kernel(pmd, addr);
- ptent = *pte;
- if(!pte_present(ptent))
- return(ERR_PTR(-EINVAL));
-
- if(pte_out != NULL)
- *pte_out = ptent;
- return((void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK));
-}
-
-char *current_cmd(void)
-{
-#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
- return("(Unknown)");
-#else
- void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
- return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
-#endif
-}
-
-void force_sigbus(void)
-{
- printk(KERN_ERR "Killing pid %d because of a lack of memory\n",
- current->pid);
- lock_kernel();
- sigaddset(&current->pending.signal, SIGBUS);
- recalc_sigpending();
- current->flags |= PF_SIGNALED;
- do_exit(SIGBUS | 0x80);
-}
-
-void dump_thread(struct pt_regs *regs, struct user *u)
-{
-}
-
-void enable_hlt(void)
-{
- panic("enable_hlt");
-}
-
-EXPORT_SYMBOL(enable_hlt);
-
-void disable_hlt(void)
-{
- panic("disable_hlt");
-}
-
-EXPORT_SYMBOL(disable_hlt);
-
-void *um_kmalloc(int size)
-{
- return(kmalloc(size, GFP_KERNEL));
-}
-
-void *um_kmalloc_atomic(int size)
-{
- return(kmalloc(size, GFP_ATOMIC));
-}
-
-void *um_vmalloc(int size)
-{
- return(vmalloc(size));
-}
-
-unsigned long get_fault_addr(void)
-{
- return((unsigned long) current->thread.fault_addr);
-}
-
-EXPORT_SYMBOL(get_fault_addr);
-
-void not_implemented(void)
-{
- printk(KERN_DEBUG "Something isn't implemented in here\n");
-}
-
-EXPORT_SYMBOL(not_implemented);
-
-int user_context(unsigned long sp)
-{
- unsigned long stack;
-
- stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
- return(stack != (unsigned long) current_thread);
-}
-
-extern void remove_umid_dir(void);
-
-__uml_exitcall(remove_umid_dir);
-
-extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
-
-void do_uml_exitcalls(void)
-{
- exitcall_t *call;
-
- call = &__uml_exitcall_end;
- while (--call >= &__uml_exitcall_begin)
- (*call)();
-}
-
-char *uml_strdup(char *string)
-{
- return kstrdup(string, GFP_KERNEL);
-}
-
-int copy_to_user_proc(void __user *to, void *from, int size)
-{
- return(copy_to_user(to, from, size));
-}
-
-int copy_from_user_proc(void *to, void __user *from, int size)
-{
- return(copy_from_user(to, from, size));
-}
-
-int clear_user_proc(void __user *buf, int size)
-{
- return(clear_user(buf, size));
-}
-
-int strlen_user_proc(char __user *str)
-{
- return(strlen_user(str));
-}
-
-int smp_sigio_handler(void)
-{
-#ifdef CONFIG_SMP
- int cpu = current_thread->cpu;
- IPI_handler(cpu);
- if(cpu != 0)
- return(1);
-#endif
- return(0);
-}
-
-int um_in_interrupt(void)
-{
- return(in_interrupt());
-}
-
-int cpu(void)
-{
- return(current_thread->cpu);
-}
-
-static atomic_t using_sysemu = ATOMIC_INIT(0);
-int sysemu_supported;
-
-void set_using_sysemu(int value)
-{
- if (value > sysemu_supported)
- return;
- atomic_set(&using_sysemu, value);
-}
-
-int get_using_sysemu(void)
-{
- return atomic_read(&using_sysemu);
-}
-
-static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
-{
- if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/
- *eof = 1;
-
- return strlen(buf);
-}
-
-static int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data)
-{
- char tmp[2];
-
- if (copy_from_user(tmp, buf, 1))
- return -EFAULT;
-
- if (tmp[0] >= '0' && tmp[0] <= '2')
- set_using_sysemu(tmp[0] - '0');
- return count; /*We use the first char, but pretend to write everything*/
-}
-
-int __init make_proc_sysemu(void)
-{
- struct proc_dir_entry *ent;
- if (!sysemu_supported)
- return 0;
-
- ent = create_proc_entry("sysemu", 0600, &proc_root);
-
- if (ent == NULL)
- {
- printk(KERN_WARNING "Failed to register /proc/sysemu\n");
- return(0);
- }
-
- ent->read_proc = proc_read_sysemu;
- ent->write_proc = proc_write_sysemu;
-
- return 0;
-}
-
-late_initcall(make_proc_sysemu);
-
-int singlestepping(void * t)
-{
- struct task_struct *task = t ? t : current;
-
- if ( ! (task->ptrace & PT_DTRACE) )
- return(0);
-
- if (task->thread.singlestep_syscall)
- return(1);
-
- return 2;
-}
-
-/*
- * Only x86 and x86_64 have an arch_align_stack().
- * All other arches have "#define arch_align_stack(x) (x)"
- * in their asm/system.h
- * As this is included in UML from asm-um/system-generic.h,
- * we can use it to behave as the subarch does.
- */
-#ifndef arch_align_stack
-unsigned long arch_align_stack(unsigned long sp)
-{
- if (randomize_va_space)
- sp -= get_random_int() % 8192;
- return sp & ~0xf;
-}
-#endif
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index 98e09395c09..694d551c889 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -1,34 +1,34 @@
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/sched.h"
-#include "linux/mm.h"
-#include "linux/errno.h"
-#include "linux/smp_lock.h"
-#include "linux/security.h"
-#include "linux/ptrace.h"
-#include "linux/audit.h"
-#ifdef CONFIG_PROC_MM
-#include "linux/proc_mm.h"
+#include <linux/audit.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/tracehook.h>
+#include <asm/uaccess.h>
+#include <skas_ptrace.h>
+
+
+
+void user_enable_single_step(struct task_struct *child)
+{
+ child->ptrace |= PT_DTRACE;
+ child->thread.singlestep_syscall = 0;
+
+#ifdef SUBARCH_SET_SINGLESTEPPING
+ SUBARCH_SET_SINGLESTEPPING(child, 1);
#endif
-#include "asm/ptrace.h"
-#include "asm/uaccess.h"
-#include "kern_util.h"
-#include "skas_ptrace.h"
-#include "sysdep/ptrace.h"
+}
-static inline void set_singlestepping(struct task_struct *child, int on)
+void user_disable_single_step(struct task_struct *child)
{
- if (on)
- child->ptrace |= PT_DTRACE;
- else
- child->ptrace &= ~PT_DTRACE;
- child->thread.singlestep_syscall = 0;
+ child->ptrace &= ~PT_DTRACE;
+ child->thread.singlestep_syscall = 0;
#ifdef SUBARCH_SET_SINGLESTEPPING
- SUBARCH_SET_SINGLESTEPPING(child, on);
+ SUBARCH_SET_SINGLESTEPPING(child, 0);
#endif
}
@@ -36,115 +36,45 @@ static inline void set_singlestepping(struct task_struct *child, int on)
* Called by kernel/ptrace.c when detaching..
*/
void ptrace_disable(struct task_struct *child)
-{
- set_singlestepping(child,0);
+{
+ user_disable_single_step(child);
}
extern int peek_user(struct task_struct * child, long addr, long data);
extern int poke_user(struct task_struct * child, long addr, long data);
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
{
int i, ret;
+ unsigned long __user *p = (void __user *)data;
+ void __user *vp = p;
switch (request) {
- /* when I and D space are separate, these will need to be fixed. */
- case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- ret = -EIO;
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp, (unsigned long __user *) data);
- break;
- }
-
/* read the word at location addr in the USER area. */
- case PTRACE_PEEKUSR:
- ret = peek_user(child, addr, data);
- break;
-
- /* when I and D space are separate, this will have to be fixed. */
- case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA:
- ret = -EIO;
- if (access_process_vm(child, addr, &data, sizeof(data),
- 1) != sizeof(data))
- break;
- ret = 0;
- break;
-
- case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
- ret = poke_user(child, addr, data);
- break;
-
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
-
- set_singlestepping(child, 0);
- if (request == PTRACE_SYSCALL) {
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- }
- else {
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- }
- child->exit_code = data;
- wake_up_process(child);
- ret = 0;
+ case PTRACE_PEEKUSR:
+ ret = peek_user(child, addr, data);
break;
- }
-/*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL: {
- ret = 0;
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- break;
-
- set_singlestepping(child, 0);
- child->exit_code = SIGKILL;
- wake_up_process(child);
+ /* write the word at location addr in the USER area */
+ case PTRACE_POKEUSR:
+ ret = poke_user(child, addr, data);
break;
- }
- case PTRACE_SINGLESTEP: { /* set the trap flag. */
+ case PTRACE_SYSEMU:
+ case PTRACE_SYSEMU_SINGLESTEP:
ret = -EIO;
- if (!valid_signal(data))
- break;
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- set_singlestepping(child, 1);
- child->exit_code = data;
- /* give it a chance to run. */
- wake_up_process(child);
- ret = 0;
break;
- }
-
- case PTRACE_DETACH:
- /* detach a process that was attached. */
- ret = ptrace_detach(child, data);
- break;
#ifdef PTRACE_GETREGS
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
- if (!access_ok(VERIFY_WRITE, (unsigned long *)data,
- MAX_REG_OFFSET)) {
+ if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
ret = -EIO;
break;
}
for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
- __put_user(getreg(child, i),
- (unsigned long __user *) data);
- data += sizeof(long);
+ __put_user(getreg(child, i), p);
+ p++;
}
ret = 0;
break;
@@ -153,50 +83,36 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#ifdef PTRACE_SETREGS
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
unsigned long tmp = 0;
- if (!access_ok(VERIFY_READ, (unsigned *)data,
- MAX_REG_OFFSET)) {
+ if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) {
ret = -EIO;
break;
}
for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
- __get_user(tmp, (unsigned long __user *) data);
+ __get_user(tmp, p);
putreg(child, i, tmp);
- data += sizeof(long);
+ p++;
}
ret = 0;
break;
}
#endif
-#ifdef PTRACE_GETFPREGS
- case PTRACE_GETFPREGS: /* Get the child FPU state. */
- ret = get_fpregs(data, child);
- break;
-#endif
-#ifdef PTRACE_SETFPREGS
- case PTRACE_SETFPREGS: /* Set the child FPU state. */
- ret = set_fpregs(data, child);
+ case PTRACE_GET_THREAD_AREA:
+ ret = ptrace_get_thread_area(child, addr, vp);
break;
-#endif
-#ifdef PTRACE_GETFPXREGS
- case PTRACE_GETFPXREGS: /* Get the child FPU state. */
- ret = get_fpxregs(data, child);
- break;
-#endif
-#ifdef PTRACE_SETFPXREGS
- case PTRACE_SETFPXREGS: /* Set the child FPU state. */
- ret = set_fpxregs(data, child);
+
+ case PTRACE_SET_THREAD_AREA:
+ ret = ptrace_set_thread_area(child, addr, vp);
break;
-#endif
+
case PTRACE_FAULTINFO: {
- /* Take the info from thread->arch->faultinfo,
- * but transfer max. sizeof(struct ptrace_faultinfo).
- * On i386, ptrace_faultinfo is smaller!
- */
- ret = copy_to_user((unsigned long __user *) data,
- &child->thread.arch.faultinfo,
- sizeof(struct ptrace_faultinfo));
- if(ret)
- break;
+ /*
+ * Take the info from thread->arch->faultinfo,
+ * but transfer max. sizeof(struct ptrace_faultinfo).
+ * On i386, ptrace_faultinfo is smaller!
+ */
+ ret = copy_to_user(p, &child->thread.arch.faultinfo,
+ sizeof(struct ptrace_faultinfo)) ?
+ -EIO : 0;
break;
}
@@ -204,46 +120,30 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_LDT: {
struct ptrace_ldt ldt;
- if(copy_from_user(&ldt, (unsigned long __user *) data,
- sizeof(ldt))){
+ if (copy_from_user(&ldt, p, sizeof(ldt))) {
ret = -EIO;
break;
}
- /* This one is confusing, so just punt and return -EIO for
+ /*
+ * This one is confusing, so just punt and return -EIO for
* now
*/
ret = -EIO;
break;
}
#endif
-#ifdef CONFIG_PROC_MM
- case PTRACE_SWITCH_MM: {
- struct mm_struct *old = child->mm;
- struct mm_struct *new = proc_mm_get_mm(data);
-
- if(IS_ERR(new)){
- ret = PTR_ERR(new);
- break;
- }
-
- atomic_inc(&new->mm_users);
- child->mm = new;
- child->active_mm = new;
- mmput(old);
- ret = 0;
- break;
- }
-#endif
default:
ret = ptrace_request(child, request, addr, data);
+ if (ret == -EIO)
+ ret = subarch_ptrace(child, request, addr, data);
break;
}
return ret;
}
-void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
+static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs,
int error_code)
{
struct siginfo info;
@@ -255,56 +155,44 @@ void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
/* User-mode eip? */
info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL;
- /* Send us the fakey SIGTRAP */
+ /* Send us the fake SIGTRAP */
force_sig_info(SIGTRAP, &info, tsk);
}
-/* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
+/*
+ * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
* PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
*/
-void syscall_trace(union uml_pt_regs *regs, int entryexit)
+void syscall_trace_enter(struct pt_regs *regs)
{
- int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
- int tracesysgood;
-
- if (unlikely(current->audit_context)) {
- if (!entryexit)
- audit_syscall_entry(current,
- HOST_AUDIT_ARCH,
- UPT_SYSCALL_NR(regs),
- UPT_SYSCALL_ARG1(regs),
- UPT_SYSCALL_ARG2(regs),
- UPT_SYSCALL_ARG3(regs),
- UPT_SYSCALL_ARG4(regs));
- else audit_syscall_exit(current,
- AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
- UPT_SYSCALL_RET(regs));
- }
-
- /* Fake a debug trap */
- if (is_singlestep)
- send_sigtrap(current, regs, 0);
+ audit_syscall_entry(HOST_AUDIT_ARCH,
+ UPT_SYSCALL_NR(&regs->regs),
+ UPT_SYSCALL_ARG1(&regs->regs),
+ UPT_SYSCALL_ARG2(&regs->regs),
+ UPT_SYSCALL_ARG3(&regs->regs),
+ UPT_SYSCALL_ARG4(&regs->regs));
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return;
- if (!(current->ptrace & PT_PTRACED))
- return;
+ tracehook_report_syscall_entry(regs);
+}
- /* the 0x80 provides a way for the tracing parent to distinguish
- between a syscall stop and SIGTRAP delivery */
- tracesysgood = (current->ptrace & PT_TRACESYSGOOD);
- ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
+void syscall_trace_leave(struct pt_regs *regs)
+{
+ int ptraced = current->ptrace;
- if (entryexit) /* force do_signal() --> is_syscall() */
- set_thread_flag(TIF_SIGPENDING);
+ audit_syscall_exit(regs);
- /* this isn't the same as continuing with a signal, but it will do
- * for normal use. strace only continues with a signal if the
- * stopping signal is not SIGTRAP. -brl
- */
- if (current->exit_code) {
- send_sig(current->exit_code, current, 1);
- current->exit_code = 0;
- }
+ /* Fake a debug trap */
+ if (ptraced & PT_DTRACE)
+ send_sigtrap(current, &regs->regs, 0);
+
+ if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ return;
+
+ tracehook_report_syscall_exit(regs, 0);
+ /* force do_signal() --> is_syscall() */
+ if (ptraced & PT_PTRACED)
+ set_thread_flag(TIF_SIGPENDING);
}
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index a637e885c58..ced8903921a 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -1,72 +1,64 @@
/*
- * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/module.h"
-#include "linux/sched.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "kern.h"
-#include "os.h"
-#include "mode.h"
-#include "choose-mode.h"
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/oom.h>
+#include <kern_util.h>
+#include <os.h>
+#include <skas.h>
-#ifdef CONFIG_SMP
-static void kill_idlers(int me)
-{
-#ifdef CONFIG_MODE_TT
- struct task_struct *p;
- int i;
-
- for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){
- p = idle_threads[i];
- if((p != NULL) && (p->thread.mode.tt.extern_pid != me))
- os_kill_process(p->thread.mode.tt.extern_pid, 0);
- }
-#endif
-}
-#endif
+void (*pm_power_off)(void);
static void kill_off_processes(void)
{
- CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas());
-#ifdef CONFIG_SMP
- kill_idlers(os_getpid());
-#endif
+ if (proc_mm)
+ /*
+ * FIXME: need to loop over userspace_pids
+ */
+ os_kill_ptraced_process(userspace_pid[0], 1);
+ else {
+ struct task_struct *p;
+ int pid;
+
+ read_lock(&tasklist_lock);
+ for_each_process(p) {
+ struct task_struct *t;
+
+ t = find_lock_task_mm(p);
+ if (!t)
+ continue;
+ pid = t->mm->context.id.u.pid;
+ task_unlock(t);
+ os_kill_ptraced_process(pid, 1);
+ }
+ read_unlock(&tasklist_lock);
+ }
}
void uml_cleanup(void)
{
- kmalloc_ok = 0;
+ kmalloc_ok = 0;
do_uml_exitcalls();
kill_off_processes();
}
void machine_restart(char * __unused)
{
- uml_cleanup();
- CHOOSE_MODE(reboot_tt(), reboot_skas());
+ uml_cleanup();
+ reboot_skas();
}
void machine_power_off(void)
{
- uml_cleanup();
- CHOOSE_MODE(halt_tt(), halt_skas());
+ uml_cleanup();
+ halt_skas();
}
void machine_halt(void)
{
machine_power_off();
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/resource.c b/arch/um/kernel/resource.c
deleted file mode 100644
index 32188e12e8a..00000000000
--- a/arch/um/kernel/resource.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/pci.h"
-
-unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
- unsigned long start, unsigned long size)
-{
- return start;
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c
new file mode 100644
index 00000000000..b5e0cbb3438
--- /dev/null
+++ b/arch/um/kernel/sigio.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/interrupt.h>
+#include <irq_kern.h>
+#include <os.h>
+#include <sigio.h>
+
+/* Protected by sigio_lock() called from write_sigio_workaround */
+static int sigio_irq_fd = -1;
+
+static irqreturn_t sigio_interrupt(int irq, void *data)
+{
+ char c;
+
+ os_read_file(sigio_irq_fd, &c, sizeof(c));
+ reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
+ return IRQ_HANDLED;
+}
+
+int write_sigio_irq(int fd)
+{
+ int err;
+
+ err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
+ 0, "write sigio", NULL);
+ if (err) {
+ printk(KERN_ERR "write_sigio_irq : um_request_irq failed, "
+ "err = %d\n", err);
+ return -1;
+ }
+ sigio_irq_fd = fd;
+ return 0;
+}
+
+/* These are called from os-Linux/sigio.c to protect its pollfds arrays. */
+static DEFINE_SPINLOCK(sigio_spinlock);
+
+void sigio_lock(void)
+{
+ spin_lock(&sigio_spinlock);
+}
+
+void sigio_unlock(void)
+{
+ spin_unlock(&sigio_spinlock);
+}
diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c
deleted file mode 100644
index 229988463c4..00000000000
--- a/arch/um/kernel/sigio_kern.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
- * Licensed under the GPL
- */
-
-#include "linux/kernel.h"
-#include "linux/list.h"
-#include "linux/slab.h"
-#include "linux/signal.h"
-#include "linux/interrupt.h"
-#include "init.h"
-#include "sigio.h"
-#include "irq_user.h"
-#include "irq_kern.h"
-
-/* Protected by sigio_lock() called from write_sigio_workaround */
-static int sigio_irq_fd = -1;
-
-static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
-{
- read_sigio_fd(sigio_irq_fd);
- reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
- return(IRQ_HANDLED);
-}
-
-int write_sigio_irq(int fd)
-{
- int err;
-
- err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
- SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio",
- NULL);
- if(err){
- printk("write_sigio_irq : um_request_irq failed, err = %d\n",
- err);
- return(-1);
- }
- sigio_irq_fd = fd;
- return(0);
-}
-
-static DEFINE_SPINLOCK(sigio_spinlock);
-
-void sigio_lock(void)
-{
- spin_lock(&sigio_spinlock);
-}
-
-void sigio_unlock(void)
-{
- spin_unlock(&sigio_spinlock);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
deleted file mode 100644
index 3fbfd956bfe..00000000000
--- a/arch/um/kernel/sigio_user.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <pty.h>
-#include <signal.h>
-#include <errno.h>
-#include <string.h>
-#include <sched.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-#include "init.h"
-#include "user.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "sigio.h"
-#include "os.h"
-
-/* Changed during early boot */
-int pty_output_sigio = 0;
-int pty_close_sigio = 0;
-
-/* Used as a flag during SIGIO testing early in boot */
-static volatile int got_sigio = 0;
-
-void __init handler(int sig)
-{
- got_sigio = 1;
-}
-
-struct openpty_arg {
- int master;
- int slave;
- int err;
-};
-
-static void openpty_cb(void *arg)
-{
- struct openpty_arg *info = arg;
-
- info->err = 0;
- if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
- info->err = -errno;
-}
-
-void __init check_one_sigio(void (*proc)(int, int))
-{
- struct sigaction old, new;
- struct openpty_arg pty = { .master = -1, .slave = -1 };
- int master, slave, err;
-
- initial_thread_cb(openpty_cb, &pty);
- if(pty.err){
- printk("openpty failed, errno = %d\n", -pty.err);
- return;
- }
-
- master = pty.master;
- slave = pty.slave;
-
- if((master == -1) || (slave == -1)){
- printk("openpty failed to allocate a pty\n");
- return;
- }
-
- /* Not now, but complain so we now where we failed. */
- err = raw(master);
- if (err < 0)
- panic("check_sigio : __raw failed, errno = %d\n", -err);
-
- err = os_sigio_async(master, slave);
- if(err < 0)
- panic("tty_fds : sigio_async failed, err = %d\n", -err);
-
- if(sigaction(SIGIO, NULL, &old) < 0)
- panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
- new = old;
- new.sa_handler = handler;
- if(sigaction(SIGIO, &new, NULL) < 0)
- panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
-
- got_sigio = 0;
- (*proc)(master, slave);
-
- os_close_file(master);
- os_close_file(slave);
-
- if(sigaction(SIGIO, &old, NULL) < 0)
- panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
-}
-
-static void tty_output(int master, int slave)
-{
- int n;
- char buf[512];
-
- printk("Checking that host ptys support output SIGIO...");
-
- memset(buf, 0, sizeof(buf));
-
- while(os_write_file(master, buf, sizeof(buf)) > 0) ;
- if(errno != EAGAIN)
- panic("check_sigio : write failed, errno = %d\n", errno);
- while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
-
- if (got_sigio) {
- printk("Yes\n");
- pty_output_sigio = 1;
- } else if (n == -EAGAIN) {
- printk("No, enabling workaround\n");
- } else {
- panic("check_sigio : read failed, err = %d\n", n);
- }
-}
-
-static void tty_close(int master, int slave)
-{
- printk("Checking that host ptys support SIGIO on close...");
-
- os_close_file(slave);
- if(got_sigio){
- printk("Yes\n");
- pty_close_sigio = 1;
- }
- else printk("No, enabling workaround\n");
-}
-
-void __init check_sigio(void)
-{
- if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
- (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
- printk("No pseudo-terminals available - skipping pty SIGIO "
- "check\n");
- return;
- }
- check_one_sigio(tty_output);
- check_one_sigio(tty_close);
-}
-
-/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
- * exitcall.
- */
-static int write_sigio_pid = -1;
-
-/* These arrays are initialized before the sigio thread is started, and
- * the descriptors closed after it is killed. So, it can't see them change.
- * On the UML side, they are changed under the sigio_lock.
- */
-static int write_sigio_fds[2] = { -1, -1 };
-static int sigio_private[2] = { -1, -1 };
-
-struct pollfds {
- struct pollfd *poll;
- int size;
- int used;
-};
-
-/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread
- * synchronizes with it.
- */
-struct pollfds current_poll = {
- .poll = NULL,
- .size = 0,
- .used = 0
-};
-
-struct pollfds next_poll = {
- .poll = NULL,
- .size = 0,
- .used = 0
-};
-
-static int write_sigio_thread(void *unused)
-{
- struct pollfds *fds, tmp;
- struct pollfd *p;
- int i, n, respond_fd;
- char c;
-
- signal(SIGWINCH, SIG_IGN);
- fds = &current_poll;
- while(1){
- n = poll(fds->poll, fds->used, -1);
- if(n < 0){
- if(errno == EINTR) continue;
- printk("write_sigio_thread : poll returned %d, "
- "errno = %d\n", n, errno);
- }
- for(i = 0; i < fds->used; i++){
- p = &fds->poll[i];
- if(p->revents == 0) continue;
- if(p->fd == sigio_private[1]){
- n = os_read_file(sigio_private[1], &c, sizeof(c));
- if(n != sizeof(c))
- printk("write_sigio_thread : "
- "read failed, err = %d\n", -n);
- tmp = current_poll;
- current_poll = next_poll;
- next_poll = tmp;
- respond_fd = sigio_private[1];
- }
- else {
- respond_fd = write_sigio_fds[1];
- fds->used--;
- memmove(&fds->poll[i], &fds->poll[i + 1],
- (fds->used - i) * sizeof(*fds->poll));
- }
-
- n = os_write_file(respond_fd, &c, sizeof(c));
- if(n != sizeof(c))
- printk("write_sigio_thread : write failed, "
- "err = %d\n", -n);
- }
- }
-}
-
-static int need_poll(int n)
-{
- if(n <= next_poll.size){
- next_poll.used = n;
- return(0);
- }
- if(next_poll.poll != NULL) kfree(next_poll.poll);
- next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
- if(next_poll.poll == NULL){
- printk("need_poll : failed to allocate new pollfds\n");
- next_poll.size = 0;
- next_poll.used = 0;
- return(-1);
- }
- next_poll.size = n;
- next_poll.used = n;
- return(0);
-}
-
-/* Must be called with sigio_lock held, because it's needed by the marked
- * critical section. */
-static void update_thread(void)
-{
- unsigned long flags;
- int n;
- char c;
-
- flags = set_signals(0);
- n = os_write_file(sigio_private[0], &c, sizeof(c));
- if(n != sizeof(c)){
- printk("update_thread : write failed, err = %d\n", -n);
- goto fail;
- }
-
- n = os_read_file(sigio_private[0], &c, sizeof(c));
- if(n != sizeof(c)){
- printk("update_thread : read failed, err = %d\n", -n);
- goto fail;
- }
-
- set_signals(flags);
- return;
- fail:
- /* Critical section start */
- if(write_sigio_pid != -1)
- os_kill_process(write_sigio_pid, 1);
- write_sigio_pid = -1;
- os_close_file(sigio_private[0]);
- os_close_file(sigio_private[1]);
- os_close_file(write_sigio_fds[0]);
- os_close_file(write_sigio_fds[1]);
- /* Critical section end */
- set_signals(flags);
-}
-
-int add_sigio_fd(int fd, int read)
-{
- int err = 0, i, n, events;
-
- sigio_lock();
- for(i = 0; i < current_poll.used; i++){
- if(current_poll.poll[i].fd == fd)
- goto out;
- }
-
- n = current_poll.used + 1;
- err = need_poll(n);
- if(err)
- goto out;
-
- for(i = 0; i < current_poll.used; i++)
- next_poll.poll[i] = current_poll.poll[i];
-
- if(read) events = POLLIN;
- else events = POLLOUT;
-
- next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd,
- .events = events,
- .revents = 0 });
- update_thread();
- out:
- sigio_unlock();
- return(err);
-}
-
-int ignore_sigio_fd(int fd)
-{
- struct pollfd *p;
- int err = 0, i, n = 0;
-
- sigio_lock();
- for(i = 0; i < current_poll.used; i++){
- if(current_poll.poll[i].fd == fd) break;
- }
- if(i == current_poll.used)
- goto out;
-
- err = need_poll(current_poll.used - 1);
- if(err)
- goto out;
-
- for(i = 0; i < current_poll.used; i++){
- p = &current_poll.poll[i];
- if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
- }
- if(n == i){
- printk("ignore_sigio_fd : fd %d not found\n", fd);
- err = -1;
- goto out;
- }
-
- update_thread();
- out:
- sigio_unlock();
- return(err);
-}
-
-static int setup_initial_poll(int fd)
-{
- struct pollfd *p;
-
- p = um_kmalloc_atomic(sizeof(struct pollfd));
- if(p == NULL){
- printk("setup_initial_poll : failed to allocate poll\n");
- return(-1);
- }
- *p = ((struct pollfd) { .fd = fd,
- .events = POLLIN,
- .revents = 0 });
- current_poll = ((struct pollfds) { .poll = p,
- .used = 1,
- .size = 1 });
- return(0);
-}
-
-void write_sigio_workaround(void)
-{
- unsigned long stack;
- int err;
-
- sigio_lock();
- if(write_sigio_pid != -1)
- goto out;
-
- err = os_pipe(write_sigio_fds, 1, 1);
- if(err < 0){
- printk("write_sigio_workaround - os_pipe 1 failed, "
- "err = %d\n", -err);
- goto out;
- }
- err = os_pipe(sigio_private, 1, 1);
- if(err < 0){
- printk("write_sigio_workaround - os_pipe 2 failed, "
- "err = %d\n", -err);
- goto out_close1;
- }
- if(setup_initial_poll(sigio_private[1]))
- goto out_close2;
-
- write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
- CLONE_FILES | CLONE_VM, &stack, 0);
-
- if(write_sigio_pid < 0) goto out_close2;
-
- if(write_sigio_irq(write_sigio_fds[0]))
- goto out_kill;
-
- out:
- sigio_unlock();
- return;
-
- out_kill:
- os_kill_process(write_sigio_pid, 1);
- write_sigio_pid = -1;
- out_close2:
- os_close_file(sigio_private[0]);
- os_close_file(sigio_private[1]);
- out_close1:
- os_close_file(write_sigio_fds[0]);
- os_close_file(write_sigio_fds[1]);
- sigio_unlock();
-}
-
-int read_sigio_fd(int fd)
-{
- int n;
- char c;
-
- n = os_read_file(fd, &c, sizeof(c));
- if(n != sizeof(c)){
- if(n < 0) {
- printk("read_sigio_fd - read failed, err = %d\n", -n);
- return(n);
- }
- else {
- printk("read_sigio_fd - short read, bytes = %d\n", n);
- return(-EIO);
- }
- }
- return(n);
-}
-
-static void sigio_cleanup(void)
-{
- if (write_sigio_pid != -1) {
- os_kill_process(write_sigio_pid, 1);
- write_sigio_pid = -1;
- }
-}
-
-__uml_exitcall(sigio_cleanup);
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
new file mode 100644
index 00000000000..f57e02e7910
--- /dev/null
+++ b/arch/um/kernel/signal.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <asm/siginfo.h>
+#include <asm/signal.h>
+#include <asm/unistd.h>
+#include <frame_kern.h>
+#include <kern_util.h>
+
+EXPORT_SYMBOL(block_signals);
+EXPORT_SYMBOL(unblock_signals);
+
+/*
+ * OK, we're invoking a handler
+ */
+static void handle_signal(struct pt_regs *regs, unsigned long signr,
+ struct k_sigaction *ka, struct siginfo *info)
+{
+ sigset_t *oldset = sigmask_to_save();
+ int singlestep = 0;
+ unsigned long sp;
+ int err;
+
+ if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
+ singlestep = 1;
+
+ /* Did we come from a system call? */
+ if (PT_REGS_SYSCALL_NR(regs) >= 0) {
+ /* If so, check system call restarting.. */
+ switch (PT_REGS_SYSCALL_RET(regs)) {
+ case -ERESTART_RESTARTBLOCK:
+ case -ERESTARTNOHAND:
+ PT_REGS_SYSCALL_RET(regs) = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ PT_REGS_SYSCALL_RET(regs) = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ PT_REGS_RESTART_SYSCALL(regs);
+ PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
+ break;
+ }
+ }
+
+ sp = PT_REGS_SP(regs);
+ if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+
+#ifdef CONFIG_ARCH_HAS_SC_SIGNALS
+ if (!(ka->sa.sa_flags & SA_SIGINFO))
+ err = setup_signal_stack_sc(sp, signr, ka, regs, oldset);
+ else
+#endif
+ err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset);
+
+ if (err)
+ force_sigsegv(signr, current);
+ else
+ signal_delivered(signr, info, ka, regs, singlestep);
+}
+
+static int kern_do_signal(struct pt_regs *regs)
+{
+ struct k_sigaction ka_copy;
+ struct siginfo info;
+ int sig, handled_sig = 0;
+
+ while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) {
+ handled_sig = 1;
+ /* Whee! Actually deliver the signal. */
+ handle_signal(regs, sig, &ka_copy, &info);
+ }
+
+ /* Did we come from a system call? */
+ if (!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)) {
+ /* Restart the system call - no handlers present */
+ switch (PT_REGS_SYSCALL_RET(regs)) {
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+ PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
+ PT_REGS_RESTART_SYSCALL(regs);
+ break;
+ case -ERESTART_RESTARTBLOCK:
+ PT_REGS_ORIG_SYSCALL(regs) = __NR_restart_syscall;
+ PT_REGS_RESTART_SYSCALL(regs);
+ break;
+ }
+ }
+
+ /*
+ * This closes a way to execute a system call on the host. If
+ * you set a breakpoint on a system call instruction and singlestep
+ * from it, the tracing thread used to PTRACE_SINGLESTEP the process
+ * rather than PTRACE_SYSCALL it, allowing the system call to execute
+ * on the host. The tracing thread will check this flag and
+ * PTRACE_SYSCALL if necessary.
+ */
+ if (current->ptrace & PT_DTRACE)
+ current->thread.singlestep_syscall =
+ is_syscall(PT_REGS_IP(&current->thread.regs));
+
+ /*
+ * if there's no signal to deliver, we just put the saved sigmask
+ * back
+ */
+ if (!handled_sig)
+ restore_saved_sigmask();
+ return handled_sig;
+}
+
+int do_signal(void)
+{
+ return kern_do_signal(&current->thread.regs);
+}
diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c
deleted file mode 100644
index 03618bd13d5..00000000000
--- a/arch/um/kernel/signal_kern.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/config.h"
-#include "linux/stddef.h"
-#include "linux/sys.h"
-#include "linux/sched.h"
-#include "linux/wait.h"
-#include "linux/kernel.h"
-#include "linux/smp_lock.h"
-#include "linux/module.h"
-#include "linux/slab.h"
-#include "linux/tty.h"
-#include "linux/binfmts.h"
-#include "linux/ptrace.h"
-#include "asm/signal.h"
-#include "asm/uaccess.h"
-#include "asm/unistd.h"
-#include "user_util.h"
-#include "asm/ucontext.h"
-#include "kern_util.h"
-#include "signal_kern.h"
-#include "signal_user.h"
-#include "kern.h"
-#include "frame_kern.h"
-#include "sigcontext.h"
-#include "mode.h"
-
-EXPORT_SYMBOL(block_signals);
-EXPORT_SYMBOL(unblock_signals);
-
-#define _S(nr) (1<<((nr)-1))
-
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-
-/*
- * OK, we're invoking a handler
- */
-static int handle_signal(struct pt_regs *regs, unsigned long signr,
- struct k_sigaction *ka, siginfo_t *info,
- sigset_t *oldset)
-{
- unsigned long sp;
- int err;
-
- /* Always make any pending restarted system calls return -EINTR */
- current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
- /* Did we come from a system call? */
- if(PT_REGS_SYSCALL_NR(regs) >= 0){
- /* If so, check system call restarting.. */
- switch(PT_REGS_SYSCALL_RET(regs)){
- case -ERESTART_RESTARTBLOCK:
- case -ERESTARTNOHAND:
- PT_REGS_SYSCALL_RET(regs) = -EINTR;
- break;
-
- case -ERESTARTSYS:
- if (!(ka->sa.sa_flags & SA_RESTART)) {
- PT_REGS_SYSCALL_RET(regs) = -EINTR;
- break;
- }
- /* fallthrough */
- case -ERESTARTNOINTR:
- PT_REGS_RESTART_SYSCALL(regs);
- PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
- break;
- }
- }
-
- sp = PT_REGS_SP(regs);
- if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
- sp = current->sas_ss_sp + current->sas_ss_size;
-
-#ifdef CONFIG_ARCH_HAS_SC_SIGNALS
- if(!(ka->sa.sa_flags & SA_SIGINFO))
- err = setup_signal_stack_sc(sp, signr, ka, regs, oldset);
- else
-#endif
- err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset);
-
- if(err){
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = *oldset;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- force_sigsegv(signr, current);
- } else {
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked,
- &ka->sa.sa_mask);
- if(!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, signr);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- }
-
- return err;
-}
-
-static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset)
-{
- struct k_sigaction ka_copy;
- siginfo_t info;
- int sig, handled_sig = 0;
-
- while((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0){
- handled_sig = 1;
- /* Whee! Actually deliver the signal. */
- if(!handle_signal(regs, sig, &ka_copy, &info, oldset))
- break;
- }
-
- /* Did we come from a system call? */
- if(!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)){
- /* Restart the system call - no handlers present */
- if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND ||
- PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS ||
- PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){
- PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
- PT_REGS_RESTART_SYSCALL(regs);
- }
- else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){
- PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall;
- PT_REGS_RESTART_SYSCALL(regs);
- }
- }
-
- /* This closes a way to execute a system call on the host. If
- * you set a breakpoint on a system call instruction and singlestep
- * from it, the tracing thread used to PTRACE_SINGLESTEP the process
- * rather than PTRACE_SYSCALL it, allowing the system call to execute
- * on the host. The tracing thread will check this flag and
- * PTRACE_SYSCALL if necessary.
- */
- if(current->ptrace & PT_DTRACE)
- current->thread.singlestep_syscall =
- is_syscall(PT_REGS_IP(&current->thread.regs));
- return(handled_sig);
-}
-
-int do_signal(void)
-{
- return(kern_do_signal(&current->thread.regs, &current->blocked));
-}
-
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
-{
- sigset_t saveset;
-
- mask &= _BLOCKABLE;
- spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
- siginitset(&current->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if(kern_do_signal(&current->thread.regs, &saveset))
- return(-EINTR);
- }
-}
-
-long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
-{
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
- current->blocked = newset;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (kern_do_signal(&current->thread.regs, &saveset))
- return(-EINTR);
- }
-}
-
-long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
- return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c
deleted file mode 100644
index 62f457835fb..00000000000
--- a/arch/um/kernel/signal_user.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/mman.h>
-#include "user_util.h"
-#include "kern_util.h"
-#include "user.h"
-#include "signal_user.h"
-#include "signal_kern.h"
-#include "sysdep/sigcontext.h"
-#include "sigcontext.h"
-
-void set_sigstack(void *sig_stack, int size)
-{
- stack_t stack = ((stack_t) { .ss_flags = 0,
- .ss_sp = (__ptr_t) sig_stack,
- .ss_size = size - sizeof(void *) });
-
- if(sigaltstack(&stack, NULL) != 0)
- panic("enabling signal stack failed, errno = %d\n", errno);
-}
-
-void set_handler(int sig, void (*handler)(int), int flags, ...)
-{
- struct sigaction action;
- va_list ap;
- int mask;
-
- va_start(ap, flags);
- action.sa_handler = handler;
- sigemptyset(&action.sa_mask);
- while((mask = va_arg(ap, int)) != -1){
- sigaddset(&action.sa_mask, mask);
- }
- va_end(ap);
- action.sa_flags = flags;
- action.sa_restorer = NULL;
- if(sigaction(sig, &action, NULL) < 0)
- panic("sigaction failed");
-}
-
-int change_sig(int signal, int on)
-{
- sigset_t sigset, old;
-
- sigemptyset(&sigset);
- sigaddset(&sigset, signal);
- sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
- return(!sigismember(&old, signal));
-}
-
-/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
- * disable profiling; it's safe because the profiling code does not interact
- * with the kernel code at all.*/
-
-static void change_signals(int type)
-{
- sigset_t mask;
-
- sigemptyset(&mask);
- sigaddset(&mask, SIGVTALRM);
- sigaddset(&mask, SIGALRM);
- sigaddset(&mask, SIGIO);
- if(sigprocmask(type, &mask, NULL) < 0)
- panic("Failed to change signal mask - errno = %d", errno);
-}
-
-void block_signals(void)
-{
- change_signals(SIG_BLOCK);
-}
-
-void unblock_signals(void)
-{
- change_signals(SIG_UNBLOCK);
-}
-
-/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled
- * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to
- * be able to profile all of UML, not just the non-critical sections. If
- * profiling is not thread-safe, then that is not my problem. We can disable
- * profiling when SMP is enabled in that case.
- */
-#define SIGIO_BIT 0
-#define SIGVTALRM_BIT 1
-
-static int enable_mask(sigset_t *mask)
-{
- int sigs;
-
- sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
- sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
- sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
- return(sigs);
-}
-
-int get_signals(void)
-{
- sigset_t mask;
-
- if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
- panic("Failed to get signal mask");
- return(enable_mask(&mask));
-}
-
-int set_signals(int enable)
-{
- sigset_t mask;
- int ret;
-
- sigemptyset(&mask);
- if(enable & (1 << SIGIO_BIT))
- sigaddset(&mask, SIGIO);
- if(enable & (1 << SIGVTALRM_BIT)){
- sigaddset(&mask, SIGVTALRM);
- sigaddset(&mask, SIGALRM);
- }
-
- /* This is safe - sigprocmask is guaranteed to copy locally the
- * value of new_set, do his work and then, at the end, write to
- * old_set.
- */
- if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
- panic("Failed to enable signals");
- ret = enable_mask(&mask);
- sigemptyset(&mask);
- if((enable & (1 << SIGIO_BIT)) == 0)
- sigaddset(&mask, SIGIO);
- if((enable & (1 << SIGVTALRM_BIT)) == 0){
- sigaddset(&mask, SIGVTALRM);
- sigaddset(&mask, SIGALRM);
- }
- if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
- panic("Failed to block signals");
-
- return(ret);
-}
-
-/*
- * 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/Makefile b/arch/um/kernel/skas/Makefile
index 8de471b59c1..0b76d8869c9 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -1,14 +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.o tlb.o trap_user.o uaccess.o
+obj-y := clone.o mmu.o process.o syscall.o uaccess.o
-USER_OBJS := process.o clone.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 ->
+# disable it
-include arch/um/scripts/Makefile.rules
+CFLAGS_clone.o := $(CFLAGS_NO_HARDENING)
+UNPROFILE_OBJS := clone.o
-# 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))
+include arch/um/scripts/Makefile.rules
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 44110c521e4..00000000000
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SKAS_MMU_H
-#define __SKAS_MMU_H
-
-#include "linux/config.h"
-#include "mm_id.h"
-#include "asm/ldt.h"
-
-struct mmu_context_skas {
- struct mm_id id;
- unsigned long last_page_table;
-#ifdef CONFIG_3_LEVEL_PGTABLES
- unsigned long last_pmd;
-#endif
- uml_ldt_t ldt;
-};
-
-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 c97a80dfe37..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 daa2f85b684..00000000000
--- a/arch/um/kernel/skas/include/skas.h
+++ /dev/null
@@ -1,50 +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, ptrace_ldt;
-extern int skas_needs_stub;
-
-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, int done, void **data);
-extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len,
- int done, void **data);
-extern int protect(struct mm_id * mm_idp, unsigned long addr,
- unsigned long len, int r, int w, int x, int done,
- void **data);
-extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
-extern int new_mm(int from, unsigned long stack);
-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);
-extern long run_syscall_stub(struct mm_id * mm_idp,
- int syscall, unsigned long *args, long expected,
- void **addr, int done);
-extern long syscall_stub_data(struct mm_id * mm_idp,
- unsigned long *data, int data_count,
- void **addr, void **stub_addr);
-
-#endif
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 7da0c2def0e..00000000000
--- a/arch/um/kernel/skas/include/uaccess-skas.h
+++ /dev/null
@@ -1,39 +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))))
-
-extern int copy_from_user_skas(void *to, const void __user *from, int n);
-extern int copy_to_user_skas(void __user *to, const void *from, int n);
-extern int strncpy_from_user_skas(char *dst, const char __user *src, int count);
-extern int __clear_user_skas(void __user *mem, int len);
-extern int clear_user_skas(void __user *mem, int len);
-extern int strnlen_user_skas(const void __user *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 88ab96c609c..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 (!skas_needs_stub)
- *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 1d89640bd50..00000000000
--- a/arch/um/kernel/skas/mem_user.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <signal.h>
-#include <errno.h>
-#include <string.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 "skas.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"
-
-extern unsigned long batch_syscall_stub, __syscall_stub_start;
-
-extern void wait_stub_done(int pid, int sig, char * fname);
-
-static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
- unsigned long *stack)
-{
- if(stack == NULL){
- stack = (unsigned long *) mm_idp->stack + 2;
- *stack = 0;
- }
- return stack;
-}
-
-extern int proc_mm;
-
-int single_count = 0;
-int multi_count = 0;
-int multi_op_count = 0;
-
-static long do_syscall_stub(struct mm_id *mm_idp, void **addr)
-{
- unsigned long regs[MAX_REG_NR];
- unsigned long *data;
- unsigned long *syscall;
- long ret, offset;
- int n, pid = mm_idp->u.pid;
-
- if(proc_mm)
-#warning Need to look up userspace_pid by cpu
- pid = userspace_pid[0];
-
- multi_count++;
-
- get_safe_registers(regs);
- regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
- ((unsigned long) &batch_syscall_stub -
- (unsigned long) &__syscall_stub_start);
- n = ptrace_setregs(pid, regs);
- if(n < 0)
- panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n",
- n);
-
- wait_stub_done(pid, 0, "do_syscall_stub");
-
- /* When the stub stops, we find the following values on the
- * beginning of the stack:
- * (long )return_value
- * (long )offset to failed sycall-data (0, if no error)
- */
- ret = *((unsigned long *) mm_idp->stack);
- offset = *((unsigned long *) mm_idp->stack + 1);
- if (offset) {
- data = (unsigned long *)(mm_idp->stack +
- offset - UML_CONFIG_STUB_DATA);
- syscall = (unsigned long *)((unsigned long)data + data[0]);
- printk("do_syscall_stub: syscall %ld failed, return value = "
- "0x%lx, expected return value = 0x%lx\n",
- syscall[0], ret, syscall[7]);
- printk(" syscall parameters: "
- "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
- syscall[1], syscall[2], syscall[3],
- syscall[4], syscall[5], syscall[6]);
- for(n = 1; n < data[0]/sizeof(long); n++) {
- if(n == 1)
- printk(" additional syscall data:");
- if(n % 4 == 1)
- printk("\n ");
- printk(" 0x%lx", data[n]);
- }
- if(n > 1)
- printk("\n");
- }
- else ret = 0;
-
- *addr = check_init_stack(mm_idp, NULL);
-
- return ret;
-}
-
-long run_syscall_stub(struct mm_id * mm_idp, int syscall,
- unsigned long *args, long expected, void **addr,
- int done)
-{
- unsigned long *stack = check_init_stack(mm_idp, *addr);
-
- if(done && *addr == NULL)
- single_count++;
-
- *stack += sizeof(long);
- stack += *stack / sizeof(long);
-
- *stack++ = syscall;
- *stack++ = args[0];
- *stack++ = args[1];
- *stack++ = args[2];
- *stack++ = args[3];
- *stack++ = args[4];
- *stack++ = args[5];
- *stack++ = expected;
- *stack = 0;
- multi_op_count++;
-
- if(!done && ((((unsigned long) stack) & ~PAGE_MASK) <
- PAGE_SIZE - 10 * sizeof(long))){
- *addr = stack;
- return 0;
- }
-
- return do_syscall_stub(mm_idp, addr);
-}
-
-long syscall_stub_data(struct mm_id * mm_idp,
- unsigned long *data, int data_count,
- void **addr, void **stub_addr)
-{
- unsigned long *stack;
- int ret = 0;
-
- /* If *addr still is uninitialized, it *must* contain NULL.
- * Thus in this case do_syscall_stub correctly won't be called.
- */
- if((((unsigned long) *addr) & ~PAGE_MASK) >=
- PAGE_SIZE - (10 + data_count) * sizeof(long)) {
- ret = do_syscall_stub(mm_idp, addr);
- /* in case of error, don't overwrite data on stack */
- if(ret)
- return ret;
- }
-
- stack = check_init_stack(mm_idp, *addr);
- *addr = stack;
-
- *stack = data_count * sizeof(long);
-
- memcpy(stack + 1, data, data_count * sizeof(long));
-
- *stub_addr = (void *)(((unsigned long)(stack + 1) & ~PAGE_MASK) +
- UML_CONFIG_STUB_DATA);
-
- return 0;
-}
-
-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 done, void **data)
-{
- int prot, ret;
-
- 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
- } } } );
- ret = os_write_file(fd, &map, sizeof(map));
- if(ret != sizeof(map))
- printk("map : /proc/mm map failed, err = %d\n", -ret);
- else ret = 0;
- }
- else {
- unsigned long args[] = { virt, len, prot,
- MAP_SHARED | MAP_FIXED, phys_fd,
- MMAP_OFFSET(offset) };
-
- ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt,
- data, done);
- }
-
- return ret;
-}
-
-int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
- void **data)
-{
- int ret;
-
- 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 } } } );
- ret = os_write_file(fd, &unmap, sizeof(unmap));
- if(ret != sizeof(unmap))
- printk("unmap - proc_mm write returned %d\n", ret);
- else ret = 0;
- }
- else {
- unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
- 0 };
-
- ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0,
- data, done);
- if(ret < 0)
- printk("munmap stub failed, errno = %d\n", ret);
- }
-
- return ret;
-}
-
-int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
- int r, int w, int x, int done, void **data)
-{
- struct proc_mm_op protect;
- int prot, ret;
-
- 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 } } } );
-
- ret = os_write_file(fd, &protect, sizeof(protect));
- if(ret != sizeof(protect))
- printk("protect failed, err = %d", -ret);
- else ret = 0;
- }
- else {
- unsigned long args[] = { addr, len, prot, 0, 0, 0 };
-
- ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0,
- data, done);
- }
-
- return ret;
-}
-
-void before_mem_skas(unsigned long unused)
-{
-}
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 677871f1b37..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,98 +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_kernel(*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 from_fd, ret = -ENOMEM;
+ 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(proc_mm){
- if(from_mm)
- from_fd = from_mm->id.u.mm_fd;
- else from_fd = -1;
-
- ret = new_mm(from_fd, stack);
- if(ret < 0){
- printk("init_new_context_skas - new_mm failed, "
- "errno = %d\n", ret);
+ 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)
+ 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;
}
@@ -137,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_page_state(nr_page_table_pages);
-#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
index 599d679bd4f..4da11b3c8dd 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -1,581 +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);
-}
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <as-layout.h>
+#include <kern.h>
+#include <os.h>
+#include <skas.h>
-void wait_stub_done(int pid, int sig, char * fname)
+int new_mm(unsigned long stack)
{
- 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;
+ int fd, err;
- CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
- } while((n >= 0) && WIFSTOPPED(status) &&
- ((WSTOPSIG(status) == SIGVTALRM) ||
- /* running UML inside a detached screen can cause
- * SIGWINCHes
- */
- (WSTOPSIG(status) == SIGWINCH)));
+ fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
+ if (fd < 0)
+ return fd;
- if((n < 0) || !WIFSTOPPED(status) ||
- (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){
- unsigned long regs[FRAME_SIZE];
- if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
- printk("Failed to get registers from stub, "
- "errno = %d\n", errno);
- else {
- int i;
-
- printk("Stub registers -\n");
- for(i = 0; i < FRAME_SIZE; i++)
- printk("\t%d - %lx\n", i, regs[i]);
+ if (skas_needs_stub) {
+ err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
+ if (err) {
+ os_close_file(fd);
+ return err;
}
- panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
- "pid = %d, n = %d, errno = %d, status = 0x%x\n",
- fname, pid, n, errno, status);
- }
-}
-
-void get_skas_faultinfo(int pid, struct faultinfo * fi)
-{
- 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);
+ return fd;
}
-extern int __syscall_stub_start;
-int stub_code_fd = -1;
-__u64 stub_code_offset;
+extern void start_kernel(void);
-static int userspace_tramp(void *stack)
+static int __init start_kernel_proc(void *unused)
{
- void *addr;
+ int pid;
- 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
- */
- addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
- PROT_EXEC, MAP_FIXED | MAP_PRIVATE,
- stub_code_fd, stub_code_offset);
- if(addr == MAP_FAILED){
- printk("mapping stub code failed, errno = %d\n",
- errno);
- exit(1);
- }
-
- if(stack != NULL){
- int fd;
- __u64 offset;
-
- 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 stub stack failed, "
- "errno = %d\n", errno);
- exit(1);
- }
- }
- }
- if(!ptrace_faultinfo){
- 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;
-
- if ( stub_code_fd == -1 )
- stub_code_fd = phys_mapping(to_phys(&__syscall_stub_start),
- &stub_code_offset);
-
- 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;
- }
- }
-}
-#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
-
-
-int copy_context_skas0(unsigned long new_stack, int pid)
-{
- 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);
-
- if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
- (void *)PTRACE_O_TRACESYSGOOD) < 0)
- panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, "
- "errno = %d\n", errno);
-
- return pid;
-}
-
-/*
- * This is used only, if stub pages are needed, while proc_mm is
- * availabl. Opening /proc/mm creates a new mm_context, which lacks
- * the stub-pages. Thus, we map them using /proc/mm-fd
- */
-void map_stub_pages(int fd, unsigned long code,
- unsigned long data, unsigned long stack)
-{
- struct proc_mm_op mmop;
- int n;
-
- mmop = ((struct proc_mm_op) { .op = MM_MMAP,
- .u =
- { .mmap =
- { .addr = code,
- .len = PAGE_SIZE,
- .prot = PROT_EXEC,
- .flags = MAP_FIXED | MAP_PRIVATE,
- .fd = stub_code_fd,
- .offset = stub_code_offset
- } } });
- n = os_write_file(fd, &mmop, sizeof(mmop));
- if(n != sizeof(mmop))
- panic("map_stub_pages : /proc/mm map for code failed, "
- "err = %d\n", -n);
-
- if ( stack ) {
- __u64 map_offset;
- int map_fd = phys_mapping(to_phys((void *)stack), &map_offset);
- mmop = ((struct proc_mm_op)
- { .op = MM_MMAP,
- .u =
- { .mmap =
- { .addr = data,
- .len = PAGE_SIZE,
- .prot = PROT_READ | PROT_WRITE,
- .flags = MAP_FIXED | MAP_SHARED,
- .fd = map_fd,
- .offset = map_offset
- } } });
- n = os_write_file(fd, &mmop, sizeof(mmop));
- if(n != sizeof(mmop))
- panic("map_stub_pages : /proc/mm map for data failed, "
- "err = %d\n", -n);
- }
-}
-
-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();
-
- set_signals(flags);
-}
-
-void thread_wait(void *sw, void *fb)
-{
- sigjmp_buf buf, **switch_buf = sw, *fork_buf;
-
- *switch_buf = &buf;
- fork_buf = fb;
- if(sigsetjmp(buf, 1) == 0)
- siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK);
-}
+ pid = os_getpid();
-void switch_threads(void *me, void *next)
-{
- sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
-
- *me_ptr = &my_buf;
- if(sigsetjmp(my_buf, 1) == 0)
- siglongjmp(*next_buf, 1);
+ 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;
}
-static sigjmp_buf initial_jmpbuf;
+extern int userspace_pid[];
-/* XXX Make these percpu */
-static void (*cb_proc)(void *arg);
-static void *cb_arg;
-static sigjmp_buf *cb_back;
+extern char cpu0_irqstack[];
-int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
+int __init start_uml(void)
{
- 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 });
+ init_new_thread_signals();
- if(sigaltstack(&stack, NULL) != 0)
- panic("disabling signal stack failed, errno = %d\n", errno);
+ 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 initial_thread_cb_skas(void (*proc)(void *), void *arg)
+unsigned long current_stub_stack(void)
{
- sigjmp_buf here;
+ if (current->mm == NULL)
+ return 0;
- cb_proc = proc;
- cb_arg = arg;
- cb_back = &here;
-
- block_signals();
- if(sigsetjmp(here, 1) == 0)
- siglongjmp(initial_jmpbuf, INIT_JMP_CALLBACK);
- unblock_signals();
-
- cb_proc = NULL;
- cb_arg = NULL;
- cb_back = NULL;
+ return current->mm->context.id.stack;
}
-
-void halt_skas(void)
-{
- block_signals();
- siglongjmp(initial_jmpbuf, INIT_JMP_HALT);
-}
-
-void reboot_skas(void)
-{
- block_signals();
- siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
-}
-
-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 9c990253966..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);
-
- switch_threads(&from->thread.mode.skas.switch_buf,
- to->thread.mode.skas.switch_buf);
-
- 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;
- 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);
-}
-
-extern void map_stub_pages(int fd, unsigned long code,
- unsigned long data, unsigned long stack);
-int new_mm(int from, unsigned long stack)
-{
- 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);
- }
-
- 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(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
index 51fb94076fc..c0681e09743 100644
--- a/arch/um/kernel/skas/syscall.c
+++ b/arch/um/kernel/skas/syscall.c
@@ -1,34 +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;
-#ifdef UML_CONFIG_SYSCALL_DEBUG
- int index;
-
- index = record_syscall_start(UPT_SYSCALL_NR(r));
-#endif
- 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.
@@ -37,14 +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);
-#ifdef UML_CONFIG_SYSCALL_DEBUG
- record_syscall_end(index, result);
-#endif
+ 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/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/smp.c b/arch/um/kernel/smp.c
index 72113b0a96e..5c8c3ea7db7 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -1,39 +1,26 @@
-/*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/config.h"
-#include "linux/percpu.h"
-#include "asm/pgalloc.h"
-#include "asm/tlb.h"
-
-/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+#include <linux/percpu.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
#ifdef CONFIG_SMP
-#include "linux/sched.h"
-#include "linux/module.h"
-#include "linux/threads.h"
-#include "linux/interrupt.h"
-#include "linux/err.h"
-#include "linux/hardirq.h"
-#include "asm/smp.h"
-#include "asm/processor.h"
-#include "asm/spinlock.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "kern.h"
-#include "irq_user.h"
-#include "os.h"
-
-/* CPU online map, set by smp_boot_cpus */
-cpumask_t cpu_online_map = CPU_MASK_NONE;
-cpumask_t cpu_possible_map = CPU_MASK_NONE;
-
-EXPORT_SYMBOL(cpu_online_map);
-EXPORT_SYMBOL(cpu_possible_map);
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/hardirq.h>
+#include <asm/smp.h>
+#include <asm/processor.h>
+#include <asm/spinlock.h>
+#include <kern.h>
+#include <irq_user.h>
+#include <os.h>
/* Per CPU bogomips and other parameters
* The only piece used here is the ipi pipe, which is set before SMP is
@@ -58,12 +45,12 @@ void smp_send_stop(void)
int i;
printk(KERN_INFO "Stopping all CPUs...");
- for(i = 0; i < num_online_cpus(); i++){
- if(i == current_thread->cpu)
+ for (i = 0; i < num_online_cpus(); i++) {
+ if (i == current_thread->cpu)
continue;
os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
}
- printk("done\n");
+ printk(KERN_CONT "done\n");
}
static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
@@ -74,46 +61,43 @@ static int idle_proc(void *cpup)
int cpu = (int) cpup, err;
err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
- if(err < 0)
+ if (err < 0)
panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
- activate_ipi(cpu_data[cpu].ipi_pipe[0],
- current->thread.mode.tt.extern_pid);
-
+ os_set_fd_async(cpu_data[cpu].ipi_pipe[0]);
+
wmb();
if (cpu_test_and_set(cpu, cpu_callin_map)) {
- printk("huh, CPU#%d already present??\n", cpu);
+ printk(KERN_ERR "huh, CPU#%d already present??\n", cpu);
BUG();
}
while (!cpu_isset(cpu, smp_commenced_mask))
cpu_relax();
- cpu_set(cpu, cpu_online_map);
+ notify_cpu_starting(cpu);
+ set_cpu_online(cpu, true);
default_idle();
- return(0);
+ return 0;
}
static struct task_struct *idle_thread(int cpu)
{
struct task_struct *new_task;
- unsigned char c;
- current->thread.request.u.thread.proc = idle_proc;
- current->thread.request.u.thread.arg = (void *) cpu;
+ current->thread.request.u.thread.proc = idle_proc;
+ current->thread.request.u.thread.arg = (void *) cpu;
new_task = fork_idle(cpu);
- if(IS_ERR(new_task))
+ if (IS_ERR(new_task))
panic("copy_process failed in idle_thread, error = %ld",
PTR_ERR(new_task));
- cpu_tasks[cpu] = ((struct cpu_task)
+ cpu_tasks[cpu] = ((struct cpu_task)
{ .pid = new_task->thread.mode.tt.extern_pid,
.task = new_task } );
idle_threads[cpu] = new_task;
- CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
- sizeof(c)),
- ({ panic("skas mode doesn't support SMP"); }));
- return(new_task);
+ panic("skas mode doesn't support SMP");
+ return new_task;
}
void smp_prepare_cpus(unsigned int maxcpus)
@@ -124,54 +108,50 @@ void smp_prepare_cpus(unsigned int maxcpus)
int i;
for (i = 0; i < ncpus; ++i)
- cpu_set(i, cpu_possible_map);
+ set_cpu_possible(i, true);
- cpu_clear(me, cpu_online_map);
- cpu_set(me, cpu_online_map);
+ set_cpu_online(me, true);
cpu_set(me, cpu_callin_map);
err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
- if(err < 0)
+ if (err < 0)
panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
- activate_ipi(cpu_data[me].ipi_pipe[0],
- current->thread.mode.tt.extern_pid);
+ os_set_fd_async(cpu_data[me].ipi_pipe[0]);
+
+ for (cpu = 1; cpu < ncpus; cpu++) {
+ printk(KERN_INFO "Booting processor %d...\n", cpu);
- for(cpu = 1; cpu < ncpus; cpu++){
- printk("Booting processor %d...\n", cpu);
-
idle = idle_thread(cpu);
init_idle(idle, cpu);
- unhash_process(idle);
waittime = 200000000;
while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
cpu_relax();
- if (cpu_isset(cpu, cpu_callin_map))
- printk("done\n");
- else printk("failed\n");
+ printk(KERN_INFO "%s\n",
+ cpu_isset(cpu, cpu_calling_map) ? "done" : "failed");
}
}
void smp_prepare_boot_cpu(void)
{
- cpu_set(smp_processor_id(), cpu_online_map);
+ set_cpu_online(smp_processor_id(), true);
}
-int __cpu_up(unsigned int cpu)
+int __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
cpu_set(cpu, smp_commenced_mask);
- while (!cpu_isset(cpu, cpu_online_map))
+ while (!cpu_online(cpu))
mb();
- return(0);
+ return 0;
}
int setup_profiling_timer(unsigned int multiplier)
{
printk(KERN_INFO "setup_profiling_timer\n");
- return(0);
+ return 0;
}
void smp_call_function_slave(int cpu);
@@ -189,17 +169,18 @@ void IPI_handler(int cpu)
break;
case 'R':
- set_tsk_need_resched(current);
+ scheduler_ipi();
break;
case 'S':
- printk("CPU#%d stopping\n", cpu);
- while(1)
+ printk(KERN_INFO "CPU#%d stopping\n", cpu);
+ while (1)
pause();
break;
default:
- printk("CPU#%d received unknown IPI [%c]!\n", cpu, c);
+ printk(KERN_ERR "CPU#%d received unknown IPI [%c]!\n",
+ cpu, c);
break;
}
}
@@ -207,7 +188,7 @@ void IPI_handler(int cpu)
int hard_smp_processor_id(void)
{
- return(pid_to_processor_id(os_getpid()));
+ return pid_to_processor_id(os_getpid());
}
static DEFINE_SPINLOCK(call_lock);
@@ -223,8 +204,7 @@ void smp_call_function_slave(int cpu)
atomic_inc(&scf_finished);
}
-int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic,
- int wait)
+int smp_call_function(void (*_func)(void *info), void *_info, int wait)
{
int cpus = num_online_cpus() - 1;
int i;
@@ -256,14 +236,3 @@ int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic,
}
#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/syscall.c b/arch/um/kernel/syscall.c
index 1429c131879..c1d0ae069b5 100644
--- a/arch/um/kernel/syscall.c
+++ b/arch/um/kernel/syscall.c
@@ -1,36 +1,28 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "kern_util.h"
-#include "syscall.h"
-#include "os.h"
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/utsname.h>
+#include <linux/syscalls.h>
+#include <asm/current.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
-struct {
- int syscall;
- int pid;
- long result;
- unsigned long long start;
- unsigned long long end;
-} syscall_record[1024];
-
-int record_syscall_start(int syscall)
+long old_mmap(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long offset)
{
- int max, index;
-
- max = sizeof(syscall_record)/sizeof(syscall_record[0]);
- index = next_syscall_index(max);
+ long err = -EINVAL;
+ if (offset & ~PAGE_MASK)
+ goto out;
- syscall_record[index].syscall = syscall;
- syscall_record[index].pid = current_pid();
- syscall_record[index].result = 0xdeadbeef;
- syscall_record[index].start = os_usecs();
- return(index);
-}
-
-void record_syscall_end(int index, long result)
-{
- syscall_record[index].result = result;
- syscall_record[index].end = os_usecs();
+ err = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+ out:
+ return err;
}
diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
deleted file mode 100644
index 8e1a3501ff4..00000000000
--- a/arch/um/kernel/syscall_kern.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
- * Licensed under the GPL
- */
-
-#include "linux/sched.h"
-#include "linux/file.h"
-#include "linux/smp_lock.h"
-#include "linux/mm.h"
-#include "linux/utsname.h"
-#include "linux/msg.h"
-#include "linux/shm.h"
-#include "linux/sys.h"
-#include "linux/syscalls.h"
-#include "linux/unistd.h"
-#include "linux/slab.h"
-#include "linux/utime.h"
-#include "asm/mman.h"
-#include "asm/uaccess.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "sysdep/syscalls.h"
-#include "mode_kern.h"
-#include "choose-mode.h"
-
-/* Unlocked, I don't care if this is a bit off */
-int nsyscalls = 0;
-
-long sys_fork(void)
-{
- long ret;
-
- current->thread.forking = 1;
- ret = do_fork(SIGCHLD, UPT_SP(&current->thread.regs.regs),
- &current->thread.regs, 0, NULL, NULL);
- current->thread.forking = 0;
- return(ret);
-}
-
-long sys_vfork(void)
-{
- long ret;
-
- current->thread.forking = 1;
- ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
- UPT_SP(&current->thread.regs.regs),
- &current->thread.regs, 0, NULL, NULL);
- current->thread.forking = 0;
- return(ret);
-}
-
-/* common code for old and new mmaps */
-long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff)
-{
- long error = -EBADF;
- struct file * file = NULL;
-
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- if (!(flags & MAP_ANONYMOUS)) {
- file = fget(fd);
- if (!file)
- goto out;
- }
-
- down_write(&current->mm->mmap_sem);
- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
- up_write(&current->mm->mmap_sem);
-
- if (file)
- fput(file);
- out:
- return error;
-}
-
-long old_mmap(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long offset)
-{
- long err = -EINVAL;
- if (offset & ~PAGE_MASK)
- goto out;
-
- err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
- out:
- return err;
-}
-/*
- * sys_pipe() is the normal C calling standard for creating
- * a pipe. It's not the way unix traditionally does this, though.
- */
-long sys_pipe(unsigned long __user * fildes)
-{
- int fd[2];
- long error;
-
- error = do_pipe(fd);
- if (!error) {
- if (copy_to_user(fildes, fd, sizeof(fd)))
- error = -EFAULT;
- }
- return error;
-}
-
-
-long sys_uname(struct old_utsname * name)
-{
- long err;
- if (!name)
- return -EFAULT;
- down_read(&uts_sem);
- err=copy_to_user(name, &system_utsname, sizeof (*name));
- up_read(&uts_sem);
- return err?-EFAULT:0;
-}
-
-long sys_olduname(struct oldold_utsname * name)
-{
- long error;
-
- if (!name)
- return -EFAULT;
- if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
- return -EFAULT;
-
- down_read(&uts_sem);
-
- error = __copy_to_user(&name->sysname,&system_utsname.sysname,
- __OLD_UTS_LEN);
- error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->nodename,&system_utsname.nodename,
- __OLD_UTS_LEN);
- error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->release,&system_utsname.release,
- __OLD_UTS_LEN);
- error |= __put_user(0,name->release+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->version,&system_utsname.version,
- __OLD_UTS_LEN);
- error |= __put_user(0,name->version+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->machine,&system_utsname.machine,
- __OLD_UTS_LEN);
- error |= __put_user(0,name->machine+__OLD_UTS_LEN);
-
- up_read(&uts_sem);
-
- error = error ? -EFAULT : 0;
-
- return error;
-}
-
-DEFINE_SPINLOCK(syscall_lock);
-
-static int syscall_index = 0;
-
-int next_syscall_index(int limit)
-{
- int ret;
-
- spin_lock(&syscall_lock);
- ret = syscall_index;
- if(++syscall_index == limit)
- syscall_index = 0;
- spin_unlock(&syscall_lock);
- return(ret);
-}
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index b331e970002..799d7e413bf 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -1,82 +1,98 @@
-/*
- * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2013 Richard Weinberger <richrd@nod.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
*/
-#include "linux/config.h"
-#include "linux/sched.h"
-#include "linux/kernel.h"
-#include "linux/module.h"
-#include "linux/kallsyms.h"
-#include "asm/page.h"
-#include "asm/processor.h"
-#include "sysrq.h"
-#include "user_util.h"
+#include <linux/kallsyms.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/sysrq.h>
+#include <os.h>
-/* Catch non-i386 SUBARCH's. */
-#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT)
-void show_trace(struct task_struct *task, unsigned long * stack)
-{
- unsigned long addr;
+struct stack_frame {
+ struct stack_frame *next_frame;
+ unsigned long return_address;
+};
- if (!stack) {
- stack = (unsigned long*) &stack;
- WARN_ON(1);
- }
+static void do_stack_trace(unsigned long *sp, unsigned long bp)
+{
+ int reliable;
+ unsigned long addr;
+ struct stack_frame *frame = (struct stack_frame *)bp;
- printk("Call Trace: \n");
- while (((long) stack & (THREAD_SIZE-1)) != 0) {
- addr = *stack;
+ printk(KERN_INFO "Call Trace:\n");
+ while (((long) sp & (THREAD_SIZE-1)) != 0) {
+ addr = *sp;
if (__kernel_text_address(addr)) {
- printk("%08lx: [<%08lx>]", (unsigned long) stack, addr);
- print_symbol(" %s", addr);
- printk("\n");
- }
- stack++;
- }
- printk("\n");
+ reliable = 0;
+ if ((unsigned long) sp == bp + sizeof(long)) {
+ frame = frame ? frame->next_frame : NULL;
+ bp = (unsigned long)frame;
+ reliable = 1;
+ }
+
+ printk(KERN_INFO " [<%08lx>]", addr);
+ printk(KERN_CONT " %s", reliable ? "" : "? ");
+ print_symbol(KERN_CONT "%s", addr);
+ printk(KERN_CONT "\n");
+ }
+ sp++;
+ }
+ printk(KERN_INFO "\n");
}
-#endif
-/*
- * stack dumps generator - this is used by arch-independent code.
- * And this is identical to i386 currently.
- */
-void dump_stack(void)
+static unsigned long get_frame_pointer(struct task_struct *task,
+ struct pt_regs *segv_regs)
{
- unsigned long stack;
-
- show_trace(current, &stack);
+ if (!task || task == current)
+ return segv_regs ? PT_REGS_BP(segv_regs) : current_bp();
+ else
+ return KSTK_EBP(task);
}
-EXPORT_SYMBOL(dump_stack);
-/*Stolen from arch/i386/kernel/traps.c */
-static int kstack_depth_to_print = 24;
+static unsigned long *get_stack_pointer(struct task_struct *task,
+ struct pt_regs *segv_regs)
+{
+ if (!task || task == current)
+ return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp();
+ else
+ return (unsigned long *)KSTK_ESP(task);
+}
-/* This recently started being used in arch-independent code too, as in
- * kernel/sched.c.*/
-void show_stack(struct task_struct *task, unsigned long *esp)
+void show_stack(struct task_struct *task, unsigned long *stack)
{
- unsigned long *stack;
+ unsigned long *sp = stack, bp = 0;
+ struct pt_regs *segv_regs = current->thread.segv_regs;
int i;
- if (esp == NULL) {
- if (task != current && task != NULL) {
- esp = (unsigned long *) KSTK_ESP(task);
- } else {
- esp = (unsigned long *) &esp;
- }
+ if (!segv_regs && os_is_signal_stack()) {
+ printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler,"
+ " aborting stack trace!\n");
+ return;
}
- stack = esp;
- for(i = 0; i < kstack_depth_to_print; i++) {
+#ifdef CONFIG_FRAME_POINTER
+ bp = get_frame_pointer(task, segv_regs);
+#endif
+
+ if (!stack)
+ sp = get_stack_pointer(task, segv_regs);
+
+ printk(KERN_INFO "Stack:\n");
+ stack = sp;
+ for (i = 0; i < 3 * STACKSLOTS_PER_LINE; i++) {
if (kstack_end(stack))
break;
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("%08lx ", *stack++);
+ if (i && ((i % STACKSLOTS_PER_LINE) == 0))
+ printk(KERN_CONT "\n");
+ printk(KERN_CONT " %08lx", *stack++);
}
+ printk(KERN_CONT "\n");
- printk("Call Trace: \n");
- show_trace(task, esp);
+ do_stack_trace(sp, bp);
}
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index c40b611e3d9..117568d4f64 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -1,171 +1,115 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
-#include <sys/time.h>
-#include <signal.h>
-#include <errno.h>
-#include "user_util.h"
-#include "kern_util.h"
-#include "user.h"
-#include "process.h"
-#include "signal_user.h"
-#include "time_user.h"
-#include "kern_constants.h"
-
-/* XXX This really needs to be declared and initialized in a kernel file since
- * it's in <linux/time.h>
- */
-extern struct timespec wall_to_monotonic;
-
-extern struct timeval xtime;
-
-struct timeval local_offset = { 0, 0 };
-
-void timer(void)
-{
- gettimeofday(&xtime, NULL);
- timeradd(&xtime, &local_offset, &xtime);
-}
-
-static void set_interval(int timer_type)
-{
- int usec = 1000000/hz();
- struct itimerval interval = ((struct itimerval) { { 0, usec },
- { 0, usec } });
-
- if(setitimer(timer_type, &interval, NULL) == -1)
- panic("setitimer failed - errno = %d\n", errno);
-}
-
-void enable_timer(void)
-{
- set_interval(ITIMER_VIRTUAL);
-}
-
-void prepare_timer(void * ptr)
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/threads.h>
+#include <asm/irq.h>
+#include <asm/param.h>
+#include <kern_util.h>
+#include <os.h>
+
+void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
{
- int usec = 1000000/hz();
- *(struct itimerval *)ptr = ((struct itimerval) { { 0, usec },
- { 0, usec }});
-}
+ unsigned long flags;
-void disable_timer(void)
-{
- struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
- if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) ||
- (setitimer(ITIMER_REAL, &disable, NULL) < 0))
- printk("disnable_timer - setitimer failed, errno = %d\n",
- errno);
- /* If there are signals already queued, after unblocking ignore them */
- set_handler(SIGALRM, SIG_IGN, 0, -1);
- set_handler(SIGVTALRM, SIG_IGN, 0, -1);
+ local_irq_save(flags);
+ do_IRQ(TIMER_IRQ, regs);
+ local_irq_restore(flags);
}
-void switch_timers(int to_real)
+static void itimer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
{
- struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
- struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() },
- { 0, 1000000/hz() }});
- int old, new;
-
- if(to_real){
- old = ITIMER_VIRTUAL;
- new = ITIMER_REAL;
- }
- else {
- old = ITIMER_REAL;
- new = ITIMER_VIRTUAL;
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ set_interval();
+ break;
+
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_ONESHOT:
+ disable_timer();
+ break;
+
+ case CLOCK_EVT_MODE_RESUME:
+ break;
}
-
- if((setitimer(old, &disable, NULL) < 0) ||
- (setitimer(new, &enable, NULL)))
- printk("switch_timers - setitimer failed, errno = %d\n",
- errno);
}
-void uml_idle_timer(void)
+static int itimer_next_event(unsigned long delta,
+ struct clock_event_device *evt)
{
- if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
- panic("Couldn't unset SIGVTALRM handler");
-
- set_handler(SIGALRM, (__sighandler_t) alarm_handler,
- SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
- set_interval(ITIMER_REAL);
+ return timer_one_shot(delta + 1);
}
-extern int do_posix_clock_monotonic_gettime(struct timespec *tp);
-
-void time_init(void)
+static struct clock_event_device itimer_clockevent = {
+ .name = "itimer",
+ .rating = 250,
+ .cpumask = cpu_all_mask,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = itimer_set_mode,
+ .set_next_event = itimer_next_event,
+ .shift = 32,
+ .irq = 0,
+};
+
+static irqreturn_t um_timer(int irq, void *dev)
{
- struct timespec now;
+ (*itimer_clockevent.event_handler)(&itimer_clockevent);
- if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
- panic("Couldn't set SIGVTALRM handler");
- set_interval(ITIMER_VIRTUAL);
-
- do_posix_clock_monotonic_gettime(&now);
- wall_to_monotonic.tv_sec = -now.tv_sec;
- wall_to_monotonic.tv_nsec = -now.tv_nsec;
+ return IRQ_HANDLED;
}
-/* Declared in linux/time.h, which can't be included here */
-extern void clock_was_set(void);
-
-void do_gettimeofday(struct timeval *tv)
+static cycle_t itimer_read(struct clocksource *cs)
{
- unsigned long flags;
-
- flags = time_lock();
- gettimeofday(tv, NULL);
- timeradd(tv, &local_offset, tv);
- time_unlock(flags);
- clock_was_set();
+ return os_nsecs() / 1000;
}
-int do_settimeofday(struct timespec *tv)
-{
- struct timeval now;
- unsigned long flags;
- struct timeval tv_in;
-
- if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC)
- return -EINVAL;
-
- tv_in.tv_sec = tv->tv_sec;
- tv_in.tv_usec = tv->tv_nsec / 1000;
+static struct clocksource itimer_clocksource = {
+ .name = "itimer",
+ .rating = 300,
+ .read = itimer_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
- flags = time_lock();
- gettimeofday(&now, NULL);
- timersub(&tv_in, &now, &local_offset);
- time_unlock(flags);
-
- return(0);
+static void __init setup_itimer(void)
+{
+ int err;
+
+ err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL);
+ if (err != 0)
+ printk(KERN_ERR "register_timer : request_irq failed - "
+ "errno = %d\n", -err);
+
+ itimer_clockevent.mult = div_sc(HZ, NSEC_PER_SEC, 32);
+ itimer_clockevent.max_delta_ns =
+ clockevent_delta2ns(60 * HZ, &itimer_clockevent);
+ itimer_clockevent.min_delta_ns =
+ clockevent_delta2ns(1, &itimer_clockevent);
+ err = clocksource_register_hz(&itimer_clocksource, USEC_PER_SEC);
+ if (err) {
+ printk(KERN_ERR "clocksource_register_hz returned %d\n", err);
+ return;
+ }
+ clockevents_register_device(&itimer_clockevent);
}
-void idle_sleep(int secs)
+void read_persistent_clock(struct timespec *ts)
{
- struct timespec ts;
+ long long nsecs = os_nsecs();
- ts.tv_sec = secs;
- ts.tv_nsec = 0;
- nanosleep(&ts, NULL);
+ set_normalized_timespec(ts, nsecs / NSEC_PER_SEC,
+ nsecs % NSEC_PER_SEC);
}
-/* XXX This partly duplicates init_irq_signals */
-
-void user_time_init(void)
+void __init time_init(void)
{
- set_handler(SIGVTALRM, (__sighandler_t) alarm_handler,
- SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH,
- SIGALRM, SIGUSR2, -1);
- set_handler(SIGALRM, (__sighandler_t) alarm_handler,
- SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH,
- SIGVTALRM, SIGUSR2, -1);
- set_interval(ITIMER_VIRTUAL);
+ timer_init();
+ late_time_init = setup_itimer;
}
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
deleted file mode 100644
index 020ca79b8d3..00000000000
--- a/arch/um/kernel/time_kern.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/kernel.h"
-#include "linux/module.h"
-#include "linux/unistd.h"
-#include "linux/stddef.h"
-#include "linux/spinlock.h"
-#include "linux/time.h"
-#include "linux/sched.h"
-#include "linux/interrupt.h"
-#include "linux/init.h"
-#include "linux/delay.h"
-#include "asm/irq.h"
-#include "asm/param.h"
-#include "asm/current.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "time_user.h"
-#include "mode.h"
-#include "os.h"
-
-int hz(void)
-{
- return(HZ);
-}
-
-/*
- * Scheduler clock - returns current time in nanosec units.
- */
-unsigned long long sched_clock(void)
-{
- return (unsigned long long)jiffies_64 * (1000000000 / HZ);
-}
-
-/* Changed at early boot */
-int timer_irq_inited = 0;
-
-static int first_tick;
-static unsigned long long prev_usecs;
-#ifdef CONFIG_UML_REAL_TIME_CLOCK
-static long long delta; /* Deviation per interval */
-#endif
-
-void timer_irq(union uml_pt_regs *regs)
-{
- unsigned long long ticks = 0;
-
- if(!timer_irq_inited){
- /* This is to ensure that ticks don't pile up when
- * the timer handler is suspended */
- first_tick = 0;
- return;
- }
-
- if(first_tick){
-#ifdef CONFIG_UML_REAL_TIME_CLOCK
- /* We've had 1 tick */
- unsigned long long usecs = os_usecs();
-
- delta += usecs - prev_usecs;
- prev_usecs = usecs;
-
- /* Protect against the host clock being set backwards */
- if(delta < 0)
- delta = 0;
-
- ticks += (delta * HZ) / MILLION;
- delta -= (ticks * MILLION) / HZ;
-#else
- ticks = 1;
-#endif
- }
- else {
- prev_usecs = os_usecs();
- first_tick = 1;
- }
-
- while(ticks > 0){
- do_IRQ(TIMER_IRQ, regs);
- ticks--;
- }
-}
-
-void boot_timer_handler(int sig)
-{
- struct pt_regs regs;
-
- CHOOSE_MODE((void)
- (UPT_SC(&regs.regs) = (struct sigcontext *) (&sig + 1)),
- (void) (regs.regs.skas.is_user = 0));
- do_timer(&regs);
-}
-
-irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
-{
- unsigned long flags;
-
- do_timer(regs);
- write_seqlock_irqsave(&xtime_lock, flags);
- timer();
- write_sequnlock_irqrestore(&xtime_lock, flags);
- return(IRQ_HANDLED);
-}
-
-long um_time(int __user *tloc)
-{
- struct timeval now;
-
- do_gettimeofday(&now);
- if (tloc) {
- if (put_user(now.tv_sec, tloc))
- now.tv_sec = -EFAULT;
- }
- return now.tv_sec;
-}
-
-long um_stime(int __user *tptr)
-{
- int value;
- struct timespec new;
-
- if (get_user(value, tptr))
- return -EFAULT;
- new.tv_sec = value;
- new.tv_nsec = 0;
- do_settimeofday(&new);
- return 0;
-}
-
-void timer_handler(int sig, union uml_pt_regs *regs)
-{
- local_irq_disable();
- irq_enter();
- update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)),
- (regs)->skas.is_user));
- irq_exit();
- local_irq_enable();
- if(current_thread->cpu == 0)
- timer_irq(regs);
-}
-
-static DEFINE_SPINLOCK(timer_spinlock);
-
-unsigned long time_lock(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&timer_spinlock, flags);
- return(flags);
-}
-
-void time_unlock(unsigned long flags)
-{
- spin_unlock_irqrestore(&timer_spinlock, flags);
-}
-
-int __init timer_init(void)
-{
- int err;
-
- user_time_init();
- err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
- if(err != 0)
- printk(KERN_ERR "timer_init : request_irq failed - "
- "errno = %d\n", -err);
- timer_irq_inited = 1;
- return(0);
-}
-
-__initcall(timer_init);
-
-/*
- * 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/tlb.c b/arch/um/kernel/tlb.c
index f5b0636f9ad..f1b3eb14b85 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -1,390 +1,544 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/mm.h"
-#include "asm/page.h"
-#include "asm/pgalloc.h"
-#include "asm/tlbflush.h"
-#include "choose-mode.h"
-#include "mode_kern.h"
-#include "user_util.h"
-#include "tlb.h"
-#include "mem.h"
-#include "mem_user.h"
-#include "os.h"
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <as-layout.h>
+#include <mem_user.h>
+#include <os.h>
+#include <skas.h>
+#include <kern_util.h>
+
+struct host_vm_change {
+ struct host_vm_op {
+ enum { NONE, MMAP, MUNMAP, MPROTECT } type;
+ union {
+ struct {
+ unsigned long addr;
+ unsigned long len;
+ unsigned int prot;
+ int fd;
+ __u64 offset;
+ } mmap;
+ struct {
+ unsigned long addr;
+ unsigned long len;
+ } munmap;
+ struct {
+ unsigned long addr;
+ unsigned long len;
+ unsigned int prot;
+ } mprotect;
+ } u;
+ } ops[1];
+ int index;
+ struct mm_id *id;
+ void *data;
+ int force;
+};
+
+#define INIT_HVC(mm, force) \
+ ((struct host_vm_change) \
+ { .ops = { { .type = NONE } }, \
+ .id = &mm->context.id, \
+ .data = NULL, \
+ .index = 0, \
+ .force = force })
+
+static int do_ops(struct host_vm_change *hvc, int end,
+ int finished)
+{
+ struct host_vm_op *op;
+ int i, ret = 0;
+
+ for (i = 0; i < end && !ret; i++) {
+ op = &hvc->ops[i];
+ switch (op->type) {
+ case MMAP:
+ ret = map(hvc->id, op->u.mmap.addr, op->u.mmap.len,
+ op->u.mmap.prot, op->u.mmap.fd,
+ op->u.mmap.offset, finished, &hvc->data);
+ break;
+ case MUNMAP:
+ ret = unmap(hvc->id, op->u.munmap.addr,
+ op->u.munmap.len, finished, &hvc->data);
+ break;
+ case MPROTECT:
+ ret = protect(hvc->id, op->u.mprotect.addr,
+ op->u.mprotect.len, op->u.mprotect.prot,
+ finished, &hvc->data);
+ break;
+ default:
+ printk(KERN_ERR "Unknown op type %d in do_ops\n",
+ op->type);
+ BUG();
+ break;
+ }
+ }
+
+ return ret;
+}
static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
- int r, int w, int x, struct host_vm_op *ops, int *index,
- int last_filled, union mm_context *mmu, void **flush,
- int (*do_ops)(union mm_context *, struct host_vm_op *,
- int, int, void **))
+ unsigned int prot, struct host_vm_change *hvc)
{
- __u64 offset;
+ __u64 offset;
struct host_vm_op *last;
int fd, ret = 0;
fd = phys_mapping(phys, &offset);
- if(*index != -1){
- last = &ops[*index];
- if((last->type == MMAP) &&
+ if (hvc->index != 0) {
+ last = &hvc->ops[hvc->index - 1];
+ if ((last->type == MMAP) &&
(last->u.mmap.addr + last->u.mmap.len == virt) &&
- (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
- (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
- (last->u.mmap.offset + last->u.mmap.len == offset)){
+ (last->u.mmap.prot == prot) && (last->u.mmap.fd == fd) &&
+ (last->u.mmap.offset + last->u.mmap.len == offset)) {
last->u.mmap.len += len;
return 0;
}
}
- if(*index == last_filled){
- ret = (*do_ops)(mmu, ops, last_filled, 0, flush);
- *index = -1;
+ if (hvc->index == ARRAY_SIZE(hvc->ops)) {
+ ret = do_ops(hvc, ARRAY_SIZE(hvc->ops), 0);
+ hvc->index = 0;
}
- ops[++*index] = ((struct host_vm_op) { .type = MMAP,
- .u = { .mmap = {
- .addr = virt,
- .len = len,
- .r = r,
- .w = w,
- .x = x,
- .fd = fd,
- .offset = offset }
+ hvc->ops[hvc->index++] = ((struct host_vm_op)
+ { .type = MMAP,
+ .u = { .mmap = { .addr = virt,
+ .len = len,
+ .prot = prot,
+ .fd = fd,
+ .offset = offset }
} });
return ret;
}
static int add_munmap(unsigned long addr, unsigned long len,
- struct host_vm_op *ops, int *index, int last_filled,
- union mm_context *mmu, void **flush,
- int (*do_ops)(union mm_context *, struct host_vm_op *,
- int, int, void **))
+ struct host_vm_change *hvc)
{
struct host_vm_op *last;
int ret = 0;
- if(*index != -1){
- last = &ops[*index];
- if((last->type == MUNMAP) &&
- (last->u.munmap.addr + last->u.mmap.len == addr)){
+ if ((addr >= STUB_START) && (addr < STUB_END))
+ return -EINVAL;
+
+ if (hvc->index != 0) {
+ last = &hvc->ops[hvc->index - 1];
+ if ((last->type == MUNMAP) &&
+ (last->u.munmap.addr + last->u.mmap.len == addr)) {
last->u.munmap.len += len;
return 0;
}
}
- if(*index == last_filled){
- ret = (*do_ops)(mmu, ops, last_filled, 0, flush);
- *index = -1;
+ if (hvc->index == ARRAY_SIZE(hvc->ops)) {
+ ret = do_ops(hvc, ARRAY_SIZE(hvc->ops), 0);
+ hvc->index = 0;
}
- ops[++*index] = ((struct host_vm_op) { .type = MUNMAP,
- .u = { .munmap = {
- .addr = addr,
- .len = len } } });
+ hvc->ops[hvc->index++] = ((struct host_vm_op)
+ { .type = MUNMAP,
+ .u = { .munmap = { .addr = addr,
+ .len = len } } });
return ret;
}
-static int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
- int x, struct host_vm_op *ops, int *index,
- int last_filled, union mm_context *mmu, void **flush,
- int (*do_ops)(union mm_context *, struct host_vm_op *,
- int, int, void **))
+static int add_mprotect(unsigned long addr, unsigned long len,
+ unsigned int prot, struct host_vm_change *hvc)
{
struct host_vm_op *last;
int ret = 0;
- if(*index != -1){
- last = &ops[*index];
- if((last->type == MPROTECT) &&
+ if (hvc->index != 0) {
+ last = &hvc->ops[hvc->index - 1];
+ if ((last->type == MPROTECT) &&
(last->u.mprotect.addr + last->u.mprotect.len == addr) &&
- (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
- (last->u.mprotect.x == x)){
+ (last->u.mprotect.prot == prot)) {
last->u.mprotect.len += len;
return 0;
}
}
- if(*index == last_filled){
- ret = (*do_ops)(mmu, ops, last_filled, 0, flush);
- *index = -1;
+ if (hvc->index == ARRAY_SIZE(hvc->ops)) {
+ ret = do_ops(hvc, ARRAY_SIZE(hvc->ops), 0);
+ hvc->index = 0;
}
- ops[++*index] = ((struct host_vm_op) { .type = MPROTECT,
- .u = { .mprotect = {
- .addr = addr,
- .len = len,
- .r = r,
- .w = w,
- .x = x } } });
+ hvc->ops[hvc->index++] = ((struct host_vm_op)
+ { .type = MPROTECT,
+ .u = { .mprotect = { .addr = addr,
+ .len = len,
+ .prot = prot } } });
return ret;
}
#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
-void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
- unsigned long end_addr, int force,
- int (*do_ops)(union mm_context *, struct host_vm_op *,
- int, int, void **))
+static inline int update_pte_range(pmd_t *pmd, unsigned long addr,
+ unsigned long end,
+ struct host_vm_change *hvc)
{
- pgd_t *npgd;
- pud_t *npud;
- pmd_t *npmd;
- pte_t *npte;
- union mm_context *mmu = &mm->context;
- unsigned long addr, end;
- int r, w, x;
- struct host_vm_op ops[1];
- void *flush = NULL;
- int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1;
- int ret = 0;
-
- if(mm == NULL) return;
-
- ops[0].type = NONE;
- for(addr = start_addr; addr < end_addr && !ret;){
- npgd = pgd_offset(mm, addr);
- if(!pgd_present(*npgd)){
- end = ADD_ROUND(addr, PGDIR_SIZE);
- if(end > end_addr)
- end = end_addr;
- if(force || pgd_newpage(*npgd)){
- ret = add_munmap(addr, end - addr, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
- pgd_mkuptodate(*npgd);
- }
- addr = end;
- continue;
- }
-
- npud = pud_offset(npgd, addr);
- if(!pud_present(*npud)){
- end = ADD_ROUND(addr, PUD_SIZE);
- if(end > end_addr)
- end = end_addr;
- if(force || pud_newpage(*npud)){
- ret = add_munmap(addr, end - addr, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
- pud_mkuptodate(*npud);
- }
- addr = end;
- continue;
- }
-
- npmd = pmd_offset(npud, addr);
- if(!pmd_present(*npmd)){
- end = ADD_ROUND(addr, PMD_SIZE);
- if(end > end_addr)
- end = end_addr;
- if(force || pmd_newpage(*npmd)){
- ret = add_munmap(addr, end - addr, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
- pmd_mkuptodate(*npmd);
- }
- addr = end;
- continue;
- }
-
- npte = pte_offset_kernel(npmd, addr);
- r = pte_read(*npte);
- w = pte_write(*npte);
- x = pte_exec(*npte);
- if (!pte_young(*npte)) {
+ pte_t *pte;
+ int r, w, x, prot, ret = 0;
+
+ pte = pte_offset_kernel(pmd, addr);
+ do {
+ if ((addr >= STUB_START) && (addr < STUB_END))
+ continue;
+
+ r = pte_read(*pte);
+ w = pte_write(*pte);
+ x = pte_exec(*pte);
+ if (!pte_young(*pte)) {
r = 0;
w = 0;
- } else if (!pte_dirty(*npte)) {
+ } else if (!pte_dirty(*pte))
w = 0;
+
+ prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) |
+ (x ? UM_PROT_EXEC : 0));
+ if (hvc->force || pte_newpage(*pte)) {
+ if (pte_present(*pte))
+ ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK,
+ PAGE_SIZE, prot, hvc);
+ else
+ ret = add_munmap(addr, PAGE_SIZE, hvc);
+ } else if (pte_newprot(*pte))
+ ret = add_mprotect(addr, PAGE_SIZE, prot, hvc);
+ *pte = pte_mkuptodate(*pte);
+ } while (pte++, addr += PAGE_SIZE, ((addr < end) && !ret));
+ return ret;
+}
+
+static inline int update_pmd_range(pud_t *pud, unsigned long addr,
+ unsigned long end,
+ struct host_vm_change *hvc)
+{
+ pmd_t *pmd;
+ unsigned long next;
+ int ret = 0;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ next = pmd_addr_end(addr, end);
+ if (!pmd_present(*pmd)) {
+ if (hvc->force || pmd_newpage(*pmd)) {
+ ret = add_munmap(addr, next - addr, hvc);
+ pmd_mkuptodate(*pmd);
+ }
+ }
+ else ret = update_pte_range(pmd, addr, next, hvc);
+ } while (pmd++, addr = next, ((addr < end) && !ret));
+ return ret;
+}
+
+static inline int update_pud_range(pgd_t *pgd, unsigned long addr,
+ unsigned long end,
+ struct host_vm_change *hvc)
+{
+ pud_t *pud;
+ unsigned long next;
+ int ret = 0;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = pud_addr_end(addr, end);
+ if (!pud_present(*pud)) {
+ if (hvc->force || pud_newpage(*pud)) {
+ ret = add_munmap(addr, next - addr, hvc);
+ pud_mkuptodate(*pud);
+ }
}
- if(force || pte_newpage(*npte)){
- if(pte_present(*npte))
- ret = add_mmap(addr,
- pte_val(*npte) & PAGE_MASK,
- PAGE_SIZE, r, w, x, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
- else ret = add_munmap(addr, PAGE_SIZE, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
- }
- else if(pte_newprot(*npte))
- ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
-
- *npte = pte_mkuptodate(*npte);
- addr += PAGE_SIZE;
- }
-
- if(!ret)
- ret = (*do_ops)(mmu, ops, op_index, 1, &flush);
+ else ret = update_pmd_range(pud, addr, next, hvc);
+ } while (pud++, addr = next, ((addr < end) && !ret));
+ return ret;
+}
+
+void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
+ unsigned long end_addr, int force)
+{
+ pgd_t *pgd;
+ struct host_vm_change hvc;
+ unsigned long addr = start_addr, next;
+ int ret = 0;
+
+ hvc = INIT_HVC(mm, force);
+ pgd = pgd_offset(mm, addr);
+ do {
+ next = pgd_addr_end(addr, end_addr);
+ if (!pgd_present(*pgd)) {
+ if (force || pgd_newpage(*pgd)) {
+ ret = add_munmap(addr, next - addr, &hvc);
+ pgd_mkuptodate(*pgd);
+ }
+ }
+ else ret = update_pud_range(pgd, addr, next, &hvc);
+ } while (pgd++, addr = next, ((addr < end_addr) && !ret));
+
+ if (!ret)
+ ret = do_ops(&hvc, hvc.index, 1);
/* This is not an else because ret is modified above */
- if(ret) {
- printk("fix_range_common: failed, killing current process\n");
+ if (ret) {
+ printk(KERN_ERR "fix_range_common: failed, killing current "
+ "process: %d\n", task_tgid_vnr(current));
+ /* We are under mmap_sem, release it such that current can terminate */
+ up_write(&current->mm->mmap_sem);
force_sig(SIGKILL, current);
+ do_signal();
}
}
-int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
+static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
{
- struct mm_struct *mm;
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- unsigned long addr, last;
- int updated = 0, err;
-
- mm = &init_mm;
- for(addr = start; addr < end;){
- pgd = pgd_offset(mm, addr);
- if(!pgd_present(*pgd)){
- last = ADD_ROUND(addr, PGDIR_SIZE);
- if(last > end)
- last = end;
- if(pgd_newpage(*pgd)){
- updated = 1;
- err = os_unmap_memory((void *) addr,
- last - addr);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- }
- addr = last;
- continue;
- }
-
- pud = pud_offset(pgd, addr);
- if(!pud_present(*pud)){
- last = ADD_ROUND(addr, PUD_SIZE);
- if(last > end)
- last = end;
- if(pud_newpage(*pud)){
- updated = 1;
- err = os_unmap_memory((void *) addr,
- last - addr);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- }
- addr = last;
- continue;
- }
-
- pmd = pmd_offset(pud, addr);
- if(!pmd_present(*pmd)){
- last = ADD_ROUND(addr, PMD_SIZE);
- if(last > end)
- last = end;
- if(pmd_newpage(*pmd)){
- updated = 1;
- err = os_unmap_memory((void *) addr,
- last - addr);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- }
- addr = last;
- continue;
- }
-
- pte = pte_offset_kernel(pmd, addr);
- if(!pte_present(*pte) || pte_newpage(*pte)){
- updated = 1;
- err = os_unmap_memory((void *) addr,
- PAGE_SIZE);
- if(err < 0)
- panic("munmap failed, errno = %d\n",
- -err);
- if(pte_present(*pte))
- map_memory(addr,
- pte_val(*pte) & PAGE_MASK,
- PAGE_SIZE, 1, 1, 1);
- }
- else if(pte_newprot(*pte)){
- updated = 1;
- os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1);
- }
- addr += PAGE_SIZE;
- }
- return(updated);
+ struct mm_struct *mm;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long addr, last;
+ int updated = 0, err;
+
+ mm = &init_mm;
+ for (addr = start; addr < end;) {
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_present(*pgd)) {
+ last = ADD_ROUND(addr, PGDIR_SIZE);
+ if (last > end)
+ last = end;
+ if (pgd_newpage(*pgd)) {
+ updated = 1;
+ err = os_unmap_memory((void *) addr,
+ last - addr);
+ if (err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ }
+ addr = last;
+ continue;
+ }
+
+ pud = pud_offset(pgd, addr);
+ if (!pud_present(*pud)) {
+ last = ADD_ROUND(addr, PUD_SIZE);
+ if (last > end)
+ last = end;
+ if (pud_newpage(*pud)) {
+ updated = 1;
+ err = os_unmap_memory((void *) addr,
+ last - addr);
+ if (err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ }
+ addr = last;
+ continue;
+ }
+
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_present(*pmd)) {
+ last = ADD_ROUND(addr, PMD_SIZE);
+ if (last > end)
+ last = end;
+ if (pmd_newpage(*pmd)) {
+ updated = 1;
+ err = os_unmap_memory((void *) addr,
+ last - addr);
+ if (err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ }
+ addr = last;
+ continue;
+ }
+
+ pte = pte_offset_kernel(pmd, addr);
+ if (!pte_present(*pte) || pte_newpage(*pte)) {
+ updated = 1;
+ err = os_unmap_memory((void *) addr,
+ PAGE_SIZE);
+ if (err < 0)
+ panic("munmap failed, errno = %d\n",
+ -err);
+ if (pte_present(*pte))
+ map_memory(addr,
+ pte_val(*pte) & PAGE_MASK,
+ PAGE_SIZE, 1, 1, 1);
+ }
+ else if (pte_newprot(*pte)) {
+ updated = 1;
+ os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1);
+ }
+ addr += PAGE_SIZE;
+ }
+ return updated;
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ struct mm_struct *mm = vma->vm_mm;
+ void *flush = NULL;
+ int r, w, x, prot, err = 0;
+ struct mm_id *mm_id;
+
+ address &= PAGE_MASK;
+ pgd = pgd_offset(mm, address);
+ if (!pgd_present(*pgd))
+ goto kill;
+
+ pud = pud_offset(pgd, address);
+ if (!pud_present(*pud))
+ goto kill;
+
+ pmd = pmd_offset(pud, address);
+ if (!pmd_present(*pmd))
+ goto kill;
+
+ pte = pte_offset_kernel(pmd, address);
+
+ r = pte_read(*pte);
+ w = pte_write(*pte);
+ x = pte_exec(*pte);
+ if (!pte_young(*pte)) {
+ r = 0;
+ w = 0;
+ } else if (!pte_dirty(*pte)) {
+ w = 0;
+ }
+
+ mm_id = &mm->context.id;
+ prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) |
+ (x ? UM_PROT_EXEC : 0));
+ if (pte_newpage(*pte)) {
+ if (pte_present(*pte)) {
+ unsigned long long offset;
+ int fd;
+
+ fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset);
+ err = map(mm_id, address, PAGE_SIZE, prot, fd, offset,
+ 1, &flush);
+ }
+ else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush);
+ }
+ else if (pte_newprot(*pte))
+ err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush);
+
+ if (err)
+ goto kill;
+
+ *pte = pte_mkuptodate(*pte);
+
+ return;
+
+kill:
+ printk(KERN_ERR "Failed to flush page for address 0x%lx\n", address);
+ force_sig(SIGKILL, current);
}
pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
{
- return(pgd_offset(mm, address));
+ return pgd_offset(mm, address);
}
pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address)
{
- return(pud_offset(pgd, address));
+ return pud_offset(pgd, address);
}
pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address)
{
- return(pmd_offset(pud, address));
+ return pmd_offset(pud, address);
}
pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
{
- return(pte_offset_kernel(pmd, address));
+ return pte_offset_kernel(pmd, address);
}
pte_t *addr_pte(struct task_struct *task, unsigned long addr)
{
- pgd_t *pgd = pgd_offset(task->mm, addr);
- pud_t *pud = pud_offset(pgd, addr);
- pmd_t *pmd = pmd_offset(pud, addr);
-
- return(pte_offset_map(pmd, addr));
-}
+ pgd_t *pgd = pgd_offset(task->mm, addr);
+ pud_t *pud = pud_offset(pgd, addr);
+ pmd_t *pmd = pmd_offset(pud, addr);
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
-{
- address &= PAGE_MASK;
- flush_tlb_range(vma, address, address + PAGE_SIZE);
+ return pte_offset_map(pmd, addr);
}
void flush_tlb_all(void)
{
- flush_tlb_mm(current->mm);
+ flush_tlb_mm(current->mm);
}
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
- CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
- flush_tlb_kernel_range_common, start, end);
+ flush_tlb_kernel_range_common(start, end);
}
void flush_tlb_kernel_vm(void)
{
- CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
- flush_tlb_kernel_range_common(start_vm, end_vm));
+ flush_tlb_kernel_range_common(start_vm, end_vm);
}
void __flush_tlb_one(unsigned long addr)
{
- CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
+ flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE);
+}
+
+static void fix_range(struct mm_struct *mm, unsigned long start_addr,
+ unsigned long end_addr, int force)
+{
+ fix_range_common(mm, start_addr, end_addr, force);
}
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
- CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
- end);
+ if (vma->vm_mm == NULL)
+ flush_tlb_kernel_range_common(start, end);
+ else fix_range(vma->vm_mm, start, end, 0);
+}
+EXPORT_SYMBOL(flush_tlb_range);
+
+void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end)
+{
+ /*
+ * Don't bother flushing if this address space is about to be
+ * destroyed.
+ */
+ if (atomic_read(&mm->mm_users) == 0)
+ return;
+
+ fix_range(mm, start, end, 0);
}
void flush_tlb_mm(struct mm_struct *mm)
{
- CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
+ struct vm_area_struct *vma = mm->mmap;
+
+ while (vma != NULL) {
+ fix_range(mm, vma->vm_start, vma->vm_end, 0);
+ vma = vma->vm_next;
+ }
}
void force_flush_all(void)
{
- CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
-}
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma = mm->mmap;
+ while (vma != NULL) {
+ fix_range(mm, vma->vm_start, vma->vm_end, 1);
+ vma = vma->vm_next;
+ }
+}
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
new file mode 100644
index 00000000000..5678c3571e7
--- /dev/null
+++ b/arch/um/kernel/trap.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/hardirq.h>
+#include <linux/module.h>
+#include <asm/current.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <arch.h>
+#include <as-layout.h>
+#include <kern_util.h>
+#include <os.h>
+#include <skas.h>
+
+/*
+ * Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by
+ * segv().
+ */
+int handle_page_fault(unsigned long address, unsigned long ip,
+ int is_write, int is_user, int *code_out)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ int err = -EFAULT;
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+
+ *code_out = SEGV_MAPERR;
+
+ /*
+ * If the fault was during atomic operation, don't take the fault, just
+ * fail.
+ */
+ if (in_atomic())
+ goto out_nosemaphore;
+
+ if (is_user)
+ flags |= FAULT_FLAG_USER;
+retry:
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, address);
+ if (!vma)
+ goto out;
+ else if (vma->vm_start <= address)
+ goto good_area;
+ else if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto out;
+ else if (is_user && !ARCH_IS_STACKGROW(address))
+ goto out;
+ else if (expand_stack(vma, address))
+ goto out;
+
+good_area:
+ *code_out = SEGV_ACCERR;
+ if (is_write) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto out;
+ flags |= FAULT_FLAG_WRITE;
+ } else {
+ /* Don't require VM_READ|VM_EXEC for write faults! */
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto out;
+ }
+
+ do {
+ int fault;
+
+ fault = handle_mm_fault(mm, vma, address, flags);
+
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+ goto out_nosemaphore;
+
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM) {
+ goto out_of_memory;
+ } else if (fault & VM_FAULT_SIGBUS) {
+ err = -EACCES;
+ goto out;
+ }
+ BUG();
+ }
+ if (flags & FAULT_FLAG_ALLOW_RETRY) {
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
+ if (fault & VM_FAULT_RETRY) {
+ flags &= ~FAULT_FLAG_ALLOW_RETRY;
+ flags |= FAULT_FLAG_TRIED;
+
+ goto retry;
+ }
+ }
+
+ pgd = pgd_offset(mm, address);
+ pud = pud_offset(pgd, address);
+ pmd = pmd_offset(pud, address);
+ pte = pte_offset_kernel(pmd, address);
+ } while (!pte_present(*pte));
+ err = 0;
+ /*
+ * The below warning was added in place of
+ * pte_mkyoung(); if (is_write) pte_mkdirty();
+ * If it's triggered, we'd see normally a hang here (a clean pte is
+ * marked read-only to emulate the dirty bit).
+ * However, the generic code can mark a PTE writable but clean on a
+ * concurrent read fault, triggering this harmlessly. So comment it out.
+ */
+#if 0
+ WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte)));
+#endif
+ flush_tlb_page(vma, address);
+out:
+ up_read(&mm->mmap_sem);
+out_nosemaphore:
+ return err;
+
+out_of_memory:
+ /*
+ * We ran out of memory, call the OOM killer, and return the userspace
+ * (which will retry the fault, or kill us if we got oom-killed).
+ */
+ up_read(&mm->mmap_sem);
+ if (!is_user)
+ goto out_nosemaphore;
+ pagefault_out_of_memory();
+ return 0;
+}
+EXPORT_SYMBOL(handle_page_fault);
+
+static void show_segv_info(struct uml_pt_regs *regs)
+{
+ struct task_struct *tsk = current;
+ struct faultinfo *fi = UPT_FAULTINFO(regs);
+
+ if (!unhandled_signal(tsk, SIGSEGV))
+ return;
+
+ if (!printk_ratelimit())
+ return;
+
+ printk("%s%s[%d]: segfault at %lx ip %p sp %p error %x",
+ task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
+ tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi),
+ (void *)UPT_IP(regs), (void *)UPT_SP(regs),
+ fi->error_code);
+
+ print_vma_addr(KERN_CONT " in ", UPT_IP(regs));
+ printk(KERN_CONT "\n");
+}
+
+static void bad_segv(struct faultinfo fi, unsigned long ip)
+{
+ struct siginfo si;
+
+ si.si_signo = SIGSEGV;
+ si.si_code = SEGV_ACCERR;
+ si.si_addr = (void __user *) FAULT_ADDRESS(fi);
+ current->thread.arch.faultinfo = fi;
+ force_sig_info(SIGSEGV, &si, current);
+}
+
+void fatal_sigsegv(void)
+{
+ force_sigsegv(SIGSEGV, current);
+ do_signal();
+ /*
+ * This is to tell gcc that we're not returning - do_signal
+ * can, in general, return, but in this case, it's not, since
+ * we just got a fatal SIGSEGV queued.
+ */
+ os_dump_core();
+}
+
+void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
+{
+ struct faultinfo * fi = UPT_FAULTINFO(regs);
+
+ if (UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)) {
+ show_segv_info(regs);
+ bad_segv(*fi, UPT_IP(regs));
+ return;
+ }
+ segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
+}
+
+/*
+ * We give a *copy* of the faultinfo in the regs to segv.
+ * This must be done, since nesting SEGVs could overwrite
+ * the info in the regs. A pointer to the info then would
+ * give us bad data!
+ */
+unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
+ struct uml_pt_regs *regs)
+{
+ struct siginfo si;
+ jmp_buf *catcher;
+ int err;
+ int is_write = FAULT_WRITE(fi);
+ unsigned long address = FAULT_ADDRESS(fi);
+
+ if (!is_user && regs)
+ current->thread.segv_regs = container_of(regs, struct pt_regs, regs);
+
+ if (!is_user && (address >= start_vm) && (address < end_vm)) {
+ flush_tlb_kernel_vm();
+ goto out;
+ }
+ else if (current->mm == NULL) {
+ show_regs(container_of(regs, struct pt_regs, regs));
+ panic("Segfault with no mm");
+ }
+
+ if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi))
+ err = handle_page_fault(address, ip, is_write, is_user,
+ &si.si_code);
+ else {
+ err = -EFAULT;
+ /*
+ * A thread accessed NULL, we get a fault, but CR2 is invalid.
+ * This code is used in __do_copy_from_user() of TT mode.
+ * XXX tt mode is gone, so maybe this isn't needed any more
+ */
+ address = 0;
+ }
+
+ catcher = current->thread.fault_catcher;
+ if (!err)
+ goto out;
+ else if (catcher != NULL) {
+ current->thread.fault_addr = (void *) address;
+ UML_LONGJMP(catcher, 1);
+ }
+ else if (current->thread.fault_addr != NULL)
+ panic("fault_addr set but no fault catcher");
+ else if (!is_user && arch_fixup(ip, regs))
+ goto out;
+
+ if (!is_user) {
+ show_regs(container_of(regs, struct pt_regs, regs));
+ panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
+ address, ip);
+ }
+
+ show_segv_info(regs);
+
+ if (err == -EACCES) {
+ si.si_signo = SIGBUS;
+ si.si_errno = 0;
+ si.si_code = BUS_ADRERR;
+ si.si_addr = (void __user *)address;
+ current->thread.arch.faultinfo = fi;
+ force_sig_info(SIGBUS, &si, current);
+ } else {
+ BUG_ON(err != -EFAULT);
+ si.si_signo = SIGSEGV;
+ si.si_addr = (void __user *) address;
+ current->thread.arch.faultinfo = fi;
+ force_sig_info(SIGSEGV, &si, current);
+ }
+
+out:
+ if (regs)
+ current->thread.segv_regs = NULL;
+
+ return 0;
+}
+
+void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs)
+{
+ struct faultinfo *fi;
+ struct siginfo clean_si;
+
+ if (!UPT_IS_USER(regs)) {
+ if (sig == SIGBUS)
+ printk(KERN_ERR "Bus error - the host /dev/shm or /tmp "
+ "mount likely just ran out of space\n");
+ panic("Kernel mode signal %d", sig);
+ }
+
+ arch_examine_signal(sig, regs);
+
+ memset(&clean_si, 0, sizeof(clean_si));
+ clean_si.si_signo = si->si_signo;
+ clean_si.si_errno = si->si_errno;
+ clean_si.si_code = si->si_code;
+ switch (sig) {
+ case SIGILL:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGTRAP:
+ fi = UPT_FAULTINFO(regs);
+ clean_si.si_addr = (void __user *) FAULT_ADDRESS(*fi);
+ current->thread.arch.faultinfo = *fi;
+#ifdef __ARCH_SI_TRAPNO
+ clean_si.si_trapno = si->si_trapno;
+#endif
+ break;
+ default:
+ printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d)\n",
+ sig, si->si_code);
+ }
+
+ force_sig_info(sig, &clean_si, current);
+}
+
+void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs)
+{
+ if (current->thread.fault_catcher != NULL)
+ UML_LONGJMP(current->thread.fault_catcher, 1);
+ else
+ relay_signal(sig, si, regs);
+}
+
+void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
+{
+ do_IRQ(WINCH_IRQ, regs);
+}
+
+void trap_init(void)
+{
+}
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
deleted file mode 100644
index 95c8f8733ba..00000000000
--- a/arch/um/kernel/trap_kern.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/kernel.h"
-#include "asm/errno.h"
-#include "linux/sched.h"
-#include "linux/mm.h"
-#include "linux/spinlock.h"
-#include "linux/config.h"
-#include "linux/init.h"
-#include "linux/ptrace.h"
-#include "asm/semaphore.h"
-#include "asm/pgtable.h"
-#include "asm/pgalloc.h"
-#include "asm/tlbflush.h"
-#include "asm/a.out.h"
-#include "asm/current.h"
-#include "asm/irq.h"
-#include "sysdep/sigcontext.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "kern.h"
-#include "chan_kern.h"
-#include "mconsole_kern.h"
-#include "mem.h"
-#include "mem_kern.h"
-#ifdef CONFIG_MODE_SKAS
-#include "skas.h"
-#endif
-
-/* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */
-int handle_page_fault(unsigned long address, unsigned long ip,
- int is_write, int is_user, int *code_out)
-{
- struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- int err = -EFAULT;
-
- *code_out = SEGV_MAPERR;
-
- /* If the fault was during atomic operation, don't take the fault, just
- * fail. */
- if (in_atomic())
- goto out_nosemaphore;
-
- down_read(&mm->mmap_sem);
- vma = find_vma(mm, address);
- if(!vma)
- goto out;
- else if(vma->vm_start <= address)
- goto good_area;
- else if(!(vma->vm_flags & VM_GROWSDOWN))
- goto out;
- else if(is_user && !ARCH_IS_STACKGROW(address))
- goto out;
- else if(expand_stack(vma, address))
- goto out;
-
-good_area:
- *code_out = SEGV_ACCERR;
- if(is_write && !(vma->vm_flags & VM_WRITE))
- goto out;
-
- /* Don't require VM_READ|VM_EXEC for write faults! */
- if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC)))
- goto out;
-
- do {
-survive:
- switch (handle_mm_fault(mm, vma, address, is_write)){
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- err = -EACCES;
- goto out;
- case VM_FAULT_OOM:
- err = -ENOMEM;
- goto out_of_memory;
- default:
- BUG();
- }
- pgd = pgd_offset(mm, address);
- pud = pud_offset(pgd, address);
- pmd = pmd_offset(pud, address);
- pte = pte_offset_kernel(pmd, address);
- } while(!pte_present(*pte));
- err = 0;
- WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte)));
- flush_tlb_page(vma, address);
-out:
- up_read(&mm->mmap_sem);
-out_nosemaphore:
- return(err);
-
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
- if (current->pid == 1) {
- up_read(&mm->mmap_sem);
- yield();
- down_read(&mm->mmap_sem);
- goto survive;
- }
- goto out;
-}
-
-/*
- * We give a *copy* of the faultinfo in the regs to segv.
- * This must be done, since nesting SEGVs could overwrite
- * the info in the regs. A pointer to the info then would
- * give us bad data!
- */
-unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
-{
- struct siginfo si;
- void *catcher;
- int err;
- int is_write = FAULT_WRITE(fi);
- unsigned long address = FAULT_ADDRESS(fi);
-
- if(!is_user && (address >= start_vm) && (address < end_vm)){
- flush_tlb_kernel_vm();
- return(0);
- }
- else if(current->mm == NULL)
- panic("Segfault with no mm");
-
- if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi))
- err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
- else {
- err = -EFAULT;
- /* A thread accessed NULL, we get a fault, but CR2 is invalid.
- * This code is used in __do_copy_from_user() of TT mode. */
- address = 0;
- }
-
- catcher = current->thread.fault_catcher;
- if(!err)
- return(0);
- else if(catcher != NULL){
- current->thread.fault_addr = (void *) address;
- do_longjmp(catcher, 1);
- }
- else if(current->thread.fault_addr != NULL)
- panic("fault_addr set but no fault catcher");
- else if(!is_user && arch_fixup(ip, sc))
- return(0);
-
- if(!is_user)
- panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
- address, ip);
-
- if (err == -EACCES) {
- si.si_signo = SIGBUS;
- si.si_errno = 0;
- si.si_code = BUS_ADRERR;
- si.si_addr = (void *)address;
- current->thread.arch.faultinfo = fi;
- force_sig_info(SIGBUS, &si, current);
- } else if (err == -ENOMEM) {
- printk("VM: killing process %s\n", current->comm);
- do_exit(SIGKILL);
- } else {
- BUG_ON(err != -EFAULT);
- si.si_signo = SIGSEGV;
- si.si_addr = (void *) address;
- current->thread.arch.faultinfo = fi;
- force_sig_info(SIGSEGV, &si, current);
- }
- return(0);
-}
-
-void bad_segv(struct faultinfo fi, unsigned long ip)
-{
- struct siginfo si;
-
- si.si_signo = SIGSEGV;
- si.si_code = SEGV_ACCERR;
- si.si_addr = (void *) FAULT_ADDRESS(fi);
- current->thread.arch.faultinfo = fi;
- force_sig_info(SIGSEGV, &si, current);
-}
-
-void relay_signal(int sig, union uml_pt_regs *regs)
-{
- if(arch_handle_signal(sig, regs)) return;
- if(!UPT_IS_USER(regs))
- panic("Kernel mode signal %d", sig);
- current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
- force_sig(sig, current);
-}
-
-void bus_handler(int sig, union uml_pt_regs *regs)
-{
- if(current->thread.fault_catcher != NULL)
- do_longjmp(current->thread.fault_catcher, 1);
- else relay_signal(sig, regs);
-}
-
-void winch(int sig, union uml_pt_regs *regs)
-{
- do_IRQ(WINCH_IRQ, regs);
-}
-
-void trap_init(void)
-{
-}
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
deleted file mode 100644
index e9ccd6b8d3c..00000000000
--- a/arch/um/kernel/trap_user.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <errno.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <asm/page.h>
-#include <asm/unistd.h>
-#include <asm/ptrace.h>
-#include "init.h"
-#include "sysdep/ptrace.h"
-#include "sigcontext.h"
-#include "sysdep/sigcontext.h"
-#include "irq_user.h"
-#include "signal_user.h"
-#include "time_user.h"
-#include "task.h"
-#include "mode.h"
-#include "choose-mode.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "os.h"
-
-void kill_child_dead(int pid)
-{
- kill(pid, SIGKILL);
- kill(pid, SIGCONT);
- do {
- int n;
- CATCH_EINTR(n = waitpid(pid, NULL, 0));
- if (n > 0)
- kill(pid, SIGCONT);
- else
- break;
- } while(1);
-}
-
-void segv_handler(int sig, union uml_pt_regs *regs)
-{
- struct faultinfo * fi = UPT_FAULTINFO(regs);
-
- if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){
- bad_segv(*fi, UPT_IP(regs));
- return;
- }
- segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
-}
-
-void usr2_handler(int sig, union uml_pt_regs *regs)
-{
- CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0);
-}
-
-struct signal_info sig_info[] = {
- [ SIGTRAP ] { .handler = relay_signal,
- .is_irq = 0 },
- [ SIGFPE ] { .handler = relay_signal,
- .is_irq = 0 },
- [ SIGILL ] { .handler = relay_signal,
- .is_irq = 0 },
- [ SIGWINCH ] { .handler = winch,
- .is_irq = 1 },
- [ SIGBUS ] { .handler = bus_handler,
- .is_irq = 0 },
- [ SIGSEGV] { .handler = segv_handler,
- .is_irq = 0 },
- [ SIGIO ] { .handler = sigio_handler,
- .is_irq = 1 },
- [ SIGVTALRM ] { .handler = timer_handler,
- .is_irq = 1 },
- [ SIGALRM ] { .handler = timer_handler,
- .is_irq = 1 },
- [ SIGUSR2 ] { .handler = usr2_handler,
- .is_irq = 0 },
-};
-
-void do_longjmp(void *b, int val)
-{
- sigjmp_buf *buf = b;
-
- siglongjmp(*buf, val);
-}
-
-/*
- * 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/tt/Makefile b/arch/um/kernel/tt/Makefile
deleted file mode 100644
index 6939e5af847..00000000000
--- a/arch/um/kernel/tt/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
-# Licensed under the GPL
-#
-
-obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
- syscall_kern.o syscall_user.o tlb.o tracer.o trap_user.o \
- uaccess.o uaccess_user.o
-
-obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
-
-USER_OBJS := gdb.o tracer.o
-
-include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
deleted file mode 100644
index 065b504a653..00000000000
--- a/arch/um/kernel/tt/exec_kern.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/kernel.h"
-#include "linux/mm.h"
-#include "asm/signal.h"
-#include "asm/ptrace.h"
-#include "asm/uaccess.h"
-#include "asm/pgalloc.h"
-#include "asm/tlbflush.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "irq_user.h"
-#include "time_user.h"
-#include "signal_user.h"
-#include "mem_user.h"
-#include "os.h"
-#include "tlb.h"
-#include "mode.h"
-
-static int exec_tramp(void *sig_stack)
-{
- init_new_thread_stack(sig_stack, NULL);
- init_new_thread_signals(1);
- os_stop_process(os_getpid());
- return(0);
-}
-
-void flush_thread_tt(void)
-{
- unsigned long stack;
- int new_pid;
-
- stack = alloc_stack(0, 0);
- if(stack == 0){
- printk(KERN_ERR
- "flush_thread : failed to allocate temporary stack\n");
- do_exit(SIGKILL);
- }
-
- new_pid = start_fork_tramp(current->thread_info, stack, 0, exec_tramp);
- if(new_pid < 0){
- printk(KERN_ERR
- "flush_thread : new thread failed, errno = %d\n",
- -new_pid);
- do_exit(SIGKILL);
- }
-
- if(current_thread->cpu == 0)
- forward_interrupts(new_pid);
- current->thread.request.op = OP_EXEC;
- current->thread.request.u.exec.pid = new_pid;
- unprotect_stack((unsigned long) current_thread);
- os_usr1_process(os_getpid());
- change_sig(SIGUSR1, 1);
-
- change_sig(SIGUSR1, 0);
- enable_timer();
- free_page(stack);
- protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
- task_protections((unsigned long) current_thread);
- force_flush_all();
- unblock_signals();
-}
-
-void start_thread_tt(struct pt_regs *regs, unsigned long eip,
- unsigned long esp)
-{
- set_fs(USER_DS);
- flush_tlb_mm(current->mm);
- PT_REGS_IP(regs) = eip;
- PT_REGS_SP(regs) = esp;
- PT_FIX_EXEC_STACK(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/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c
deleted file mode 100644
index a92c02ff2ce..00000000000
--- a/arch/um/kernel/tt/exec_user.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sched.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include "user_util.h"
-#include "kern_util.h"
-#include "user.h"
-#include "ptrace_user.h"
-#include "os.h"
-
-void do_exec(int old_pid, int new_pid)
-{
- unsigned long regs[FRAME_SIZE];
- int err;
-
- if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
- (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
- tracer_panic("do_exec failed to attach proc - errno = %d",
- errno);
-
- CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
- if (err < 0)
- tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
- errno);
-
- if(ptrace_getregs(old_pid, regs) < 0)
- tracer_panic("do_exec failed to get registers - errno = %d",
- errno);
-
- os_kill_ptraced_process(old_pid, 0);
-
- if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
- tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno);
-
- if(ptrace_setregs(new_pid, regs) < 0)
- tracer_panic("do_exec failed to start new proc - errno = %d",
- errno);
-}
-
-/*
- * 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/tt/gdb.c b/arch/um/kernel/tt/gdb.c
deleted file mode 100644
index 37e22d71a0d..00000000000
--- a/arch/um/kernel/tt/gdb.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/types.h>
-#include "ptrace_user.h"
-#include "uml-config.h"
-#include "kern_constants.h"
-#include "chan_user.h"
-#include "init.h"
-#include "user.h"
-#include "debug.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "tt.h"
-#include "sysdep/thread.h"
-
-extern int debugger_pid;
-extern int debugger_fd;
-extern int debugger_parent;
-
-int detach(int pid, int sig)
-{
- return(ptrace(PTRACE_DETACH, pid, 0, sig));
-}
-
-int attach(int pid)
-{
- int err;
-
- err = ptrace(PTRACE_ATTACH, pid, 0, 0);
- if(err < 0) return(-errno);
- else return(err);
-}
-
-int cont(int pid)
-{
- return(ptrace(PTRACE_CONT, pid, 0, 0));
-}
-
-#ifdef UML_CONFIG_PT_PROXY
-
-int debugger_signal(int status, pid_t pid)
-{
- return(debugger_proxy(status, pid));
-}
-
-void child_signal(pid_t pid, int status)
-{
- child_proxy(pid, status);
-}
-
-static void gdb_announce(char *dev_name, int dev)
-{
- printf("gdb assigned device '%s'\n", dev_name);
-}
-
-static struct chan_opts opts = {
- .announce = gdb_announce,
- .xterm_title = "UML kernel debugger",
- .raw = 0,
- .tramp_stack = 0,
- .in_kernel = 0,
-};
-
-/* Accessed by the tracing thread, which automatically serializes access */
-static void *xterm_data;
-static int xterm_fd;
-
-extern void *xterm_init(char *, int, struct chan_opts *);
-extern int xterm_open(int, int, int, void *, char **);
-extern void xterm_close(int, void *);
-
-int open_gdb_chan(void)
-{
- char stack[UM_KERN_PAGE_SIZE], *dummy;
-
- opts.tramp_stack = (unsigned long) stack;
- xterm_data = xterm_init("", 0, &opts);
- xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy);
- return(xterm_fd);
-}
-
-static void exit_debugger_cb(void *unused)
-{
- if(debugger_pid != -1){
- if(gdb_pid != -1){
- fake_child_exit();
- gdb_pid = -1;
- }
- else kill_child_dead(debugger_pid);
- debugger_pid = -1;
- if(debugger_parent != -1)
- detach(debugger_parent, SIGINT);
- }
- if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
-}
-
-static void exit_debugger(void)
-{
- initial_thread_cb(exit_debugger_cb, NULL);
-}
-
-__uml_exitcall(exit_debugger);
-
-struct gdb_data {
- char *str;
- int err;
-};
-
-static void config_gdb_cb(void *arg)
-{
- struct gdb_data *data = arg;
- void *task;
- int pid;
-
- data->err = -1;
- if(debugger_pid != -1) exit_debugger_cb(NULL);
- if(!strncmp(data->str, "pid,", strlen("pid,"))){
- data->str += strlen("pid,");
- pid = strtoul(data->str, NULL, 0);
- task = cpu_tasks[0].task;
- debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0);
- if(debugger_pid != -1){
- data->err = 0;
- gdb_pid = pid;
- }
- return;
- }
- data->err = 0;
- debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
- init_proxy(debugger_pid, 0, 0);
-}
-
-int gdb_config(char *str)
-{
- struct gdb_data data;
-
- if(*str++ != '=') return(-1);
- data.str = str;
- initial_thread_cb(config_gdb_cb, &data);
- return(data.err);
-}
-
-void remove_gdb_cb(void *unused)
-{
- exit_debugger_cb(NULL);
-}
-
-int gdb_remove(int unused)
-{
- initial_thread_cb(remove_gdb_cb, NULL);
- return 0;
-}
-
-void signal_usr1(int sig)
-{
- if(debugger_pid != -1){
- printf("The debugger is already running\n");
- return;
- }
- debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
- init_proxy(debugger_pid, 0, 0);
-}
-
-int init_ptrace_proxy(int idle_pid, int startup, int stop)
-{
- int pid, status;
-
- pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
- status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
- if(pid < 0){
- cont(idle_pid);
- return(-1);
- }
- init_proxy(pid, 1, status);
- return(pid);
-}
-
-int attach_debugger(int idle_pid, int pid, int stop)
-{
- int status = 0, err;
-
- err = attach(pid);
- if(err < 0){
- printf("Failed to attach pid %d, errno = %d\n", pid, -err);
- return(-1);
- }
- if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
- init_proxy(pid, 1, status);
- return(pid);
-}
-
-#ifdef notdef /* Put this back in when it does something useful */
-static int __init uml_gdb_init_setup(char *line, int *add)
-{
- gdb_init = uml_strdup(line);
- return 0;
-}
-
-__uml_setup("gdb=", uml_gdb_init_setup,
-"gdb=<channel description>\n\n"
-);
-#endif
-
-static int __init uml_gdb_pid_setup(char *line, int *add)
-{
- gdb_pid = strtoul(line, NULL, 0);
- *add = 0;
- return 0;
-}
-
-__uml_setup("gdb-pid=", uml_gdb_pid_setup,
-"gdb-pid=<pid>\n"
-" gdb-pid is used to attach an external debugger to UML. This may be\n"
-" an already-running gdb or a debugger-like process like strace.\n\n"
-);
-
-#else
-
-int debugger_signal(int status, pid_t pid){ return(0); }
-void child_signal(pid_t pid, int status){ }
-int init_ptrace_proxy(int idle_pid, int startup, int stop)
-{
- printf("debug requested when CONFIG_PT_PROXY is off\n");
- kill_child_dead(idle_pid);
- exit(1);
-}
-
-void signal_usr1(int sig)
-{
- printf("debug requested when CONFIG_PT_PROXY is off\n");
-}
-
-int attach_debugger(int idle_pid, int pid, int stop)
-{
- printf("attach_debugger called when CONFIG_PT_PROXY "
- "is off\n");
- return(-1);
-}
-
-int config_gdb(char *str)
-{
- return(-1);
-}
-
-int remove_gdb(void)
-{
- return(-1);
-}
-
-int init_parent_proxy(int pid)
-{
- return(-1);
-}
-
-void debugger_parent_signal(int status, int pid)
-{
-}
-
-#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/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
deleted file mode 100644
index 26506388a6a..00000000000
--- a/arch/um/kernel/tt/gdb_kern.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/init.h"
-#include "linux/config.h"
-#include "mconsole_kern.h"
-
-#ifdef CONFIG_MCONSOLE
-
-extern int gdb_config(char *str);
-extern int gdb_remove(int n);
-
-static struct mc_device gdb_mc = {
- .name = "gdb",
- .config = gdb_config,
- .remove = gdb_remove,
-};
-
-int gdb_mc_init(void)
-{
- mconsole_register_dev(&gdb_mc);
- return(0);
-}
-
-__initcall(gdb_mc_init);
-
-#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/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h
deleted file mode 100644
index 738435461e1..00000000000
--- a/arch/um/kernel/tt/include/debug.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and
- * Lars Brinkhoff.
- * Licensed under the GPL
- */
-
-#ifndef __UML_TT_DEBUG_H
-#define __UML_TT_DEBUG_H
-
-extern int debugger_proxy(int status, pid_t pid);
-extern void child_proxy(pid_t pid, int status);
-extern void init_proxy (pid_t pid, int waiting, int status);
-extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
-extern void fake_child_exit(void);
-extern int gdb_config(char *str);
-extern int gdb_remove(int unused);
-
-#endif
diff --git a/arch/um/kernel/tt/include/mmu-tt.h b/arch/um/kernel/tt/include/mmu-tt.h
deleted file mode 100644
index 0440510ab3f..00000000000
--- a/arch/um/kernel/tt/include/mmu-tt.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __TT_MMU_H
-#define __TT_MMU_H
-
-struct mmu_context_tt {
-};
-
-#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/tt/include/mode-tt.h b/arch/um/kernel/tt/include/mode-tt.h
deleted file mode 100644
index e171e15fead..00000000000
--- a/arch/um/kernel/tt/include/mode-tt.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __MODE_TT_H__
-#define __MODE_TT_H__
-
-#include "sysdep/ptrace.h"
-
-enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
-
-extern int tracing_pid;
-
-extern int tracer(int (*init_proc)(void *), void *sp);
-extern void sig_handler_common_tt(int sig, void *sc);
-extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
-extern void reboot_tt(void);
-extern void halt_tt(void);
-extern int is_tracer_winch(int pid, int fd, void *data);
-extern void kill_off_processes_tt(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/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h
deleted file mode 100644
index 2a35b15c5fe..00000000000
--- a/arch/um/kernel/tt/include/mode_kern-tt.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __TT_MODE_KERN_H__
-#define __TT_MODE_KERN_H__
-
-#include "linux/sched.h"
-#include "asm/page.h"
-#include "asm/ptrace.h"
-#include "asm/uaccess.h"
-
-extern void switch_to_tt(void *prev, void *next);
-extern void flush_thread_tt(void);
-extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
- unsigned long esp);
-extern int copy_thread_tt(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_tt(struct task_struct *task);
-extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
-extern void init_idle_tt(void);
-extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
-extern void flush_tlb_kernel_vm_tt(void);
-extern void __flush_tlb_one_tt(unsigned long addr);
-extern void flush_tlb_range_tt(struct vm_area_struct *vma,
- unsigned long start, unsigned long end);
-extern void flush_tlb_mm_tt(struct mm_struct *mm);
-extern void force_flush_all_tt(void);
-extern long execute_syscall_tt(void *r);
-extern void before_mem_tt(unsigned long brk_start);
-extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
- unsigned long *task_size_out);
-extern int start_uml_tt(void);
-extern int external_pid_tt(struct task_struct *task);
-extern int thread_pid_tt(struct task_struct *task);
-
-#define kmem_end_tt (host_task_size - ABOVE_KMEM)
-
-#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/tt/include/tt.h b/arch/um/kernel/tt/include/tt.h
deleted file mode 100644
index c667b67af40..00000000000
--- a/arch/um/kernel/tt/include/tt.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __TT_H__
-#define __TT_H__
-
-#include "sysdep/ptrace.h"
-
-extern int gdb_pid;
-extern int debug;
-extern int debug_stop;
-extern int debug_trace;
-
-extern int honeypot;
-
-extern int fork_tramp(void *sig_stack);
-extern int do_proc_op(void *t, int proc_id);
-extern int tracer(int (*init_proc)(void *), void *sp);
-extern void attach_process(int pid);
-extern void tracer_panic(char *format, ...);
-extern void set_init_pid(int pid);
-extern int set_user_mode(void *task);
-extern void set_tracing(void *t, int tracing);
-extern int is_tracing(void *task);
-extern void syscall_handler(int sig, union uml_pt_regs *regs);
-extern void exit_kernel(int pid, void *task);
-extern void do_syscall(void *task, int pid, int local_using_sysemu);
-extern void do_sigtrap(void *task);
-extern int is_valid_pid(int pid);
-extern void remap_data(void *segment_start, void *segment_end, int w);
-extern long execute_syscall_tt(void *r);
-
-#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/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h
deleted file mode 100644
index dc2ebfa8c54..00000000000
--- a/arch/um/kernel/tt/include/uaccess-tt.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
- * Licensed under the GPL
- */
-
-#ifndef __TT_UACCESS_H
-#define __TT_UACCESS_H
-
-#include "linux/string.h"
-#include "linux/sched.h"
-#include "asm/processor.h"
-#include "asm/errno.h"
-#include "asm/current.h"
-#include "asm/a.out.h"
-#include "uml_uaccess.h"
-
-#define ABOVE_KMEM (16 * 1024 * 1024)
-
-extern unsigned long end_vm;
-extern unsigned long uml_physmem;
-
-#define under_task_size(addr, size) \
- (((unsigned long) (addr) < TASK_SIZE) && \
- (((unsigned long) (addr) + (size)) < TASK_SIZE))
-
-#define is_stack(addr, size) \
- (((unsigned long) (addr) < STACK_TOP) && \
- ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
- (((unsigned long) (addr) + (size)) <= STACK_TOP))
-
-#define access_ok_tt(type, addr, size) \
- ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
- (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
- (under_task_size(addr, size) || is_stack(addr, size))))
-
-extern unsigned long get_fault_addr(void);
-
-extern int __do_copy_from_user(void *to, const void *from, int n,
- void **fault_addr, void **fault_catcher);
-extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
- void **fault_addr, void **fault_catcher);
-extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
- void **fault_catcher);
-extern int __do_strnlen_user(const char *str, unsigned long n,
- void **fault_addr, void **fault_catcher);
-
-extern int copy_from_user_tt(void *to, const void __user *from, int n);
-extern int copy_to_user_tt(void __user *to, const void *from, int n);
-extern int strncpy_from_user_tt(char *dst, const char __user *src, int count);
-extern int __clear_user_tt(void __user *mem, int len);
-extern int clear_user_tt(void __user *mem, int len);
-extern int strnlen_user_tt(const void __user *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/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c
deleted file mode 100644
index 84a9385a8fe..00000000000
--- a/arch/um/kernel/tt/ksyms.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/module.h"
-#include "asm/uaccess.h"
-#include "mode.h"
-
-EXPORT_SYMBOL(__do_copy_from_user);
-EXPORT_SYMBOL(__do_copy_to_user);
-EXPORT_SYMBOL(__do_strncpy_from_user);
-EXPORT_SYMBOL(__do_strnlen_user);
-EXPORT_SYMBOL(__do_clear_user);
-EXPORT_SYMBOL(clear_user_tt);
-
-EXPORT_SYMBOL(tracing_pid);
-EXPORT_SYMBOL(honeypot);
-
-/*
- * 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/tt/mem.c b/arch/um/kernel/tt/mem.c
deleted file mode 100644
index bcb8796c3cb..00000000000
--- a/arch/um/kernel/tt/mem.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/stddef.h"
-#include "linux/config.h"
-#include "linux/mm.h"
-#include "asm/uaccess.h"
-#include "mem_user.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "kern.h"
-#include "tt.h"
-
-void before_mem_tt(unsigned long brk_start)
-{
- if(debug)
- remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
- remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
- remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
-}
-
-#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
-#define START (CONFIG_TOP_ADDR - SIZE)
-
-unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
- unsigned long *task_size_out)
-{
- /* Round up to the nearest 4M */
- *host_size_out = ROUND_4M((unsigned long) &arg);
- *task_size_out = START;
- return(START);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c
deleted file mode 100644
index 03e58989538..00000000000
--- a/arch/um/kernel/tt/mem_user.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include "tt.h"
-#include "mem_user.h"
-#include "user_util.h"
-#include "os.h"
-
-void remap_data(void *segment_start, void *segment_end, int w)
-{
- void *addr;
- unsigned long size;
- int data, prot;
-
- if(w) prot = PROT_WRITE;
- else prot = 0;
- prot |= PROT_READ | PROT_EXEC;
- size = (unsigned long) segment_end -
- (unsigned long) segment_start;
- data = create_mem_file(size);
- addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
- if(addr == MAP_FAILED){
- perror("mapping new data segment");
- exit(1);
- }
- memcpy(addr, segment_start, size);
- if(switcheroo(data, prot, addr, segment_start, size) < 0){
- printf("switcheroo failed\n");
- exit(1);
- }
-}
-
-/*
- * 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/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
deleted file mode 100644
index cfaa373a6e7..00000000000
--- a/arch/um/kernel/tt/process_kern.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/sched.h"
-#include "linux/signal.h"
-#include "linux/kernel.h"
-#include "linux/interrupt.h"
-#include "linux/ptrace.h"
-#include "asm/system.h"
-#include "asm/pgalloc.h"
-#include "asm/ptrace.h"
-#include "asm/tlbflush.h"
-#include "irq_user.h"
-#include "signal_user.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "os.h"
-#include "kern.h"
-#include "sigcontext.h"
-#include "time_user.h"
-#include "mem_user.h"
-#include "tlb.h"
-#include "mode.h"
-#include "mode_kern.h"
-#include "init.h"
-#include "tt.h"
-
-void switch_to_tt(void *prev, void *next)
-{
- struct task_struct *from, *to, *prev_sched;
- unsigned long flags;
- int err, vtalrm, alrm, prof, cpu;
- char c;
-
- from = prev;
- to = next;
-
- cpu = from->thread_info->cpu;
- if(cpu == 0)
- forward_interrupts(to->thread.mode.tt.extern_pid);
-#ifdef CONFIG_SMP
- forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid);
-#endif
- local_irq_save(flags);
-
- vtalrm = change_sig(SIGVTALRM, 0);
- alrm = change_sig(SIGALRM, 0);
- prof = change_sig(SIGPROF, 0);
-
- forward_pending_sigio(to->thread.mode.tt.extern_pid);
-
- c = 0;
-
- err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
- if(err != sizeof(c))
- panic("write of switch_pipe failed, err = %d", -err);
-
- if(from->thread.mode.tt.switch_pipe[0] == -1)
- os_kill_process(os_getpid(), 0);
-
- err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
- if(err != sizeof(c))
- panic("read of switch_pipe failed, errno = %d", -err);
-
- /* If the process that we have just scheduled away from has exited,
- * then it needs to be killed here. The reason is that, even though
- * it will kill itself when it next runs, that may be too late. Its
- * stack will be freed, possibly before then, and if that happens,
- * we have a use-after-free situation. So, it gets killed here
- * in case it has not already killed itself.
- */
- prev_sched = current->thread.prev_sched;
- if(prev_sched->thread.mode.tt.switch_pipe[0] == -1)
- os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
-
- change_sig(SIGVTALRM, vtalrm);
- change_sig(SIGALRM, alrm);
- change_sig(SIGPROF, prof);
-
- arch_switch();
-
- flush_tlb_all();
- local_irq_restore(flags);
-}
-
-void release_thread_tt(struct task_struct *task)
-{
- int pid = task->thread.mode.tt.extern_pid;
-
- /*
- * We first have to kill the other process, before
- * closing its switch_pipe. Else it might wake up
- * and receive "EOF" before we could kill it.
- */
- if(os_getpid() != pid)
- os_kill_process(pid, 0);
-
- os_close_file(task->thread.mode.tt.switch_pipe[0]);
- os_close_file(task->thread.mode.tt.switch_pipe[1]);
- /* use switch_pipe as flag: thread is released */
- task->thread.mode.tt.switch_pipe[0] = -1;
-}
-
-void suspend_new_thread(int fd)
-{
- int err;
- char c;
-
- os_stop_process(os_getpid());
- err = os_read_file(fd, &c, sizeof(c));
- if(err != sizeof(c))
- panic("read failed in suspend_new_thread, err = %d", -err);
-}
-
-void schedule_tail(task_t *prev);
-
-static void new_thread_handler(int sig)
-{
- unsigned long disable;
- int (*fn)(void *);
- void *arg;
-
- fn = current->thread.request.u.thread.proc;
- arg = current->thread.request.u.thread.arg;
-
- UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
- disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
- (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
- SC_SIGMASK(UPT_SC(&current->thread.regs.regs)) &= ~disable;
-
- suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
-
- force_flush_all();
- if(current->thread.prev_sched != NULL)
- schedule_tail(current->thread.prev_sched);
- current->thread.prev_sched = NULL;
-
- init_new_thread_signals(1);
- enable_timer();
- free_page(current->thread.temp_stack);
- set_cmdline("(kernel thread)");
-
- change_sig(SIGUSR1, 1);
- change_sig(SIGVTALRM, 1);
- change_sig(SIGPROF, 1);
- local_irq_enable();
- if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
- do_exit(0);
-
- /* XXX No set_user_mode here because a newly execed process will
- * immediately segfault on its non-existent IP, coming straight back
- * to the signal handler, which will call set_user_mode on its way
- * out. This should probably change since it's confusing.
- */
-}
-
-static int new_thread_proc(void *stack)
-{
- /* local_irq_disable is needed to block out signals until this thread is
- * properly scheduled. Otherwise, the tracing thread will get mighty
- * upset about any signals that arrive before that.
- * This has the complication that it sets the saved signal mask in
- * the sigcontext to block signals. This gets restored when this
- * thread (or a descendant, since they get a copy of this sigcontext)
- * returns to userspace.
- * So, this is compensated for elsewhere.
- * XXX There is still a small window until local_irq_disable() actually
- * finishes where signals are possible - shouldn't be a problem in
- * practice since SIGIO hasn't been forwarded here yet, and the
- * local_irq_disable should finish before a SIGVTALRM has time to be
- * delivered.
- */
-
- local_irq_disable();
- init_new_thread_stack(stack, new_thread_handler);
- os_usr1_process(os_getpid());
- change_sig(SIGUSR1, 1);
- return(0);
-}
-
-/* Signal masking - signals are blocked at the start of fork_tramp. They
- * are re-enabled when finish_fork_handler is entered by fork_tramp hitting
- * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off,
- * so it is blocked before it's called. They are re-enabled on sigreturn
- * despite the fact that they were blocked when the SIGUSR1 was issued because
- * copy_thread copies the parent's sigcontext, including the signal mask
- * onto the signal frame.
- */
-
-void finish_fork_handler(int sig)
-{
- UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
- suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
-
- force_flush_all();
- if(current->thread.prev_sched != NULL)
- schedule_tail(current->thread.prev_sched);
- current->thread.prev_sched = NULL;
-
- enable_timer();
- change_sig(SIGVTALRM, 1);
- local_irq_enable();
- if(current->mm != current->parent->mm)
- protect_memory(uml_reserved, high_physmem - uml_reserved, 1,
- 1, 0, 1);
- task_protections((unsigned long) current_thread);
-
- free_page(current->thread.temp_stack);
- local_irq_disable();
- change_sig(SIGUSR1, 0);
- set_user_mode(current);
-}
-
-int fork_tramp(void *stack)
-{
- local_irq_disable();
- arch_init_thread();
- init_new_thread_stack(stack, finish_fork_handler);
-
- os_usr1_process(os_getpid());
- change_sig(SIGUSR1, 1);
- return(0);
-}
-
-int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
- unsigned long stack_top, struct task_struct * p,
- struct pt_regs *regs)
-{
- int (*tramp)(void *);
- int new_pid, err;
- unsigned long stack;
-
- if(current->thread.forking)
- tramp = fork_tramp;
- else {
- tramp = new_thread_proc;
- p->thread.request.u.thread = current->thread.request.u.thread;
- }
-
- err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
- if(err < 0){
- printk("copy_thread : pipe failed, err = %d\n", -err);
- return(err);
- }
-
- stack = alloc_stack(0, 0);
- if(stack == 0){
- printk(KERN_ERR "copy_thread : failed to allocate "
- "temporary stack\n");
- return(-ENOMEM);
- }
-
- clone_flags &= CLONE_VM;
- p->thread.temp_stack = stack;
- new_pid = start_fork_tramp(p->thread_info, stack, clone_flags, tramp);
- if(new_pid < 0){
- printk(KERN_ERR "copy_thread : clone failed - errno = %d\n",
- -new_pid);
- return(new_pid);
- }
-
- if(current->thread.forking){
- sc_to_sc(UPT_SC(&p->thread.regs.regs), UPT_SC(&regs->regs));
- SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
- if(sp != 0)
- SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
- }
- p->thread.mode.tt.extern_pid = new_pid;
-
- current->thread.request.op = OP_FORK;
- current->thread.request.u.fork.pid = new_pid;
- os_usr1_process(os_getpid());
-
- /* Enable the signal and then disable it to ensure that it is handled
- * here, and nowhere else.
- */
- change_sig(SIGUSR1, 1);
-
- change_sig(SIGUSR1, 0);
- err = 0;
- return(err);
-}
-
-void reboot_tt(void)
-{
- current->thread.request.op = OP_REBOOT;
- os_usr1_process(os_getpid());
- change_sig(SIGUSR1, 1);
-}
-
-void halt_tt(void)
-{
- current->thread.request.op = OP_HALT;
- os_usr1_process(os_getpid());
- change_sig(SIGUSR1, 1);
-}
-
-void kill_off_processes_tt(void)
-{
- struct task_struct *p;
- int me;
-
- me = os_getpid();
- for_each_process(p){
- if(p->thread.mode.tt.extern_pid != me)
- os_kill_process(p->thread.mode.tt.extern_pid, 0);
- }
- if(init_task.thread.mode.tt.extern_pid != me)
- os_kill_process(init_task.thread.mode.tt.extern_pid, 0);
-}
-
-void initial_thread_cb_tt(void (*proc)(void *), void *arg)
-{
- if(os_getpid() == tracing_pid){
- (*proc)(arg);
- }
- else {
- current->thread.request.op = OP_CB;
- current->thread.request.u.cb.proc = proc;
- current->thread.request.u.cb.arg = arg;
- os_usr1_process(os_getpid());
- change_sig(SIGUSR1, 1);
-
- change_sig(SIGUSR1, 0);
- }
-}
-
-int do_proc_op(void *t, int proc_id)
-{
- struct task_struct *task;
- struct thread_struct *thread;
- int op, pid;
-
- task = t;
- thread = &task->thread;
- op = thread->request.op;
- switch(op){
- case OP_NONE:
- case OP_TRACE_ON:
- break;
- case OP_EXEC:
- pid = thread->request.u.exec.pid;
- do_exec(thread->mode.tt.extern_pid, pid);
- thread->mode.tt.extern_pid = pid;
- cpu_tasks[task->thread_info->cpu].pid = pid;
- break;
- case OP_FORK:
- attach_process(thread->request.u.fork.pid);
- break;
- case OP_CB:
- (*thread->request.u.cb.proc)(thread->request.u.cb.arg);
- break;
- case OP_REBOOT:
- case OP_HALT:
- break;
- default:
- tracer_panic("Bad op in do_proc_op");
- break;
- }
- thread->request.op = OP_NONE;
- return(op);
-}
-
-void init_idle_tt(void)
-{
- 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
- if(debug) os_stop_process(pid);
- start_kernel();
- return(0);
-}
-
-void set_tracing(void *task, int tracing)
-{
- ((struct task_struct *) task)->thread.mode.tt.tracing = tracing;
-}
-
-int is_tracing(void *t)
-{
- return (((struct task_struct *) t)->thread.mode.tt.tracing);
-}
-
-int set_user_mode(void *t)
-{
- struct task_struct *task;
-
- task = t ? t : current;
- if(task->thread.mode.tt.tracing)
- return(1);
- task->thread.request.op = OP_TRACE_ON;
- os_usr1_process(os_getpid());
- return(0);
-}
-
-void set_init_pid(int pid)
-{
- int err;
-
- init_task.thread.mode.tt.extern_pid = pid;
- err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
- if(err)
- panic("Can't create switch pipe for init_task, errno = %d",
- -err);
-}
-
-int start_uml_tt(void)
-{
- void *sp;
- int pages;
-
- pages = (1 << CONFIG_KERNEL_STACK_ORDER);
- sp = (void *) ((unsigned long) init_task.thread_info) +
- pages * PAGE_SIZE - sizeof(unsigned long);
- return(tracer(start_kernel_proc, sp));
-}
-
-int external_pid_tt(struct task_struct *task)
-{
- return(task->thread.mode.tt.extern_pid);
-}
-
-int thread_pid_tt(struct task_struct *task)
-{
- return(task->thread.mode.tt.extern_pid);
-}
-
-int is_valid_pid(int pid)
-{
- struct task_struct *task;
-
- read_lock(&tasklist_lock);
- for_each_process(task){
- if(task->thread.mode.tt.extern_pid == pid){
- read_unlock(&tasklist_lock);
- return(1);
- }
- }
- read_unlock(&tasklist_lock);
- return(0);
-}
diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile
deleted file mode 100644
index 3ad5b774de5..00000000000
--- a/arch/um/kernel/tt/ptproxy/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
-# Licensed under the GPL
-#
-
-obj-y = proxy.o ptrace.o sysdep.o wait.o
-
-USER_OBJS := $(obj-y)
-
-include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
deleted file mode 100644
index 58800c50b10..00000000000
--- a/arch/um/kernel/tt/ptproxy/proxy.c
+++ /dev/null
@@ -1,377 +0,0 @@
-/**********************************************************************
-proxy.c
-
-Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
-terms and conditions.
-
-Jeff Dike (jdike@karaya.com) : Modified for integration into uml
-**********************************************************************/
-
-/* XXX This file shouldn't refer to CONFIG_* */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <string.h>
-#include <termios.h>
-#include <sys/wait.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <asm/unistd.h>
-#include "ptrace_user.h"
-
-#include "ptproxy.h"
-#include "sysdep.h"
-#include "wait.h"
-
-#include "user_util.h"
-#include "user.h"
-#include "os.h"
-#include "tempfile.h"
-
-static int debugger_wait(debugger_state *debugger, int *status, int options,
- int (*syscall)(debugger_state *debugger, pid_t child),
- int (*normal_return)(debugger_state *debugger,
- pid_t unused),
- int (*wait_return)(debugger_state *debugger,
- pid_t unused))
-{
- if(debugger->real_wait){
- debugger->handle_trace = normal_return;
- syscall_continue(debugger->pid);
- debugger->real_wait = 0;
- return(1);
- }
- debugger->wait_status_ptr = status;
- debugger->wait_options = options;
- if((debugger->debugee != NULL) && debugger->debugee->event){
- syscall_continue(debugger->pid);
- wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
- NULL);
- (*wait_return)(debugger, -1);
- return(0);
- }
- else if(debugger->wait_options & WNOHANG){
- syscall_cancel(debugger->pid, 0);
- debugger->handle_trace = syscall;
- return(0);
- }
- else {
- syscall_pause(debugger->pid);
- debugger->handle_trace = wait_return;
- debugger->waiting = 1;
- }
- return(1);
-}
-
-/*
- * Handle debugger trap, i.e. syscall.
- */
-
-int debugger_syscall(debugger_state *debugger, pid_t child)
-{
- long arg1, arg2, arg3, arg4, arg5, result;
- int syscall, ret = 0;
-
- syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,
- &arg5);
-
- switch(syscall){
- case __NR_execve:
- /* execve never returns */
- debugger->handle_trace = debugger_syscall;
- break;
-
- case __NR_ptrace:
- if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
- if(!debugger->debugee->in_context)
- child = debugger->debugee->pid;
- result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
- &ret);
- syscall_cancel(debugger->pid, result);
- debugger->handle_trace = debugger_syscall;
- return(ret);
-
-#ifdef __NR_waitpid
- case __NR_waitpid:
-#endif
- case __NR_wait4:
- if(!debugger_wait(debugger, (int *) arg2, arg3,
- debugger_syscall, debugger_normal_return,
- proxy_wait_return))
- return(0);
- break;
-
- case __NR_kill:
- if(!debugger->debugee->in_context)
- child = debugger->debugee->pid;
- if(arg1 == debugger->debugee->pid){
- result = kill(child, arg2);
- syscall_cancel(debugger->pid, result);
- debugger->handle_trace = debugger_syscall;
- return(0);
- }
- else debugger->handle_trace = debugger_normal_return;
- break;
-
- default:
- debugger->handle_trace = debugger_normal_return;
- }
-
- syscall_continue(debugger->pid);
- return(0);
-}
-
-/* Used by the tracing thread */
-static debugger_state parent;
-static int parent_syscall(debugger_state *debugger, int pid);
-
-int init_parent_proxy(int pid)
-{
- parent = ((debugger_state) { .pid = pid,
- .wait_options = 0,
- .wait_status_ptr = NULL,
- .waiting = 0,
- .real_wait = 0,
- .expecting_child = 0,
- .handle_trace = parent_syscall,
- .debugee = NULL } );
- return(0);
-}
-
-int parent_normal_return(debugger_state *debugger, pid_t unused)
-{
- debugger->handle_trace = parent_syscall;
- syscall_continue(debugger->pid);
- return(0);
-}
-
-static int parent_syscall(debugger_state *debugger, int pid)
-{
- long arg1, arg2, arg3, arg4, arg5;
- int syscall;
-
- syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
-
- if((syscall == __NR_wait4)
-#ifdef __NR_waitpid
- || (syscall == __NR_waitpid)
-#endif
- ){
- debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
- parent_normal_return, parent_wait_return);
- }
- else ptrace(PTRACE_SYSCALL, pid, 0, 0);
- return(0);
-}
-
-int debugger_normal_return(debugger_state *debugger, pid_t unused)
-{
- debugger->handle_trace = debugger_syscall;
- syscall_continue(debugger->pid);
- return(0);
-}
-
-void debugger_cancelled_return(debugger_state *debugger, int result)
-{
- debugger->handle_trace = debugger_syscall;
- syscall_set_result(debugger->pid, result);
- syscall_continue(debugger->pid);
-}
-
-/* Used by the tracing thread */
-static debugger_state debugger;
-static debugee_state debugee;
-
-void init_proxy (pid_t debugger_pid, int stopped, int status)
-{
- debugger.pid = debugger_pid;
- debugger.handle_trace = debugger_syscall;
- debugger.debugee = &debugee;
- debugger.waiting = 0;
- debugger.real_wait = 0;
- debugger.expecting_child = 0;
-
- debugee.pid = 0;
- debugee.traced = 0;
- debugee.stopped = stopped;
- debugee.event = 0;
- debugee.zombie = 0;
- debugee.died = 0;
- debugee.wait_status = status;
- debugee.in_context = 1;
-}
-
-int debugger_proxy(int status, int pid)
-{
- int ret = 0, sig;
-
- if(WIFSTOPPED(status)){
- sig = WSTOPSIG(status);
- if (sig == SIGTRAP)
- ret = (*debugger.handle_trace)(&debugger, pid);
-
- else if(sig == SIGCHLD){
- if(debugger.expecting_child){
- ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
- debugger.expecting_child = 0;
- }
- else if(debugger.waiting)
- real_wait_return(&debugger);
- else {
- ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
- debugger.real_wait = 1;
- }
- }
- else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
- }
- else if(WIFEXITED(status)){
- tracer_panic("debugger (pid %d) exited with status %d",
- debugger.pid, WEXITSTATUS(status));
- }
- else if(WIFSIGNALED(status)){
- tracer_panic("debugger (pid %d) exited with signal %d",
- debugger.pid, WTERMSIG(status));
- }
- else {
- tracer_panic("proxy got unknown status (0x%x) on debugger "
- "(pid %d)", status, debugger.pid);
- }
- return(ret);
-}
-
-void child_proxy(pid_t pid, int status)
-{
- debugee.event = 1;
- debugee.wait_status = status;
-
- if(WIFSTOPPED(status)){
- debugee.stopped = 1;
- debugger.expecting_child = 1;
- kill(debugger.pid, SIGCHLD);
- }
- else if(WIFEXITED(status) || WIFSIGNALED(status)){
- debugee.zombie = 1;
- debugger.expecting_child = 1;
- kill(debugger.pid, SIGCHLD);
- }
- else panic("proxy got unknown status (0x%x) on child (pid %d)",
- status, pid);
-}
-
-void debugger_parent_signal(int status, int pid)
-{
- int sig;
-
- if(WIFSTOPPED(status)){
- sig = WSTOPSIG(status);
- if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
- else ptrace(PTRACE_SYSCALL, pid, 0, sig);
- }
-}
-
-void fake_child_exit(void)
-{
- int status, pid;
-
- child_proxy(1, W_EXITCODE(0, 0));
- while(debugger.waiting == 1){
- CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
- if(pid != debugger.pid){
- printk("fake_child_exit - waitpid failed, "
- "errno = %d\n", errno);
- return;
- }
- debugger_proxy(status, debugger.pid);
- }
- CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
- if(pid != debugger.pid){
- printk("fake_child_exit - waitpid failed, "
- "errno = %d\n", errno);
- return;
- }
- if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
- printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
- errno);
-}
-
-char gdb_init_string[] =
-"att 1 \n\
-b panic \n\
-b stop \n\
-handle SIGWINCH nostop noprint pass \n\
-";
-
-int start_debugger(char *prog, int startup, int stop, int *fd_out)
-{
- int slave, child;
-
- slave = open_gdb_chan();
- child = fork();
- if(child == 0){
- char *tempname = NULL;
- int fd;
-
- if(setsid() < 0) perror("setsid");
- if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) ||
- (dup2(slave, 2) < 0)){
- printk("start_debugger : dup2 failed, errno = %d\n",
- errno);
- exit(1);
- }
- if(ioctl(0, TIOCSCTTY, 0) < 0){
- printk("start_debugger : TIOCSCTTY failed, "
- "errno = %d\n", errno);
- exit(1);
- }
- if(tcsetpgrp (1, os_getpid()) < 0){
- printk("start_debugger : tcsetpgrp failed, "
- "errno = %d\n", errno);
-#ifdef notdef
- exit(1);
-#endif
- }
- fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
- if(fd < 0){
- printk("start_debugger : make_tempfile failed,"
- "err = %d\n", -fd);
- exit(1);
- }
- os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
- if(startup){
- if(stop){
- os_write_file(fd, "b start_kernel\n",
- strlen("b start_kernel\n"));
- }
- os_write_file(fd, "c\n", strlen("c\n"));
- }
- if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
- printk("start_debugger : PTRACE_TRACEME failed, "
- "errno = %d\n", errno);
- exit(1);
- }
- execlp("gdb", "gdb", "--command", tempname, prog, NULL);
- printk("start_debugger : exec of gdb failed, errno = %d\n",
- errno);
- }
- if(child < 0){
- printk("start_debugger : fork for gdb failed, errno = %d\n",
- errno);
- return(-1);
- }
- *fd_out = slave;
- return(child);
-}
-
-/*
- * 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/tt/ptproxy/ptproxy.h b/arch/um/kernel/tt/ptproxy/ptproxy.h
deleted file mode 100644
index 5eb0285b196..00000000000
--- a/arch/um/kernel/tt/ptproxy/ptproxy.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/**********************************************************************
-ptproxy.h
-
-Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
-terms and conditions.
-**********************************************************************/
-
-#ifndef __PTPROXY_H
-#define __PTPROXY_H
-
-#include <sys/types.h>
-
-typedef struct debugger debugger_state;
-typedef struct debugee debugee_state;
-
-struct debugger
-{
- pid_t pid;
- int wait_options;
- int *wait_status_ptr;
- unsigned int waiting : 1;
- unsigned int real_wait : 1;
- unsigned int expecting_child : 1;
- int (*handle_trace) (debugger_state *, pid_t);
-
- debugee_state *debugee;
-};
-
-struct debugee
-{
- pid_t pid;
- int wait_status;
- unsigned int died : 1;
- unsigned int event : 1;
- unsigned int stopped : 1;
- unsigned int trace_singlestep : 1;
- unsigned int trace_syscall : 1;
- unsigned int traced : 1;
- unsigned int zombie : 1;
- unsigned int in_context : 1;
-};
-
-extern int debugger_syscall(debugger_state *debugger, pid_t pid);
-extern int debugger_normal_return (debugger_state *debugger, pid_t unused);
-
-extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t,
- int *strace_out);
-extern void debugger_cancelled_return(debugger_state *debugger, int 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/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
deleted file mode 100644
index 528a5fc8d88..00000000000
--- a/arch/um/kernel/tt/ptproxy/ptrace.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/**********************************************************************
-ptrace.c
-
-Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
-terms and conditions.
-
-Jeff Dike (jdike@karaya.com) : Modified for integration into uml
-**********************************************************************/
-
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-
-#include "ptproxy.h"
-#include "debug.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "ptrace_user.h"
-#include "tt.h"
-
-long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
- long arg3, long arg4, pid_t child, int *ret)
-{
- sigset_t relay;
- long result;
- int status;
-
- *ret = 0;
- if(debugger->debugee->died) return(-ESRCH);
-
- switch(arg1){
- case PTRACE_ATTACH:
- if(debugger->debugee->traced) return(-EPERM);
-
- debugger->debugee->pid = arg2;
- debugger->debugee->traced = 1;
-
- if(is_valid_pid(arg2) && (arg2 != child)){
- debugger->debugee->in_context = 0;
- kill(arg2, SIGSTOP);
- debugger->debugee->event = 1;
- debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
- }
- else {
- debugger->debugee->in_context = 1;
- if(debugger->debugee->stopped)
- child_proxy(child, W_STOPCODE(SIGSTOP));
- else kill(child, SIGSTOP);
- }
-
- return(0);
-
- case PTRACE_DETACH:
- if(!debugger->debugee->traced) return(-EPERM);
-
- debugger->debugee->traced = 0;
- debugger->debugee->pid = 0;
- if(!debugger->debugee->in_context)
- kill(child, SIGCONT);
-
- return(0);
-
- case PTRACE_CONT:
- if(!debugger->debugee->in_context) return(-EPERM);
- *ret = PTRACE_CONT;
- return(ptrace(PTRACE_CONT, child, arg3, arg4));
-
-#ifdef UM_HAVE_GETFPREGS
- case PTRACE_GETFPREGS:
- {
- long regs[FP_FRAME_SIZE];
- int i, result;
-
- result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
- if(result == -1) return(-errno);
-
- for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
- ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
- regs[i]);
- return(result);
- }
-#endif
-
-#ifdef UM_HAVE_GETFPXREGS
- case PTRACE_GETFPXREGS:
- {
- long regs[FPX_FRAME_SIZE];
- int i, result;
-
- result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
- if(result == -1) return(-errno);
-
- for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
- ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
- regs[i]);
- return(result);
- }
-#endif
-
-#ifdef UM_HAVE_GETREGS
- case PTRACE_GETREGS:
- {
- long regs[FRAME_SIZE];
- int i, result;
-
- result = ptrace(PTRACE_GETREGS, child, 0, regs);
- if(result == -1) return(-errno);
-
- for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
- ptrace (PTRACE_POKEDATA, debugger->pid,
- arg4 + 4 * i, regs[i]);
- return(result);
- }
- break;
-#endif
-
- case PTRACE_KILL:
- result = ptrace(PTRACE_KILL, child, arg3, arg4);
- if(result == -1) return(-errno);
-
- return(result);
-
- case PTRACE_PEEKDATA:
- case PTRACE_PEEKTEXT:
- case PTRACE_PEEKUSR:
- /* The value being read out could be -1, so we have to
- * check errno to see if there's an error, and zero it
- * beforehand so we're not faked out by an old error
- */
-
- errno = 0;
- result = ptrace(arg1, child, arg3, 0);
- if((result == -1) && (errno != 0)) return(-errno);
-
- result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
- if(result == -1) return(-errno);
-
- return(result);
-
- case PTRACE_POKEDATA:
- case PTRACE_POKETEXT:
- case PTRACE_POKEUSR:
- result = ptrace(arg1, child, arg3, arg4);
- if(result == -1) return(-errno);
-
- if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4);
- return(result);
-
-#ifdef UM_HAVE_SETFPREGS
- case PTRACE_SETFPREGS:
- {
- long regs[FP_FRAME_SIZE];
- int i;
-
- for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
- regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
- arg4 + 4 * i, 0);
- result = ptrace(PTRACE_SETFPREGS, child, 0, regs);
- if(result == -1) return(-errno);
-
- return(result);
- }
-#endif
-
-#ifdef UM_HAVE_SETFPXREGS
- case PTRACE_SETFPXREGS:
- {
- long regs[FPX_FRAME_SIZE];
- int i;
-
- for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
- regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
- arg4 + 4 * i, 0);
- result = ptrace(PTRACE_SETFPXREGS, child, 0, regs);
- if(result == -1) return(-errno);
-
- return(result);
- }
-#endif
-
-#ifdef UM_HAVE_SETREGS
- case PTRACE_SETREGS:
- {
- long regs[FRAME_SIZE];
- int i;
-
- for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
- regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid,
- arg4 + 4 * i, 0);
- result = ptrace(PTRACE_SETREGS, child, 0, regs);
- if(result == -1) return(-errno);
-
- return(result);
- }
-#endif
-
- case PTRACE_SINGLESTEP:
- if(!debugger->debugee->in_context) return(-EPERM);
- sigemptyset(&relay);
- sigaddset(&relay, SIGSEGV);
- sigaddset(&relay, SIGILL);
- sigaddset(&relay, SIGBUS);
- result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
- if(result == -1) return(-errno);
-
- status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP,
- &relay);
- child_proxy(child, status);
- return(result);
-
- case PTRACE_SYSCALL:
- if(!debugger->debugee->in_context) return(-EPERM);
- result = ptrace(PTRACE_SYSCALL, child, arg3, arg4);
- if(result == -1) return(-errno);
-
- *ret = PTRACE_SYSCALL;
- return(result);
-
- case PTRACE_TRACEME:
- default:
- return(-EINVAL);
- }
-}
-
-/*
- * 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/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
deleted file mode 100644
index a5f0e01e214..00000000000
--- a/arch/um/kernel/tt/ptproxy/sysdep.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/**********************************************************************
-sysdep.c
-
-Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
-terms and conditions.
-**********************************************************************/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <linux/unistd.h>
-#include "ptrace_user.h"
-#include "user_util.h"
-#include "user.h"
-
-int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4,
- long *arg5)
-{
- *arg1 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG1_OFFSET, 0);
- *arg2 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG2_OFFSET, 0);
- *arg3 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG3_OFFSET, 0);
- *arg4 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG4_OFFSET, 0);
- *arg5 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG5_OFFSET, 0);
- return(ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0));
-}
-
-void syscall_cancel(pid_t pid, int result)
-{
- if((ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
- __NR_getpid) < 0) ||
- (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
- (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
- (ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
- (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
- printk("ptproxy: couldn't cancel syscall: errno = %d\n",
- errno);
-}
-
-void syscall_set_result(pid_t pid, long result)
-{
- ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result);
-}
-
-void syscall_continue(pid_t pid)
-{
- ptrace(PTRACE_SYSCALL, pid, 0, 0);
-}
-
-int syscall_pause(pid_t pid)
-{
- if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
- printk("syscall_change - ptrace failed, errno = %d\n", errno);
- return(-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:
- */
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.h b/arch/um/kernel/tt/ptproxy/sysdep.h
deleted file mode 100644
index 735f488049a..00000000000
--- a/arch/um/kernel/tt/ptproxy/sysdep.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/**********************************************************************
-sysdep.h
-
-Copyright (C) 1999 Lars Brinkhoff.
-Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
-See the file COPYING for licensing terms and conditions.
-**********************************************************************/
-
-extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3,
- long *arg4, long *arg5);
-extern void syscall_cancel (pid_t pid, long result);
-extern void syscall_set_result (pid_t pid, long result);
-extern void syscall_continue (pid_t pid);
-extern int syscall_pause(pid_t 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/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
deleted file mode 100644
index 12f6319d8d7..00000000000
--- a/arch/um/kernel/tt/ptproxy/wait.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/**********************************************************************
-wait.c
-
-Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
-terms and conditions.
-
-**********************************************************************/
-
-#include <errno.h>
-#include <signal.h>
-#include <sys/wait.h>
-
-#include "ptproxy.h"
-#include "sysdep.h"
-#include "wait.h"
-#include "user_util.h"
-#include "ptrace_user.h"
-#include "sysdep/ptrace.h"
-#include "sysdep/sigcontext.h"
-
-int proxy_wait_return(struct debugger *debugger, pid_t unused)
-{
- debugger->waiting = 0;
-
- if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){
- debugger_cancelled_return(debugger, -ECHILD);
- return(0);
- }
-
- if(debugger->debugee->zombie && debugger->debugee->event)
- debugger->debugee->died = 1;
-
- if(debugger->debugee->event){
- debugger->debugee->event = 0;
- ptrace(PTRACE_POKEDATA, debugger->pid,
- debugger->wait_status_ptr,
- debugger->debugee->wait_status);
- /* if (wait4)
- ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */
- debugger_cancelled_return(debugger, debugger->debugee->pid);
- return(0);
- }
-
- /* pause will return -EINTR, which happens to be right for wait */
- debugger_normal_return(debugger, -1);
- return(0);
-}
-
-int parent_wait_return(struct debugger *debugger, pid_t unused)
-{
- return(debugger_normal_return(debugger, -1));
-}
-
-int real_wait_return(struct debugger *debugger)
-{
- unsigned long ip;
- int pid;
-
- pid = debugger->pid;
-
- ip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
- IP_RESTART_SYSCALL(ip);
-
- if(ptrace(PTRACE_POKEUSR, pid, PT_IP_OFFSET, ip) < 0)
- tracer_panic("real_wait_return : Failed to restart system "
- "call, errno = %d\n", errno);
-
- if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
- (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
- (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
- debugger_normal_return(debugger, -1))
- tracer_panic("real_wait_return : gdb failed to wait, "
- "errno = %d\n", errno);
- 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/tt/ptproxy/wait.h b/arch/um/kernel/tt/ptproxy/wait.h
deleted file mode 100644
index 542e73ee2ce..00000000000
--- a/arch/um/kernel/tt/ptproxy/wait.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/**********************************************************************
-wait.h
-
-Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
-terms and conditions.
-**********************************************************************/
-
-#ifndef __PTPROXY_WAIT_H
-#define __PTPROXY_WAIT_H
-
-extern int proxy_wait_return(struct debugger *debugger, pid_t unused);
-extern int real_wait_return(struct debugger *debugger);
-extern int parent_wait_return(struct debugger *debugger, pid_t unused);
-
-#endif
diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
deleted file mode 100644
index 3d29c90514c..00000000000
--- a/arch/um/kernel/tt/syscall_kern.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
- * Licensed under the GPL
- */
-
-#include "linux/types.h"
-#include "linux/utime.h"
-#include "linux/sys.h"
-#include "linux/ptrace.h"
-#include "asm/unistd.h"
-#include "asm/ptrace.h"
-#include "asm/uaccess.h"
-#include "asm/stat.h"
-#include "sysdep/syscalls.h"
-#include "sysdep/sigcontext.h"
-#include "kern_util.h"
-#include "syscall.h"
-
-void syscall_handler_tt(int sig, struct pt_regs *regs)
-{
- void *sc;
- long result;
- int syscall;
-#ifdef CONFIG_SYSCALL_DEBUG
- int index;
- index = record_syscall_start(syscall);
-#endif
- sc = UPT_SC(&regs->regs);
- SC_START_SYSCALL(sc);
-
- syscall_trace(&regs->regs, 0);
-
- current->thread.nsyscalls++;
- nsyscalls++;
- syscall = UPT_SYSCALL_NR(&regs->regs);
-
- if((syscall >= NR_syscalls) || (syscall < 0))
- result = -ENOSYS;
- else result = EXECUTE_SYSCALL(syscall, regs);
-
- /* regs->sc may have changed while the system call ran (there may
- * have been an interrupt or segfault), so it needs to be refreshed.
- */
- UPT_SC(&regs->regs) = sc;
-
- SC_SET_SYSCALL_RETURN(sc, result);
-
- syscall_trace(&regs->regs, 1);
-#ifdef CONFIG_SYSCALL_DEBUG
- record_syscall_end(index, result);
-#endif
-}
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
deleted file mode 100644
index 902987bf379..00000000000
--- a/arch/um/kernel/tt/syscall_user.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-#include <asm/unistd.h>
-#include "sysdep/ptrace.h"
-#include "sigcontext.h"
-#include "ptrace_user.h"
-#include "task.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "syscall.h"
-#include "tt.h"
-
-void do_sigtrap(void *task)
-{
- UPT_SYSCALL_NR(TASK_REGS(task)) = -1;
-}
-
-void do_syscall(void *task, int pid, int local_using_sysemu)
-{
- unsigned long proc_regs[FRAME_SIZE];
-
- if(ptrace_getregs(pid, proc_regs) < 0)
- tracer_panic("Couldn't read registers");
-
- UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs);
-
-#ifdef UPT_ORIGGPR2
- UPT_ORIGGPR2(TASK_REGS(task)) = REGS_ORIGGPR2(proc_regs);
-#endif
-
- if(((unsigned long *) PT_IP(proc_regs) >= &_stext) &&
- ((unsigned long *) PT_IP(proc_regs) <= &_etext))
- tracer_panic("I'm tracing myself and I can't get out");
-
- /* advanced sysemu mode set syscall number to -1 automatically */
- if (local_using_sysemu==2)
- return;
-
- /* syscall number -1 in sysemu skips syscall restarting in host */
- if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
- local_using_sysemu ? -1 : __NR_getpid) < 0)
- tracer_panic("do_syscall : Nullifying syscall failed, "
- "errno = %d", errno);
-}
-
-/*
- * 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/tt/tlb.c b/arch/um/kernel/tt/tlb.c
deleted file mode 100644
index ae6217c8613..00000000000
--- a/arch/um/kernel/tt/tlb.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Copyright 2003 PathScale, Inc.
- * Licensed under the GPL
- */
-
-#include "linux/stddef.h"
-#include "linux/kernel.h"
-#include "linux/sched.h"
-#include "linux/mm.h"
-#include "asm/page.h"
-#include "asm/pgtable.h"
-#include "asm/uaccess.h"
-#include "asm/tlbflush.h"
-#include "user_util.h"
-#include "mem_user.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 = os_map_memory((void *) op->u.mmap.addr,
- op->u.mmap.fd, op->u.mmap.offset,
- op->u.mmap.len, op->u.mmap.r,
- op->u.mmap.w, op->u.mmap.x);
- break;
- case MUNMAP:
- ret = os_unmap_memory((void *) op->u.munmap.addr,
- op->u.munmap.len);
- break;
- case MPROTECT:
- ret = protect_memory(op->u.mprotect.addr,
- op->u.munmap.len,
- op->u.mprotect.r,
- op->u.mprotect.w,
- op->u.mprotect.x, 1);
- protect_memory(op->u.mprotect.addr, op->u.munmap.len,
- op->u.mprotect.r, op->u.mprotect.w,
- op->u.mprotect.x, 1);
- break;
- default:
- printk("Unknown op type %d in do_ops\n", op->type);
- break;
- }
- }
-
- return ret;
-}
-
-static void fix_range(struct mm_struct *mm, unsigned long start_addr,
- unsigned long end_addr, int force)
-{
- if((current->thread.mode.tt.extern_pid != -1) &&
- (current->thread.mode.tt.extern_pid != os_getpid()))
- panic("fix_range fixing wrong address space, current = 0x%p",
- current);
-
- fix_range_common(mm, start_addr, end_addr, force, do_ops);
-}
-
-atomic_t vmchange_seq = ATOMIC_INIT(1);
-
-void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end)
-{
- if(flush_tlb_kernel_range_common(start, end))
- atomic_inc(&vmchange_seq);
-}
-
-void flush_tlb_kernel_vm_tt(void)
-{
- flush_tlb_kernel_range(start_vm, end_vm);
-}
-
-void __flush_tlb_one_tt(unsigned long addr)
-{
- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
-}
-
-void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start,
- unsigned long end)
-{
- if(vma->vm_mm != current->mm) return;
-
- /* Assumes that the range start ... end is entirely within
- * either process memory or kernel vm
- */
- if((start >= start_vm) && (start < end_vm)){
- if(flush_tlb_kernel_range_common(start, end))
- atomic_inc(&vmchange_seq);
- }
- else fix_range(vma->vm_mm, start, end, 0);
-}
-
-void flush_tlb_mm_tt(struct mm_struct *mm)
-{
- unsigned long seq;
-
- if(mm != current->mm) return;
-
- fix_range(mm, 0, STACK_TOP, 0);
-
- seq = atomic_read(&vmchange_seq);
- if(current->thread.mode.tt.vm_seq == seq)
- return;
- current->thread.mode.tt.vm_seq = seq;
- flush_tlb_kernel_range_common(start_vm, end_vm);
-}
-
-void force_flush_all_tt(void)
-{
- fix_range(current->mm, 0, STACK_TOP, 1);
- flush_tlb_kernel_range_common(start_vm, end_vm);
-}
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
deleted file mode 100644
index d11e7399d7a..00000000000
--- a/arch/um/kernel/tt/tracer.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-#include <sched.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include "user.h"
-#include "sysdep/ptrace.h"
-#include "sigcontext.h"
-#include "sysdep/sigcontext.h"
-#include "os.h"
-#include "signal_user.h"
-#include "user_util.h"
-#include "mem_user.h"
-#include "process.h"
-#include "kern_util.h"
-#include "chan_user.h"
-#include "ptrace_user.h"
-#include "irq_user.h"
-#include "mode.h"
-#include "tt.h"
-
-static int tracer_winch[2];
-
-int is_tracer_winch(int pid, int fd, void *data)
-{
- if(pid != os_getpgrp())
- return(0);
-
- register_winch_irq(tracer_winch[0], fd, -1, data);
- return(1);
-}
-
-static void tracer_winch_handler(int sig)
-{
- int n;
- char c = 1;
-
- n = os_write_file(tracer_winch[1], &c, sizeof(c));
- if(n != sizeof(c))
- printk("tracer_winch_handler - write failed, err = %d\n", -n);
-}
-
-/* Called only by the tracing thread during initialization */
-
-static void setup_tracer_winch(void)
-{
- int err;
-
- err = os_pipe(tracer_winch, 1, 1);
- if(err < 0){
- printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
- return;
- }
- signal(SIGWINCH, tracer_winch_handler);
-}
-
-void attach_process(int pid)
-{
- if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
- (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
- tracer_panic("OP_FORK failed to attach pid");
- wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
- if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
- tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno);
- if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
- tracer_panic("OP_FORK failed to continue process");
-}
-
-void tracer_panic(char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- vprintf(format, ap);
- va_end(ap);
- printf("\n");
- while(1) pause();
-}
-
-static void tracer_segv(int sig, struct sigcontext sc)
-{
- struct faultinfo fi;
- GET_FAULTINFO_FROM_SC(fi, &sc);
- printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
- FAULT_ADDRESS(fi), SC_IP(&sc));
- while(1)
- pause();
-}
-
-/* Changed early in boot, and then only read */
-int debug = 0;
-int debug_stop = 1;
-int debug_parent = 0;
-int honeypot = 0;
-
-static int signal_tramp(void *arg)
-{
- int (*proc)(void *);
-
- if(honeypot && munmap((void *) (host_task_size - 0x10000000),
- 0x10000000))
- panic("Unmapping stack failed");
- if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
- panic("ptrace PTRACE_TRACEME failed");
- os_stop_process(os_getpid());
- change_sig(SIGWINCH, 0);
- signal(SIGUSR1, SIG_IGN);
- change_sig(SIGCHLD, 0);
- signal(SIGSEGV, (__sighandler_t) sig_handler);
- set_cmdline("(idle thread)");
- set_init_pid(os_getpid());
- init_irq_signals(0);
- proc = arg;
- return((*proc)(NULL));
-}
-
-static void sleeping_process_signal(int pid, int sig)
-{
- switch(sig){
- /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is
- * right because the process must be in the kernel already.
- */
- case SIGCONT:
- case SIGTSTP:
- if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
- tracer_panic("sleeping_process_signal : Failed to "
- "continue pid %d, signal = %d, "
- "errno = %d\n", pid, sig, errno);
- break;
-
- /* This happens when the debugger (e.g. strace) is doing system call
- * tracing on the kernel. During a context switch, the current task
- * will be set to the incoming process and the outgoing process will
- * hop into write and then read. Since it's not the current process
- * any more, the trace of those will land here. So, we need to just
- * PTRACE_SYSCALL it.
- */
- case (SIGTRAP + 0x80):
- if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
- tracer_panic("sleeping_process_signal : Failed to "
- "PTRACE_SYSCALL pid %d, errno = %d\n",
- pid, errno);
- break;
- case SIGSTOP:
- break;
- default:
- tracer_panic("sleeping process %d got unexpected "
- "signal : %d\n", pid, sig);
- break;
- }
-}
-
-/* Accessed only by the tracing thread */
-int debugger_pid = -1;
-int debugger_parent = -1;
-int debugger_fd = -1;
-int gdb_pid = -1;
-
-struct {
- int pid;
- int signal;
- unsigned long addr;
- struct timeval time;
-} signal_record[1024][32];
-
-int signal_index[32];
-int nsignals = 0;
-int debug_trace = 0;
-extern int io_nsignals, io_count, intr_count;
-
-extern void signal_usr1(int sig);
-
-int tracing_pid = -1;
-
-int tracer(int (*init_proc)(void *), void *sp)
-{
- void *task = NULL;
- int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
- int proc_id = 0, n, err, old_tracing = 0, strace = 0;
- int local_using_sysemu = 0;
-#ifdef UML_CONFIG_SYSCALL_DEBUG
- unsigned long eip = 0;
- int last_index;
-#endif
- signal(SIGPIPE, SIG_IGN);
- setup_tracer_winch();
- tracing_pid = os_getpid();
- printf("tracing thread pid = %d\n", tracing_pid);
-
- pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
- CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
- if(n < 0){
- printf("waitpid on idle thread failed, errno = %d\n", errno);
- exit(1);
- }
- if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) {
- printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno);
- exit(1);
- }
- if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
- printf("Failed to continue idle thread, errno = %d\n", errno);
- exit(1);
- }
-
- signal(SIGSEGV, (sighandler_t) tracer_segv);
- signal(SIGUSR1, signal_usr1);
- if(debug_trace){
- printf("Tracing thread pausing to be attached\n");
- stop();
- }
- if(debug){
- if(gdb_pid != -1)
- debugger_pid = attach_debugger(pid, gdb_pid, 1);
- else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
- if(debug_parent){
- debugger_parent = os_process_parent(debugger_pid);
- init_parent_proxy(debugger_parent);
- err = attach(debugger_parent);
- if(err){
- printf("Failed to attach debugger parent %d, "
- "errno = %d\n", debugger_parent, -err);
- debugger_parent = -1;
- }
- else {
- if(ptrace(PTRACE_SYSCALL, debugger_parent,
- 0, 0) < 0){
- printf("Failed to continue debugger "
- "parent, errno = %d\n", errno);
- debugger_parent = -1;
- }
- }
- }
- }
- set_cmdline("(tracing thread)");
- while(1){
- CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
- if(pid <= 0){
- if(errno != ECHILD){
- printf("wait failed - errno = %d\n", errno);
- }
- continue;
- }
- if(pid == debugger_pid){
- int cont = 0;
-
- if(WIFEXITED(status) || WIFSIGNALED(status))
- debugger_pid = -1;
- /* XXX Figure out how to deal with gdb and SMP */
- else cont = debugger_signal(status, cpu_tasks[0].pid);
- if(cont == PTRACE_SYSCALL) strace = 1;
- continue;
- }
- else if(pid == debugger_parent){
- debugger_parent_signal(status, pid);
- continue;
- }
- nsignals++;
- if(WIFEXITED(status)) ;
-#ifdef notdef
- {
- printf("Child %d exited with status %d\n", pid,
- WEXITSTATUS(status));
- }
-#endif
- else if(WIFSIGNALED(status)){
- sig = WTERMSIG(status);
- if(sig != 9){
- printf("Child %d exited with signal %d\n", pid,
- sig);
- }
- }
- else if(WIFSTOPPED(status)){
- proc_id = pid_to_processor_id(pid);
- sig = WSTOPSIG(status);
-#ifdef UML_CONFIG_SYSCALL_DEBUG
- if(signal_index[proc_id] == 1024){
- signal_index[proc_id] = 0;
- last_index = 1023;
- }
- else last_index = signal_index[proc_id] - 1;
- if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
- (sig == SIGALRM)) &&
- (signal_record[proc_id][last_index].signal == sig)&&
- (signal_record[proc_id][last_index].pid == pid))
- signal_index[proc_id] = last_index;
- signal_record[proc_id][signal_index[proc_id]].pid = pid;
- gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
- eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
- signal_record[proc_id][signal_index[proc_id]].addr = eip;
- signal_record[proc_id][signal_index[proc_id]++].signal = sig;
-#endif
- if(proc_id == -1){
- sleeping_process_signal(pid, sig);
- continue;
- }
-
- task = cpu_tasks[proc_id].task;
- tracing = is_tracing(task);
- old_tracing = tracing;
-
- /* Assume: no syscall, when coming from user */
- if ( tracing )
- do_sigtrap(task);
-
- switch(sig){
- case SIGUSR1:
- sig = 0;
- op = do_proc_op(task, proc_id);
- switch(op){
- /*
- * This is called when entering user mode; after
- * this, we start intercepting syscalls.
- *
- * In fact, a process is started in kernel mode,
- * so with is_tracing() == 0 (and that is reset
- * when executing syscalls, since UML kernel has
- * the right to do syscalls);
- */
- case OP_TRACE_ON:
- arch_leave_kernel(task, pid);
- tracing = 1;
- break;
- case OP_REBOOT:
- case OP_HALT:
- unmap_physmem();
- kmalloc_ok = 0;
- os_kill_ptraced_process(pid, 0);
- /* Now let's reap remaining zombies */
- errno = 0;
- do {
- waitpid(-1, &status,
- WUNTRACED);
- } while (errno != ECHILD);
- return(op == OP_REBOOT);
- case OP_NONE:
- printf("Detaching pid %d\n", pid);
- detach(pid, SIGSTOP);
- continue;
- default:
- break;
- }
- /* OP_EXEC switches host processes on us,
- * we want to continue the new one.
- */
- pid = cpu_tasks[proc_id].pid;
- break;
- case (SIGTRAP + 0x80):
- if(!tracing && (debugger_pid != -1)){
- child_signal(pid, status & 0x7fff);
- continue;
- }
- tracing = 0;
- /* local_using_sysemu has been already set
- * below, since if we are here, is_tracing() on
- * the traced task was 1, i.e. the process had
- * already run through one iteration of the
- * loop which executed a OP_TRACE_ON request.*/
- do_syscall(task, pid, local_using_sysemu);
- sig = SIGUSR2;
- break;
- case SIGTRAP:
- if(!tracing && (debugger_pid != -1)){
- child_signal(pid, status);
- continue;
- }
- tracing = 0;
- break;
- case SIGPROF:
- if(tracing) sig = 0;
- break;
- case SIGCHLD:
- case SIGHUP:
- sig = 0;
- break;
- case SIGSEGV:
- case SIGIO:
- case SIGALRM:
- case SIGVTALRM:
- case SIGFPE:
- case SIGBUS:
- case SIGILL:
- case SIGWINCH:
-
- default:
- tracing = 0;
- break;
- }
- set_tracing(task, tracing);
-
- if(!tracing && old_tracing)
- arch_enter_kernel(task, pid);
-
- if(!tracing && (debugger_pid != -1) && (sig != 0) &&
- (sig != SIGALRM) && (sig != SIGVTALRM) &&
- (sig != SIGSEGV) && (sig != SIGTRAP) &&
- (sig != SIGUSR2) && (sig != SIGIO) &&
- (sig != SIGFPE)){
- child_signal(pid, status);
- continue;
- }
-
- local_using_sysemu = get_using_sysemu();
-
- if(tracing)
- cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu,
- singlestepping(task));
- else if((debugger_pid != -1) && strace)
- cont_type = PTRACE_SYSCALL;
- else
- cont_type = PTRACE_CONT;
-
- if(ptrace(cont_type, pid, 0, sig) != 0){
- tracer_panic("ptrace failed to continue "
- "process - errno = %d\n",
- errno);
- }
- }
- }
- return(0);
-}
-
-static int __init uml_debug_setup(char *line, int *add)
-{
- char *next;
-
- debug = 1;
- *add = 0;
- if(*line != '=') return(0);
- line++;
-
- while(line != NULL){
- next = strchr(line, ',');
- if(next) *next++ = '\0';
-
- if(!strcmp(line, "go")) debug_stop = 0;
- else if(!strcmp(line, "parent")) debug_parent = 1;
- else printf("Unknown debug option : '%s'\n", line);
-
- line = next;
- }
- return(0);
-}
-
-__uml_setup("debug", uml_debug_setup,
-"debug\n"
-" Starts up the kernel under the control of gdb. See the \n"
-" kernel debugging tutorial and the debugging session pages\n"
-" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
-);
-
-static int __init uml_debugtrace_setup(char *line, int *add)
-{
- debug_trace = 1;
- return 0;
-}
-__uml_setup("debugtrace", uml_debugtrace_setup,
-"debugtrace\n"
-" Causes the tracing thread to pause until it is attached by a\n"
-" debugger and continued. This is mostly for debugging crashes\n"
-" early during boot, and should be pretty much obsoleted by\n"
-" the debug switch.\n\n"
-);
-
-/*
- * 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/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c
deleted file mode 100644
index fc108615bea..00000000000
--- a/arch/um/kernel/tt/trap_user.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <errno.h>
-#include <signal.h>
-#include "sysdep/ptrace.h"
-#include "sysdep/sigcontext.h"
-#include "signal_user.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "task.h"
-#include "tt.h"
-
-void sig_handler_common_tt(int sig, void *sc_ptr)
-{
- struct sigcontext *sc = sc_ptr;
- struct tt_regs save_regs, *r;
- struct signal_info *info;
- int save_errno = errno, is_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.
- */
- if(sig == SIGSEGV)
- change_sig(SIGSEGV, 1);
-
- r = &TASK_REGS(get_current())->tt;
- if ( sig == SIGFPE || sig == SIGSEGV ||
- sig == SIGBUS || sig == SIGILL ||
- sig == SIGTRAP ) {
- GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
- }
- save_regs = *r;
- is_user = user_context(SC_SP(sc));
- r->sc = sc;
- if(sig != SIGUSR2)
- r->syscall = -1;
-
- info = &sig_info[sig];
- if(!info->is_irq) unblock_signals();
-
- (*info->handler)(sig, (union uml_pt_regs *) r);
-
- if(is_user){
- interrupt_end();
- block_signals();
- set_user_mode(NULL);
- }
- *r = save_regs;
- errno = save_errno;
-}
-
-/*
- * 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/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c
deleted file mode 100644
index a72aa632972..00000000000
--- a/arch/um/kernel/tt/uaccess.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
- * Licensed under the GPL
- */
-
-#include "linux/sched.h"
-#include "asm/uaccess.h"
-
-int copy_from_user_tt(void *to, const void __user *from, int n)
-{
- if(!access_ok_tt(VERIFY_READ, from, n))
- return(n);
-
- return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
- &current->thread.fault_catcher));
-}
-
-int copy_to_user_tt(void __user *to, const void *from, int n)
-{
- if(!access_ok_tt(VERIFY_WRITE, to, n))
- return(n);
-
- return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
- &current->thread.fault_catcher));
-}
-
-int strncpy_from_user_tt(char *dst, const char __user *src, int count)
-{
- int n;
-
- if(!access_ok_tt(VERIFY_READ, src, 1))
- return(-EFAULT);
-
- n = __do_strncpy_from_user(dst, src, count,
- &current->thread.fault_addr,
- &current->thread.fault_catcher);
- if(n < 0) return(-EFAULT);
- return(n);
-}
-
-int __clear_user_tt(void __user *mem, int len)
-{
- return(__do_clear_user(mem, len,
- &current->thread.fault_addr,
- &current->thread.fault_catcher));
-}
-
-int clear_user_tt(void __user *mem, int len)
-{
- if(!access_ok_tt(VERIFY_WRITE, mem, len))
- return(len);
-
- return(__do_clear_user(mem, len, &current->thread.fault_addr,
- &current->thread.fault_catcher));
-}
-
-int strnlen_user_tt(const void __user *str, int len)
-{
- return(__do_strnlen_user(str, len,
- &current->thread.fault_addr,
- &current->thread.fault_catcher));
-}
-
-/*
- * 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/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
deleted file mode 100644
index 6c92bbccb49..00000000000
--- a/arch/um/kernel/tt/uaccess_user.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
- * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <setjmp.h>
-#include <string.h>
-#include "user_util.h"
-#include "uml_uaccess.h"
-#include "task.h"
-#include "kern_util.h"
-#include "os.h"
-
-int __do_copy_from_user(void *to, const void *from, int n,
- void **fault_addr, void **fault_catcher)
-{
- struct tt_regs save = TASK_REGS(get_current())->tt;
- unsigned long fault;
- int faulted;
-
- fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
- __do_copy, &faulted);
- TASK_REGS(get_current())->tt = save;
-
- if(!faulted)
- return 0;
- else if (fault)
- return n - (fault - (unsigned long) from);
- else
- /* In case of a general protection fault, we don't have the
- * fault address, so NULL is used instead. Pretend we didn't
- * copy anything. */
- return n;
-}
-
-static void __do_strncpy(void *dst, const void *src, int count)
-{
- strncpy(dst, src, count);
-}
-
-int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
- void **fault_addr, void **fault_catcher)
-{
- struct tt_regs save = TASK_REGS(get_current())->tt;
- unsigned long fault;
- int faulted;
-
- fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
- __do_strncpy, &faulted);
- TASK_REGS(get_current())->tt = save;
-
- if(!faulted) return(strlen(dst));
- else return(-1);
-}
-
-static void __do_clear(void *to, const void *from, int n)
-{
- memset(to, 0, n);
-}
-
-int __do_clear_user(void *mem, unsigned long len,
- void **fault_addr, void **fault_catcher)
-{
- struct tt_regs save = TASK_REGS(get_current())->tt;
- unsigned long fault;
- int faulted;
-
- fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
- __do_clear, &faulted);
- TASK_REGS(get_current())->tt = save;
-
- if(!faulted) return(0);
- else return(len - (fault - (unsigned long) mem));
-}
-
-int __do_strnlen_user(const char *str, unsigned long n,
- void **fault_addr, void **fault_catcher)
-{
- struct tt_regs save = TASK_REGS(get_current())->tt;
- int ret;
- unsigned long *faddrp = (unsigned long *)fault_addr;
- sigjmp_buf jbuf;
-
- *fault_catcher = &jbuf;
- if(sigsetjmp(jbuf, 1) == 0)
- ret = strlen(str) + 1;
- else ret = *faddrp - (unsigned long) str;
-
- *fault_addr = NULL;
- *fault_catcher = NULL;
-
- TASK_REGS(get_current())->tt = save;
- return ret;
-}
-
-/*
- * 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/tty_log.c b/arch/um/kernel/tty_log.c
deleted file mode 100644
index 9ada656f68c..00000000000
--- a/arch/um/kernel/tty_log.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and
- * geoffrey hing <ghing@net.ohio-state.edu>
- * Licensed under the GPL
- */
-
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include "init.h"
-#include "user.h"
-#include "kern_util.h"
-#include "os.h"
-
-#define TTY_LOG_DIR "./"
-
-/* Set early in boot and then unchanged */
-static char *tty_log_dir = TTY_LOG_DIR;
-static int tty_log_fd = -1;
-
-#define TTY_LOG_OPEN 1
-#define TTY_LOG_CLOSE 2
-#define TTY_LOG_WRITE 3
-#define TTY_LOG_EXEC 4
-
-#define TTY_READ 1
-#define TTY_WRITE 2
-
-struct tty_log_buf {
- int what;
- unsigned long tty;
- int len;
- int direction;
- unsigned long sec;
- unsigned long usec;
-};
-
-int open_tty_log(void *tty, void *current_tty)
-{
- struct timeval tv;
- struct tty_log_buf data;
- char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
- int fd;
-
- gettimeofday(&tv, NULL);
- if(tty_log_fd != -1){
- data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN,
- .tty = (unsigned long) tty,
- .len = sizeof(current_tty),
- .direction = 0,
- .sec = tv.tv_sec,
- .usec = tv.tv_usec } );
- os_write_file(tty_log_fd, &data, sizeof(data));
- os_write_file(tty_log_fd, &current_tty, data.len);
- return(tty_log_fd);
- }
-
- sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec,
- (unsigned int) tv.tv_usec);
-
- fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))),
- 0644);
- if(fd < 0){
- printk("open_tty_log : couldn't open '%s', errno = %d\n",
- buf, -fd);
- }
- return(fd);
-}
-
-void close_tty_log(int fd, void *tty)
-{
- struct tty_log_buf data;
- struct timeval tv;
-
- if(tty_log_fd != -1){
- gettimeofday(&tv, NULL);
- data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE,
- .tty = (unsigned long) tty,
- .len = 0,
- .direction = 0,
- .sec = tv.tv_sec,
- .usec = tv.tv_usec } );
- os_write_file(tty_log_fd, &data, sizeof(data));
- return;
- }
- os_close_file(fd);
-}
-
-static int log_chunk(int fd, const char *buf, int len)
-{
- int total = 0, try, missed, n;
- char chunk[64];
-
- while(len > 0){
- try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
- missed = copy_from_user_proc(chunk, (char *) buf, try);
- try -= missed;
- n = os_write_file(fd, chunk, try);
- if(n != try) {
- if(n < 0)
- return(n);
- return(-EIO);
- }
- if(missed != 0)
- return(-EFAULT);
-
- len -= try;
- total += try;
- buf += try;
- }
-
- return(total);
-}
-
-int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
-{
- struct timeval tv;
- struct tty_log_buf data;
- int direction;
-
- if(fd == tty_log_fd){
- gettimeofday(&tv, NULL);
- direction = is_read ? TTY_READ : TTY_WRITE;
- data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE,
- .tty = (unsigned long) tty,
- .len = len,
- .direction = direction,
- .sec = tv.tv_sec,
- .usec = tv.tv_usec } );
- os_write_file(tty_log_fd, &data, sizeof(data));
- }
-
- return(log_chunk(fd, buf, len));
-}
-
-void log_exec(char **argv, void *tty)
-{
- struct timeval tv;
- struct tty_log_buf data;
- char **ptr,*arg;
- int len;
-
- if(tty_log_fd == -1) return;
-
- gettimeofday(&tv, NULL);
-
- len = 0;
- for(ptr = argv; ; ptr++){
- if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
- return;
- if(arg == NULL) break;
- len += strlen_user_proc(arg);
- }
-
- data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC,
- .tty = (unsigned long) tty,
- .len = len,
- .direction = 0,
- .sec = tv.tv_sec,
- .usec = tv.tv_usec } );
- os_write_file(tty_log_fd, &data, sizeof(data));
-
- for(ptr = argv; ; ptr++){
- if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
- return;
- if(arg == NULL) break;
- log_chunk(tty_log_fd, arg, strlen_user_proc(arg));
- }
-}
-
-extern void register_tty_logger(int (*opener)(void *, void *),
- int (*writer)(int, const char *, int,
- void *, int),
- void (*closer)(int, void *));
-
-static int register_logger(void)
-{
- register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
- return(0);
-}
-
-__uml_initcall(register_logger);
-
-static int __init set_tty_log_dir(char *name, int *add)
-{
- tty_log_dir = name;
- return 0;
-}
-
-__uml_setup("tty_log_dir=", set_tty_log_dir,
-"tty_log_dir=<directory>\n"
-" This is used to specify the directory where the logs of all pty\n"
-" data from this UML machine will be written.\n\n"
-);
-
-static int __init set_tty_log_fd(char *name, int *add)
-{
- char *end;
-
- tty_log_fd = strtoul(name, &end, 0);
- if((*end != '\0') || (end == name)){
- printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
- tty_log_fd = -1;
- }
-
- *add = 0;
- return 0;
-}
-
-__uml_setup("tty_log_fd=", set_tty_log_fd,
-"tty_log_fd=<fd>\n"
-" This is used to specify a preconfigured file descriptor to which all\n"
-" tty data will be written. Preconfigure the descriptor with something\n"
-" like '10>tty_log tty_log_fd=10'.\n\n"
-);
-
-
-/*
- * 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/uaccess.c b/arch/um/kernel/uaccess.c
deleted file mode 100644
index 054e3de0784..00000000000
--- a/arch/um/kernel/uaccess.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-/* These are here rather than tt/uaccess.c because skas mode needs them in
- * order to do SIGBUS recovery when a tmpfs mount runs out of room.
- */
-
-#include <linux/string.h>
-#include "os.h"
-
-void __do_copy(void *to, const void *from, int n)
-{
- memcpy(to, from, n);
-}
-
-
-int __do_copy_to_user(void *to, const void *from, int n,
- void **fault_addr, void **fault_catcher)
-{
- unsigned long fault;
- int faulted;
-
- fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
- __do_copy, &faulted);
- if(!faulted) return(0);
- else return(n - (fault - (unsigned long) to));
-}
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 142a9493912..016adf0985d 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -1,74 +1,67 @@
-/*
- * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/config.h"
-#include "linux/kernel.h"
-#include "linux/sched.h"
-#include "linux/notifier.h"
-#include "linux/mm.h"
-#include "linux/types.h"
-#include "linux/tty.h"
-#include "linux/init.h"
-#include "linux/bootmem.h"
-#include "linux/spinlock.h"
-#include "linux/utsname.h"
-#include "linux/sysrq.h"
-#include "linux/seq_file.h"
-#include "linux/delay.h"
-#include "linux/module.h"
-#include "asm/page.h"
-#include "asm/pgtable.h"
-#include "asm/ptrace.h"
-#include "asm/elf.h"
-#include "asm/user.h"
-#include "asm/setup.h"
-#include "ubd_user.h"
-#include "asm/current.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "kern.h"
-#include "mem_user.h"
-#include "mem.h"
-#include "umid.h"
-#include "initrd.h"
-#include "init.h"
-#include "os.h"
-#include "choose-mode.h"
-#include "mode_kern.h"
-#include "mode.h"
-#ifdef UML_CONFIG_MODE_SKAS
-#include "skas.h"
-#endif
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/utsname.h>
+#include <linux/sched.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <as-layout.h>
+#include <arch.h>
+#include <init.h>
+#include <kern.h>
+#include <kern_util.h>
+#include <mem_user.h>
+#include <os.h>
#define DEFAULT_COMMAND_LINE "root=98:0"
-/* Changed in linux_main and setup_arch, which run before SMP is started */
-static char command_line[COMMAND_LINE_SIZE] = { 0 };
+/* Changed in add_arg and setup_arch, which run before SMP is started */
+static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
-static void add_arg(char *arg)
+static void __init add_arg(char *arg)
{
if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
printf("add_arg: Too many command line arguments!\n");
exit(1);
}
- if(strlen(command_line) > 0)
+ if (strlen(command_line) > 0)
strcat(command_line, " ");
strcat(command_line, arg);
}
-struct cpuinfo_um boot_cpu_data = {
+/*
+ * These fields are initialized at boot time and not changed.
+ * XXX This structure is used only in the non-SMP case. Maybe this
+ * should be moved to smp.c.
+ */
+struct cpuinfo_um boot_cpu_data = {
.loops_per_jiffy = 0,
.ipi_pipe = { -1, -1 }
};
+union thread_union cpu0_irqstack
+ __attribute__((__section__(".data..init_irqstack"))) =
+ { INIT_THREAD_INFO(init_task) };
+
unsigned long thread_saved_pc(struct task_struct *task)
{
- return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
- task)));
+ /* FIXME: Need to look up userspace_pid by cpu */
+ return os_process_pc(userspace_pid[0]);
}
+/* Changed in setup_arch, which is called in early boot */
+static char host_info[(__NEW_UTS_LEN + 1) * 5];
+
static int show_cpuinfo(struct seq_file *m, void *v)
{
int index = 0;
@@ -82,13 +75,13 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "processor\t: %d\n", index);
seq_printf(m, "vendor_id\t: User Mode Linux\n");
seq_printf(m, "model name\t: UML\n");
- seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
+ seq_printf(m, "mode\t\t: skas\n");
seq_printf(m, "host\t\t: %s\n", host_info);
seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ)) % 100);
- return(0);
+ return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
@@ -106,7 +99,7 @@ static void c_stop(struct seq_file *m, void *v)
{
}
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
@@ -114,60 +107,29 @@ struct seq_operations cpuinfo_op = {
};
/* Set in linux_main */
-unsigned long host_task_size;
-unsigned long task_size;
-
-unsigned long uml_start;
-
-/* Set in early boot */
unsigned long uml_physmem;
-unsigned long uml_reserved;
+EXPORT_SYMBOL(uml_physmem);
+
+unsigned long uml_reserved; /* Also modified in mem_init */
unsigned long start_vm;
unsigned long end_vm;
-int ncpus = 1;
-#ifdef CONFIG_CMDLINE_ON_HOST
-/* Pointer set in linux_main, the array itself is private to each thread,
- * and changed at address space creation time so this poses no concurrency
- * problems.
- */
-static char *argv1_begin = NULL;
-static char *argv1_end = NULL;
-#endif
+/* Set in uml_ncpus_setup */
+int ncpus = 1;
/* Set in early boot */
static int have_root __initdata = 0;
-long long physmem_size = 32 * 1024 * 1024;
-
-void set_cmdline(char *cmd)
-{
-#ifdef CONFIG_CMDLINE_ON_HOST
- char *umid, *ptr;
-
- if(CHOOSE_MODE(honeypot, 0)) return;
- umid = get_umid(1);
- if(umid != NULL){
- snprintf(argv1_begin,
- (argv1_end - argv1_begin) * sizeof(*ptr),
- "(%s) ", umid);
- ptr = &argv1_begin[strlen(argv1_begin)];
- }
- else ptr = argv1_begin;
-
- snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
- memset(argv1_begin + strlen(argv1_begin), '\0',
- argv1_end - argv1_begin - strlen(argv1_begin));
-#endif
-}
+/* Set in uml_mem_setup and modified in linux_main */
+long long physmem_size = 32 * 1024 * 1024;
-static char *usage_string =
+static const char *usage_string =
"User Mode Linux v%s\n"
" available at http://user-mode-linux.sourceforge.net/\n\n";
static int __init uml_version_setup(char *line, int *add)
{
- printf("%s\n", system_utsname.release);
+ printf("%s\n", init_utsname()->release);
exit(0);
return 0;
@@ -193,85 +155,47 @@ __uml_setup("root=", uml_root_setup,
" root=/dev/ubd5\n\n"
);
-#ifdef CONFIG_SMP
-static int __init uml_ncpus_setup(char *line, int *add)
+static int __init no_skas_debug_setup(char *line, int *add)
{
- if (!sscanf(line, "%d", &ncpus)) {
- printf("Couldn't parse [%s]\n", line);
- return -1;
- }
+ printf("'debug' is not necessary to gdb UML in skas mode - run \n");
+ printf("'gdb linux'\n");
- return 0;
+ return 0;
}
-__uml_setup("ncpus=", uml_ncpus_setup,
-"ncpus=<# of desired CPUs>\n"
-" This tells an SMP kernel how many virtual processors to start.\n\n"
+__uml_setup("debug", no_skas_debug_setup,
+"debug\n"
+" this flag is not needed to run gdb on UML in skas mode\n\n"
);
-#endif
-
-static int force_tt = 0;
-
-#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
-#define DEFAULT_TT 0
-
-static int __init mode_tt_setup(char *line, int *add)
-{
- force_tt = 1;
- return(0);
-}
-
-#else
-#ifdef CONFIG_MODE_SKAS
-
-#define DEFAULT_TT 0
-static int __init mode_tt_setup(char *line, int *add)
+#ifdef CONFIG_SMP
+static int __init uml_ncpus_setup(char *line, int *add)
{
- printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
- return(0);
-}
-
-#else
-#ifdef CONFIG_MODE_TT
-
-#define DEFAULT_TT 1
+ if (!sscanf(line, "%d", &ncpus)) {
+ printf("Couldn't parse [%s]\n", line);
+ return -1;
+ }
-static int __init mode_tt_setup(char *line, int *add)
-{
- printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
- return(0);
+ return 0;
}
-#else
-
-#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled
-
-#endif
-#endif
-#endif
-
-__uml_setup("mode=tt", mode_tt_setup,
-"mode=tt\n"
-" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
-" forces UML to run in tt (tracing thread) mode. It is not the default\n"
-" because it's slower and less secure than skas mode.\n\n"
+__uml_setup("ncpus=", uml_ncpus_setup,
+"ncpus=<# of desired CPUs>\n"
+" This tells an SMP kernel how many virtual processors to start.\n\n"
);
-
-int mode_tt = DEFAULT_TT;
+#endif
static int __init Usage(char *line, int *add)
{
- const char **p;
-
- printf(usage_string, system_utsname.release);
- p = &__uml_help_start;
- while (p < &__uml_help_end) {
- printf("%s", *p);
- p++;
- }
- exit(0);
+ const char **p;
+ printf(usage_string, init_utsname()->release);
+ p = &__uml_help_start;
+ while (p < &__uml_help_end) {
+ printf("%s", *p);
+ p++;
+ }
+ exit(0);
return 0;
}
@@ -280,21 +204,19 @@ __uml_setup("--help", Usage,
" Prints this message.\n\n"
);
-static int __init uml_checksetup(char *line, int *add)
+static void __init uml_checksetup(char *line, int *add)
{
struct uml_param *p;
p = &__uml_setup_start;
- while(p < &__uml_setup_end) {
- int n;
+ while (p < &__uml_setup_end) {
+ size_t n;
n = strlen(p->str);
- if(!strncmp(line, p->str, n)){
- if (p->setup_func(line + n, add)) return 1;
- }
+ if (!strncmp(line, p->str, n) && p->setup_func(line + n, add))
+ return;
p++;
}
- return 0;
}
static void __init uml_postsetup(void)
@@ -302,107 +224,120 @@ static void __init uml_postsetup(void)
initcall_t *p;
p = &__uml_postsetup_start;
- while(p < &__uml_postsetup_end){
+ while (p < &__uml_postsetup_end) {
(*p)();
p++;
}
return;
}
+static int panic_exit(struct notifier_block *self, unsigned long unused1,
+ void *unused2)
+{
+ bust_spinlocks(1);
+ bust_spinlocks(0);
+ uml_exitcode = 1;
+ os_dump_core();
+ return 0;
+}
+
+static struct notifier_block panic_exit_notifier = {
+ .notifier_call = panic_exit,
+ .next = NULL,
+ .priority = 0
+};
+
/* Set during early boot */
+unsigned long task_size;
+EXPORT_SYMBOL(task_size);
+
+unsigned long host_task_size;
+
unsigned long brk_start;
unsigned long end_iomem;
EXPORT_SYMBOL(end_iomem);
#define MIN_VMALLOC (32 * 1024 * 1024)
-int linux_main(int argc, char **argv)
+extern char __binary_start;
+
+int __init linux_main(int argc, char **argv)
{
unsigned long avail, diff;
unsigned long virtmem_size, max_physmem;
- unsigned int i, add;
+ unsigned long stack;
+ unsigned int i;
+ int add;
char * mode;
- for (i = 1; i < argc; i++){
- if((i == 1) && (argv[i][0] == ' ')) continue;
+ for (i = 1; i < argc; i++) {
+ if ((i == 1) && (argv[i][0] == ' '))
+ continue;
add = 1;
uml_checksetup(argv[i], &add);
if (add)
add_arg(argv[i]);
}
- if(have_root == 0)
+ if (have_root == 0)
add_arg(DEFAULT_COMMAND_LINE);
+ host_task_size = os_get_top_address();
+ /*
+ * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps
+ * out
+ */
+ task_size = host_task_size & PGDIR_MASK;
+
+ /* OS sanity checks that need to happen before the kernel runs */
os_early_checks();
- if (force_tt)
- clear_can_do_skas();
- mode_tt = force_tt ? 1 : !can_do_skas();
-#ifndef CONFIG_MODE_TT
- if (mode_tt) {
- /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
- * can_do_skas() returned 0, and the message is correct. */
- printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
- exit(1);
- }
-#endif
-#ifndef CONFIG_MODE_SKAS
- mode = "TT";
-#else
- /* Show to the user the result of selection */
- if (mode_tt)
- mode = "TT";
- else if (proc_mm && ptrace_faultinfo)
+ can_do_skas();
+
+ if (proc_mm && ptrace_faultinfo)
mode = "SKAS3";
else
mode = "SKAS0";
-#endif
printf("UML running in %s mode\n", mode);
- uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
- &host_task_size, &task_size);
-
brk_start = (unsigned long) sbrk(0);
- CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
- /* Increase physical memory size for exec-shield users
- so they actually get what they asked for. This should
- add zero for non-exec shield users */
+
+ /*
+ * Increase physical memory size for exec-shield users
+ * so they actually get what they asked for. This should
+ * add zero for non-exec shield users
+ */
diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
- if(diff > 1024 * 1024){
+ if (diff > 1024 * 1024) {
printf("Adding %ld bytes to physical memory to account for "
"exec-shield gap\n", diff);
physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
}
- uml_physmem = uml_start;
+ uml_physmem = (unsigned long) &__binary_start & PAGE_MASK;
/* Reserve up to 4M after the current brk */
uml_reserved = ROUND_4M(brk_start) + (1 << 22);
- setup_machinename(system_utsname.machine);
+ setup_machinename(init_utsname()->machine);
-#ifdef CONFIG_CMDLINE_ON_HOST
- argv1_begin = argv[1];
- argv1_end = &argv[1][strlen(argv[1])];
-#endif
-
highmem = 0;
iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
- max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
+ max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC;
- /* Zones have to begin on a 1 << MAX_ORDER page boundary,
+ /*
+ * Zones have to begin on a 1 << MAX_ORDER page boundary,
* so this makes sure that's true for highmem
*/
max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
- if(physmem_size + iomem_size > max_physmem){
+ if (physmem_size + iomem_size > max_physmem) {
highmem = physmem_size + iomem_size - max_physmem;
physmem_size -= highmem;
#ifndef CONFIG_HIGHMEM
highmem = 0;
printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
- "to %lu bytes\n", physmem_size);
+ "to %Lu bytes\n", physmem_size);
#endif
}
@@ -413,65 +348,62 @@ int linux_main(int argc, char **argv)
start_vm = VMALLOC_START;
setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
- if(init_maps(physmem_size, iomem_size, highmem)){
- printf("Failed to allocate mem_map for %lu bytes of physical "
- "memory and %lu bytes of highmem\n", physmem_size,
+ if (init_maps(physmem_size, iomem_size, highmem)) {
+ printf("Failed to allocate mem_map for %Lu bytes of physical "
+ "memory and %Lu bytes of highmem\n", physmem_size,
highmem);
exit(1);
}
virtmem_size = physmem_size;
- avail = get_kmem_end() - start_vm;
- if(physmem_size > avail) virtmem_size = avail;
+ stack = (unsigned long) argv;
+ stack &= ~(1024 * 1024 - 1);
+ avail = stack - start_vm;
+ if (physmem_size > avail)
+ virtmem_size = avail;
end_vm = start_vm + virtmem_size;
- if(virtmem_size < physmem_size)
+ if (virtmem_size < physmem_size)
printf("Kernel virtual memory size shrunk to %lu bytes\n",
virtmem_size);
- uml_postsetup();
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &panic_exit_notifier);
- task_protections((unsigned long) &init_thread_info);
- os_flush_stdout();
-
- return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
-}
+ uml_postsetup();
-extern int uml_exitcode;
+ stack_protections((unsigned long) &init_thread_info);
+ os_flush_stdout();
-static int panic_exit(struct notifier_block *self, unsigned long unused1,
- void *unused2)
-{
- bust_spinlocks(1);
- show_regs(&(current->thread.regs));
- bust_spinlocks(0);
- uml_exitcode = 1;
- machine_halt();
- return(0);
+ return start_uml();
}
-static struct notifier_block panic_exit_notifier = {
- .notifier_call = panic_exit,
- .next = NULL,
- .priority = 0
-};
-
void __init setup_arch(char **cmdline_p)
{
- notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
paging_init();
- strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
- *cmdline_p = command_line;
- setup_hostinfo();
+ strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
+ *cmdline_p = command_line;
+ setup_hostinfo(host_info, sizeof host_info);
}
void __init check_bugs(void)
{
arch_check_bugs();
- check_sigio();
- check_devanon();
+ os_check_bugs();
+}
+
+void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
+{
}
-void apply_alternatives(void *start, void *end)
+#ifdef CONFIG_SMP
+void alternatives_smp_module_add(struct module *mod, char *name,
+ void *locks, void *locks_end,
+ void *text, void *text_end)
{
}
+
+void alternatives_smp_module_del(struct module *mod)
+{
+}
+#endif
diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
index 0b21d59ba0c..f6cc3bd6178 100644
--- a/arch/um/kernel/umid.c
+++ b/arch/um/kernel/umid.c
@@ -1,330 +1,38 @@
-/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <dirent.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include "user.h"
-#include "umid.h"
-#include "init.h"
-#include "os.h"
-#include "user_util.h"
-#include "choose-mode.h"
-
-#define UMID_LEN 64
-#define UML_DIR "~/.uml/"
-
-/* Changed by set_umid and make_umid, which are run early in boot */
-static char umid[UMID_LEN] = { 0 };
+#include <asm/errno.h>
+#include <init.h>
+#include <kern.h>
+#include <os.h>
-/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */
-static char *uml_dir = UML_DIR;
-
-/* Changed by set_umid */
-static int umid_is_random = 1;
+/* Changed by set_umid_arg */
static int umid_inited = 0;
-/* Have we created the files? Should we remove them? */
-static int umid_owned = 0;
-
-static int make_umid(int (*printer)(const char *fmt, ...));
-static int __init set_umid(char *name, int is_random,
- int (*printer)(const char *fmt, ...))
+static int __init set_umid_arg(char *name, int *add)
{
- if(umid_inited){
- (*printer)("Unique machine name can't be set twice\n");
- return(-1);
+ int err;
+
+ if (umid_inited) {
+ printf("umid already set\n");
+ return 0;
}
- if(strlen(name) > UMID_LEN - 1)
- (*printer)("Unique machine name is being truncated to %d "
- "characters\n", UMID_LEN);
- strlcpy(umid, name, sizeof(umid));
+ *add = 0;
+ err = set_umid(name);
+ if (err == -EEXIST)
+ printf("umid '%s' already in use\n", name);
+ else if (!err)
+ umid_inited = 1;
- umid_is_random = is_random;
- umid_inited = 1;
return 0;
}
-static int __init set_umid_arg(char *name, int *add)
-{
- *add = 0;
- return(set_umid(name, 0, printf));
-}
-
__uml_setup("umid=", set_umid_arg,
"umid=<name>\n"
" This is used to assign a unique identity to this UML machine and\n"
" is used for naming the pid file and management console socket.\n\n"
);
-int __init umid_file_name(char *name, char *buf, int len)
-{
- int n;
-
- if(!umid_inited && make_umid(printk)) return(-1);
-
- n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
- if(n > len){
- printk("umid_file_name : buffer too short\n");
- return(-1);
- }
-
- sprintf(buf, "%s%s/%s", uml_dir, umid, name);
- return(0);
-}
-
-extern int tracing_pid;
-
-static void __init create_pid_file(void)
-{
- char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
- char pid[sizeof("nnnnn\0")];
- int fd, n;
-
- if(umid_file_name("pid", file, sizeof(file)))
- return;
-
- fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))),
- 0644);
- if(fd < 0){
- printf("Open of machine pid file \"%s\" failed: %s\n",
- file, strerror(-fd));
- return;
- }
-
- sprintf(pid, "%d\n", os_getpid());
- n = os_write_file(fd, pid, strlen(pid));
- if(n != strlen(pid))
- printf("Write of pid file failed - err = %d\n", -n);
- os_close_file(fd);
-}
-
-static int actually_do_remove(char *dir)
-{
- DIR *directory;
- struct dirent *ent;
- int len;
- char file[256];
-
- directory = opendir(dir);
- if(directory == NULL){
- printk("actually_do_remove : couldn't open directory '%s', "
- "errno = %d\n", dir, errno);
- return(1);
- }
- while((ent = readdir(directory)) != NULL){
- if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
- continue;
- len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1;
- if(len > sizeof(file)){
- printk("Not deleting '%s' from '%s' - name too long\n",
- ent->d_name, dir);
- continue;
- }
- sprintf(file, "%s/%s", dir, ent->d_name);
- if(unlink(file) < 0){
- printk("actually_do_remove : couldn't remove '%s' "
- "from '%s', errno = %d\n", ent->d_name, dir,
- errno);
- return(1);
- }
- }
- if(rmdir(dir) < 0){
- printk("actually_do_remove : couldn't rmdir '%s', "
- "errno = %d\n", dir, errno);
- return(1);
- }
- return(0);
-}
-
-void remove_umid_dir(void)
-{
- char dir[strlen(uml_dir) + UMID_LEN + 1];
- if (!umid_owned)
- return;
-
- sprintf(dir, "%s%s", uml_dir, umid);
- actually_do_remove(dir);
-}
-
-char *get_umid(int only_if_set)
-{
- if(only_if_set && umid_is_random)
- return NULL;
- return umid;
-}
-
-static int not_dead_yet(char *dir)
-{
- char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
- char pid[sizeof("nnnnn\0")], *end;
- int dead, fd, p, n;
-
- sprintf(file, "%s/pid", dir);
- dead = 0;
- fd = os_open_file(file, of_read(OPENFLAGS()), 0);
- if(fd < 0){
- if(fd != -ENOENT){
- printk("not_dead_yet : couldn't open pid file '%s', "
- "err = %d\n", file, -fd);
- return(1);
- }
- dead = 1;
- }
- if(fd > 0){
- n = os_read_file(fd, pid, sizeof(pid));
- if(n < 0){
- printk("not_dead_yet : couldn't read pid file '%s', "
- "err = %d\n", file, -n);
- return(1);
- }
- p = strtoul(pid, &end, 0);
- if(end == pid){
- printk("not_dead_yet : couldn't parse pid file '%s', "
- "errno = %d\n", file, errno);
- dead = 1;
- }
- if(((kill(p, 0) < 0) && (errno == ESRCH)) ||
- (p == CHOOSE_MODE(tracing_pid, os_getpid())))
- dead = 1;
- }
- if(!dead)
- return(1);
- return(actually_do_remove(dir));
-}
-
-static int __init set_uml_dir(char *name, int *add)
-{
- if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
- uml_dir = malloc(strlen(name) + 2);
- if(uml_dir == NULL){
- printf("Failed to malloc uml_dir - error = %d\n",
- errno);
- uml_dir = name;
- /* Return 0 here because do_initcalls doesn't look at
- * the return value.
- */
- return(0);
- }
- sprintf(uml_dir, "%s/", name);
- }
- else uml_dir = name;
- return(0);
-}
-
-static int __init make_uml_dir(void)
-{
- char dir[MAXPATHLEN + 1] = { '\0' };
- int len;
-
- if(*uml_dir == '~'){
- char *home = getenv("HOME");
-
- if(home == NULL){
- printf("make_uml_dir : no value in environment for "
- "$HOME\n");
- exit(1);
- }
- strlcpy(dir, home, sizeof(dir));
- uml_dir++;
- }
- strlcat(dir, uml_dir, sizeof(dir));
- len = strlen(dir);
- if (len > 0 && dir[len - 1] != '/')
- strlcat(dir, "/", sizeof(dir));
-
- uml_dir = malloc(strlen(dir) + 1);
- if (uml_dir == NULL) {
- printf("make_uml_dir : malloc failed, errno = %d\n", errno);
- exit(1);
- }
- strcpy(uml_dir, dir);
-
- if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
- printf("Failed to mkdir %s: %s\n", uml_dir, strerror(errno));
- return(-1);
- }
- return 0;
-}
-
-static int __init make_umid(int (*printer)(const char *fmt, ...))
-{
- int fd, err;
- char tmp[strlen(uml_dir) + UMID_LEN + 1];
-
- strlcpy(tmp, uml_dir, sizeof(tmp));
-
- if(!umid_inited){
- strcat(tmp, "XXXXXX");
- fd = mkstemp(tmp);
- if(fd < 0){
- (*printer)("make_umid - mkstemp(%s) failed: %s\n",
- tmp,strerror(errno));
- return(1);
- }
-
- os_close_file(fd);
- /* There's a nice tiny little race between this unlink and
- * the mkdir below. It'd be nice if there were a mkstemp
- * for directories.
- */
- unlink(tmp);
- set_umid(&tmp[strlen(uml_dir)], 1, printer);
- }
-
- sprintf(tmp, "%s%s", uml_dir, umid);
-
- err = mkdir(tmp, 0777);
- if(err < 0){
- if(errno == EEXIST){
- if(not_dead_yet(tmp)){
- (*printer)("umid '%s' is in use\n", umid);
- umid_owned = 0;
- return(-1);
- }
- err = mkdir(tmp, 0777);
- }
- }
- if(err < 0){
- (*printer)("Failed to create %s - errno = %d\n", umid, errno);
- return(-1);
- }
-
- umid_owned = 1;
- return 0;
-}
-
-__uml_setup("uml_dir=", set_uml_dir,
-"uml_dir=<directory>\n"
-" The location to place the pid and umid files.\n\n"
-);
-
-static int __init make_umid_setup(void)
-{
- /* one function with the ordering we need ... */
- make_uml_dir();
- make_umid(printf);
- create_pid_file();
- return 0;
-}
-__uml_postsetup(make_umid_setup);
-
-/*
- * 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/uml.lds.S b/arch/um/kernel/uml.lds.S
index af11915ce0a..6899195602b 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -1,4 +1,5 @@
#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
OUTPUT_FORMAT(ELF_FORMAT)
OUTPUT_ARCH(ELF_ARCH)
@@ -7,55 +8,69 @@ jiffies = jiffies_64;
SECTIONS
{
- /*This must contain the right address - not quite the default ELF one.*/
+ /* This must contain the right address - not quite the default ELF one.*/
PROVIDE (__executable_start = START);
- . = START + SIZEOF_HEADERS;
-
- /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
- * is remapped.*/
- __binary_start = .;
+ /* Static binaries stick stuff here, like the sigreturn trampoline,
+ * invisibly to objdump. So, just make __binary_start equal to the very
+ * beginning of the executable, and if there are unmapped pages after this,
+ * they are forever unusable.
+ */
+ __binary_start = START;
-#ifdef MODE_TT
- .remap_data : { UNMAP_PATH (.data .bss) }
- .remap : { UNMAP_PATH (.text) }
+ . = START + SIZEOF_HEADERS;
- . = ALIGN(4096); /* Init code and data */
-#endif
-
- _stext = .;
- __init_begin = .;
- .init.text : {
- _sinittext = .;
- *(.init.text)
- _einittext = .;
- }
- . = ALIGN(4096);
+ _text = .;
+ INIT_TEXT_SECTION(0)
+ . = ALIGN(PAGE_SIZE);
.text :
{
- *(.text)
+ _stext = .;
+ TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
*(.fixup)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
+ }
- . = ALIGN(4096);
- __syscall_stub_start = .;
- *(.__syscall_stub*)
- __syscall_stub_end = .;
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
+ .syscall_stub : {
+ __syscall_stub_start = .;
+ *(.__syscall_stub*)
+ __syscall_stub_end = .;
}
- #include "asm/common.lds.S"
+ /*
+ * These are needed even in a static link, even if they wind up being empty.
+ * Newer glibc needs these __rel{,a}_iplt_{start,end} symbols.
+ */
+ .rel.plt : {
+ *(.rel.plt)
+ PROVIDE_HIDDEN(__rel_iplt_start = .);
+ *(.rel.iplt)
+ PROVIDE_HIDDEN(__rel_iplt_end = .);
+ }
+ .rela.plt : {
+ *(.rela.plt)
+ PROVIDE_HIDDEN(__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN(__rela_iplt_end = .);
+ }
+
+ #include <asm/common.lds.S>
+
+ __init_begin = .;
+ init.data : { INIT_DATA }
+ __init_end = .;
- init.data : { *(init.data) }
.data :
{
- . = ALIGN(KERNEL_STACK_SIZE); /* init_task */
- *(.data.init_task)
- *(.data)
+ INIT_TASK_DATA(KERNEL_STACK_SIZE)
+ . = ALIGN(KERNEL_STACK_SIZE);
+ *(.data..init_irqstack)
+ DATA_DATA
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
@@ -79,24 +94,18 @@ SECTIONS
.sdata : { *(.sdata) }
_edata = .;
PROVIDE (edata = .);
- . = ALIGN(0x1000);
- .sbss :
- {
- __bss_start = .;
- PROVIDE(_bss_start = .);
- *(.sbss)
- *(.scommon)
- }
- .bss :
- {
- *(.dynbss)
- *(.bss)
- *(COMMON)
- }
+ . = ALIGN(PAGE_SIZE);
+ __bss_start = .;
+ PROVIDE(_bss_start = .);
+ SBSS(0)
+ BSS(0)
+ __bss_stop = .;
_end = .;
PROVIDE (end = .);
STABS_DEBUG
DWARF_DEBUG
+
+ DISCARDS
}
diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c
deleted file mode 100644
index 4c231161f25..00000000000
--- a/arch/um/kernel/user_util.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <limits.h>
-#include <setjmp.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/utsname.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include "asm/types.h"
-#include <ctype.h>
-#include <signal.h>
-#include <wait.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <sched.h>
-#include <termios.h>
-#include <string.h>
-#include "user_util.h"
-#include "kern_util.h"
-#include "user.h"
-#include "mem_user.h"
-#include "init.h"
-#include "ptrace_user.h"
-#include "uml-config.h"
-
-void stop(void)
-{
- while(1) sleep(1000000);
-}
-
-void stack_protections(unsigned long address)
-{
- int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
-
- if(mprotect((void *) address, page_size(), prot) < 0)
- panic("protecting stack failed, errno = %d", errno);
-}
-
-void task_protections(unsigned long address)
-{
- unsigned long guard = address + page_size();
- unsigned long stack = guard + page_size();
- int prot = 0, pages;
-
-#ifdef notdef
- if(mprotect((void *) stack, page_size(), prot) < 0)
- panic("protecting guard page failed, errno = %d", errno);
-#endif
- pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
- prot = PROT_READ | PROT_WRITE | PROT_EXEC;
- if(mprotect((void *) stack, pages * page_size(), prot) < 0)
- panic("protecting stack failed, errno = %d", errno);
-}
-
-int wait_for_stop(int pid, int sig, int cont_type, void *relay)
-{
- sigset_t *relay_signals = relay;
- int status, ret;
-
- while(1){
- CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED));
- if((ret < 0) ||
- !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
- if(ret < 0){
- printk("wait failed, errno = %d\n",
- errno);
- }
- else if(WIFEXITED(status))
- printk("process %d exited with status %d\n",
- pid, WEXITSTATUS(status));
- else if(WIFSIGNALED(status))
- printk("process %d exited with signal %d\n",
- pid, WTERMSIG(status));
- else if((WSTOPSIG(status) == SIGVTALRM) ||
- (WSTOPSIG(status) == SIGALRM) ||
- (WSTOPSIG(status) == SIGIO) ||
- (WSTOPSIG(status) == SIGPROF) ||
- (WSTOPSIG(status) == SIGCHLD) ||
- (WSTOPSIG(status) == SIGWINCH) ||
- (WSTOPSIG(status) == SIGINT)){
- ptrace(cont_type, pid, 0, WSTOPSIG(status));
- continue;
- }
- else if((relay_signals != NULL) &&
- sigismember(relay_signals, WSTOPSIG(status))){
- ptrace(cont_type, pid, 0, WSTOPSIG(status));
- continue;
- }
- else printk("process %d stopped with signal %d\n",
- pid, WSTOPSIG(status));
- panic("wait_for_stop failed to wait for %d to stop "
- "with %d\n", pid, sig);
- }
- return(status);
- }
-}
-
-int raw(int fd)
-{
- struct termios tt;
- int err;
-
- CATCH_EINTR(err = tcgetattr(fd, &tt));
- if(err < 0)
- return -errno;
-
- cfmakeraw(&tt);
-
- CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt));
- if(err < 0)
- return -errno;
-
- /* XXX tcsetattr could have applied only some changes
- * (and cfmakeraw() is a set of changes) */
- return(0);
-}
-
-void setup_machinename(char *machine_out)
-{
- struct utsname host;
-
- uname(&host);
-#if defined(UML_CONFIG_UML_X86) && !defined(UML_CONFIG_64BIT)
- if (!strcmp(host.machine, "x86_64")) {
- strcpy(machine_out, "i686");
- return;
- }
-#endif
- strcpy(machine_out, host.machine);
-}
-
-char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1];
-
-void setup_hostinfo(void)
-{
- struct utsname host;
-
- uname(&host);
- sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename,
- host.release, host.version, host.machine);
-}
-
-int setjmp_wrapper(void (*proc)(void *, void *), ...)
-{
- va_list args;
- sigjmp_buf buf;
- int n;
-
- n = sigsetjmp(buf, 1);
- if(n == 0){
- va_start(args, proc);
- (*proc)(&buf, &args);
- }
- va_end(args);
- return(n);
-}
-
-/*
- * 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/vmlinux.lds.S b/arch/um/kernel/vmlinux.lds.S
index 1660a769674..16e49bfa2b4 100644
--- a/arch/um/kernel/vmlinux.lds.S
+++ b/arch/um/kernel/vmlinux.lds.S
@@ -1,4 +1,6 @@
-#include <linux/config.h>
+
+KERNEL_STACK_SIZE = 4096 * (1 << CONFIG_KERNEL_STACK_ORDER);
+
#ifdef CONFIG_LD_SCRIPT_STATIC
#include "uml.lds.S"
#else