aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/um/kernel
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/um/kernel')
-rw-r--r--arch/um/kernel/Makefile58
-rw-r--r--arch/um/kernel/checksum.c36
-rw-r--r--arch/um/kernel/config.c.in32
-rw-r--r--arch/um/kernel/dyn.lds.S176
-rw-r--r--arch/um/kernel/exec_kern.c91
-rw-r--r--arch/um/kernel/exitcode.c73
-rw-r--r--arch/um/kernel/gmon_syms.c34
-rw-r--r--arch/um/kernel/gprof_syms.c20
-rw-r--r--arch/um/kernel/helper.c173
-rw-r--r--arch/um/kernel/init_task.c61
-rw-r--r--arch/um/kernel/initrd_kern.c59
-rw-r--r--arch/um/kernel/initrd_user.c46
-rw-r--r--arch/um/kernel/irq.c178
-rw-r--r--arch/um/kernel/irq_user.c443
-rw-r--r--arch/um/kernel/ksyms.c137
-rw-r--r--arch/um/kernel/main.c271
-rw-r--r--arch/um/kernel/mem.c359
-rw-r--r--arch/um/kernel/mem_user.c273
-rw-r--r--arch/um/kernel/physmem.c478
-rw-r--r--arch/um/kernel/process.c423
-rw-r--r--arch/um/kernel/process_kern.c500
-rw-r--r--arch/um/kernel/ptrace.c388
-rw-r--r--arch/um/kernel/reboot.c79
-rw-r--r--arch/um/kernel/resource.c23
-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_kern.c213
-rw-r--r--arch/um/kernel/signal_user.c157
-rw-r--r--arch/um/kernel/skas/Makefile13
-rw-r--r--arch/um/kernel/skas/exec_kern.c41
-rw-r--r--arch/um/kernel/skas/include/mmu-skas.h24
-rw-r--r--arch/um/kernel/skas/include/mode-skas.h34
-rw-r--r--arch/um/kernel/skas/include/mode_kern-skas.h53
-rw-r--r--arch/um/kernel/skas/include/proc_mm.h55
-rw-r--r--arch/um/kernel/skas/include/skas.h46
-rw-r--r--arch/um/kernel/skas/include/uaccess-skas.h45
-rw-r--r--arch/um/kernel/skas/mem.c35
-rw-r--r--arch/um/kernel/skas/mem_user.c102
-rw-r--r--arch/um/kernel/skas/mmu.c48
-rw-r--r--arch/um/kernel/skas/process.c339
-rw-r--r--arch/um/kernel/skas/process_kern.c213
-rw-r--r--arch/um/kernel/skas/syscall_kern.c43
-rw-r--r--arch/um/kernel/skas/syscall_user.c44
-rw-r--r--arch/um/kernel/skas/time.c30
-rw-r--r--arch/um/kernel/skas/tlb.c85
-rw-r--r--arch/um/kernel/skas/trap_user.c71
-rw-r--r--arch/um/kernel/skas/uaccess.c259
-rw-r--r--arch/um/kernel/skas/util/Makefile4
-rw-r--r--arch/um/kernel/skas/util/mk_ptregs-i386.c51
-rw-r--r--arch/um/kernel/skas/util/mk_ptregs-x86_64.c68
-rw-r--r--arch/um/kernel/smp.c269
-rw-r--r--arch/um/kernel/sys_call_table.c276
-rw-r--r--arch/um/kernel/syscall_kern.c176
-rw-r--r--arch/um/kernel/syscall_user.c48
-rw-r--r--arch/um/kernel/sysrq.c81
-rw-r--r--arch/um/kernel/tempfile.c82
-rw-r--r--arch/um/kernel/time.c167
-rw-r--r--arch/um/kernel/time_kern.c203
-rw-r--r--arch/um/kernel/tlb.c369
-rw-r--r--arch/um/kernel/trap_kern.c251
-rw-r--r--arch/um/kernel/trap_user.c120
-rw-r--r--arch/um/kernel/tt/Makefile28
-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.h29
-rw-r--r--arch/um/kernel/tt/include/mmu-tt.h23
-rw-r--r--arch/um/kernel/tt/include/mode-tt.h35
-rw-r--r--arch/um/kernel/tt/include/mode_kern-tt.h53
-rw-r--r--arch/um/kernel/tt/include/tt.h46
-rw-r--r--arch/um/kernel/tt/include/uaccess-tt.h71
-rw-r--r--arch/um/kernel/tt/ksyms.c28
-rw-r--r--arch/um/kernel/tt/mem.c51
-rw-r--r--arch/um/kernel/tt/mem_user.c49
-rw-r--r--arch/um/kernel/tt/process_kern.c476
-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.c47
-rw-r--r--arch/um/kernel/tt/syscall_user.c90
-rw-r--r--arch/um/kernel/tt/time.c28
-rw-r--r--arch/um/kernel/tt/tlb.c149
-rw-r--r--arch/um/kernel/tt/tracer.c480
-rw-r--r--arch/um/kernel/tt/trap_user.c60
-rw-r--r--arch/um/kernel/tt/uaccess.c73
-rw-r--r--arch/um/kernel/tt/uaccess_user.c98
-rw-r--r--arch/um/kernel/tt/unmap.c31
-rw-r--r--arch/um/kernel/tty_log.c230
-rw-r--r--arch/um/kernel/uaccess_user.c64
-rw-r--r--arch/um/kernel/um_arch.c467
-rw-r--r--arch/um/kernel/umid.c325
-rw-r--r--arch/um/kernel/uml.lds.S106
-rw-r--r--arch/um/kernel/user_util.c173
99 files changed, 13673 insertions, 0 deletions
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
new file mode 100644
index 000000000000..dc796c1bf39e
--- /dev/null
+++ b/arch/um/kernel/Makefile
@@ -0,0 +1,58 @@
1#
2# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6extra-y := vmlinux.lds
7clean-files := vmlinux.lds.S config.tmp
8
9obj-y = checksum.o config.o exec_kern.o exitcode.o \
10 helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \
11 physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \
12 sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
13 syscall_kern.o sysrq.o sys_call_table.o tempfile.o time.o time_kern.o \
14 tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o umid.o \
15 user_util.o
16
17obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
18obj-$(CONFIG_GPROF) += gprof_syms.o
19obj-$(CONFIG_GCOV) += gmon_syms.o
20obj-$(CONFIG_TTY_LOG) += tty_log.o
21obj-$(CONFIG_SYSCALL_DEBUG) += syscall_user.o
22
23obj-$(CONFIG_MODE_TT) += tt/
24obj-$(CONFIG_MODE_SKAS) += skas/
25
26# This needs be compiled with frame pointers regardless of how the rest of the
27# kernel is built.
28CFLAGS_frame.o := -fno-omit-frame-pointer
29
30user-objs-$(CONFIG_TTY_LOG) += tty_log.o
31
32USER_OBJS := $(user-objs-y) config.o helper.o main.o process.o tempfile.o \
33 time.o tty_log.o umid.o user_util.o frame.o
34
35include arch/um/scripts/Makefile.rules
36
37targets += config.c
38
39# Be careful with the below Sed code - sed is pitfall-rich!
40# We use sed to lower build requirements, for "embedded" builders for instance.
41
42$(obj)/config.tmp: $(objtree)/.config FORCE
43 $(call if_changed,quote1)
44
45quiet_cmd_quote1 = QUOTE $@
46 cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' \
47 $< > $@
48
49$(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE
50 $(call if_changed,quote2)
51
52quiet_cmd_quote2 = QUOTE $@
53 cmd_quote2 = sed -e '/CONFIG/{' \
54 -e 's/"CONFIG"\;/""/' \
55 -e 'r $(obj)/config.tmp' \
56 -e 'a""\;' \
57 -e '}' \
58 $< > $@
diff --git a/arch/um/kernel/checksum.c b/arch/um/kernel/checksum.c
new file mode 100644
index 000000000000..e69b2be951d1
--- /dev/null
+++ b/arch/um/kernel/checksum.c
@@ -0,0 +1,36 @@
1#include "asm/uaccess.h"
2#include "linux/errno.h"
3#include "linux/module.h"
4
5unsigned int arch_csum_partial(const unsigned char *buff, int len, int sum);
6
7unsigned int csum_partial(unsigned char *buff, int len, int sum)
8{
9 return arch_csum_partial(buff, len, sum);
10}
11
12EXPORT_SYMBOL(csum_partial);
13
14unsigned int csum_partial_copy_to(const unsigned char *src,
15 unsigned char __user *dst, int len, int sum,
16 int *err_ptr)
17{
18 if(copy_to_user(dst, src, len)){
19 *err_ptr = -EFAULT;
20 return(-1);
21 }
22
23 return(arch_csum_partial(src, len, sum));
24}
25
26unsigned int csum_partial_copy_from(const unsigned char __user *src,
27 unsigned char *dst, int len, int sum,
28 int *err_ptr)
29{
30 if(copy_from_user(dst, src, len)){
31 *err_ptr = -EFAULT;
32 return(-1);
33 }
34
35 return arch_csum_partial(dst, len, sum);
36}
diff --git a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in
new file mode 100644
index 000000000000..c062cbfe386e
--- /dev/null
+++ b/arch/um/kernel/config.c.in
@@ -0,0 +1,32 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include "init.h"
9
10static __initdata char *config = "CONFIG";
11
12static int __init print_config(char *line, int *add)
13{
14 printf("%s", config);
15 exit(0);
16}
17
18__uml_setup("--showconfig", print_config,
19"--showconfig\n"
20" Prints the config file that this UML binary was generated from.\n\n"
21);
22
23/*
24 * Overrides for Emacs so that we follow Linus's tabbing style.
25 * Emacs will notice this stuff at the end of the file and automatically
26 * adjust the settings for this buffer only. This must remain at the end
27 * of the file.
28 * ---------------------------------------------------------------------------
29 * Local variables:
30 * c-file-style: "linux"
31 * End:
32 */
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
new file mode 100644
index 000000000000..715b0838a68c
--- /dev/null
+++ b/arch/um/kernel/dyn.lds.S
@@ -0,0 +1,176 @@
1#include <asm-generic/vmlinux.lds.h>
2
3OUTPUT_FORMAT(ELF_FORMAT)
4OUTPUT_ARCH(ELF_ARCH)
5ENTRY(_start)
6jiffies = jiffies_64;
7
8SECTIONS
9{
10 PROVIDE (__executable_start = START);
11 . = START + SIZEOF_HEADERS;
12 .interp : { *(.interp) }
13 /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
14 * is remapped.*/
15 __binary_start = .;
16 . = ALIGN(4096); /* Init code and data */
17 _stext = .;
18 __init_begin = .;
19 .init.text : {
20 _sinittext = .;
21 *(.init.text)
22 _einittext = .;
23 }
24
25 . = ALIGN(4096);
26
27 /* Read-only sections, merged into text segment: */
28 .hash : { *(.hash) }
29 .dynsym : { *(.dynsym) }
30 .dynstr : { *(.dynstr) }
31 .gnu.version : { *(.gnu.version) }
32 .gnu.version_d : { *(.gnu.version_d) }
33 .gnu.version_r : { *(.gnu.version_r) }
34 .rel.init : { *(.rel.init) }
35 .rela.init : { *(.rela.init) }
36 .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
37 .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
38 .rel.fini : { *(.rel.fini) }
39 .rela.fini : { *(.rela.fini) }
40 .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
41 .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
42 .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
43 .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
44 .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
45 .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
46 .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
47 .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
48 .rel.ctors : { *(.rel.ctors) }
49 .rela.ctors : { *(.rela.ctors) }
50 .rel.dtors : { *(.rel.dtors) }
51 .rela.dtors : { *(.rela.dtors) }
52 .rel.got : { *(.rel.got) }
53 .rela.got : { *(.rela.got) }
54 .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
55 .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
56 .rel.plt : { *(.rel.plt) }
57 .rela.plt : { *(.rela.plt) }
58 .init : {
59 KEEP (*(.init))
60 } =0x90909090
61 .plt : { *(.plt) }
62 .text : {
63 *(.text)
64 SCHED_TEXT
65 LOCK_TEXT
66 *(.fixup)
67 *(.stub .text.* .gnu.linkonce.t.*)
68 /* .gnu.warning sections are handled specially by elf32.em. */
69 *(.gnu.warning)
70 } =0x90909090
71 .fini : {
72 KEEP (*(.fini))
73 } =0x90909090
74
75 .kstrtab : { *(.kstrtab) }
76
77 #include "asm/common.lds.S"
78
79 init.data : { *(.init.data) }
80
81 /* Ensure the __preinit_array_start label is properly aligned. We
82 could instead move the label definition inside the section, but
83 the linker would then create the section even if it turns out to
84 be empty, which isn't pretty. */
85 . = ALIGN(32 / 8);
86 .preinit_array : { *(.preinit_array) }
87 .init_array : { *(.init_array) }
88 .fini_array : { *(.fini_array) }
89 .data : {
90 . = ALIGN(KERNEL_STACK_SIZE); /* init_task */
91 *(.data.init_task)
92 *(.data .data.* .gnu.linkonce.d.*)
93 SORT(CONSTRUCTORS)
94 }
95 .data1 : { *(.data1) }
96 .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
97 .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
98 .eh_frame : { KEEP (*(.eh_frame)) }
99 .gcc_except_table : { *(.gcc_except_table) }
100 .dynamic : { *(.dynamic) }
101 .ctors : {
102 /* gcc uses crtbegin.o to find the start of
103 the constructors, so we make sure it is
104 first. Because this is a wildcard, it
105 doesn't matter if the user does not
106 actually link against crtbegin.o; the
107 linker won't look for a file to match a
108 wildcard. The wildcard also means that it
109 doesn't matter which directory crtbegin.o
110 is in. */
111 KEEP (*crtbegin.o(.ctors))
112 /* We don't want to include the .ctor section from
113 from the crtend.o file until after the sorted ctors.
114 The .ctor section from the crtend file contains the
115 end of ctors marker and it must be last */
116 KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
117 KEEP (*(SORT(.ctors.*)))
118 KEEP (*(.ctors))
119 }
120 .dtors : {
121 KEEP (*crtbegin.o(.dtors))
122 KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
123 KEEP (*(SORT(.dtors.*)))
124 KEEP (*(.dtors))
125 }
126 .jcr : { KEEP (*(.jcr)) }
127 .got : { *(.got.plt) *(.got) }
128 _edata = .;
129 PROVIDE (edata = .);
130 __bss_start = .;
131 .bss : {
132 *(.dynbss)
133 *(.bss .bss.* .gnu.linkonce.b.*)
134 *(COMMON)
135 /* Align here to ensure that the .bss section occupies space up to
136 _end. Align after .bss to ensure correct alignment even if the
137 .bss section disappears because there are no input sections. */
138 . = ALIGN(32 / 8);
139 . = ALIGN(32 / 8);
140 }
141 _end = .;
142 PROVIDE (end = .);
143 /* Stabs debugging sections. */
144 .stab 0 : { *(.stab) }
145 .stabstr 0 : { *(.stabstr) }
146 .stab.excl 0 : { *(.stab.excl) }
147 .stab.exclstr 0 : { *(.stab.exclstr) }
148 .stab.index 0 : { *(.stab.index) }
149 .stab.indexstr 0 : { *(.stab.indexstr) }
150 .comment 0 : { *(.comment) }
151 /* DWARF debug sections.
152 Symbols in the DWARF debugging sections are relative to the beginning
153 of the section so we begin them at 0. */
154 /* DWARF 1 */
155 .debug 0 : { *(.debug) }
156 .line 0 : { *(.line) }
157 /* GNU DWARF 1 extensions */
158 .debug_srcinfo 0 : { *(.debug_srcinfo) }
159 .debug_sfnames 0 : { *(.debug_sfnames) }
160 /* DWARF 1.1 and DWARF 2 */
161 .debug_aranges 0 : { *(.debug_aranges) }
162 .debug_pubnames 0 : { *(.debug_pubnames) }
163 /* DWARF 2 */
164 .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
165 .debug_abbrev 0 : { *(.debug_abbrev) }
166 .debug_line 0 : { *(.debug_line) }
167 .debug_frame 0 : { *(.debug_frame) }
168 .debug_str 0 : { *(.debug_str) }
169 .debug_loc 0 : { *(.debug_loc) }
170 .debug_macinfo 0 : { *(.debug_macinfo) }
171 /* SGI/MIPS DWARF 2 extensions */
172 .debug_weaknames 0 : { *(.debug_weaknames) }
173 .debug_funcnames 0 : { *(.debug_funcnames) }
174 .debug_typenames 0 : { *(.debug_typenames) }
175 .debug_varnames 0 : { *(.debug_varnames) }
176}
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
new file mode 100644
index 000000000000..49ddabe69be7
--- /dev/null
+++ b/arch/um/kernel/exec_kern.c
@@ -0,0 +1,91 @@
1/*
2 * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/slab.h"
7#include "linux/smp_lock.h"
8#include "linux/ptrace.h"
9#include "asm/ptrace.h"
10#include "asm/pgtable.h"
11#include "asm/tlbflush.h"
12#include "asm/uaccess.h"
13#include "user_util.h"
14#include "kern_util.h"
15#include "mem_user.h"
16#include "kern.h"
17#include "irq_user.h"
18#include "tlb.h"
19#include "2_5compat.h"
20#include "os.h"
21#include "time_user.h"
22#include "choose-mode.h"
23#include "mode_kern.h"
24
25void flush_thread(void)
26{
27 CHOOSE_MODE(flush_thread_tt(), flush_thread_skas());
28}
29
30void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
31{
32 CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp);
33}
34
35extern void log_exec(char **argv, void *tty);
36
37static long execve1(char *file, char __user * __user *argv,
38 char *__user __user *env)
39{
40 long error;
41
42#ifdef CONFIG_TTY_LOG
43 log_exec(argv, current->tty);
44#endif
45 error = do_execve(file, argv, env, &current->thread.regs);
46 if (error == 0){
47 task_lock(current);
48 current->ptrace &= ~PT_DTRACE;
49 task_unlock(current);
50 set_cmdline(current_cmd());
51 }
52 return(error);
53}
54
55long um_execve(char *file, char __user *__user *argv, char __user *__user *env)
56{
57 long err;
58
59 err = execve1(file, argv, env);
60 if(!err)
61 do_longjmp(current->thread.exec_buf, 1);
62 return(err);
63}
64
65long sys_execve(char *file, char __user *__user *argv,
66 char __user *__user *env)
67{
68 long error;
69 char *filename;
70
71 lock_kernel();
72 filename = getname((char __user *) file);
73 error = PTR_ERR(filename);
74 if (IS_ERR(filename)) goto out;
75 error = execve1(filename, argv, env);
76 putname(filename);
77 out:
78 unlock_kernel();
79 return(error);
80}
81
82/*
83 * Overrides for Emacs so that we follow Linus's tabbing style.
84 * Emacs will notice this stuff at the end of the file and automatically
85 * adjust the settings for this buffer only. This must remain at the end
86 * of the file.
87 * ---------------------------------------------------------------------------
88 * Local variables:
89 * c-file-style: "linux"
90 * End:
91 */
diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
new file mode 100644
index 000000000000..0ea87f24b36f
--- /dev/null
+++ b/arch/um/kernel/exitcode.c
@@ -0,0 +1,73 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/init.h"
7#include "linux/ctype.h"
8#include "linux/proc_fs.h"
9#include "asm/uaccess.h"
10
11/* If read and write race, the read will still atomically read a valid
12 * value.
13 */
14int uml_exitcode = 0;
15
16static int read_proc_exitcode(char *page, char **start, off_t off,
17 int count, int *eof, void *data)
18{
19 int len;
20
21 len = sprintf(page, "%d\n", uml_exitcode);
22 len -= off;
23 if(len <= off+count) *eof = 1;
24 *start = page + off;
25 if(len > count) len = count;
26 if(len < 0) len = 0;
27 return(len);
28}
29
30static int write_proc_exitcode(struct file *file, const char __user *buffer,
31 unsigned long count, void *data)
32{
33 char *end, buf[sizeof("nnnnn\0")];
34 int tmp;
35
36 if(copy_from_user(buf, buffer, count))
37 return(-EFAULT);
38 tmp = simple_strtol(buf, &end, 0);
39 if((*end != '\0') && !isspace(*end))
40 return(-EINVAL);
41 uml_exitcode = tmp;
42 return(count);
43}
44
45static int make_proc_exitcode(void)
46{
47 struct proc_dir_entry *ent;
48
49 ent = create_proc_entry("exitcode", 0600, &proc_root);
50 if(ent == NULL){
51 printk("make_proc_exitcode : Failed to register "
52 "/proc/exitcode\n");
53 return(0);
54 }
55
56 ent->read_proc = read_proc_exitcode;
57 ent->write_proc = write_proc_exitcode;
58
59 return(0);
60}
61
62__initcall(make_proc_exitcode);
63
64/*
65 * Overrides for Emacs so that we follow Linus's tabbing style.
66 * Emacs will notice this stuff at the end of the file and automatically
67 * adjust the settings for this buffer only. This must remain at the end
68 * of the file.
69 * ---------------------------------------------------------------------------
70 * Local variables:
71 * c-file-style: "linux"
72 * End:
73 */
diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c
new file mode 100644
index 000000000000..2c86e7fdb014
--- /dev/null
+++ b/arch/um/kernel/gmon_syms.c
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/module.h"
7
8extern void __bb_init_func(void *);
9EXPORT_SYMBOL(__bb_init_func);
10
11/* This is defined (and referred to in profiling stub code) only by some GCC
12 * versions in libgcov.
13 *
14 * Since SuSE backported the fix, we cannot handle it depending on GCC version.
15 * So, unconditinally export it. But also give it a weak declaration, which will
16 * be overriden by any other one.
17 */
18
19extern void __gcov_init(void *) __attribute__((weak));
20EXPORT_SYMBOL(__gcov_init);
21
22extern void __gcov_merge_add(void *) __attribute__((weak));
23EXPORT_SYMBOL(__gcov_merge_add);
24
25/*
26 * Overrides for Emacs so that we follow Linus's tabbing style.
27 * Emacs will notice this stuff at the end of the file and automatically
28 * adjust the settings for this buffer only. This must remain at the end
29 * of the file.
30 * ---------------------------------------------------------------------------
31 * Local variables:
32 * c-file-style: "linux"
33 * End:
34 */
diff --git a/arch/um/kernel/gprof_syms.c b/arch/um/kernel/gprof_syms.c
new file mode 100644
index 000000000000..9244f018d44c
--- /dev/null
+++ b/arch/um/kernel/gprof_syms.c
@@ -0,0 +1,20 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/module.h"
7
8extern void mcount(void);
9EXPORT_SYMBOL(mcount);
10
11/*
12 * Overrides for Emacs so that we follow Linus's tabbing style.
13 * Emacs will notice this stuff at the end of the file and automatically
14 * adjust the settings for this buffer only. This must remain at the end
15 * of the file.
16 * ---------------------------------------------------------------------------
17 * Local variables:
18 * c-file-style: "linux"
19 * End:
20 */
diff --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c
new file mode 100644
index 000000000000..13b1f5c2f7ee
--- /dev/null
+++ b/arch/um/kernel/helper.c
@@ -0,0 +1,173 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <errno.h>
10#include <sched.h>
11#include <sys/signal.h>
12#include <sys/wait.h>
13#include "user.h"
14#include "kern_util.h"
15#include "user_util.h"
16#include "os.h"
17
18struct helper_data {
19 void (*pre_exec)(void*);
20 void *pre_data;
21 char **argv;
22 int fd;
23};
24
25/* Debugging aid, changed only from gdb */
26int helper_pause = 0;
27
28static void helper_hup(int sig)
29{
30}
31
32static int helper_child(void *arg)
33{
34 struct helper_data *data = arg;
35 char **argv = data->argv;
36 int errval;
37
38 if(helper_pause){
39 signal(SIGHUP, helper_hup);
40 pause();
41 }
42 if(data->pre_exec != NULL)
43 (*data->pre_exec)(data->pre_data);
44 execvp(argv[0], argv);
45 errval = errno;
46 printk("execvp of '%s' failed - errno = %d\n", argv[0], errno);
47 os_write_file(data->fd, &errval, sizeof(errval));
48 os_kill_process(os_getpid(), 0);
49 return(0);
50}
51
52/* Returns either the pid of the child process we run or -E* on failure.
53 * XXX The alloc_stack here breaks if this is called in the tracing thread */
54int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
55 unsigned long *stack_out)
56{
57 struct helper_data data;
58 unsigned long stack, sp;
59 int pid, fds[2], ret, n;
60
61 if((stack_out != NULL) && (*stack_out != 0))
62 stack = *stack_out;
63 else stack = alloc_stack(0, um_in_interrupt());
64 if(stack == 0)
65 return(-ENOMEM);
66
67 ret = os_pipe(fds, 1, 0);
68 if(ret < 0){
69 printk("run_helper : pipe failed, ret = %d\n", -ret);
70 goto out_free;
71 }
72
73 ret = os_set_exec_close(fds[1], 1);
74 if(ret < 0){
75 printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n",
76 -ret);
77 goto out_close;
78 }
79
80 sp = stack + page_size() - sizeof(void *);
81 data.pre_exec = pre_exec;
82 data.pre_data = pre_data;
83 data.argv = argv;
84 data.fd = fds[1];
85 pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data);
86 if(pid < 0){
87 printk("run_helper : clone failed, errno = %d\n", errno);
88 ret = -errno;
89 goto out_close;
90 }
91
92 os_close_file(fds[1]);
93 fds[1] = -1;
94
95 /*Read the errno value from the child.*/
96 n = os_read_file(fds[0], &ret, sizeof(ret));
97 if(n < 0){
98 printk("run_helper : read on pipe failed, ret = %d\n", -n);
99 ret = n;
100 os_kill_process(pid, 1);
101 }
102 else if(n != 0){
103 CATCH_EINTR(n = waitpid(pid, NULL, 0));
104 ret = -errno;
105 } else {
106 ret = pid;
107 }
108
109out_close:
110 if (fds[1] != -1)
111 os_close_file(fds[1]);
112 os_close_file(fds[0]);
113out_free:
114 if(stack_out == NULL)
115 free_stack(stack, 0);
116 else *stack_out = stack;
117 return(ret);
118}
119
120int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
121 unsigned long *stack_out, int stack_order)
122{
123 unsigned long stack, sp;
124 int pid, status;
125
126 stack = alloc_stack(stack_order, um_in_interrupt());
127 if(stack == 0) return(-ENOMEM);
128
129 sp = stack + (page_size() << stack_order) - sizeof(void *);
130 pid = clone(proc, (void *) sp, flags | SIGCHLD, arg);
131 if(pid < 0){
132 printk("run_helper_thread : clone failed, errno = %d\n",
133 errno);
134 return(-errno);
135 }
136 if(stack_out == NULL){
137 CATCH_EINTR(pid = waitpid(pid, &status, 0));
138 if(pid < 0){
139 printk("run_helper_thread - wait failed, errno = %d\n",
140 errno);
141 pid = -errno;
142 }
143 if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
144 printk("run_helper_thread - thread returned status "
145 "0x%x\n", status);
146 free_stack(stack, stack_order);
147 }
148 else *stack_out = stack;
149 return(pid);
150}
151
152int helper_wait(int pid, int block)
153{
154 int ret;
155
156 CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG));
157 if(ret < 0){
158 printk("helper_wait : waitpid failed, errno = %d\n", errno);
159 return(-errno);
160 }
161 return(ret);
162}
163
164/*
165 * Overrides for Emacs so that we follow Linus's tabbing style.
166 * Emacs will notice this stuff at the end of the file and automatically
167 * adjust the settings for this buffer only. This must remain at the end
168 * of the file.
169 * ---------------------------------------------------------------------------
170 * Local variables:
171 * c-file-style: "linux"
172 * End:
173 */
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
new file mode 100644
index 000000000000..cd7c85be0a1b
--- /dev/null
+++ b/arch/um/kernel/init_task.c
@@ -0,0 +1,61 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/mm.h"
8#include "linux/module.h"
9#include "linux/sched.h"
10#include "linux/init_task.h"
11#include "linux/mqueue.h"
12#include "asm/uaccess.h"
13#include "asm/pgtable.h"
14#include "user_util.h"
15#include "mem_user.h"
16
17static struct fs_struct init_fs = INIT_FS;
18struct mm_struct init_mm = INIT_MM(init_mm);
19static struct files_struct init_files = INIT_FILES;
20static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
21static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
22EXPORT_SYMBOL(init_mm);
23
24/*
25 * Initial task structure.
26 *
27 * All other task structs will be allocated on slabs in fork.c
28 */
29
30struct task_struct init_task = INIT_TASK(init_task);
31
32EXPORT_SYMBOL(init_task);
33
34/*
35 * Initial thread structure.
36 *
37 * We need to make sure that this is 16384-byte aligned due to the
38 * way process stacks are handled. This is done by having a special
39 * "init_task" linker map entry..
40 */
41
42union thread_union init_thread_union
43__attribute__((__section__(".data.init_task"))) =
44{ INIT_THREAD_INFO(init_task) };
45
46void unprotect_stack(unsigned long stack)
47{
48 protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE,
49 1, 1, 0, 1);
50}
51
52/*
53 * Overrides for Emacs so that we follow Linus's tabbing style.
54 * Emacs will notice this stuff at the end of the file and automatically
55 * adjust the settings for this buffer only. This must remain at the end
56 * of the file.
57 * ---------------------------------------------------------------------------
58 * Local variables:
59 * c-file-style: "linux"
60 * End:
61 */
diff --git a/arch/um/kernel/initrd_kern.c b/arch/um/kernel/initrd_kern.c
new file mode 100644
index 000000000000..fc568af468b9
--- /dev/null
+++ b/arch/um/kernel/initrd_kern.c
@@ -0,0 +1,59 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/init.h"
7#include "linux/bootmem.h"
8#include "linux/initrd.h"
9#include "asm/types.h"
10#include "user_util.h"
11#include "kern_util.h"
12#include "initrd.h"
13#include "init.h"
14#include "os.h"
15
16/* Changed by uml_initrd_setup, which is a setup */
17static char *initrd __initdata = NULL;
18
19static int __init read_initrd(void)
20{
21 void *area;
22 long long size;
23 int err;
24
25 if(initrd == NULL) return 0;
26 err = os_file_size(initrd, &size);
27 if(err) return 0;
28 area = alloc_bootmem(size);
29 if(area == NULL) return 0;
30 if(load_initrd(initrd, area, size) == -1) return 0;
31 initrd_start = (unsigned long) area;
32 initrd_end = initrd_start + size;
33 return 0;
34}
35
36__uml_postsetup(read_initrd);
37
38static int __init uml_initrd_setup(char *line, int *add)
39{
40 initrd = line;
41 return 0;
42}
43
44__uml_setup("initrd=", uml_initrd_setup,
45"initrd=<initrd image>\n"
46" This is used to boot UML from an initrd image. The argument is the\n"
47" name of the file containing the image.\n\n"
48);
49
50/*
51 * Overrides for Emacs so that we follow Linus's tabbing style.
52 * Emacs will notice this stuff at the end of the file and automatically
53 * adjust the settings for this buffer only. This must remain at the end
54 * of the file.
55 * ---------------------------------------------------------------------------
56 * Local variables:
57 * c-file-style: "linux"
58 * End:
59 */
diff --git a/arch/um/kernel/initrd_user.c b/arch/um/kernel/initrd_user.c
new file mode 100644
index 000000000000..cb90681e151c
--- /dev/null
+++ b/arch/um/kernel/initrd_user.c
@@ -0,0 +1,46 @@
1/*
2 * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <errno.h>
10
11#include "user_util.h"
12#include "kern_util.h"
13#include "user.h"
14#include "initrd.h"
15#include "os.h"
16
17int load_initrd(char *filename, void *buf, int size)
18{
19 int fd, n;
20
21 fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
22 if(fd < 0){
23 printk("Opening '%s' failed - err = %d\n", filename, -fd);
24 return(-1);
25 }
26 n = os_read_file(fd, buf, size);
27 if(n != size){
28 printk("Read of %d bytes from '%s' failed, err = %d\n", size,
29 filename, -n);
30 return(-1);
31 }
32
33 os_close_file(fd);
34 return(0);
35}
36
37/*
38 * Overrides for Emacs so that we follow Linus's tabbing style.
39 * Emacs will notice this stuff at the end of the file and automatically
40 * adjust the settings for this buffer only. This must remain at the end
41 * of the file.
42 * ---------------------------------------------------------------------------
43 * Local variables:
44 * c-file-style: "linux"
45 * End:
46 */
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
new file mode 100644
index 000000000000..d71e8f00810f
--- /dev/null
+++ b/arch/um/kernel/irq.c
@@ -0,0 +1,178 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
5 * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
6 */
7
8#include "linux/config.h"
9#include "linux/kernel.h"
10#include "linux/module.h"
11#include "linux/smp.h"
12#include "linux/irq.h"
13#include "linux/kernel_stat.h"
14#include "linux/interrupt.h"
15#include "linux/random.h"
16#include "linux/slab.h"
17#include "linux/file.h"
18#include "linux/proc_fs.h"
19#include "linux/init.h"
20#include "linux/seq_file.h"
21#include "linux/profile.h"
22#include "linux/hardirq.h"
23#include "asm/irq.h"
24#include "asm/hw_irq.h"
25#include "asm/atomic.h"
26#include "asm/signal.h"
27#include "asm/system.h"
28#include "asm/errno.h"
29#include "asm/uaccess.h"
30#include "user_util.h"
31#include "kern_util.h"
32#include "irq_user.h"
33#include "irq_kern.h"
34
35
36/*
37 * Generic, controller-independent functions:
38 */
39
40int show_interrupts(struct seq_file *p, void *v)
41{
42 int i = *(loff_t *) v, j;
43 struct irqaction * action;
44 unsigned long flags;
45
46 if (i == 0) {
47 seq_printf(p, " ");
48 for_each_online_cpu(j)
49 seq_printf(p, "CPU%d ",j);
50 seq_putc(p, '\n');
51 }
52
53 if (i < NR_IRQS) {
54 spin_lock_irqsave(&irq_desc[i].lock, flags);
55 action = irq_desc[i].action;
56 if (!action)
57 goto skip;
58 seq_printf(p, "%3d: ",i);
59#ifndef CONFIG_SMP
60 seq_printf(p, "%10u ", kstat_irqs(i));
61#else
62 for_each_online_cpu(j)
63 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
64#endif
65 seq_printf(p, " %14s", irq_desc[i].handler->typename);
66 seq_printf(p, " %s", action->name);
67
68 for (action=action->next; action; action = action->next)
69 seq_printf(p, ", %s", action->name);
70
71 seq_putc(p, '\n');
72skip:
73 spin_unlock_irqrestore(&irq_desc[i].lock, flags);
74 } else if (i == NR_IRQS) {
75 seq_putc(p, '\n');
76 }
77
78 return 0;
79}
80
81/*
82 * do_IRQ handles all normal device IRQ's (the special
83 * SMP cross-CPU interrupts have their own specific
84 * handlers).
85 */
86unsigned int do_IRQ(int irq, union uml_pt_regs *regs)
87{
88 irq_enter();
89 __do_IRQ(irq, (struct pt_regs *) regs);
90 irq_exit();
91 return 1;
92}
93
94int um_request_irq(unsigned int irq, int fd, int type,
95 irqreturn_t (*handler)(int, void *, struct pt_regs *),
96 unsigned long irqflags, const char * devname,
97 void *dev_id)
98{
99 int err;
100
101 err = request_irq(irq, handler, irqflags, devname, dev_id);
102 if(err)
103 return(err);
104
105 if(fd != -1)
106 err = activate_fd(irq, fd, type, dev_id);
107 return(err);
108}
109EXPORT_SYMBOL(um_request_irq);
110EXPORT_SYMBOL(reactivate_fd);
111
112static DEFINE_SPINLOCK(irq_spinlock);
113
114unsigned long irq_lock(void)
115{
116 unsigned long flags;
117
118 spin_lock_irqsave(&irq_spinlock, flags);
119 return(flags);
120}
121
122void irq_unlock(unsigned long flags)
123{
124 spin_unlock_irqrestore(&irq_spinlock, flags);
125}
126
127/* presently hw_interrupt_type must define (startup || enable) &&
128 * disable && end */
129static void dummy(unsigned int irq)
130{
131}
132
133static struct hw_interrupt_type SIGIO_irq_type = {
134 .typename = "SIGIO",
135 .disable = dummy,
136 .enable = dummy,
137 .ack = dummy,
138 .end = dummy
139};
140
141static struct hw_interrupt_type SIGVTALRM_irq_type = {
142 .typename = "SIGVTALRM",
143 .shutdown = dummy, /* never called */
144 .disable = dummy,
145 .enable = dummy,
146 .ack = dummy,
147 .end = dummy
148};
149
150void __init init_IRQ(void)
151{
152 int i;
153
154 irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
155 irq_desc[TIMER_IRQ].action = NULL;
156 irq_desc[TIMER_IRQ].depth = 1;
157 irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;
158 enable_irq(TIMER_IRQ);
159 for(i=1;i<NR_IRQS;i++){
160 irq_desc[i].status = IRQ_DISABLED;
161 irq_desc[i].action = NULL;
162 irq_desc[i].depth = 1;
163 irq_desc[i].handler = &SIGIO_irq_type;
164 enable_irq(i);
165 }
166 init_irq_signals(0);
167}
168
169/*
170 * Overrides for Emacs so that we follow Linus's tabbing style.
171 * Emacs will notice this stuff at the end of the file and automatically
172 * adjust the settings for this buffer only. This must remain at the end
173 * of the file.
174 * ---------------------------------------------------------------------------
175 * Local variables:
176 * c-file-style: "linux"
177 * End:
178 */
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
new file mode 100644
index 000000000000..6d6f9484b884
--- /dev/null
+++ b/arch/um/kernel/irq_user.c
@@ -0,0 +1,443 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <unistd.h>
8#include <errno.h>
9#include <signal.h>
10#include <string.h>
11#include <sys/poll.h>
12#include <sys/types.h>
13#include <sys/time.h>
14#include "user_util.h"
15#include "kern_util.h"
16#include "user.h"
17#include "process.h"
18#include "signal_user.h"
19#include "sigio.h"
20#include "irq_user.h"
21#include "os.h"
22
23struct irq_fd {
24 struct irq_fd *next;
25 void *id;
26 int fd;
27 int type;
28 int irq;
29 int pid;
30 int events;
31 int current_events;
32 int freed;
33};
34
35static struct irq_fd *active_fds = NULL;
36static struct irq_fd **last_irq_ptr = &active_fds;
37
38static struct pollfd *pollfds = NULL;
39static int pollfds_num = 0;
40static int pollfds_size = 0;
41
42extern int io_count, intr_count;
43
44void sigio_handler(int sig, union uml_pt_regs *regs)
45{
46 struct irq_fd *irq_fd, *next;
47 int i, n;
48
49 if(smp_sigio_handler()) return;
50 while(1){
51 n = poll(pollfds, pollfds_num, 0);
52 if(n < 0){
53 if(errno == EINTR) continue;
54 printk("sigio_handler : poll returned %d, "
55 "errno = %d\n", n, errno);
56 break;
57 }
58 if(n == 0) break;
59
60 irq_fd = active_fds;
61 for(i = 0; i < pollfds_num; i++){
62 if(pollfds[i].revents != 0){
63 irq_fd->current_events = pollfds[i].revents;
64 pollfds[i].fd = -1;
65 }
66 irq_fd = irq_fd->next;
67 }
68
69 for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){
70 next = irq_fd->next;
71 if(irq_fd->current_events != 0){
72 irq_fd->current_events = 0;
73 do_IRQ(irq_fd->irq, regs);
74
75 /* This is here because the next irq may be
76 * freed in the handler. If a console goes
77 * away, both the read and write irqs will be
78 * freed. After do_IRQ, ->next will point to
79 * a good IRQ.
80 * Irqs can't be freed inside their handlers,
81 * so the next best thing is to have them
82 * marked as needing freeing, so that they
83 * can be freed here.
84 */
85 next = irq_fd->next;
86 if(irq_fd->freed){
87 free_irq(irq_fd->irq, irq_fd->id);
88 free_irq_by_irq_and_dev(irq_fd->irq,
89 irq_fd->id);
90 }
91 }
92 }
93 }
94}
95
96int activate_ipi(int fd, int pid)
97{
98 return(os_set_fd_async(fd, pid));
99}
100
101static void maybe_sigio_broken(int fd, int type)
102{
103 if(isatty(fd)){
104 if((type == IRQ_WRITE) && !pty_output_sigio){
105 write_sigio_workaround();
106 add_sigio_fd(fd, 0);
107 }
108 else if((type == IRQ_READ) && !pty_close_sigio){
109 write_sigio_workaround();
110 add_sigio_fd(fd, 1);
111 }
112 }
113}
114
115int activate_fd(int irq, int fd, int type, void *dev_id)
116{
117 struct pollfd *tmp_pfd;
118 struct irq_fd *new_fd, *irq_fd;
119 unsigned long flags;
120 int pid, events, err, n, size;
121
122 pid = os_getpid();
123 err = os_set_fd_async(fd, pid);
124 if(err < 0)
125 goto out;
126
127 new_fd = um_kmalloc(sizeof(*new_fd));
128 err = -ENOMEM;
129 if(new_fd == NULL)
130 goto out;
131
132 if(type == IRQ_READ) events = POLLIN | POLLPRI;
133 else events = POLLOUT;
134 *new_fd = ((struct irq_fd) { .next = NULL,
135 .id = dev_id,
136 .fd = fd,
137 .type = type,
138 .irq = irq,
139 .pid = pid,
140 .events = events,
141 .current_events = 0,
142 .freed = 0 } );
143
144 /* Critical section - locked by a spinlock because this stuff can
145 * be changed from interrupt handlers. The stuff above is done
146 * outside the lock because it allocates memory.
147 */
148
149 /* Actually, it only looks like it can be called from interrupt
150 * context. The culprit is reactivate_fd, which calls
151 * maybe_sigio_broken, which calls write_sigio_workaround,
152 * which calls activate_fd. However, write_sigio_workaround should
153 * only be called once, at boot time. That would make it clear that
154 * this is called only from process context, and can be locked with
155 * a semaphore.
156 */
157 flags = irq_lock();
158 for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
159 if((irq_fd->fd == fd) && (irq_fd->type == type)){
160 printk("Registering fd %d twice\n", fd);
161 printk("Irqs : %d, %d\n", irq_fd->irq, irq);
162 printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id);
163 goto out_unlock;
164 }
165 }
166
167 n = pollfds_num;
168 if(n == pollfds_size){
169 while(1){
170 /* Here we have to drop the lock in order to call
171 * kmalloc, which might sleep. If something else
172 * came in and changed the pollfds array, we free
173 * the buffer and try again.
174 */
175 irq_unlock(flags);
176 size = (pollfds_num + 1) * sizeof(pollfds[0]);
177 tmp_pfd = um_kmalloc(size);
178 flags = irq_lock();
179 if(tmp_pfd == NULL)
180 goto out_unlock;
181 if(n == pollfds_size)
182 break;
183 kfree(tmp_pfd);
184 }
185 if(pollfds != NULL){
186 memcpy(tmp_pfd, pollfds,
187 sizeof(pollfds[0]) * pollfds_size);
188 kfree(pollfds);
189 }
190 pollfds = tmp_pfd;
191 pollfds_size++;
192 }
193
194 if(type == IRQ_WRITE)
195 fd = -1;
196
197 pollfds[pollfds_num] = ((struct pollfd) { .fd = fd,
198 .events = events,
199 .revents = 0 });
200 pollfds_num++;
201
202 *last_irq_ptr = new_fd;
203 last_irq_ptr = &new_fd->next;
204
205 irq_unlock(flags);
206
207 /* This calls activate_fd, so it has to be outside the critical
208 * section.
209 */
210 maybe_sigio_broken(fd, type);
211
212 return(0);
213
214 out_unlock:
215 irq_unlock(flags);
216 kfree(new_fd);
217 out:
218 return(err);
219}
220
221static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
222{
223 struct irq_fd **prev;
224 unsigned long flags;
225 int i = 0;
226
227 flags = irq_lock();
228 prev = &active_fds;
229 while(*prev != NULL){
230 if((*test)(*prev, arg)){
231 struct irq_fd *old_fd = *prev;
232 if((pollfds[i].fd != -1) &&
233 (pollfds[i].fd != (*prev)->fd)){
234 printk("free_irq_by_cb - mismatch between "
235 "active_fds and pollfds, fd %d vs %d\n",
236 (*prev)->fd, pollfds[i].fd);
237 goto out;
238 }
239 memcpy(&pollfds[i], &pollfds[i + 1],
240 (pollfds_num - i - 1) * sizeof(pollfds[0]));
241 pollfds_num--;
242 if(last_irq_ptr == &old_fd->next)
243 last_irq_ptr = prev;
244 *prev = (*prev)->next;
245 if(old_fd->type == IRQ_WRITE)
246 ignore_sigio_fd(old_fd->fd);
247 kfree(old_fd);
248 continue;
249 }
250 prev = &(*prev)->next;
251 i++;
252 }
253 out:
254 irq_unlock(flags);
255}
256
257struct irq_and_dev {
258 int irq;
259 void *dev;
260};
261
262static int same_irq_and_dev(struct irq_fd *irq, void *d)
263{
264 struct irq_and_dev *data = d;
265
266 return((irq->irq == data->irq) && (irq->id == data->dev));
267}
268
269void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
270{
271 struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq,
272 .dev = dev });
273
274 free_irq_by_cb(same_irq_and_dev, &data);
275}
276
277static int same_fd(struct irq_fd *irq, void *fd)
278{
279 return(irq->fd == *((int *) fd));
280}
281
282void free_irq_by_fd(int fd)
283{
284 free_irq_by_cb(same_fd, &fd);
285}
286
287static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
288{
289 struct irq_fd *irq;
290 int i = 0;
291
292 for(irq=active_fds; irq != NULL; irq = irq->next){
293 if((irq->fd == fd) && (irq->irq == irqnum)) break;
294 i++;
295 }
296 if(irq == NULL){
297 printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
298 goto out;
299 }
300 if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){
301 printk("find_irq_by_fd - mismatch between active_fds and "
302 "pollfds, fd %d vs %d, need %d\n", irq->fd,
303 pollfds[i].fd, fd);
304 irq = NULL;
305 goto out;
306 }
307 *index_out = i;
308 out:
309 return(irq);
310}
311
312void free_irq_later(int irq, void *dev_id)
313{
314 struct irq_fd *irq_fd;
315 unsigned long flags;
316
317 flags = irq_lock();
318 for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
319 if((irq_fd->irq == irq) && (irq_fd->id == dev_id))
320 break;
321 }
322 if(irq_fd == NULL){
323 printk("free_irq_later found no irq, irq = %d, "
324 "dev_id = 0x%p\n", irq, dev_id);
325 goto out;
326 }
327 irq_fd->freed = 1;
328 out:
329 irq_unlock(flags);
330}
331
332void reactivate_fd(int fd, int irqnum)
333{
334 struct irq_fd *irq;
335 unsigned long flags;
336 int i;
337
338 flags = irq_lock();
339 irq = find_irq_by_fd(fd, irqnum, &i);
340 if(irq == NULL){
341 irq_unlock(flags);
342 return;
343 }
344
345 pollfds[i].fd = irq->fd;
346
347 irq_unlock(flags);
348
349 /* This calls activate_fd, so it has to be outside the critical
350 * section.
351 */
352 maybe_sigio_broken(fd, irq->type);
353}
354
355void deactivate_fd(int fd, int irqnum)
356{
357 struct irq_fd *irq;
358 unsigned long flags;
359 int i;
360
361 flags = irq_lock();
362 irq = find_irq_by_fd(fd, irqnum, &i);
363 if(irq == NULL)
364 goto out;
365 pollfds[i].fd = -1;
366 out:
367 irq_unlock(flags);
368}
369
370int deactivate_all_fds(void)
371{
372 struct irq_fd *irq;
373 int err;
374
375 for(irq=active_fds;irq != NULL;irq = irq->next){
376 err = os_clear_fd_async(irq->fd);
377 if(err)
378 return(err);
379 }
380 /* If there is a signal already queued, after unblocking ignore it */
381 set_handler(SIGIO, SIG_IGN, 0, -1);
382
383 return(0);
384}
385
386void forward_ipi(int fd, int pid)
387{
388 int err;
389
390 err = os_set_owner(fd, pid);
391 if(err < 0)
392 printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
393 "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
394}
395
396void forward_interrupts(int pid)
397{
398 struct irq_fd *irq;
399 unsigned long flags;
400 int err;
401
402 flags = irq_lock();
403 for(irq=active_fds;irq != NULL;irq = irq->next){
404 err = os_set_owner(irq->fd, pid);
405 if(err < 0){
406 /* XXX Just remove the irq rather than
407 * print out an infinite stream of these
408 */
409 printk("Failed to forward %d to pid %d, err = %d\n",
410 irq->fd, pid, -err);
411 }
412
413 irq->pid = pid;
414 }
415 irq_unlock(flags);
416}
417
418void init_irq_signals(int on_sigstack)
419{
420 __sighandler_t h;
421 int flags;
422
423 flags = on_sigstack ? SA_ONSTACK : 0;
424 if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
425 else h = boot_timer_handler;
426
427 set_handler(SIGVTALRM, h, flags | SA_RESTART,
428 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1);
429 set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
430 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
431 signal(SIGWINCH, SIG_IGN);
432}
433
434/*
435 * Overrides for Emacs so that we follow Linus's tabbing style.
436 * Emacs will notice this stuff at the end of the file and automatically
437 * adjust the settings for this buffer only. This must remain at the end
438 * of the file.
439 * ---------------------------------------------------------------------------
440 * Local variables:
441 * c-file-style: "linux"
442 * End:
443 */
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
new file mode 100644
index 000000000000..b41d3397d07b
--- /dev/null
+++ b/arch/um/kernel/ksyms.c
@@ -0,0 +1,137 @@
1/*
2 * Copyright (C) 2001 - 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/module.h"
8#include "linux/string.h"
9#include "linux/smp_lock.h"
10#include "linux/spinlock.h"
11#include "linux/highmem.h"
12#include "asm/current.h"
13#include "asm/delay.h"
14#include "asm/processor.h"
15#include "asm/unistd.h"
16#include "asm/pgalloc.h"
17#include "asm/pgtable.h"
18#include "asm/page.h"
19#include "asm/tlbflush.h"
20#include "kern_util.h"
21#include "user_util.h"
22#include "mem_user.h"
23#include "os.h"
24#include "helper.h"
25
26EXPORT_SYMBOL(stop);
27EXPORT_SYMBOL(uml_physmem);
28EXPORT_SYMBOL(set_signals);
29EXPORT_SYMBOL(get_signals);
30EXPORT_SYMBOL(kernel_thread);
31EXPORT_SYMBOL(__const_udelay);
32EXPORT_SYMBOL(__udelay);
33EXPORT_SYMBOL(sys_waitpid);
34EXPORT_SYMBOL(task_size);
35EXPORT_SYMBOL(flush_tlb_range);
36EXPORT_SYMBOL(host_task_size);
37EXPORT_SYMBOL(arch_validate);
38EXPORT_SYMBOL(get_kmem_end);
39
40EXPORT_SYMBOL(page_to_phys);
41EXPORT_SYMBOL(phys_to_page);
42EXPORT_SYMBOL(high_physmem);
43EXPORT_SYMBOL(empty_zero_page);
44EXPORT_SYMBOL(um_virt_to_phys);
45EXPORT_SYMBOL(__virt_to_page);
46EXPORT_SYMBOL(to_phys);
47EXPORT_SYMBOL(to_virt);
48EXPORT_SYMBOL(mode_tt);
49EXPORT_SYMBOL(handle_page_fault);
50EXPORT_SYMBOL(find_iomem);
51EXPORT_SYMBOL(end_iomem);
52
53#ifdef CONFIG_MODE_TT
54EXPORT_SYMBOL(strncpy_from_user_tt);
55EXPORT_SYMBOL(copy_from_user_tt);
56EXPORT_SYMBOL(copy_to_user_tt);
57#endif
58
59#ifdef CONFIG_MODE_SKAS
60EXPORT_SYMBOL(strncpy_from_user_skas);
61EXPORT_SYMBOL(copy_to_user_skas);
62EXPORT_SYMBOL(copy_from_user_skas);
63#endif
64EXPORT_SYMBOL(uml_strdup);
65
66EXPORT_SYMBOL(os_stat_fd);
67EXPORT_SYMBOL(os_stat_file);
68EXPORT_SYMBOL(os_access);
69EXPORT_SYMBOL(os_print_error);
70EXPORT_SYMBOL(os_get_exec_close);
71EXPORT_SYMBOL(os_set_exec_close);
72EXPORT_SYMBOL(os_getpid);
73EXPORT_SYMBOL(os_open_file);
74EXPORT_SYMBOL(os_read_file);
75EXPORT_SYMBOL(os_write_file);
76EXPORT_SYMBOL(os_seek_file);
77EXPORT_SYMBOL(os_lock_file);
78EXPORT_SYMBOL(os_ioctl_generic);
79EXPORT_SYMBOL(os_pipe);
80EXPORT_SYMBOL(os_file_type);
81EXPORT_SYMBOL(os_file_mode);
82EXPORT_SYMBOL(os_file_size);
83EXPORT_SYMBOL(os_flush_stdout);
84EXPORT_SYMBOL(os_close_file);
85EXPORT_SYMBOL(os_set_fd_async);
86EXPORT_SYMBOL(os_set_fd_block);
87EXPORT_SYMBOL(helper_wait);
88EXPORT_SYMBOL(os_shutdown_socket);
89EXPORT_SYMBOL(os_create_unix_socket);
90EXPORT_SYMBOL(os_connect_socket);
91EXPORT_SYMBOL(os_accept_connection);
92EXPORT_SYMBOL(os_rcv_fd);
93EXPORT_SYMBOL(run_helper);
94EXPORT_SYMBOL(start_thread);
95EXPORT_SYMBOL(dump_thread);
96
97EXPORT_SYMBOL(do_gettimeofday);
98EXPORT_SYMBOL(do_settimeofday);
99
100/* This is here because UML expands open to sys_open, not to a system
101 * call instruction.
102 */
103EXPORT_SYMBOL(sys_open);
104EXPORT_SYMBOL(sys_lseek);
105EXPORT_SYMBOL(sys_read);
106EXPORT_SYMBOL(sys_wait4);
107
108#ifdef CONFIG_SMP
109
110/* required for SMP */
111
112extern void FASTCALL( __write_lock_failed(rwlock_t *rw));
113EXPORT_SYMBOL(__write_lock_failed);
114
115extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
116EXPORT_SYMBOL(__read_lock_failed);
117
118#endif
119
120#ifdef CONFIG_HIGHMEM
121EXPORT_SYMBOL(kmap);
122EXPORT_SYMBOL(kunmap);
123EXPORT_SYMBOL(kmap_atomic);
124EXPORT_SYMBOL(kunmap_atomic);
125EXPORT_SYMBOL(kmap_atomic_to_page);
126#endif
127
128/*
129 * Overrides for Emacs so that we follow Linus's tabbing style.
130 * Emacs will notice this stuff at the end of the file and automatically
131 * adjust the settings for this buffer only. This must remain at the end
132 * of the file.
133 * ---------------------------------------------------------------------------
134 * Local variables:
135 * c-file-style: "linux"
136 * End:
137 */
diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c
new file mode 100644
index 000000000000..a17c49703f9b
--- /dev/null
+++ b/arch/um/kernel/main.c
@@ -0,0 +1,271 @@
1/*
2 * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <signal.h>
11#include <errno.h>
12#include <sys/resource.h>
13#include <sys/mman.h>
14#include <sys/user.h>
15#include <asm/page.h>
16#include "user_util.h"
17#include "kern_util.h"
18#include "mem_user.h"
19#include "signal_user.h"
20#include "time_user.h"
21#include "irq_user.h"
22#include "user.h"
23#include "init.h"
24#include "mode.h"
25#include "choose-mode.h"
26#include "uml-config.h"
27#include "irq_user.h"
28#include "time_user.h"
29#include "os.h"
30
31/* Set in set_stklim, which is called from main and __wrap_malloc.
32 * __wrap_malloc only calls it if main hasn't started.
33 */
34unsigned long stacksizelim;
35
36/* Set in main */
37char *linux_prog;
38
39#define PGD_BOUND (4 * 1024 * 1024)
40#define STACKSIZE (8 * 1024 * 1024)
41#define THREAD_NAME_LEN (256)
42
43static void set_stklim(void)
44{
45 struct rlimit lim;
46
47 if(getrlimit(RLIMIT_STACK, &lim) < 0){
48 perror("getrlimit");
49 exit(1);
50 }
51 if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){
52 lim.rlim_cur = STACKSIZE;
53 if(setrlimit(RLIMIT_STACK, &lim) < 0){
54 perror("setrlimit");
55 exit(1);
56 }
57 }
58 stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1);
59}
60
61static __init void do_uml_initcalls(void)
62{
63 initcall_t *call;
64
65 call = &__uml_initcall_start;
66 while (call < &__uml_initcall_end){;
67 (*call)();
68 call++;
69 }
70}
71
72static void last_ditch_exit(int sig)
73{
74 CHOOSE_MODE(kmalloc_ok = 0, (void) 0);
75 signal(SIGINT, SIG_DFL);
76 signal(SIGTERM, SIG_DFL);
77 signal(SIGHUP, SIG_DFL);
78 uml_cleanup();
79 exit(1);
80}
81
82extern int uml_exitcode;
83
84extern void scan_elf_aux( char **envp);
85
86int main(int argc, char **argv, char **envp)
87{
88 char **new_argv;
89 sigset_t mask;
90 int ret, i;
91
92 /* Enable all signals except SIGIO - in some environments, we can
93 * enter with some signals blocked
94 */
95
96 sigemptyset(&mask);
97 sigaddset(&mask, SIGIO);
98 if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
99 perror("sigprocmask");
100 exit(1);
101 }
102
103#ifdef UML_CONFIG_MODE_TT
104 /* Allocate memory for thread command lines */
105 if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
106
107 char padding[THREAD_NAME_LEN] = {
108 [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0'
109 };
110
111 new_argv = malloc((argc + 2) * sizeof(char*));
112 if(!new_argv) {
113 perror("Allocating extended argv");
114 exit(1);
115 }
116
117 new_argv[0] = argv[0];
118 new_argv[1] = padding;
119
120 for(i = 2; i <= argc; i++)
121 new_argv[i] = argv[i - 1];
122 new_argv[argc + 1] = NULL;
123
124 execvp(new_argv[0], new_argv);
125 perror("execing with extended args");
126 exit(1);
127 }
128#endif
129
130 linux_prog = argv[0];
131
132 set_stklim();
133
134 new_argv = malloc((argc + 1) * sizeof(char *));
135 if(new_argv == NULL){
136 perror("Mallocing argv");
137 exit(1);
138 }
139 for(i=0;i<argc;i++){
140 new_argv[i] = strdup(argv[i]);
141 if(new_argv[i] == NULL){
142 perror("Mallocing an arg");
143 exit(1);
144 }
145 }
146 new_argv[argc] = NULL;
147
148 set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
149 set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
150 set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
151
152 scan_elf_aux( envp);
153
154 do_uml_initcalls();
155 ret = linux_main(argc, argv);
156
157 /* Disable SIGPROF - I have no idea why libc doesn't do this or turn
158 * off the profiling time, but UML dies with a SIGPROF just before
159 * exiting when profiling is active.
160 */
161 change_sig(SIGPROF, 0);
162
163 /* Reboot */
164 if(ret){
165 int err;
166
167 printf("\n");
168
169 /* stop timers and set SIG*ALRM to be ignored */
170 disable_timer();
171
172 /* disable SIGIO for the fds and set SIGIO to be ignored */
173 err = deactivate_all_fds();
174 if(err)
175 printf("deactivate_all_fds failed, errno = %d\n",
176 -err);
177
178 /* Let any pending signals fire now. This ensures
179 * that they won't be delivered after the exec, when
180 * they are definitely not expected.
181 */
182 unblock_signals();
183
184 execvp(new_argv[0], new_argv);
185 perror("Failed to exec kernel");
186 ret = 1;
187 }
188 printf("\n");
189 return(uml_exitcode);
190}
191
192#define CAN_KMALLOC() \
193 (kmalloc_ok && CHOOSE_MODE((os_getpid() != tracing_pid), 1))
194
195extern void *__real_malloc(int);
196
197void *__wrap_malloc(int size)
198{
199 void *ret;
200
201 if(!CAN_KMALLOC())
202 return(__real_malloc(size));
203 else if(size <= PAGE_SIZE) /* finding contiguos pages can be hard*/
204 ret = um_kmalloc(size);
205 else ret = um_vmalloc(size);
206
207 /* glibc people insist that if malloc fails, errno should be
208 * set by malloc as well. So we do.
209 */
210 if(ret == NULL)
211 errno = ENOMEM;
212
213 return(ret);
214}
215
216void *__wrap_calloc(int n, int size)
217{
218 void *ptr = __wrap_malloc(n * size);
219
220 if(ptr == NULL) return(NULL);
221 memset(ptr, 0, n * size);
222 return(ptr);
223}
224
225extern void __real_free(void *);
226
227extern unsigned long high_physmem;
228
229void __wrap_free(void *ptr)
230{
231 unsigned long addr = (unsigned long) ptr;
232
233 /* We need to know how the allocation happened, so it can be correctly
234 * freed. This is done by seeing what region of memory the pointer is
235 * in -
236 * physical memory - kmalloc/kfree
237 * kernel virtual memory - vmalloc/vfree
238 * anywhere else - malloc/free
239 * If kmalloc is not yet possible, then either high_physmem and/or
240 * end_vm are still 0 (as at startup), in which case we call free, or
241 * we have set them, but anyway addr has not been allocated from those
242 * areas. So, in both cases __real_free is called.
243 *
244 * CAN_KMALLOC is checked because it would be bad to free a buffer
245 * with kmalloc/vmalloc after they have been turned off during
246 * shutdown.
247 * XXX: However, we sometimes shutdown CAN_KMALLOC temporarily, so
248 * there is a possibility for memory leaks.
249 */
250
251 if((addr >= uml_physmem) && (addr < high_physmem)){
252 if(CAN_KMALLOC())
253 kfree(ptr);
254 }
255 else if((addr >= start_vm) && (addr < end_vm)){
256 if(CAN_KMALLOC())
257 vfree(ptr);
258 }
259 else __real_free(ptr);
260}
261
262/*
263 * Overrides for Emacs so that we follow Linus's tabbing style.
264 * Emacs will notice this stuff at the end of the file and automatically
265 * adjust the settings for this buffer only. This must remain at the end
266 * of the file.
267 * ---------------------------------------------------------------------------
268 * Local variables:
269 * c-file-style: "linux"
270 * End:
271 */
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
new file mode 100644
index 000000000000..f156661781cb
--- /dev/null
+++ b/arch/um/kernel/mem.c
@@ -0,0 +1,359 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/stddef.h"
7#include "linux/kernel.h"
8#include "linux/mm.h"
9#include "linux/bootmem.h"
10#include "linux/swap.h"
11#include "linux/highmem.h"
12#include "linux/gfp.h"
13#include "asm/page.h"
14#include "asm/fixmap.h"
15#include "asm/pgalloc.h"
16#include "user_util.h"
17#include "kern_util.h"
18#include "kern.h"
19#include "mem_user.h"
20#include "uml_uaccess.h"
21#include "os.h"
22
23extern char __binary_start;
24
25/* Changed during early boot */
26unsigned long *empty_zero_page = NULL;
27unsigned long *empty_bad_page = NULL;
28pgd_t swapper_pg_dir[PTRS_PER_PGD];
29unsigned long highmem;
30int kmalloc_ok = 0;
31
32static unsigned long brk_end;
33
34void unmap_physmem(void)
35{
36 os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
37}
38
39static void map_cb(void *unused)
40{
41 map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
42}
43
44#ifdef CONFIG_HIGHMEM
45static void setup_highmem(unsigned long highmem_start,
46 unsigned long highmem_len)
47{
48 struct page *page;
49 unsigned long highmem_pfn;
50 int i;
51
52 highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
53 for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
54 page = &mem_map[highmem_pfn + i];
55 ClearPageReserved(page);
56 set_bit(PG_highmem, &page->flags);
57 set_page_count(page, 1);
58 __free_page(page);
59 }
60}
61#endif
62
63void mem_init(void)
64{
65 unsigned long start;
66
67 max_low_pfn = (high_physmem - uml_physmem) >> PAGE_SHIFT;
68
69 /* clear the zero-page */
70 memset((void *) empty_zero_page, 0, PAGE_SIZE);
71
72 /* Map in the area just after the brk now that kmalloc is about
73 * to be turned on.
74 */
75 brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
76 map_cb(NULL);
77 initial_thread_cb(map_cb, NULL);
78 free_bootmem(__pa(brk_end), uml_reserved - brk_end);
79 uml_reserved = brk_end;
80
81 /* Fill in any hole at the start of the binary */
82 start = (unsigned long) &__binary_start & PAGE_MASK;
83 if(uml_physmem != start){
84 map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem,
85 1, 1, 0);
86 }
87
88 /* this will put all low memory onto the freelists */
89 totalram_pages = free_all_bootmem();
90 totalhigh_pages = highmem >> PAGE_SHIFT;
91 totalram_pages += totalhigh_pages;
92 num_physpages = totalram_pages;
93 max_pfn = totalram_pages;
94 printk(KERN_INFO "Memory: %luk available\n",
95 (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
96 kmalloc_ok = 1;
97
98#ifdef CONFIG_HIGHMEM
99 setup_highmem(end_iomem, highmem);
100#endif
101}
102
103static void __init fixrange_init(unsigned long start, unsigned long end,
104 pgd_t *pgd_base)
105{
106 pgd_t *pgd;
107 pmd_t *pmd;
108 pte_t *pte;
109 int i, j;
110 unsigned long vaddr;
111
112 vaddr = start;
113 i = pgd_index(vaddr);
114 j = pmd_index(vaddr);
115 pgd = pgd_base + i;
116
117 for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
118 pmd = (pmd_t *)pgd;
119 for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
120 if (pmd_none(*pmd)) {
121 pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
122 set_pmd(pmd, __pmd(_KERNPG_TABLE +
123 (unsigned long) __pa(pte)));
124 if (pte != pte_offset_kernel(pmd, 0))
125 BUG();
126 }
127 vaddr += PMD_SIZE;
128 }
129 j = 0;
130 }
131}
132
133#ifdef CONFIG_HIGHMEM
134pte_t *kmap_pte;
135pgprot_t kmap_prot;
136
137#define kmap_get_fixmap_pte(vaddr) \
138 pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\
139 (vaddr)), (vaddr))
140
141static void __init kmap_init(void)
142{
143 unsigned long kmap_vstart;
144
145 /* cache the first kmap pte */
146 kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
147 kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
148
149 kmap_prot = PAGE_KERNEL;
150}
151
152static void init_highmem(void)
153{
154 pgd_t *pgd;
155 pud_t *pud;
156 pmd_t *pmd;
157 pte_t *pte;
158 unsigned long vaddr;
159
160 /*
161 * Permanent kmaps:
162 */
163 vaddr = PKMAP_BASE;
164 fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir);
165
166 pgd = swapper_pg_dir + pgd_index(vaddr);
167 pud = pud_offset(pgd, vaddr);
168 pmd = pmd_offset(pud, vaddr);
169 pte = pte_offset_kernel(pmd, vaddr);
170 pkmap_page_table = pte;
171
172 kmap_init();
173}
174#endif /* CONFIG_HIGHMEM */
175
176static void __init fixaddr_user_init( void)
177{
178#if CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
179 long size = FIXADDR_USER_END - FIXADDR_USER_START;
180 pgd_t *pgd;
181 pud_t *pud;
182 pmd_t *pmd;
183 pte_t *pte;
184 unsigned long paddr, vaddr = FIXADDR_USER_START;
185
186 if ( ! size )
187 return;
188
189 fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir);
190 paddr = (unsigned long)alloc_bootmem_low_pages( size);
191 memcpy( (void *)paddr, (void *)FIXADDR_USER_START, size);
192 paddr = __pa(paddr);
193 for ( ; size > 0; size-=PAGE_SIZE, vaddr+=PAGE_SIZE, paddr+=PAGE_SIZE){
194 pgd = swapper_pg_dir + pgd_index(vaddr);
195 pud = pud_offset(pgd, vaddr);
196 pmd = pmd_offset(pud, vaddr);
197 pte = pte_offset_kernel(pmd, vaddr);
198 pte_set_val( (*pte), paddr, PAGE_READONLY);
199 }
200#endif
201}
202
203void paging_init(void)
204{
205 unsigned long zones_size[MAX_NR_ZONES], vaddr;
206 int i;
207
208 empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
209 empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
210 for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++)
211 zones_size[i] = 0;
212 zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
213 zones_size[2] = highmem >> PAGE_SHIFT;
214 free_area_init(zones_size);
215
216 /*
217 * Fixed mappings, only the page table structure has to be
218 * created - mappings will be set by set_fixmap():
219 */
220 vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
221 fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir);
222
223 fixaddr_user_init();
224
225#ifdef CONFIG_HIGHMEM
226 init_highmem();
227#endif
228}
229
230struct page *arch_validate(struct page *page, int mask, int order)
231{
232 unsigned long addr, zero = 0;
233 int i;
234
235 again:
236 if(page == NULL) return(page);
237 if(PageHighMem(page)) return(page);
238
239 addr = (unsigned long) page_address(page);
240 for(i = 0; i < (1 << order); i++){
241 current->thread.fault_addr = (void *) addr;
242 if(__do_copy_to_user((void __user *) addr, &zero,
243 sizeof(zero),
244 &current->thread.fault_addr,
245 &current->thread.fault_catcher)){
246 if(!(mask & __GFP_WAIT)) return(NULL);
247 else break;
248 }
249 addr += PAGE_SIZE;
250 }
251
252 if(i == (1 << order)) return(page);
253 page = alloc_pages(mask, order);
254 goto again;
255}
256
257/* This can't do anything because nothing in the kernel image can be freed
258 * since it's not in kernel physical memory.
259 */
260
261void free_initmem(void)
262{
263}
264
265#ifdef CONFIG_BLK_DEV_INITRD
266
267void free_initrd_mem(unsigned long start, unsigned long end)
268{
269 if (start < end)
270 printk ("Freeing initrd memory: %ldk freed\n",
271 (end - start) >> 10);
272 for (; start < end; start += PAGE_SIZE) {
273 ClearPageReserved(virt_to_page(start));
274 set_page_count(virt_to_page(start), 1);
275 free_page(start);
276 totalram_pages++;
277 }
278}
279
280#endif
281
282void show_mem(void)
283{
284 int pfn, total = 0, reserved = 0;
285 int shared = 0, cached = 0;
286 int highmem = 0;
287 struct page *page;
288
289 printk("Mem-info:\n");
290 show_free_areas();
291 printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
292 pfn = max_mapnr;
293 while(pfn-- > 0) {
294 page = pfn_to_page(pfn);
295 total++;
296 if(PageHighMem(page))
297 highmem++;
298 if(PageReserved(page))
299 reserved++;
300 else if(PageSwapCache(page))
301 cached++;
302 else if(page_count(page))
303 shared += page_count(page) - 1;
304 }
305 printk("%d pages of RAM\n", total);
306 printk("%d pages of HIGHMEM\n", highmem);
307 printk("%d reserved pages\n", reserved);
308 printk("%d pages shared\n", shared);
309 printk("%d pages swap cached\n", cached);
310}
311
312/*
313 * Allocate and free page tables.
314 */
315
316pgd_t *pgd_alloc(struct mm_struct *mm)
317{
318 pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
319
320 if (pgd) {
321 memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
322 memcpy(pgd + USER_PTRS_PER_PGD,
323 swapper_pg_dir + USER_PTRS_PER_PGD,
324 (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
325 }
326 return pgd;
327}
328
329void pgd_free(pgd_t *pgd)
330{
331 free_page((unsigned long) pgd);
332}
333
334pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
335{
336 pte_t *pte;
337
338 pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
339 return pte;
340}
341
342struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
343{
344 struct page *pte;
345
346 pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
347 return pte;
348}
349
350/*
351 * Overrides for Emacs so that we follow Linus's tabbing style.
352 * Emacs will notice this stuff at the end of the file and automatically
353 * adjust the settings for this buffer only. This must remain at the end
354 * of the file.
355 * ---------------------------------------------------------------------------
356 * Local variables:
357 * c-file-style: "linux"
358 * End:
359 */
diff --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c
new file mode 100644
index 000000000000..4a663fd434bb
--- /dev/null
+++ b/arch/um/kernel/mem_user.c
@@ -0,0 +1,273 @@
1/*
2 * arch/um/kernel/mem_user.c
3 *
4 * BRIEF MODULE DESCRIPTION
5 * user side memory routines for supporting IO memory inside user mode linux
6 *
7 * Copyright (C) 2001 RidgeRun, Inc.
8 * Author: RidgeRun, Inc.
9 * Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 *
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
22 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 675 Mass Ave, Cambridge, MA 02139, USA.
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <stddef.h>
35#include <stdarg.h>
36#include <unistd.h>
37#include <errno.h>
38#include <string.h>
39#include <fcntl.h>
40#include <sys/types.h>
41#include <sys/mman.h>
42#include "kern_util.h"
43#include "user.h"
44#include "user_util.h"
45#include "mem_user.h"
46#include "init.h"
47#include "os.h"
48#include "tempfile.h"
49#include "kern_constants.h"
50
51#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
52
53static int create_tmp_file(unsigned long len)
54{
55 int fd, err;
56 char zero;
57
58 fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
59 if(fd < 0) {
60 os_print_error(fd, "make_tempfile");
61 exit(1);
62 }
63
64 err = os_mode_fd(fd, 0777);
65 if(err < 0){
66 os_print_error(err, "os_mode_fd");
67 exit(1);
68 }
69 err = os_seek_file(fd, len);
70 if(err < 0){
71 os_print_error(err, "os_seek_file");
72 exit(1);
73 }
74 zero = 0;
75 err = os_write_file(fd, &zero, 1);
76 if(err != 1){
77 os_print_error(err, "os_write_file");
78 exit(1);
79 }
80
81 return(fd);
82}
83
84void check_tmpexec(void)
85{
86 void *addr;
87 int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
88
89 addr = mmap(NULL, UM_KERN_PAGE_SIZE,
90 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
91 printf("Checking PROT_EXEC mmap in /tmp...");
92 fflush(stdout);
93 if(addr == MAP_FAILED){
94 err = errno;
95 perror("failed");
96 if(err == EPERM)
97 printf("/tmp must be not mounted noexec\n");
98 exit(1);
99 }
100 printf("OK\n");
101 munmap(addr, UM_KERN_PAGE_SIZE);
102
103 os_close_file(fd);
104}
105
106static int have_devanon = 0;
107
108void check_devanon(void)
109{
110 int fd;
111
112 printk("Checking for /dev/anon on the host...");
113 fd = open("/dev/anon", O_RDWR);
114 if(fd < 0){
115 printk("Not available (open failed with errno %d)\n", errno);
116 return;
117 }
118
119 printk("OK\n");
120 have_devanon = 1;
121}
122
123static int create_anon_file(unsigned long len)
124{
125 void *addr;
126 int fd;
127
128 fd = open("/dev/anon", O_RDWR);
129 if(fd < 0) {
130 os_print_error(fd, "opening /dev/anon");
131 exit(1);
132 }
133
134 addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
135 if(addr == MAP_FAILED){
136 perror("mapping physmem file");
137 exit(1);
138 }
139 munmap(addr, len);
140
141 return(fd);
142}
143
144int create_mem_file(unsigned long len)
145{
146 int err, fd;
147
148 if(have_devanon)
149 fd = create_anon_file(len);
150 else fd = create_tmp_file(len);
151
152 err = os_set_exec_close(fd, 1);
153 if(err < 0)
154 os_print_error(err, "exec_close");
155 return(fd);
156}
157
158struct iomem_region *iomem_regions = NULL;
159int iomem_size = 0;
160
161static int __init parse_iomem(char *str, int *add)
162{
163 struct iomem_region *new;
164 struct uml_stat buf;
165 char *file, *driver;
166 int fd, err, size;
167
168 driver = str;
169 file = strchr(str,',');
170 if(file == NULL){
171 printf("parse_iomem : failed to parse iomem\n");
172 goto out;
173 }
174 *file = '\0';
175 file++;
176 fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
177 if(fd < 0){
178 os_print_error(fd, "parse_iomem - Couldn't open io file");
179 goto out;
180 }
181
182 err = os_stat_fd(fd, &buf);
183 if(err < 0){
184 os_print_error(err, "parse_iomem - cannot stat_fd file");
185 goto out_close;
186 }
187
188 new = malloc(sizeof(*new));
189 if(new == NULL){
190 perror("Couldn't allocate iomem_region struct");
191 goto out_close;
192 }
193
194 size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
195
196 *new = ((struct iomem_region) { .next = iomem_regions,
197 .driver = driver,
198 .fd = fd,
199 .size = size,
200 .phys = 0,
201 .virt = 0 });
202 iomem_regions = new;
203 iomem_size += new->size + UM_KERN_PAGE_SIZE;
204
205 return(0);
206 out_close:
207 os_close_file(fd);
208 out:
209 return(1);
210}
211
212__uml_setup("iomem=", parse_iomem,
213"iomem=<name>,<file>\n"
214" Configure <file> as an IO memory region named <name>.\n\n"
215);
216
217int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
218 int must_succeed)
219{
220 int err;
221
222 err = os_protect_memory((void *) addr, len, r, w, x);
223 if(err < 0){
224 if(must_succeed)
225 panic("protect failed, err = %d", -err);
226 else return(err);
227 }
228 return(0);
229}
230
231#if 0
232/* Debugging facility for dumping stuff out to the host, avoiding the timing
233 * problems that come with printf and breakpoints.
234 * Enable in case of emergency.
235 */
236
237int logging = 1;
238int logging_fd = -1;
239
240int logging_line = 0;
241char logging_buf[512];
242
243void log(char *fmt, ...)
244{
245 va_list ap;
246 struct timeval tv;
247 struct openflags flags;
248
249 if(logging == 0) return;
250 if(logging_fd < 0){
251 flags = of_create(of_trunc(of_rdwr(OPENFLAGS())));
252 logging_fd = os_open_file("log", flags, 0644);
253 }
254 gettimeofday(&tv, NULL);
255 sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec,
256 tv.tv_usec);
257 va_start(ap, fmt);
258 vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap);
259 va_end(ap);
260 write(logging_fd, logging_buf, strlen(logging_buf));
261}
262#endif
263
264/*
265 * Overrides for Emacs so that we follow Linus's tabbing style.
266 * Emacs will notice this stuff at the end of the file and automatically
267 * adjust the settings for this buffer only. This must remain at the end
268 * of the file.
269 * ---------------------------------------------------------------------------
270 * Local variables:
271 * c-file-style: "linux"
272 * End:
273 */
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
new file mode 100644
index 000000000000..420e6d51fa0f
--- /dev/null
+++ b/arch/um/kernel/physmem.c
@@ -0,0 +1,478 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/mm.h"
7#include "linux/rbtree.h"
8#include "linux/slab.h"
9#include "linux/vmalloc.h"
10#include "linux/bootmem.h"
11#include "linux/module.h"
12#include "asm/types.h"
13#include "asm/pgtable.h"
14#include "kern_util.h"
15#include "user_util.h"
16#include "mode_kern.h"
17#include "mem.h"
18#include "mem_user.h"
19#include "os.h"
20#include "kern.h"
21#include "init.h"
22
23struct phys_desc {
24 struct rb_node rb;
25 int fd;
26 __u64 offset;
27 void *virt;
28 unsigned long phys;
29 struct list_head list;
30};
31
32static struct rb_root phys_mappings = RB_ROOT;
33
34static struct rb_node **find_rb(void *virt)
35{
36 struct rb_node **n = &phys_mappings.rb_node;
37 struct phys_desc *d;
38
39 while(*n != NULL){
40 d = rb_entry(*n, struct phys_desc, rb);
41 if(d->virt == virt)
42 return(n);
43
44 if(d->virt > virt)
45 n = &(*n)->rb_left;
46 else
47 n = &(*n)->rb_right;
48 }
49
50 return(n);
51}
52
53static struct phys_desc *find_phys_mapping(void *virt)
54{
55 struct rb_node **n = find_rb(virt);
56
57 if(*n == NULL)
58 return(NULL);
59
60 return(rb_entry(*n, struct phys_desc, rb));
61}
62
63static void insert_phys_mapping(struct phys_desc *desc)
64{
65 struct rb_node **n = find_rb(desc->virt);
66
67 if(*n != NULL)
68 panic("Physical remapping for %p already present",
69 desc->virt);
70
71 rb_link_node(&desc->rb, (*n)->rb_parent, n);
72 rb_insert_color(&desc->rb, &phys_mappings);
73}
74
75LIST_HEAD(descriptor_mappings);
76
77struct desc_mapping {
78 int fd;
79 struct list_head list;
80 struct list_head pages;
81};
82
83static struct desc_mapping *find_mapping(int fd)
84{
85 struct desc_mapping *desc;
86 struct list_head *ele;
87
88 list_for_each(ele, &descriptor_mappings){
89 desc = list_entry(ele, struct desc_mapping, list);
90 if(desc->fd == fd)
91 return(desc);
92 }
93
94 return(NULL);
95}
96
97static struct desc_mapping *descriptor_mapping(int fd)
98{
99 struct desc_mapping *desc;
100
101 desc = find_mapping(fd);
102 if(desc != NULL)
103 return(desc);
104
105 desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
106 if(desc == NULL)
107 return(NULL);
108
109 *desc = ((struct desc_mapping)
110 { .fd = fd,
111 .list = LIST_HEAD_INIT(desc->list),
112 .pages = LIST_HEAD_INIT(desc->pages) });
113 list_add(&desc->list, &descriptor_mappings);
114
115 return(desc);
116}
117
118int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
119{
120 struct desc_mapping *fd_maps;
121 struct phys_desc *desc;
122 unsigned long phys;
123 int err;
124
125 fd_maps = descriptor_mapping(fd);
126 if(fd_maps == NULL)
127 return(-ENOMEM);
128
129 phys = __pa(virt);
130 desc = find_phys_mapping(virt);
131 if(desc != NULL)
132 panic("Address 0x%p is already substituted\n", virt);
133
134 err = -ENOMEM;
135 desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
136 if(desc == NULL)
137 goto out;
138
139 *desc = ((struct phys_desc)
140 { .fd = fd,
141 .offset = offset,
142 .virt = virt,
143 .phys = __pa(virt),
144 .list = LIST_HEAD_INIT(desc->list) });
145 insert_phys_mapping(desc);
146
147 list_add(&desc->list, &fd_maps->pages);
148
149 virt = (void *) ((unsigned long) virt & PAGE_MASK);
150 err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0);
151 if(!err)
152 goto out;
153
154 rb_erase(&desc->rb, &phys_mappings);
155 kfree(desc);
156 out:
157 return(err);
158}
159
160static int physmem_fd = -1;
161
162static void remove_mapping(struct phys_desc *desc)
163{
164 void *virt = desc->virt;
165 int err;
166
167 rb_erase(&desc->rb, &phys_mappings);
168 list_del(&desc->list);
169 kfree(desc);
170
171 err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0);
172 if(err)
173 panic("Failed to unmap block device page from physical memory, "
174 "errno = %d", -err);
175}
176
177int physmem_remove_mapping(void *virt)
178{
179 struct phys_desc *desc;
180
181 virt = (void *) ((unsigned long) virt & PAGE_MASK);
182 desc = find_phys_mapping(virt);
183 if(desc == NULL)
184 return(0);
185
186 remove_mapping(desc);
187 return(1);
188}
189
190void physmem_forget_descriptor(int fd)
191{
192 struct desc_mapping *desc;
193 struct phys_desc *page;
194 struct list_head *ele, *next;
195 __u64 offset;
196 void *addr;
197 int err;
198
199 desc = find_mapping(fd);
200 if(desc == NULL)
201 return;
202
203 list_for_each_safe(ele, next, &desc->pages){
204 page = list_entry(ele, struct phys_desc, list);
205 offset = page->offset;
206 addr = page->virt;
207 remove_mapping(page);
208 err = os_seek_file(fd, offset);
209 if(err)
210 panic("physmem_forget_descriptor - failed to seek "
211 "to %lld in fd %d, error = %d\n",
212 offset, fd, -err);
213 err = os_read_file(fd, addr, PAGE_SIZE);
214 if(err < 0)
215 panic("physmem_forget_descriptor - failed to read "
216 "from fd %d to 0x%p, error = %d\n",
217 fd, addr, -err);
218 }
219
220 list_del(&desc->list);
221 kfree(desc);
222}
223
224EXPORT_SYMBOL(physmem_forget_descriptor);
225EXPORT_SYMBOL(physmem_remove_mapping);
226EXPORT_SYMBOL(physmem_subst_mapping);
227
228void arch_free_page(struct page *page, int order)
229{
230 void *virt;
231 int i;
232
233 for(i = 0; i < (1 << order); i++){
234 virt = __va(page_to_phys(page + i));
235 physmem_remove_mapping(virt);
236 }
237}
238
239int is_remapped(void *virt)
240{
241 struct phys_desc *desc = find_phys_mapping(virt);
242
243 return(desc != NULL);
244}
245
246/* Changed during early boot */
247unsigned long high_physmem;
248
249extern unsigned long physmem_size;
250
251void *to_virt(unsigned long phys)
252{
253 return((void *) uml_physmem + phys);
254}
255
256unsigned long to_phys(void *virt)
257{
258 return(((unsigned long) virt) - uml_physmem);
259}
260
261int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
262{
263 struct page *p, *map;
264 unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
265 unsigned long iomem_len, iomem_pages, total_len, total_pages;
266 int i;
267
268 phys_pages = physmem >> PAGE_SHIFT;
269 phys_len = phys_pages * sizeof(struct page);
270
271 iomem_pages = iomem >> PAGE_SHIFT;
272 iomem_len = iomem_pages * sizeof(struct page);
273
274 highmem_pages = highmem >> PAGE_SHIFT;
275 highmem_len = highmem_pages * sizeof(struct page);
276
277 total_pages = phys_pages + iomem_pages + highmem_pages;
278 total_len = phys_len + iomem_pages + highmem_len;
279
280 if(kmalloc_ok){
281 map = kmalloc(total_len, GFP_KERNEL);
282 if(map == NULL)
283 map = vmalloc(total_len);
284 }
285 else map = alloc_bootmem_low_pages(total_len);
286
287 if(map == NULL)
288 return(-ENOMEM);
289
290 for(i = 0; i < total_pages; i++){
291 p = &map[i];
292 set_page_count(p, 0);
293 SetPageReserved(p);
294 INIT_LIST_HEAD(&p->lru);
295 }
296
297 max_mapnr = total_pages;
298 return(0);
299}
300
301struct page *phys_to_page(const unsigned long phys)
302{
303 return(&mem_map[phys >> PAGE_SHIFT]);
304}
305
306struct page *__virt_to_page(const unsigned long virt)
307{
308 return(&mem_map[__pa(virt) >> PAGE_SHIFT]);
309}
310
311phys_t page_to_phys(struct page *page)
312{
313 return((page - mem_map) << PAGE_SHIFT);
314}
315
316pte_t mk_pte(struct page *page, pgprot_t pgprot)
317{
318 pte_t pte;
319
320 pte_set_val(pte, page_to_phys(page), pgprot);
321 if(pte_present(pte))
322 pte_mknewprot(pte_mknewpage(pte));
323 return(pte);
324}
325
326/* Changed during early boot */
327static unsigned long kmem_top = 0;
328
329unsigned long get_kmem_end(void)
330{
331 if(kmem_top == 0)
332 kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
333 return(kmem_top);
334}
335
336void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
337 int r, int w, int x)
338{
339 __u64 offset;
340 int fd, err;
341
342 fd = phys_mapping(phys, &offset);
343 err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
344 if(err) {
345 if(err == -ENOMEM)
346 printk("try increasing the host's "
347 "/proc/sys/vm/max_map_count to <physical "
348 "memory size>/4096\n");
349 panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
350 "err = %d\n", virt, fd, offset, len, r, w, x, err);
351 }
352}
353
354#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
355
356void setup_physmem(unsigned long start, unsigned long reserve_end,
357 unsigned long len, unsigned long highmem)
358{
359 unsigned long reserve = reserve_end - start;
360 int pfn = PFN_UP(__pa(reserve_end));
361 int delta = (len - reserve) >> PAGE_SHIFT;
362 int err, offset, bootmap_size;
363
364 physmem_fd = create_mem_file(len + highmem);
365
366 offset = uml_reserved - uml_physmem;
367 err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
368 len - offset, 1, 1, 0);
369 if(err < 0){
370 os_print_error(err, "Mapping memory");
371 exit(1);
372 }
373
374 bootmap_size = init_bootmem(pfn, pfn + delta);
375 free_bootmem(__pa(reserve_end) + bootmap_size,
376 len - bootmap_size - reserve);
377}
378
379int phys_mapping(unsigned long phys, __u64 *offset_out)
380{
381 struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK));
382 int fd = -1;
383
384 if(desc != NULL){
385 fd = desc->fd;
386 *offset_out = desc->offset;
387 }
388 else if(phys < physmem_size){
389 fd = physmem_fd;
390 *offset_out = phys;
391 }
392 else if(phys < __pa(end_iomem)){
393 struct iomem_region *region = iomem_regions;
394
395 while(region != NULL){
396 if((phys >= region->phys) &&
397 (phys < region->phys + region->size)){
398 fd = region->fd;
399 *offset_out = phys - region->phys;
400 break;
401 }
402 region = region->next;
403 }
404 }
405 else if(phys < __pa(end_iomem) + highmem){
406 fd = physmem_fd;
407 *offset_out = phys - iomem_size;
408 }
409
410 return(fd);
411}
412
413static int __init uml_mem_setup(char *line, int *add)
414{
415 char *retptr;
416 physmem_size = memparse(line,&retptr);
417 return 0;
418}
419__uml_setup("mem=", uml_mem_setup,
420"mem=<Amount of desired ram>\n"
421" This controls how much \"physical\" memory the kernel allocates\n"
422" for the system. The size is specified as a number followed by\n"
423" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
424" This is not related to the amount of memory in the host. It can\n"
425" be more, and the excess, if it's ever used, will just be swapped out.\n"
426" Example: mem=64M\n\n"
427);
428
429unsigned long find_iomem(char *driver, unsigned long *len_out)
430{
431 struct iomem_region *region = iomem_regions;
432
433 while(region != NULL){
434 if(!strcmp(region->driver, driver)){
435 *len_out = region->size;
436 return(region->virt);
437 }
438 }
439
440 return(0);
441}
442
443int setup_iomem(void)
444{
445 struct iomem_region *region = iomem_regions;
446 unsigned long iomem_start = high_physmem + PAGE_SIZE;
447 int err;
448
449 while(region != NULL){
450 err = os_map_memory((void *) iomem_start, region->fd, 0,
451 region->size, 1, 1, 0);
452 if(err)
453 printk("Mapping iomem region for driver '%s' failed, "
454 "errno = %d\n", region->driver, -err);
455 else {
456 region->virt = iomem_start;
457 region->phys = __pa(region->virt);
458 }
459
460 iomem_start += region->size + PAGE_SIZE;
461 region = region->next;
462 }
463
464 return(0);
465}
466
467__initcall(setup_iomem);
468
469/*
470 * Overrides for Emacs so that we follow Linus's tabbing style.
471 * Emacs will notice this stuff at the end of the file and automatically
472 * adjust the settings for this buffer only. This must remain at the end
473 * of the file.
474 * ---------------------------------------------------------------------------
475 * Local variables:
476 * c-file-style: "linux"
477 * End:
478 */
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
new file mode 100644
index 000000000000..f76a2692adca
--- /dev/null
+++ b/arch/um/kernel/process.c
@@ -0,0 +1,423 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <unistd.h>
8#include <signal.h>
9#include <sched.h>
10#include <errno.h>
11#include <stdarg.h>
12#include <stdlib.h>
13#include <setjmp.h>
14#include <sys/time.h>
15#include <sys/wait.h>
16#include <sys/mman.h>
17#include <asm/unistd.h>
18#include <asm/page.h>
19#include "user_util.h"
20#include "kern_util.h"
21#include "user.h"
22#include "process.h"
23#include "signal_kern.h"
24#include "signal_user.h"
25#include "sysdep/ptrace.h"
26#include "sysdep/sigcontext.h"
27#include "irq_user.h"
28#include "ptrace_user.h"
29#include "time_user.h"
30#include "init.h"
31#include "os.h"
32#include "uml-config.h"
33#include "ptrace_user.h"
34#include "choose-mode.h"
35#include "mode.h"
36#ifdef UML_CONFIG_MODE_SKAS
37#include "skas.h"
38#include "skas_ptrace.h"
39#include "registers.h"
40#endif
41
42void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
43{
44 int flags = 0, pages;
45
46 if(sig_stack != NULL){
47 pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
48 set_sigstack(sig_stack, pages * page_size());
49 flags = SA_ONSTACK;
50 }
51 if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
52}
53
54void init_new_thread_signals(int altstack)
55{
56 int flags = altstack ? SA_ONSTACK : 0;
57
58 set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
59 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
60 set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
61 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
62 set_handler(SIGFPE, (__sighandler_t) sig_handler, flags,
63 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
64 set_handler(SIGILL, (__sighandler_t) sig_handler, flags,
65 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
66 set_handler(SIGBUS, (__sighandler_t) sig_handler, flags,
67 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
68 set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags,
69 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
70 set_handler(SIGUSR2, (__sighandler_t) sig_handler,
71 flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
72 signal(SIGHUP, SIG_IGN);
73
74 init_irq_signals(altstack);
75}
76
77struct tramp {
78 int (*tramp)(void *);
79 void *tramp_data;
80 unsigned long temp_stack;
81 int flags;
82 int pid;
83};
84
85/* See above for why sigkill is here */
86
87int sigkill = SIGKILL;
88
89int outer_tramp(void *arg)
90{
91 struct tramp *t;
92 int sig = sigkill;
93
94 t = arg;
95 t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
96 t->flags, t->tramp_data);
97 if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
98 kill(os_getpid(), sig);
99 _exit(0);
100}
101
102int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
103 int clone_flags, int (*tramp)(void *))
104{
105 struct tramp arg;
106 unsigned long sp;
107 int new_pid, status, err;
108
109 /* The trampoline will run on the temporary stack */
110 sp = stack_sp(temp_stack);
111
112 clone_flags |= CLONE_FILES | SIGCHLD;
113
114 arg.tramp = tramp;
115 arg.tramp_data = thread_arg;
116 arg.temp_stack = temp_stack;
117 arg.flags = clone_flags;
118
119 /* Start the process and wait for it to kill itself */
120 new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
121 if(new_pid < 0)
122 return(new_pid);
123
124 CATCH_EINTR(err = waitpid(new_pid, &status, 0));
125 if(err < 0)
126 panic("Waiting for outer trampoline failed - errno = %d",
127 errno);
128
129 if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
130 panic("outer trampoline didn't exit with SIGKILL, "
131 "status = %d", status);
132
133 return(arg.pid);
134}
135
136static int ptrace_child(void *arg)
137{
138 int ret;
139 int pid = os_getpid(), ppid = getppid();
140 int sc_result;
141
142 if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
143 perror("ptrace");
144 os_kill_process(pid, 0);
145 }
146 os_stop_process(pid);
147
148 /*This syscall will be intercepted by the parent. Don't call more than
149 * once, please.*/
150 sc_result = os_getpid();
151
152 if (sc_result == pid)
153 ret = 1; /*Nothing modified by the parent, we are running
154 normally.*/
155 else if (sc_result == ppid)
156 ret = 0; /*Expected in check_ptrace and check_sysemu when they
157 succeed in modifying the stack frame*/
158 else
159 ret = 2; /*Serious trouble! This could be caused by a bug in
160 host 2.6 SKAS3/2.6 patch before release -V6, together
161 with a bug in the UML code itself.*/
162 _exit(ret);
163}
164
165static int start_ptraced_child(void **stack_out)
166{
167 void *stack;
168 unsigned long sp;
169 int pid, n, status;
170
171 stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
172 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
173 if(stack == MAP_FAILED)
174 panic("check_ptrace : mmap failed, errno = %d", errno);
175 sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
176 pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
177 if(pid < 0)
178 panic("check_ptrace : clone failed, errno = %d", errno);
179 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
180 if(n < 0)
181 panic("check_ptrace : wait failed, errno = %d", errno);
182 if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
183 panic("check_ptrace : expected SIGSTOP, got status = %d",
184 status);
185
186 *stack_out = stack;
187 return(pid);
188}
189
190/* When testing for SYSEMU support, if it is one of the broken versions, we must
191 * just avoid using sysemu, not panic, but only if SYSEMU features are broken.
192 * So only for SYSEMU features we test mustpanic, while normal host features
193 * must work anyway!*/
194static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
195{
196 int status, n, ret = 0;
197
198 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
199 panic("check_ptrace : ptrace failed, errno = %d", errno);
200 CATCH_EINTR(n = waitpid(pid, &status, 0));
201 if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
202 int exit_with = WEXITSTATUS(status);
203 if (exit_with == 2)
204 printk("check_ptrace : child exited with status 2. "
205 "Serious trouble happening! Try updating your "
206 "host skas patch!\nDisabling SYSEMU support.");
207 printk("check_ptrace : child exited with exitcode %d, while "
208 "expecting %d; status 0x%x", exit_with,
209 exitcode, status);
210 if (mustpanic)
211 panic("\n");
212 else
213 printk("\n");
214 ret = -1;
215 }
216
217 if(munmap(stack, PAGE_SIZE) < 0)
218 panic("check_ptrace : munmap failed, errno = %d", errno);
219 return ret;
220}
221
222static int force_sysemu_disabled = 0;
223
224static int __init nosysemu_cmd_param(char *str, int* add)
225{
226 force_sysemu_disabled = 1;
227 return 0;
228}
229
230__uml_setup("nosysemu", nosysemu_cmd_param,
231 "nosysemu\n"
232 " Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
233 " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
234 " behaviour of ptrace() and helps reducing host context switch rate.\n"
235 " To make it working, you need a kernel patch for your host, too.\n"
236 " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n\n");
237
238static void __init check_sysemu(void)
239{
240 void *stack;
241 int pid, syscall, n, status, count=0;
242
243 printk("Checking syscall emulation patch for ptrace...");
244 sysemu_supported = 0;
245 pid = start_ptraced_child(&stack);
246
247 if(ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
248 goto fail;
249
250 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
251 if (n < 0)
252 panic("check_sysemu : wait failed, errno = %d", errno);
253 if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
254 panic("check_sysemu : expected SIGTRAP, "
255 "got status = %d", status);
256
257 n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
258 os_getpid());
259 if(n < 0)
260 panic("check_sysemu : failed to modify system "
261 "call return, errno = %d", errno);
262
263 if (stop_ptraced_child(pid, stack, 0, 0) < 0)
264 goto fail_stopped;
265
266 sysemu_supported = 1;
267 printk("OK\n");
268 set_using_sysemu(!force_sysemu_disabled);
269
270 printk("Checking advanced syscall emulation patch for ptrace...");
271 pid = start_ptraced_child(&stack);
272 while(1){
273 count++;
274 if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
275 goto fail;
276 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
277 if(n < 0)
278 panic("check_ptrace : wait failed, errno = %d", errno);
279 if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
280 panic("check_ptrace : expected (SIGTRAP|SYSCALL_TRAP), "
281 "got status = %d", status);
282
283 syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
284 0);
285 if(syscall == __NR_getpid){
286 if (!count)
287 panic("check_ptrace : SYSEMU_SINGLESTEP doesn't singlestep");
288 n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
289 os_getpid());
290 if(n < 0)
291 panic("check_sysemu : failed to modify system "
292 "call return, errno = %d", errno);
293 break;
294 }
295 }
296 if (stop_ptraced_child(pid, stack, 0, 0) < 0)
297 goto fail_stopped;
298
299 sysemu_supported = 2;
300 printk("OK\n");
301
302 if ( !force_sysemu_disabled )
303 set_using_sysemu(sysemu_supported);
304 return;
305
306fail:
307 stop_ptraced_child(pid, stack, 1, 0);
308fail_stopped:
309 printk("missing\n");
310}
311
312void __init check_ptrace(void)
313{
314 void *stack;
315 int pid, syscall, n, status;
316
317 printk("Checking that ptrace can change system call numbers...");
318 pid = start_ptraced_child(&stack);
319
320 if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
321 panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno);
322
323 while(1){
324 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
325 panic("check_ptrace : ptrace failed, errno = %d",
326 errno);
327 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
328 if(n < 0)
329 panic("check_ptrace : wait failed, errno = %d", errno);
330 if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP + 0x80))
331 panic("check_ptrace : expected SIGTRAP + 0x80, "
332 "got status = %d", status);
333
334 syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
335 0);
336 if(syscall == __NR_getpid){
337 n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
338 __NR_getppid);
339 if(n < 0)
340 panic("check_ptrace : failed to modify system "
341 "call, errno = %d", errno);
342 break;
343 }
344 }
345 stop_ptraced_child(pid, stack, 0, 1);
346 printk("OK\n");
347 check_sysemu();
348}
349
350int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
351{
352 sigjmp_buf buf;
353 int n;
354
355 *jmp_ptr = &buf;
356 n = sigsetjmp(buf, 1);
357 if(n != 0)
358 return(n);
359 (*fn)(arg);
360 return(0);
361}
362
363void forward_pending_sigio(int target)
364{
365 sigset_t sigs;
366
367 if(sigpending(&sigs))
368 panic("forward_pending_sigio : sigpending failed");
369 if(sigismember(&sigs, SIGIO))
370 kill(target, SIGIO);
371}
372
373#ifdef UML_CONFIG_MODE_SKAS
374static inline int check_skas3_ptrace_support(void)
375{
376 struct ptrace_faultinfo fi;
377 void *stack;
378 int pid, n, ret = 1;
379
380 printf("Checking for the skas3 patch in the host...");
381 pid = start_ptraced_child(&stack);
382
383 n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
384 if (n < 0) {
385 if(errno == EIO)
386 printf("not found\n");
387 else {
388 perror("not found");
389 }
390 ret = 0;
391 } else {
392 printf("found\n");
393 }
394
395 init_registers(pid);
396 stop_ptraced_child(pid, stack, 1, 1);
397
398 return(ret);
399}
400
401int can_do_skas(void)
402{
403 int ret = 1;
404
405 printf("Checking for /proc/mm...");
406 if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
407 printf("not found\n");
408 ret = 0;
409 goto out;
410 } else {
411 printf("found\n");
412 }
413
414 ret = check_skas3_ptrace_support();
415out:
416 return ret;
417}
418#else
419int can_do_skas(void)
420{
421 return(0);
422}
423#endif
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
new file mode 100644
index 000000000000..1d719d5b4bb9
--- /dev/null
+++ b/arch/um/kernel/process_kern.c
@@ -0,0 +1,500 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Copyright 2003 PathScale, Inc.
4 * Licensed under the GPL
5 */
6
7#include "linux/config.h"
8#include "linux/kernel.h"
9#include "linux/sched.h"
10#include "linux/interrupt.h"
11#include "linux/mm.h"
12#include "linux/slab.h"
13#include "linux/utsname.h"
14#include "linux/fs.h"
15#include "linux/utime.h"
16#include "linux/smp_lock.h"
17#include "linux/module.h"
18#include "linux/init.h"
19#include "linux/capability.h"
20#include "linux/vmalloc.h"
21#include "linux/spinlock.h"
22#include "linux/proc_fs.h"
23#include "linux/ptrace.h"
24#include "linux/random.h"
25#include "asm/unistd.h"
26#include "asm/mman.h"
27#include "asm/segment.h"
28#include "asm/stat.h"
29#include "asm/pgtable.h"
30#include "asm/processor.h"
31#include "asm/tlbflush.h"
32#include "asm/uaccess.h"
33#include "asm/user.h"
34#include "user_util.h"
35#include "kern_util.h"
36#include "kern.h"
37#include "signal_kern.h"
38#include "signal_user.h"
39#include "init.h"
40#include "irq_user.h"
41#include "mem_user.h"
42#include "time_user.h"
43#include "tlb.h"
44#include "frame_kern.h"
45#include "sigcontext.h"
46#include "2_5compat.h"
47#include "os.h"
48#include "mode.h"
49#include "mode_kern.h"
50#include "choose-mode.h"
51
52/* This is a per-cpu array. A processor only modifies its entry and it only
53 * cares about its entry, so it's OK if another processor is modifying its
54 * entry.
55 */
56struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
57
58struct task_struct *get_task(int pid, int require)
59{
60 struct task_struct *ret;
61
62 read_lock(&tasklist_lock);
63 ret = find_task_by_pid(pid);
64 read_unlock(&tasklist_lock);
65
66 if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
67 return(ret);
68}
69
70int external_pid(void *t)
71{
72 struct task_struct *task = t ? t : current;
73
74 return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
75}
76
77int pid_to_processor_id(int pid)
78{
79 int i;
80
81 for(i = 0; i < ncpus; i++){
82 if(cpu_tasks[i].pid == pid) return(i);
83 }
84 return(-1);
85}
86
87void free_stack(unsigned long stack, int order)
88{
89 free_pages(stack, order);
90}
91
92unsigned long alloc_stack(int order, int atomic)
93{
94 unsigned long page;
95 int flags = GFP_KERNEL;
96
97 if(atomic) flags |= GFP_ATOMIC;
98 page = __get_free_pages(flags, order);
99 if(page == 0)
100 return(0);
101 stack_protections(page);
102 return(page);
103}
104
105int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
106{
107 int pid;
108
109 current->thread.request.u.thread.proc = fn;
110 current->thread.request.u.thread.arg = arg;
111 pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0, NULL,
112 NULL);
113 if(pid < 0)
114 panic("do_fork failed in kernel_thread, errno = %d", pid);
115 return(pid);
116}
117
118void switch_mm(struct mm_struct *prev, struct mm_struct *next,
119 struct task_struct *tsk)
120{
121 int cpu = smp_processor_id();
122
123 if (prev != next)
124 cpu_clear(cpu, prev->cpu_vm_mask);
125 cpu_set(cpu, next->cpu_vm_mask);
126}
127
128void set_current(void *t)
129{
130 struct task_struct *task = t;
131
132 cpu_tasks[task->thread_info->cpu] = ((struct cpu_task)
133 { external_pid(task), task });
134}
135
136void *_switch_to(void *prev, void *next, void *last)
137{
138 return(CHOOSE_MODE(switch_to_tt(prev, next),
139 switch_to_skas(prev, next)));
140}
141
142void interrupt_end(void)
143{
144 if(need_resched()) schedule();
145 if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal();
146}
147
148void release_thread(struct task_struct *task)
149{
150 CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
151}
152
153void exit_thread(void)
154{
155 CHOOSE_MODE(exit_thread_tt(), exit_thread_skas());
156 unprotect_stack((unsigned long) current_thread);
157}
158
159void *get_current(void)
160{
161 return(current);
162}
163
164void prepare_to_copy(struct task_struct *tsk)
165{
166}
167
168int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
169 unsigned long stack_top, struct task_struct * p,
170 struct pt_regs *regs)
171{
172 p->thread = (struct thread_struct) INIT_THREAD;
173 return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
174 clone_flags, sp, stack_top, p, regs));
175}
176
177void initial_thread_cb(void (*proc)(void *), void *arg)
178{
179 int save_kmalloc_ok = kmalloc_ok;
180
181 kmalloc_ok = 0;
182 CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc,
183 arg);
184 kmalloc_ok = save_kmalloc_ok;
185}
186
187unsigned long stack_sp(unsigned long page)
188{
189 return(page + PAGE_SIZE - sizeof(void *));
190}
191
192int current_pid(void)
193{
194 return(current->pid);
195}
196
197void default_idle(void)
198{
199 uml_idle_timer();
200
201 atomic_inc(&init_mm.mm_count);
202 current->mm = &init_mm;
203 current->active_mm = &init_mm;
204
205 while(1){
206 /* endless idle loop with no priority at all */
207 SET_PRI(current);
208
209 /*
210 * although we are an idle CPU, we do not want to
211 * get into the scheduler unnecessarily.
212 */
213 if(need_resched())
214 schedule();
215
216 idle_sleep(10);
217 }
218}
219
220void cpu_idle(void)
221{
222 CHOOSE_MODE(init_idle_tt(), init_idle_skas());
223}
224
225int page_size(void)
226{
227 return(PAGE_SIZE);
228}
229
230unsigned long page_mask(void)
231{
232 return(PAGE_MASK);
233}
234
235void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
236 pte_t *pte_out)
237{
238 pgd_t *pgd;
239 pud_t *pud;
240 pmd_t *pmd;
241 pte_t *pte;
242
243 if(task->mm == NULL)
244 return(ERR_PTR(-EINVAL));
245 pgd = pgd_offset(task->mm, addr);
246 if(!pgd_present(*pgd))
247 return(ERR_PTR(-EINVAL));
248
249 pud = pud_offset(pgd, addr);
250 if(!pud_present(*pud))
251 return(ERR_PTR(-EINVAL));
252
253 pmd = pmd_offset(pud, addr);
254 if(!pmd_present(*pmd))
255 return(ERR_PTR(-EINVAL));
256
257 pte = pte_offset_kernel(pmd, addr);
258 if(!pte_present(*pte))
259 return(ERR_PTR(-EINVAL));
260
261 if(pte_out != NULL)
262 *pte_out = *pte;
263 return((void *) (pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK));
264}
265
266char *current_cmd(void)
267{
268#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
269 return("(Unknown)");
270#else
271 void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
272 return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
273#endif
274}
275
276void force_sigbus(void)
277{
278 printk(KERN_ERR "Killing pid %d because of a lack of memory\n",
279 current->pid);
280 lock_kernel();
281 sigaddset(&current->pending.signal, SIGBUS);
282 recalc_sigpending();
283 current->flags |= PF_SIGNALED;
284 do_exit(SIGBUS | 0x80);
285}
286
287void dump_thread(struct pt_regs *regs, struct user *u)
288{
289}
290
291void enable_hlt(void)
292{
293 panic("enable_hlt");
294}
295
296EXPORT_SYMBOL(enable_hlt);
297
298void disable_hlt(void)
299{
300 panic("disable_hlt");
301}
302
303EXPORT_SYMBOL(disable_hlt);
304
305void *um_kmalloc(int size)
306{
307 return(kmalloc(size, GFP_KERNEL));
308}
309
310void *um_kmalloc_atomic(int size)
311{
312 return(kmalloc(size, GFP_ATOMIC));
313}
314
315void *um_vmalloc(int size)
316{
317 return(vmalloc(size));
318}
319
320unsigned long get_fault_addr(void)
321{
322 return((unsigned long) current->thread.fault_addr);
323}
324
325EXPORT_SYMBOL(get_fault_addr);
326
327void not_implemented(void)
328{
329 printk(KERN_DEBUG "Something isn't implemented in here\n");
330}
331
332EXPORT_SYMBOL(not_implemented);
333
334int user_context(unsigned long sp)
335{
336 unsigned long stack;
337
338 stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
339 return(stack != (unsigned long) current_thread);
340}
341
342extern void remove_umid_dir(void);
343
344__uml_exitcall(remove_umid_dir);
345
346extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
347
348void do_uml_exitcalls(void)
349{
350 exitcall_t *call;
351
352 call = &__uml_exitcall_end;
353 while (--call >= &__uml_exitcall_begin)
354 (*call)();
355}
356
357char *uml_strdup(char *string)
358{
359 char *new;
360
361 new = kmalloc(strlen(string) + 1, GFP_KERNEL);
362 if(new == NULL) return(NULL);
363 strcpy(new, string);
364 return(new);
365}
366
367void *get_init_task(void)
368{
369 return(&init_thread_union.thread_info.task);
370}
371
372int copy_to_user_proc(void __user *to, void *from, int size)
373{
374 return(copy_to_user(to, from, size));
375}
376
377int copy_from_user_proc(void *to, void __user *from, int size)
378{
379 return(copy_from_user(to, from, size));
380}
381
382int clear_user_proc(void __user *buf, int size)
383{
384 return(clear_user(buf, size));
385}
386
387int strlen_user_proc(char __user *str)
388{
389 return(strlen_user(str));
390}
391
392int smp_sigio_handler(void)
393{
394#ifdef CONFIG_SMP
395 int cpu = current_thread->cpu;
396 IPI_handler(cpu);
397 if(cpu != 0)
398 return(1);
399#endif
400 return(0);
401}
402
403int um_in_interrupt(void)
404{
405 return(in_interrupt());
406}
407
408int cpu(void)
409{
410 return(current_thread->cpu);
411}
412
413static atomic_t using_sysemu = ATOMIC_INIT(0);
414int sysemu_supported;
415
416void set_using_sysemu(int value)
417{
418 if (value > sysemu_supported)
419 return;
420 atomic_set(&using_sysemu, value);
421}
422
423int get_using_sysemu(void)
424{
425 return atomic_read(&using_sysemu);
426}
427
428static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
429{
430 if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/
431 *eof = 1;
432
433 return strlen(buf);
434}
435
436static int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data)
437{
438 char tmp[2];
439
440 if (copy_from_user(tmp, buf, 1))
441 return -EFAULT;
442
443 if (tmp[0] >= '0' && tmp[0] <= '2')
444 set_using_sysemu(tmp[0] - '0');
445 return count; /*We use the first char, but pretend to write everything*/
446}
447
448int __init make_proc_sysemu(void)
449{
450 struct proc_dir_entry *ent;
451 if (!sysemu_supported)
452 return 0;
453
454 ent = create_proc_entry("sysemu", 0600, &proc_root);
455
456 if (ent == NULL)
457 {
458 printk("Failed to register /proc/sysemu\n");
459 return(0);
460 }
461
462 ent->read_proc = proc_read_sysemu;
463 ent->write_proc = proc_write_sysemu;
464
465 return 0;
466}
467
468late_initcall(make_proc_sysemu);
469
470int singlestepping(void * t)
471{
472 struct task_struct *task = t ? t : current;
473
474 if ( ! (task->ptrace & PT_DTRACE) )
475 return(0);
476
477 if (task->thread.singlestep_syscall)
478 return(1);
479
480 return 2;
481}
482
483unsigned long arch_align_stack(unsigned long sp)
484{
485 if (randomize_va_space)
486 sp -= get_random_int() % 8192;
487 return sp & ~0xf;
488}
489
490
491/*
492 * Overrides for Emacs so that we follow Linus's tabbing style.
493 * Emacs will notice this stuff at the end of the file and automatically
494 * adjust the settings for this buffer only. This must remain at the end
495 * of the file.
496 * ---------------------------------------------------------------------------
497 * Local variables:
498 * c-file-style: "linux"
499 * End:
500 */
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
new file mode 100644
index 000000000000..3a99ee6d94eb
--- /dev/null
+++ b/arch/um/kernel/ptrace.c
@@ -0,0 +1,388 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/mm.h"
8#include "linux/errno.h"
9#include "linux/smp_lock.h"
10#include "linux/security.h"
11#include "linux/ptrace.h"
12#include "linux/audit.h"
13#ifdef CONFIG_PROC_MM
14#include "linux/proc_mm.h"
15#endif
16#include "asm/ptrace.h"
17#include "asm/uaccess.h"
18#include "kern_util.h"
19#include "skas_ptrace.h"
20#include "sysdep/ptrace.h"
21
22/*
23 * Called by kernel/ptrace.c when detaching..
24 */
25void ptrace_disable(struct task_struct *child)
26{
27 child->ptrace &= ~PT_DTRACE;
28 child->thread.singlestep_syscall = 0;
29}
30
31long sys_ptrace(long request, long pid, long addr, long data)
32{
33 struct task_struct *child;
34 int i, ret;
35
36 lock_kernel();
37 ret = -EPERM;
38 if (request == PTRACE_TRACEME) {
39 /* are we already being traced? */
40 if (current->ptrace & PT_PTRACED)
41 goto out;
42
43 ret = security_ptrace(current->parent, current);
44 if (ret)
45 goto out;
46
47 /* set the ptrace bit in the process flags. */
48 current->ptrace |= PT_PTRACED;
49 ret = 0;
50 goto out;
51 }
52 ret = -ESRCH;
53 read_lock(&tasklist_lock);
54 child = find_task_by_pid(pid);
55 if (child)
56 get_task_struct(child);
57 read_unlock(&tasklist_lock);
58 if (!child)
59 goto out;
60
61 ret = -EPERM;
62 if (pid == 1) /* you may not mess with init */
63 goto out_tsk;
64
65 if (request == PTRACE_ATTACH) {
66 ret = ptrace_attach(child);
67 goto out_tsk;
68 }
69
70 ret = ptrace_check_attach(child, request == PTRACE_KILL);
71 if (ret < 0)
72 goto out_tsk;
73
74 switch (request) {
75 /* when I and D space are separate, these will need to be fixed. */
76 case PTRACE_PEEKTEXT: /* read word at location addr. */
77 case PTRACE_PEEKDATA: {
78 unsigned long tmp;
79 int copied;
80
81 ret = -EIO;
82 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
83 if (copied != sizeof(tmp))
84 break;
85 ret = put_user(tmp, (unsigned long __user *) data);
86 break;
87 }
88
89 /* read the word at location addr in the USER area. */
90 case PTRACE_PEEKUSR: {
91 unsigned long tmp;
92
93 ret = -EIO;
94 if ((addr & 3) || addr < 0)
95 break;
96
97 tmp = 0; /* Default return condition */
98 if(addr < MAX_REG_OFFSET){
99 tmp = getreg(child, addr);
100 }
101 else if((addr >= offsetof(struct user, u_debugreg[0])) &&
102 (addr <= offsetof(struct user, u_debugreg[7]))){
103 addr -= offsetof(struct user, u_debugreg[0]);
104 addr = addr >> 2;
105 tmp = child->thread.arch.debugregs[addr];
106 }
107 ret = put_user(tmp, (unsigned long __user *) data);
108 break;
109 }
110
111 /* when I and D space are separate, this will have to be fixed. */
112 case PTRACE_POKETEXT: /* write the word at location addr. */
113 case PTRACE_POKEDATA:
114 ret = -EIO;
115 if (access_process_vm(child, addr, &data, sizeof(data),
116 1) != sizeof(data))
117 break;
118 ret = 0;
119 break;
120
121 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
122 ret = -EIO;
123 if ((addr & 3) || addr < 0)
124 break;
125
126 if (addr < MAX_REG_OFFSET) {
127 ret = putreg(child, addr, data);
128 break;
129 }
130#if 0 /* XXX x86_64 */
131 else if((addr >= offsetof(struct user, u_debugreg[0])) &&
132 (addr <= offsetof(struct user, u_debugreg[7]))){
133 addr -= offsetof(struct user, u_debugreg[0]);
134 addr = addr >> 2;
135 if((addr == 4) || (addr == 5)) break;
136 child->thread.arch.debugregs[addr] = data;
137 ret = 0;
138 }
139#endif
140
141 break;
142
143 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
144 case PTRACE_CONT: { /* restart after signal. */
145 ret = -EIO;
146 if ((unsigned long) data > _NSIG)
147 break;
148
149 child->ptrace &= ~PT_DTRACE;
150 child->thread.singlestep_syscall = 0;
151 if (request == PTRACE_SYSCALL) {
152 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
153 }
154 else {
155 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
156 }
157 child->exit_code = data;
158 wake_up_process(child);
159 ret = 0;
160 break;
161 }
162
163/*
164 * make the child exit. Best I can do is send it a sigkill.
165 * perhaps it should be put in the status that it wants to
166 * exit.
167 */
168 case PTRACE_KILL: {
169 ret = 0;
170 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
171 break;
172
173 child->ptrace &= ~PT_DTRACE;
174 child->thread.singlestep_syscall = 0;
175 child->exit_code = SIGKILL;
176 wake_up_process(child);
177 break;
178 }
179
180 case PTRACE_SINGLESTEP: { /* set the trap flag. */
181 ret = -EIO;
182 if ((unsigned long) data > _NSIG)
183 break;
184 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
185 child->ptrace |= PT_DTRACE;
186 child->thread.singlestep_syscall = 0;
187 child->exit_code = data;
188 /* give it a chance to run. */
189 wake_up_process(child);
190 ret = 0;
191 break;
192 }
193
194 case PTRACE_DETACH:
195 /* detach a process that was attached. */
196 ret = ptrace_detach(child, data);
197 break;
198
199#ifdef PTRACE_GETREGS
200 case PTRACE_GETREGS: { /* Get all gp regs from the child. */
201 if (!access_ok(VERIFY_WRITE, (unsigned long *)data,
202 MAX_REG_OFFSET)) {
203 ret = -EIO;
204 break;
205 }
206 for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
207 __put_user(getreg(child, i),
208 (unsigned long __user *) data);
209 data += sizeof(long);
210 }
211 ret = 0;
212 break;
213 }
214#endif
215#ifdef PTRACE_SETREGS
216 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
217 unsigned long tmp = 0;
218 if (!access_ok(VERIFY_READ, (unsigned *)data,
219 MAX_REG_OFFSET)) {
220 ret = -EIO;
221 break;
222 }
223 for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
224 __get_user(tmp, (unsigned long __user *) data);
225 putreg(child, i, tmp);
226 data += sizeof(long);
227 }
228 ret = 0;
229 break;
230 }
231#endif
232#ifdef PTRACE_GETFPREGS
233 case PTRACE_GETFPREGS: /* Get the child FPU state. */
234 ret = get_fpregs(data, child);
235 break;
236#endif
237#ifdef PTRACE_SETFPREGS
238 case PTRACE_SETFPREGS: /* Set the child FPU state. */
239 ret = set_fpregs(data, child);
240 break;
241#endif
242#ifdef PTRACE_GETFPXREGS
243 case PTRACE_GETFPXREGS: /* Get the child FPU state. */
244 ret = get_fpxregs(data, child);
245 break;
246#endif
247#ifdef PTRACE_SETFPXREGS
248 case PTRACE_SETFPXREGS: /* Set the child FPU state. */
249 ret = set_fpxregs(data, child);
250 break;
251#endif
252 case PTRACE_FAULTINFO: {
253 struct ptrace_faultinfo fault;
254
255 fault = ((struct ptrace_faultinfo)
256 { .is_write = child->thread.err,
257 .addr = child->thread.cr2 });
258 ret = copy_to_user((unsigned long __user *) data, &fault,
259 sizeof(fault));
260 if(ret)
261 break;
262 break;
263 }
264 case PTRACE_SIGPENDING:
265 ret = copy_to_user((unsigned long __user *) data,
266 &child->pending.signal,
267 sizeof(child->pending.signal));
268 break;
269
270 case PTRACE_LDT: {
271 struct ptrace_ldt ldt;
272
273 if(copy_from_user(&ldt, (unsigned long __user *) data,
274 sizeof(ldt))){
275 ret = -EIO;
276 break;
277 }
278
279 /* This one is confusing, so just punt and return -EIO for
280 * now
281 */
282 ret = -EIO;
283 break;
284 }
285#ifdef CONFIG_PROC_MM
286 case PTRACE_SWITCH_MM: {
287 struct mm_struct *old = child->mm;
288 struct mm_struct *new = proc_mm_get_mm(data);
289
290 if(IS_ERR(new)){
291 ret = PTR_ERR(new);
292 break;
293 }
294
295 atomic_inc(&new->mm_users);
296 child->mm = new;
297 child->active_mm = new;
298 mmput(old);
299 ret = 0;
300 break;
301 }
302#endif
303 default:
304 ret = ptrace_request(child, request, addr, data);
305 break;
306 }
307 out_tsk:
308 put_task_struct(child);
309 out:
310 unlock_kernel();
311 return ret;
312}
313
314void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
315 int error_code)
316{
317 struct siginfo info;
318
319 memset(&info, 0, sizeof(info));
320 info.si_signo = SIGTRAP;
321 info.si_code = TRAP_BRKPT;
322
323 /* User-mode eip? */
324 info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL;
325
326 /* Send us the fakey SIGTRAP */
327 force_sig_info(SIGTRAP, &info, tsk);
328}
329
330/* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
331 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
332 */
333void syscall_trace(union uml_pt_regs *regs, int entryexit)
334{
335 int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
336 int tracesysgood;
337
338 if (unlikely(current->audit_context)) {
339 if (!entryexit)
340 audit_syscall_entry(current,
341 UPT_SYSCALL_NR(&regs->regs),
342 UPT_SYSCALL_ARG1(&regs->regs),
343 UPT_SYSCALL_ARG2(&regs->regs),
344 UPT_SYSCALL_ARG3(&regs->regs),
345 UPT_SYSCALL_ARG4(&regs->regs));
346 else
347 audit_syscall_exit(current,
348 UPT_SYSCALL_RET(&regs->regs));
349 }
350
351 /* Fake a debug trap */
352 if (is_singlestep)
353 send_sigtrap(current, regs, 0);
354
355 if (!test_thread_flag(TIF_SYSCALL_TRACE))
356 return;
357
358 if (!(current->ptrace & PT_PTRACED))
359 return;
360
361 /* the 0x80 provides a way for the tracing parent to distinguish
362 between a syscall stop and SIGTRAP delivery */
363 tracesysgood = (current->ptrace & PT_TRACESYSGOOD);
364 ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
365
366 if (entryexit) /* force do_signal() --> is_syscall() */
367 set_thread_flag(TIF_SIGPENDING);
368
369 /* this isn't the same as continuing with a signal, but it will do
370 * for normal use. strace only continues with a signal if the
371 * stopping signal is not SIGTRAP. -brl
372 */
373 if (current->exit_code) {
374 send_sig(current->exit_code, current, 1);
375 current->exit_code = 0;
376 }
377}
378
379/*
380 * Overrides for Emacs so that we follow Linus's tabbing style.
381 * Emacs will notice this stuff at the end of the file and automatically
382 * adjust the settings for this buffer only. This must remain at the end
383 * of the file.
384 * ---------------------------------------------------------------------------
385 * Local variables:
386 * c-file-style: "linux"
387 * End:
388 */
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
new file mode 100644
index 000000000000..207f89d74908
--- /dev/null
+++ b/arch/um/kernel/reboot.c
@@ -0,0 +1,79 @@
1/*
2 * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/module.h"
7#include "linux/sched.h"
8#include "user_util.h"
9#include "kern_util.h"
10#include "kern.h"
11#include "os.h"
12#include "mode.h"
13#include "choose-mode.h"
14
15#ifdef CONFIG_SMP
16static void kill_idlers(int me)
17{
18#ifdef CONFIG_MODE_TT
19 struct task_struct *p;
20 int i;
21
22 for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){
23 p = idle_threads[i];
24 if((p != NULL) && (p->thread.mode.tt.extern_pid != me))
25 os_kill_process(p->thread.mode.tt.extern_pid, 0);
26 }
27#endif
28}
29#endif
30
31static void kill_off_processes(void)
32{
33 CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas());
34#ifdef CONFIG_SMP
35 kill_idlers(os_getpid());
36#endif
37}
38
39void uml_cleanup(void)
40{
41 kill_off_processes();
42 do_uml_exitcalls();
43}
44
45void machine_restart(char * __unused)
46{
47 do_uml_exitcalls();
48 kill_off_processes();
49 CHOOSE_MODE(reboot_tt(), reboot_skas());
50}
51
52EXPORT_SYMBOL(machine_restart);
53
54void machine_power_off(void)
55{
56 do_uml_exitcalls();
57 kill_off_processes();
58 CHOOSE_MODE(halt_tt(), halt_skas());
59}
60
61EXPORT_SYMBOL(machine_power_off);
62
63void machine_halt(void)
64{
65 machine_power_off();
66}
67
68EXPORT_SYMBOL(machine_halt);
69
70/*
71 * Overrides for Emacs so that we follow Linus's tabbing style.
72 * Emacs will notice this stuff at the end of the file and automatically
73 * adjust the settings for this buffer only. This must remain at the end
74 * of the file.
75 * ---------------------------------------------------------------------------
76 * Local variables:
77 * c-file-style: "linux"
78 * End:
79 */
diff --git a/arch/um/kernel/resource.c b/arch/um/kernel/resource.c
new file mode 100644
index 000000000000..32188e12e8af
--- /dev/null
+++ b/arch/um/kernel/resource.c
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/pci.h"
7
8unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
9 unsigned long start, unsigned long size)
10{
11 return start;
12}
13
14/*
15 * Overrides for Emacs so that we follow Linus's tabbing style.
16 * Emacs will notice this stuff at the end of the file and automatically
17 * adjust the settings for this buffer only. This must remain at the end
18 * of the file.
19 * ---------------------------------------------------------------------------
20 * Local variables:
21 * c-file-style: "linux"
22 * End:
23 */
diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c
new file mode 100644
index 000000000000..229988463c4c
--- /dev/null
+++ b/arch/um/kernel/sigio_kern.c
@@ -0,0 +1,63 @@
1/*
2 * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "linux/list.h"
8#include "linux/slab.h"
9#include "linux/signal.h"
10#include "linux/interrupt.h"
11#include "init.h"
12#include "sigio.h"
13#include "irq_user.h"
14#include "irq_kern.h"
15
16/* Protected by sigio_lock() called from write_sigio_workaround */
17static int sigio_irq_fd = -1;
18
19static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
20{
21 read_sigio_fd(sigio_irq_fd);
22 reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
23 return(IRQ_HANDLED);
24}
25
26int write_sigio_irq(int fd)
27{
28 int err;
29
30 err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
31 SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio",
32 NULL);
33 if(err){
34 printk("write_sigio_irq : um_request_irq failed, err = %d\n",
35 err);
36 return(-1);
37 }
38 sigio_irq_fd = fd;
39 return(0);
40}
41
42static DEFINE_SPINLOCK(sigio_spinlock);
43
44void sigio_lock(void)
45{
46 spin_lock(&sigio_spinlock);
47}
48
49void sigio_unlock(void)
50{
51 spin_unlock(&sigio_spinlock);
52}
53
54/*
55 * Overrides for Emacs so that we follow Linus's tabbing style.
56 * Emacs will notice this stuff at the end of the file and automatically
57 * adjust the settings for this buffer only. This must remain at the end
58 * of the file.
59 * ---------------------------------------------------------------------------
60 * Local variables:
61 * c-file-style: "linux"
62 * End:
63 */
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
new file mode 100644
index 000000000000..668df13d8c9d
--- /dev/null
+++ b/arch/um/kernel/sigio_user.c
@@ -0,0 +1,431 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <stdlib.h>
8#include <termios.h>
9#include <pty.h>
10#include <signal.h>
11#include <errno.h>
12#include <string.h>
13#include <sched.h>
14#include <sys/socket.h>
15#include <sys/poll.h>
16#include "init.h"
17#include "user.h"
18#include "kern_util.h"
19#include "user_util.h"
20#include "sigio.h"
21#include "helper.h"
22#include "os.h"
23
24/* Changed during early boot */
25int pty_output_sigio = 0;
26int pty_close_sigio = 0;
27
28/* Used as a flag during SIGIO testing early in boot */
29static volatile int got_sigio = 0;
30
31void __init handler(int sig)
32{
33 got_sigio = 1;
34}
35
36struct openpty_arg {
37 int master;
38 int slave;
39 int err;
40};
41
42static void openpty_cb(void *arg)
43{
44 struct openpty_arg *info = arg;
45
46 info->err = 0;
47 if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
48 info->err = -errno;
49}
50
51void __init check_one_sigio(void (*proc)(int, int))
52{
53 struct sigaction old, new;
54 struct openpty_arg pty = { .master = -1, .slave = -1 };
55 int master, slave, err;
56
57 initial_thread_cb(openpty_cb, &pty);
58 if(pty.err){
59 printk("openpty failed, errno = %d\n", -pty.err);
60 return;
61 }
62
63 master = pty.master;
64 slave = pty.slave;
65
66 if((master == -1) || (slave == -1)){
67 printk("openpty failed to allocate a pty\n");
68 return;
69 }
70
71 /* Not now, but complain so we now where we failed. */
72 err = raw(master);
73 if (err < 0)
74 panic("check_sigio : __raw failed, errno = %d\n", -err);
75
76 err = os_sigio_async(master, slave);
77 if(err < 0)
78 panic("tty_fds : sigio_async failed, err = %d\n", -err);
79
80 if(sigaction(SIGIO, NULL, &old) < 0)
81 panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
82 new = old;
83 new.sa_handler = handler;
84 if(sigaction(SIGIO, &new, NULL) < 0)
85 panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
86
87 got_sigio = 0;
88 (*proc)(master, slave);
89
90 os_close_file(master);
91 os_close_file(slave);
92
93 if(sigaction(SIGIO, &old, NULL) < 0)
94 panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
95}
96
97static void tty_output(int master, int slave)
98{
99 int n;
100 char buf[512];
101
102 printk("Checking that host ptys support output SIGIO...");
103
104 memset(buf, 0, sizeof(buf));
105
106 while(os_write_file(master, buf, sizeof(buf)) > 0) ;
107 if(errno != EAGAIN)
108 panic("check_sigio : write failed, errno = %d\n", errno);
109 while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
110
111 if (got_sigio) {
112 printk("Yes\n");
113 pty_output_sigio = 1;
114 } else if (n == -EAGAIN) {
115 printk("No, enabling workaround\n");
116 } else {
117 panic("check_sigio : read failed, err = %d\n", n);
118 }
119}
120
121static void tty_close(int master, int slave)
122{
123 printk("Checking that host ptys support SIGIO on close...");
124
125 os_close_file(slave);
126 if(got_sigio){
127 printk("Yes\n");
128 pty_close_sigio = 1;
129 }
130 else printk("No, enabling workaround\n");
131}
132
133void __init check_sigio(void)
134{
135 if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
136 (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
137 printk("No pseudo-terminals available - skipping pty SIGIO "
138 "check\n");
139 return;
140 }
141 check_one_sigio(tty_output);
142 check_one_sigio(tty_close);
143}
144
145/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
146 * exitcall.
147 */
148static int write_sigio_pid = -1;
149
150/* These arrays are initialized before the sigio thread is started, and
151 * the descriptors closed after it is killed. So, it can't see them change.
152 * On the UML side, they are changed under the sigio_lock.
153 */
154static int write_sigio_fds[2] = { -1, -1 };
155static int sigio_private[2] = { -1, -1 };
156
157struct pollfds {
158 struct pollfd *poll;
159 int size;
160 int used;
161};
162
163/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread
164 * synchronizes with it.
165 */
166struct pollfds current_poll = {
167 .poll = NULL,
168 .size = 0,
169 .used = 0
170};
171
172struct pollfds next_poll = {
173 .poll = NULL,
174 .size = 0,
175 .used = 0
176};
177
178static int write_sigio_thread(void *unused)
179{
180 struct pollfds *fds, tmp;
181 struct pollfd *p;
182 int i, n, respond_fd;
183 char c;
184
185 fds = &current_poll;
186 while(1){
187 n = poll(fds->poll, fds->used, -1);
188 if(n < 0){
189 if(errno == EINTR) continue;
190 printk("write_sigio_thread : poll returned %d, "
191 "errno = %d\n", n, errno);
192 }
193 for(i = 0; i < fds->used; i++){
194 p = &fds->poll[i];
195 if(p->revents == 0) continue;
196 if(p->fd == sigio_private[1]){
197 n = os_read_file(sigio_private[1], &c, sizeof(c));
198 if(n != sizeof(c))
199 printk("write_sigio_thread : "
200 "read failed, err = %d\n", -n);
201 tmp = current_poll;
202 current_poll = next_poll;
203 next_poll = tmp;
204 respond_fd = sigio_private[1];
205 }
206 else {
207 respond_fd = write_sigio_fds[1];
208 fds->used--;
209 memmove(&fds->poll[i], &fds->poll[i + 1],
210 (fds->used - i) * sizeof(*fds->poll));
211 }
212
213 n = os_write_file(respond_fd, &c, sizeof(c));
214 if(n != sizeof(c))
215 printk("write_sigio_thread : write failed, "
216 "err = %d\n", -n);
217 }
218 }
219}
220
221static int need_poll(int n)
222{
223 if(n <= next_poll.size){
224 next_poll.used = n;
225 return(0);
226 }
227 if(next_poll.poll != NULL) kfree(next_poll.poll);
228 next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
229 if(next_poll.poll == NULL){
230 printk("need_poll : failed to allocate new pollfds\n");
231 next_poll.size = 0;
232 next_poll.used = 0;
233 return(-1);
234 }
235 next_poll.size = n;
236 next_poll.used = n;
237 return(0);
238}
239
240/* Must be called with sigio_lock held, because it's needed by the marked
241 * critical section. */
242static void update_thread(void)
243{
244 unsigned long flags;
245 int n;
246 char c;
247
248 flags = set_signals(0);
249 n = os_write_file(sigio_private[0], &c, sizeof(c));
250 if(n != sizeof(c)){
251 printk("update_thread : write failed, err = %d\n", -n);
252 goto fail;
253 }
254
255 n = os_read_file(sigio_private[0], &c, sizeof(c));
256 if(n != sizeof(c)){
257 printk("update_thread : read failed, err = %d\n", -n);
258 goto fail;
259 }
260
261 set_signals(flags);
262 return;
263 fail:
264 /* Critical section start */
265 if(write_sigio_pid != -1)
266 os_kill_process(write_sigio_pid, 1);
267 write_sigio_pid = -1;
268 os_close_file(sigio_private[0]);
269 os_close_file(sigio_private[1]);
270 os_close_file(write_sigio_fds[0]);
271 os_close_file(write_sigio_fds[1]);
272 /* Critical section end */
273 set_signals(flags);
274}
275
276int add_sigio_fd(int fd, int read)
277{
278 int err = 0, i, n, events;
279
280 sigio_lock();
281 for(i = 0; i < current_poll.used; i++){
282 if(current_poll.poll[i].fd == fd)
283 goto out;
284 }
285
286 n = current_poll.used + 1;
287 err = need_poll(n);
288 if(err)
289 goto out;
290
291 for(i = 0; i < current_poll.used; i++)
292 next_poll.poll[i] = current_poll.poll[i];
293
294 if(read) events = POLLIN;
295 else events = POLLOUT;
296
297 next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd,
298 .events = events,
299 .revents = 0 });
300 update_thread();
301 out:
302 sigio_unlock();
303 return(err);
304}
305
306int ignore_sigio_fd(int fd)
307{
308 struct pollfd *p;
309 int err = 0, i, n = 0;
310
311 sigio_lock();
312 for(i = 0; i < current_poll.used; i++){
313 if(current_poll.poll[i].fd == fd) break;
314 }
315 if(i == current_poll.used)
316 goto out;
317
318 err = need_poll(current_poll.used - 1);
319 if(err)
320 goto out;
321
322 for(i = 0; i < current_poll.used; i++){
323 p = &current_poll.poll[i];
324 if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
325 }
326 if(n == i){
327 printk("ignore_sigio_fd : fd %d not found\n", fd);
328 err = -1;
329 goto out;
330 }
331
332 update_thread();
333 out:
334 sigio_unlock();
335 return(err);
336}
337
338static int setup_initial_poll(int fd)
339{
340 struct pollfd *p;
341
342 p = um_kmalloc(sizeof(struct pollfd));
343 if(p == NULL){
344 printk("setup_initial_poll : failed to allocate poll\n");
345 return(-1);
346 }
347 *p = ((struct pollfd) { .fd = fd,
348 .events = POLLIN,
349 .revents = 0 });
350 current_poll = ((struct pollfds) { .poll = p,
351 .used = 1,
352 .size = 1 });
353 return(0);
354}
355
356void write_sigio_workaround(void)
357{
358 unsigned long stack;
359 int err;
360
361 sigio_lock();
362 if(write_sigio_pid != -1)
363 goto out;
364
365 err = os_pipe(write_sigio_fds, 1, 1);
366 if(err < 0){
367 printk("write_sigio_workaround - os_pipe 1 failed, "
368 "err = %d\n", -err);
369 goto out;
370 }
371 err = os_pipe(sigio_private, 1, 1);
372 if(err < 0){
373 printk("write_sigio_workaround - os_pipe 2 failed, "
374 "err = %d\n", -err);
375 goto out_close1;
376 }
377 if(setup_initial_poll(sigio_private[1]))
378 goto out_close2;
379
380 write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
381 CLONE_FILES | CLONE_VM, &stack, 0);
382
383 if(write_sigio_pid < 0) goto out_close2;
384
385 if(write_sigio_irq(write_sigio_fds[0]))
386 goto out_kill;
387
388 out:
389 sigio_unlock();
390 return;
391
392 out_kill:
393 os_kill_process(write_sigio_pid, 1);
394 write_sigio_pid = -1;
395 out_close2:
396 os_close_file(sigio_private[0]);
397 os_close_file(sigio_private[1]);
398 out_close1:
399 os_close_file(write_sigio_fds[0]);
400 os_close_file(write_sigio_fds[1]);
401 sigio_unlock();
402}
403
404int read_sigio_fd(int fd)
405{
406 int n;
407 char c;
408
409 n = os_read_file(fd, &c, sizeof(c));
410 if(n != sizeof(c)){
411 if(n < 0) {
412 printk("read_sigio_fd - read failed, err = %d\n", -n);
413 return(n);
414 }
415 else {
416 printk("read_sigio_fd - short read, bytes = %d\n", n);
417 return(-EIO);
418 }
419 }
420 return(n);
421}
422
423static void sigio_cleanup(void)
424{
425 if (write_sigio_pid != -1) {
426 os_kill_process(write_sigio_pid, 1);
427 write_sigio_pid = -1;
428 }
429}
430
431__uml_exitcall(sigio_cleanup);
diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c
new file mode 100644
index 000000000000..7807a3e8c426
--- /dev/null
+++ b/arch/um/kernel/signal_kern.c
@@ -0,0 +1,213 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/stddef.h"
8#include "linux/sys.h"
9#include "linux/sched.h"
10#include "linux/wait.h"
11#include "linux/kernel.h"
12#include "linux/smp_lock.h"
13#include "linux/module.h"
14#include "linux/slab.h"
15#include "linux/tty.h"
16#include "linux/binfmts.h"
17#include "linux/ptrace.h"
18#include "asm/signal.h"
19#include "asm/uaccess.h"
20#include "asm/unistd.h"
21#include "user_util.h"
22#include "asm/ucontext.h"
23#include "kern_util.h"
24#include "signal_kern.h"
25#include "signal_user.h"
26#include "kern.h"
27#include "frame_kern.h"
28#include "sigcontext.h"
29#include "mode.h"
30
31EXPORT_SYMBOL(block_signals);
32EXPORT_SYMBOL(unblock_signals);
33
34#define _S(nr) (1<<((nr)-1))
35
36#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
37
38/*
39 * OK, we're invoking a handler
40 */
41static int handle_signal(struct pt_regs *regs, unsigned long signr,
42 struct k_sigaction *ka, siginfo_t *info,
43 sigset_t *oldset)
44{
45 unsigned long sp;
46 int err;
47
48 /* Always make any pending restarted system calls return -EINTR */
49 current_thread_info()->restart_block.fn = do_no_restart_syscall;
50
51 /* Did we come from a system call? */
52 if(PT_REGS_SYSCALL_NR(regs) >= 0){
53 /* If so, check system call restarting.. */
54 switch(PT_REGS_SYSCALL_RET(regs)){
55 case -ERESTART_RESTARTBLOCK:
56 case -ERESTARTNOHAND:
57 PT_REGS_SYSCALL_RET(regs) = -EINTR;
58 break;
59
60 case -ERESTARTSYS:
61 if (!(ka->sa.sa_flags & SA_RESTART)) {
62 PT_REGS_SYSCALL_RET(regs) = -EINTR;
63 break;
64 }
65 /* fallthrough */
66 case -ERESTARTNOINTR:
67 PT_REGS_RESTART_SYSCALL(regs);
68 PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
69 break;
70 }
71 }
72
73 sp = PT_REGS_SP(regs);
74 if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
75 sp = current->sas_ss_sp + current->sas_ss_size;
76
77#ifdef CONFIG_ARCH_HAS_SC_SIGNALS
78 if(!(ka->sa.sa_flags & SA_SIGINFO))
79 err = setup_signal_stack_sc(sp, signr, ka, regs, oldset);
80 else
81#endif
82 err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset);
83
84 if(err){
85 spin_lock_irq(&current->sighand->siglock);
86 current->blocked = *oldset;
87 recalc_sigpending();
88 spin_unlock_irq(&current->sighand->siglock);
89 force_sigsegv(signr, current);
90 }
91 else if(!(ka->sa.sa_flags & SA_NODEFER)){
92 spin_lock_irq(&current->sighand->siglock);
93 sigorsets(&current->blocked, &current->blocked,
94 &ka->sa.sa_mask);
95 sigaddset(&current->blocked, signr);
96 recalc_sigpending();
97 spin_unlock_irq(&current->sighand->siglock);
98 }
99
100 return err;
101}
102
103static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset)
104{
105 struct k_sigaction ka_copy;
106 siginfo_t info;
107 int sig, handled_sig = 0;
108
109 while((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0){
110 handled_sig = 1;
111 /* Whee! Actually deliver the signal. */
112 if(!handle_signal(regs, sig, &ka_copy, &info, oldset))
113 break;
114 }
115
116 /* Did we come from a system call? */
117 if(!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)){
118 /* Restart the system call - no handlers present */
119 if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND ||
120 PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS ||
121 PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){
122 PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
123 PT_REGS_RESTART_SYSCALL(regs);
124 }
125 else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){
126 PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall;
127 PT_REGS_RESTART_SYSCALL(regs);
128 }
129 }
130
131 /* This closes a way to execute a system call on the host. If
132 * you set a breakpoint on a system call instruction and singlestep
133 * from it, the tracing thread used to PTRACE_SINGLESTEP the process
134 * rather than PTRACE_SYSCALL it, allowing the system call to execute
135 * on the host. The tracing thread will check this flag and
136 * PTRACE_SYSCALL if necessary.
137 */
138 if(current->ptrace & PT_DTRACE)
139 current->thread.singlestep_syscall =
140 is_syscall(PT_REGS_IP(&current->thread.regs));
141 return(handled_sig);
142}
143
144int do_signal(void)
145{
146 return(kern_do_signal(&current->thread.regs, &current->blocked));
147}
148
149/*
150 * Atomically swap in the new signal mask, and wait for a signal.
151 */
152long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
153{
154 sigset_t saveset;
155
156 mask &= _BLOCKABLE;
157 spin_lock_irq(&current->sighand->siglock);
158 saveset = current->blocked;
159 siginitset(&current->blocked, mask);
160 recalc_sigpending();
161 spin_unlock_irq(&current->sighand->siglock);
162
163 PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
164 while (1) {
165 current->state = TASK_INTERRUPTIBLE;
166 schedule();
167 if(kern_do_signal(&current->thread.regs, &saveset))
168 return(-EINTR);
169 }
170}
171
172long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
173{
174 sigset_t saveset, newset;
175
176 /* XXX: Don't preclude handling different sized sigset_t's. */
177 if (sigsetsize != sizeof(sigset_t))
178 return -EINVAL;
179
180 if (copy_from_user(&newset, unewset, sizeof(newset)))
181 return -EFAULT;
182 sigdelsetmask(&newset, ~_BLOCKABLE);
183
184 spin_lock_irq(&current->sighand->siglock);
185 saveset = current->blocked;
186 current->blocked = newset;
187 recalc_sigpending();
188 spin_unlock_irq(&current->sighand->siglock);
189
190 PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
191 while (1) {
192 current->state = TASK_INTERRUPTIBLE;
193 schedule();
194 if (kern_do_signal(&current->thread.regs, &saveset))
195 return(-EINTR);
196 }
197}
198
199long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
200{
201 return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
202}
203
204/*
205 * Overrides for Emacs so that we follow Linus's tabbing style.
206 * Emacs will notice this stuff at the end of the file and automatically
207 * adjust the settings for this buffer only. This must remain at the end
208 * of the file.
209 * ---------------------------------------------------------------------------
210 * Local variables:
211 * c-file-style: "linux"
212 * End:
213 */
diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c
new file mode 100644
index 000000000000..62f457835fb1
--- /dev/null
+++ b/arch/um/kernel/signal_user.c
@@ -0,0 +1,157 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <unistd.h>
8#include <stdlib.h>
9#include <signal.h>
10#include <errno.h>
11#include <stdarg.h>
12#include <string.h>
13#include <sys/mman.h>
14#include "user_util.h"
15#include "kern_util.h"
16#include "user.h"
17#include "signal_user.h"
18#include "signal_kern.h"
19#include "sysdep/sigcontext.h"
20#include "sigcontext.h"
21
22void set_sigstack(void *sig_stack, int size)
23{
24 stack_t stack = ((stack_t) { .ss_flags = 0,
25 .ss_sp = (__ptr_t) sig_stack,
26 .ss_size = size - sizeof(void *) });
27
28 if(sigaltstack(&stack, NULL) != 0)
29 panic("enabling signal stack failed, errno = %d\n", errno);
30}
31
32void set_handler(int sig, void (*handler)(int), int flags, ...)
33{
34 struct sigaction action;
35 va_list ap;
36 int mask;
37
38 va_start(ap, flags);
39 action.sa_handler = handler;
40 sigemptyset(&action.sa_mask);
41 while((mask = va_arg(ap, int)) != -1){
42 sigaddset(&action.sa_mask, mask);
43 }
44 va_end(ap);
45 action.sa_flags = flags;
46 action.sa_restorer = NULL;
47 if(sigaction(sig, &action, NULL) < 0)
48 panic("sigaction failed");
49}
50
51int change_sig(int signal, int on)
52{
53 sigset_t sigset, old;
54
55 sigemptyset(&sigset);
56 sigaddset(&sigset, signal);
57 sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
58 return(!sigismember(&old, signal));
59}
60
61/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
62 * disable profiling; it's safe because the profiling code does not interact
63 * with the kernel code at all.*/
64
65static void change_signals(int type)
66{
67 sigset_t mask;
68
69 sigemptyset(&mask);
70 sigaddset(&mask, SIGVTALRM);
71 sigaddset(&mask, SIGALRM);
72 sigaddset(&mask, SIGIO);
73 if(sigprocmask(type, &mask, NULL) < 0)
74 panic("Failed to change signal mask - errno = %d", errno);
75}
76
77void block_signals(void)
78{
79 change_signals(SIG_BLOCK);
80}
81
82void unblock_signals(void)
83{
84 change_signals(SIG_UNBLOCK);
85}
86
87/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled
88 * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to
89 * be able to profile all of UML, not just the non-critical sections. If
90 * profiling is not thread-safe, then that is not my problem. We can disable
91 * profiling when SMP is enabled in that case.
92 */
93#define SIGIO_BIT 0
94#define SIGVTALRM_BIT 1
95
96static int enable_mask(sigset_t *mask)
97{
98 int sigs;
99
100 sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
101 sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
102 sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
103 return(sigs);
104}
105
106int get_signals(void)
107{
108 sigset_t mask;
109
110 if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
111 panic("Failed to get signal mask");
112 return(enable_mask(&mask));
113}
114
115int set_signals(int enable)
116{
117 sigset_t mask;
118 int ret;
119
120 sigemptyset(&mask);
121 if(enable & (1 << SIGIO_BIT))
122 sigaddset(&mask, SIGIO);
123 if(enable & (1 << SIGVTALRM_BIT)){
124 sigaddset(&mask, SIGVTALRM);
125 sigaddset(&mask, SIGALRM);
126 }
127
128 /* This is safe - sigprocmask is guaranteed to copy locally the
129 * value of new_set, do his work and then, at the end, write to
130 * old_set.
131 */
132 if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
133 panic("Failed to enable signals");
134 ret = enable_mask(&mask);
135 sigemptyset(&mask);
136 if((enable & (1 << SIGIO_BIT)) == 0)
137 sigaddset(&mask, SIGIO);
138 if((enable & (1 << SIGVTALRM_BIT)) == 0){
139 sigaddset(&mask, SIGVTALRM);
140 sigaddset(&mask, SIGALRM);
141 }
142 if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
143 panic("Failed to block signals");
144
145 return(ret);
146}
147
148/*
149 * Overrides for Emacs so that we follow Linus's tabbing style.
150 * Emacs will notice this stuff at the end of the file and automatically
151 * adjust the settings for this buffer only. This must remain at the end
152 * of the file.
153 * ---------------------------------------------------------------------------
154 * Local variables:
155 * c-file-style: "linux"
156 * End:
157 */
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
new file mode 100644
index 000000000000..d37d1bfcd6f7
--- /dev/null
+++ b/arch/um/kernel/skas/Makefile
@@ -0,0 +1,13 @@
1#
2# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
3# Licensed under the GPL
4#
5
6obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
7 syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o \
8
9subdir- := util
10
11USER_OBJS := process.o time.o
12
13include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
new file mode 100644
index 000000000000..c6b4d5dba789
--- /dev/null
+++ b/arch/um/kernel/skas/exec_kern.c
@@ -0,0 +1,41 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "asm/current.h"
8#include "asm/page.h"
9#include "asm/signal.h"
10#include "asm/ptrace.h"
11#include "asm/uaccess.h"
12#include "asm/mmu_context.h"
13#include "tlb.h"
14#include "skas.h"
15#include "um_mmu.h"
16#include "os.h"
17
18void flush_thread_skas(void)
19{
20 force_flush_all();
21 switch_mm_skas(current->mm->context.skas.mm_fd);
22}
23
24void start_thread_skas(struct pt_regs *regs, unsigned long eip,
25 unsigned long esp)
26{
27 set_fs(USER_DS);
28 PT_REGS_IP(regs) = eip;
29 PT_REGS_SP(regs) = esp;
30}
31
32/*
33 * Overrides for Emacs so that we follow Linus's tabbing style.
34 * Emacs will notice this stuff at the end of the file and automatically
35 * adjust the settings for this buffer only. This must remain at the end
36 * of the file.
37 * ---------------------------------------------------------------------------
38 * Local variables:
39 * c-file-style: "linux"
40 * End:
41 */
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
new file mode 100644
index 000000000000..4cd60d7213f3
--- /dev/null
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -0,0 +1,24 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_MMU_H
7#define __SKAS_MMU_H
8
9struct mmu_context_skas {
10 int mm_fd;
11};
12
13#endif
14
15/*
16 * Overrides for Emacs so that we follow Linus's tabbing style.
17 * Emacs will notice this stuff at the end of the file and automatically
18 * adjust the settings for this buffer only. This must remain at the end
19 * of the file.
20 * ---------------------------------------------------------------------------
21 * Local variables:
22 * c-file-style: "linux"
23 * End:
24 */
diff --git a/arch/um/kernel/skas/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h
new file mode 100644
index 000000000000..c1e33bd788db
--- /dev/null
+++ b/arch/um/kernel/skas/include/mode-skas.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MODE_SKAS_H__
7#define __MODE_SKAS_H__
8
9#include <sysdep/ptrace.h>
10
11extern unsigned long exec_regs[];
12extern unsigned long exec_fp_regs[];
13extern unsigned long exec_fpx_regs[];
14extern int have_fpx_regs;
15
16extern void user_time_init_skas(void);
17extern void sig_handler_common_skas(int sig, void *sc_ptr);
18extern void halt_skas(void);
19extern void reboot_skas(void);
20extern void kill_off_processes_skas(void);
21extern int is_skas_winch(int pid, int fd, void *data);
22
23#endif
24
25/*
26 * Overrides for Emacs so that we follow Linus's tabbing style.
27 * Emacs will notice this stuff at the end of the file and automatically
28 * adjust the settings for this buffer only. This must remain at the end
29 * of the file.
30 * ---------------------------------------------------------------------------
31 * Local variables:
32 * c-file-style: "linux"
33 * End:
34 */
diff --git a/arch/um/kernel/skas/include/mode_kern-skas.h b/arch/um/kernel/skas/include/mode_kern-skas.h
new file mode 100644
index 000000000000..94c564962378
--- /dev/null
+++ b/arch/um/kernel/skas/include/mode_kern-skas.h
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_MODE_KERN_H__
7#define __SKAS_MODE_KERN_H__
8
9#include "linux/sched.h"
10#include "asm/page.h"
11#include "asm/ptrace.h"
12
13extern void flush_thread_skas(void);
14extern void *switch_to_skas(void *prev, void *next);
15extern void start_thread_skas(struct pt_regs *regs, unsigned long eip,
16 unsigned long esp);
17extern int copy_thread_skas(int nr, unsigned long clone_flags,
18 unsigned long sp, unsigned long stack_top,
19 struct task_struct *p, struct pt_regs *regs);
20extern void release_thread_skas(struct task_struct *task);
21extern void exit_thread_skas(void);
22extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
23extern void init_idle_skas(void);
24extern void flush_tlb_kernel_range_skas(unsigned long start,
25 unsigned long end);
26extern void flush_tlb_kernel_vm_skas(void);
27extern void __flush_tlb_one_skas(unsigned long addr);
28extern void flush_tlb_range_skas(struct vm_area_struct *vma,
29 unsigned long start, unsigned long end);
30extern void flush_tlb_mm_skas(struct mm_struct *mm);
31extern void force_flush_all_skas(void);
32extern long execute_syscall_skas(void *r);
33extern void before_mem_skas(unsigned long unused);
34extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
35 unsigned long *task_size_out);
36extern int start_uml_skas(void);
37extern int external_pid_skas(struct task_struct *task);
38extern int thread_pid_skas(struct task_struct *task);
39
40#define kmem_end_skas (host_task_size - 1024 * 1024)
41
42#endif
43
44/*
45 * Overrides for Emacs so that we follow Linus's tabbing style.
46 * Emacs will notice this stuff at the end of the file and automatically
47 * adjust the settings for this buffer only. This must remain at the end
48 * of the file.
49 * ---------------------------------------------------------------------------
50 * Local variables:
51 * c-file-style: "linux"
52 * End:
53 */
diff --git a/arch/um/kernel/skas/include/proc_mm.h b/arch/um/kernel/skas/include/proc_mm.h
new file mode 100644
index 000000000000..cce61a679052
--- /dev/null
+++ b/arch/um/kernel/skas/include/proc_mm.h
@@ -0,0 +1,55 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_PROC_MM_H
7#define __SKAS_PROC_MM_H
8
9#define MM_MMAP 54
10#define MM_MUNMAP 55
11#define MM_MPROTECT 56
12#define MM_COPY_SEGMENTS 57
13
14struct mm_mmap {
15 unsigned long addr;
16 unsigned long len;
17 unsigned long prot;
18 unsigned long flags;
19 unsigned long fd;
20 unsigned long offset;
21};
22
23struct mm_munmap {
24 unsigned long addr;
25 unsigned long len;
26};
27
28struct mm_mprotect {
29 unsigned long addr;
30 unsigned long len;
31 unsigned int prot;
32};
33
34struct proc_mm_op {
35 int op;
36 union {
37 struct mm_mmap mmap;
38 struct mm_munmap munmap;
39 struct mm_mprotect mprotect;
40 int copy_segments;
41 } u;
42};
43
44#endif
45
46/*
47 * Overrides for Emacs so that we follow Linus's tabbing style.
48 * Emacs will notice this stuff at the end of the file and automatically
49 * adjust the settings for this buffer only. This must remain at the end
50 * of the file.
51 * ---------------------------------------------------------------------------
52 * Local variables:
53 * c-file-style: "linux"
54 * End:
55 */
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
new file mode 100644
index 000000000000..f0702c2c7204
--- /dev/null
+++ b/arch/um/kernel/skas/include/skas.h
@@ -0,0 +1,46 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_H
7#define __SKAS_H
8
9#include "sysdep/ptrace.h"
10
11extern int userspace_pid[];
12
13extern void switch_threads(void *me, void *next);
14extern void thread_wait(void *sw, void *fb);
15extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
16 void (*handler)(int));
17extern int start_idle_thread(void *stack, void *switch_buf_ptr,
18 void **fork_buf_ptr);
19extern int user_thread(unsigned long stack, int flags);
20extern void userspace(union uml_pt_regs *regs);
21extern void new_thread_proc(void *stack, void (*handler)(int sig));
22extern void remove_sigstack(void);
23extern void new_thread_handler(int sig);
24extern void handle_syscall(union uml_pt_regs *regs);
25extern void map(int fd, unsigned long virt, unsigned long len, int r, int w,
26 int x, int phys_fd, unsigned long long offset);
27extern int unmap(int fd, void *addr, unsigned long len);
28extern int protect(int fd, unsigned long addr, unsigned long len,
29 int r, int w, int x);
30extern void user_signal(int sig, union uml_pt_regs *regs);
31extern int new_mm(int from);
32extern void start_userspace(int cpu);
33extern long execute_syscall_skas(void *r);
34
35#endif
36
37/*
38 * Overrides for Emacs so that we follow Linus's tabbing style.
39 * Emacs will notice this stuff at the end of the file and automatically
40 * adjust the settings for this buffer only. This must remain at the end
41 * of the file.
42 * ---------------------------------------------------------------------------
43 * Local variables:
44 * c-file-style: "linux"
45 * End:
46 */
diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h
new file mode 100644
index 000000000000..11986c9b9ddf
--- /dev/null
+++ b/arch/um/kernel/skas/include/uaccess-skas.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_UACCESS_H
7#define __SKAS_UACCESS_H
8
9#include "asm/errno.h"
10#include "asm/fixmap.h"
11
12#define access_ok_skas(type, addr, size) \
13 ((segment_eq(get_fs(), KERNEL_DS)) || \
14 (((unsigned long) (addr) < TASK_SIZE) && \
15 ((unsigned long) (addr) + (size) <= TASK_SIZE)) || \
16 ((type == VERIFY_READ ) && \
17 ((unsigned long) (addr) >= FIXADDR_USER_START) && \
18 ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
19 ((unsigned long) (addr) + (size) >= (unsigned long)(addr))))
20
21static inline int verify_area_skas(int type, const void * addr,
22 unsigned long size)
23{
24 return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
25}
26
27extern int copy_from_user_skas(void *to, const void *from, int n);
28extern int copy_to_user_skas(void *to, const void *from, int n);
29extern int strncpy_from_user_skas(char *dst, const char *src, int count);
30extern int __clear_user_skas(void *mem, int len);
31extern int clear_user_skas(void *mem, int len);
32extern int strnlen_user_skas(const void *str, int len);
33
34#endif
35
36/*
37 * Overrides for Emacs so that we follow Linus's tabbing style.
38 * Emacs will notice this stuff at the end of the file and automatically
39 * adjust the settings for this buffer only. This must remain at the end
40 * of the file.
41 * ---------------------------------------------------------------------------
42 * Local variables:
43 * c-file-style: "linux"
44 * End:
45 */
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
new file mode 100644
index 000000000000..438db2f43456
--- /dev/null
+++ b/arch/um/kernel/skas/mem.c
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/mm.h"
8#include "mem_user.h"
9
10unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
11 unsigned long *task_size_out)
12{
13 /* Round up to the nearest 4M */
14 unsigned long top = ROUND_4M((unsigned long) &arg);
15
16#ifdef CONFIG_HOST_TASK_SIZE
17 *host_size_out = CONFIG_HOST_TASK_SIZE;
18 *task_size_out = CONFIG_HOST_TASK_SIZE;
19#else
20 *host_size_out = top;
21 *task_size_out = top;
22#endif
23 return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
24}
25
26/*
27 * Overrides for Emacs so that we follow Linus's tabbing style.
28 * Emacs will notice this stuff at the end of the file and automatically
29 * adjust the settings for this buffer only. This must remain at the end
30 * of the file.
31 * ---------------------------------------------------------------------------
32 * Local variables:
33 * c-file-style: "linux"
34 * End:
35 */
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
new file mode 100644
index 000000000000..1310bf1e88d1
--- /dev/null
+++ b/arch/um/kernel/skas/mem_user.c
@@ -0,0 +1,102 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <errno.h>
7#include <sys/mman.h>
8#include "mem_user.h"
9#include "mem.h"
10#include "user.h"
11#include "os.h"
12#include "proc_mm.h"
13
14void map(int fd, unsigned long virt, unsigned long len, int r, int w,
15 int x, int phys_fd, unsigned long long offset)
16{
17 struct proc_mm_op map;
18 int prot, n;
19
20 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
21 (x ? PROT_EXEC : 0);
22
23 map = ((struct proc_mm_op) { .op = MM_MMAP,
24 .u =
25 { .mmap =
26 { .addr = virt,
27 .len = len,
28 .prot = prot,
29 .flags = MAP_SHARED |
30 MAP_FIXED,
31 .fd = phys_fd,
32 .offset = offset
33 } } } );
34 n = os_write_file(fd, &map, sizeof(map));
35 if(n != sizeof(map))
36 printk("map : /proc/mm map failed, err = %d\n", -n);
37}
38
39int unmap(int fd, void *addr, unsigned long len)
40{
41 struct proc_mm_op unmap;
42 int n;
43
44 unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
45 .u =
46 { .munmap =
47 { .addr = (unsigned long) addr,
48 .len = len } } } );
49 n = os_write_file(fd, &unmap, sizeof(unmap));
50 if(n != sizeof(unmap)) {
51 if(n < 0)
52 return(n);
53 else if(n > 0)
54 return(-EIO);
55 }
56
57 return(0);
58}
59
60int protect(int fd, unsigned long addr, unsigned long len, int r, int w,
61 int x, int must_succeed)
62{
63 struct proc_mm_op protect;
64 int prot, n;
65
66 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
67 (x ? PROT_EXEC : 0);
68
69 protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
70 .u =
71 { .mprotect =
72 { .addr = (unsigned long) addr,
73 .len = len,
74 .prot = prot } } } );
75
76 n = os_write_file(fd, &protect, sizeof(protect));
77 if(n != sizeof(protect)) {
78 if(n == 0) return(0);
79
80 if(must_succeed)
81 panic("protect failed, err = %d", -n);
82
83 return(-EIO);
84 }
85
86 return(0);
87}
88
89void before_mem_skas(unsigned long unused)
90{
91}
92
93/*
94 * Overrides for Emacs so that we follow Linus's tabbing style.
95 * Emacs will notice this stuff at the end of the file and automatically
96 * adjust the settings for this buffer only. This must remain at the end
97 * of the file.
98 * ---------------------------------------------------------------------------
99 * Local variables:
100 * c-file-style: "linux"
101 * End:
102 */
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
new file mode 100644
index 000000000000..6cb9a6d028a9
--- /dev/null
+++ b/arch/um/kernel/skas/mmu.c
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/list.h"
8#include "linux/spinlock.h"
9#include "linux/slab.h"
10#include "asm/current.h"
11#include "asm/segment.h"
12#include "asm/mmu.h"
13#include "os.h"
14#include "skas.h"
15
16int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
17{
18 int from;
19
20 if((current->mm != NULL) && (current->mm != &init_mm))
21 from = current->mm->context.skas.mm_fd;
22 else from = -1;
23
24 mm->context.skas.mm_fd = new_mm(from);
25 if(mm->context.skas.mm_fd < 0){
26 printk("init_new_context_skas - new_mm failed, errno = %d\n",
27 mm->context.skas.mm_fd);
28 return(mm->context.skas.mm_fd);
29 }
30
31 return(0);
32}
33
34void destroy_context_skas(struct mm_struct *mm)
35{
36 os_close_file(mm->context.skas.mm_fd);
37}
38
39/*
40 * Overrides for Emacs so that we follow Linus's tabbing style.
41 * Emacs will notice this stuff at the end of the file and automatically
42 * adjust the settings for this buffer only. This must remain at the end
43 * of the file.
44 * ---------------------------------------------------------------------------
45 * Local variables:
46 * c-file-style: "linux"
47 * End:
48 */
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
new file mode 100644
index 000000000000..b4ffaaa81241
--- /dev/null
+++ b/arch/um/kernel/skas/process.c
@@ -0,0 +1,339 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <unistd.h>
8#include <errno.h>
9#include <signal.h>
10#include <setjmp.h>
11#include <sched.h>
12#include <sys/wait.h>
13#include <sys/mman.h>
14#include <sys/user.h>
15#include <asm/unistd.h>
16#include "user.h"
17#include "ptrace_user.h"
18#include "time_user.h"
19#include "sysdep/ptrace.h"
20#include "user_util.h"
21#include "kern_util.h"
22#include "skas.h"
23#include "sysdep/sigcontext.h"
24#include "os.h"
25#include "proc_mm.h"
26#include "skas_ptrace.h"
27#include "chan_user.h"
28#include "signal_user.h"
29#include "registers.h"
30
31int is_skas_winch(int pid, int fd, void *data)
32{
33 if(pid != os_getpid())
34 return(0);
35
36 register_winch_irq(-1, fd, -1, data);
37 return(1);
38}
39
40static void handle_segv(int pid)
41{
42 struct ptrace_faultinfo fault;
43 int err;
44
45 err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault);
46 if(err)
47 panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n",
48 errno);
49
50 segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
51}
52
53/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
54static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu)
55{
56 int err, status;
57
58 /* Mark this as a syscall */
59 UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs);
60
61 if (!local_using_sysemu)
62 {
63 err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
64 if(err < 0)
65 panic("handle_trap - nullifying syscall failed errno = %d\n",
66 errno);
67
68 err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
69 if(err < 0)
70 panic("handle_trap - continuing to end of syscall failed, "
71 "errno = %d\n", errno);
72
73 CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
74 if((err < 0) || !WIFSTOPPED(status) ||
75 (WSTOPSIG(status) != SIGTRAP + 0x80))
76 panic("handle_trap - failed to wait at end of syscall, "
77 "errno = %d, status = %d\n", errno, status);
78 }
79
80 handle_syscall(regs);
81}
82
83static int userspace_tramp(void *arg)
84{
85 init_new_thread_signals(0);
86 enable_timer();
87 ptrace(PTRACE_TRACEME, 0, 0, 0);
88 os_stop_process(os_getpid());
89 return(0);
90}
91
92/* Each element set once, and only accessed by a single processor anyway */
93#undef NR_CPUS
94#define NR_CPUS 1
95int userspace_pid[NR_CPUS];
96
97void start_userspace(int cpu)
98{
99 void *stack;
100 unsigned long sp;
101 int pid, status, n;
102
103 stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
104 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
105 if(stack == MAP_FAILED)
106 panic("start_userspace : mmap failed, errno = %d", errno);
107 sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
108
109 pid = clone(userspace_tramp, (void *) sp,
110 CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
111 if(pid < 0)
112 panic("start_userspace : clone failed, errno = %d", errno);
113
114 do {
115 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
116 if(n < 0)
117 panic("start_userspace : wait failed, errno = %d",
118 errno);
119 } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
120
121 if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
122 panic("start_userspace : expected SIGSTOP, got status = %d",
123 status);
124
125 if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, (void *)PTRACE_O_TRACESYSGOOD) < 0)
126 panic("start_userspace : PTRACE_SETOPTIONS failed, errno=%d\n",
127 errno);
128
129 if(munmap(stack, PAGE_SIZE) < 0)
130 panic("start_userspace : munmap failed, errno = %d\n", errno);
131
132 userspace_pid[cpu] = pid;
133}
134
135void userspace(union uml_pt_regs *regs)
136{
137 int err, status, op, pid = userspace_pid[0];
138 int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
139
140 while(1){
141 restore_registers(pid, regs);
142
143 /* Now we set local_using_sysemu to be used for one loop */
144 local_using_sysemu = get_using_sysemu();
145
146 op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
147
148 err = ptrace(op, pid, 0, 0);
149 if(err)
150 panic("userspace - could not resume userspace process, "
151 "pid=%d, ptrace operation = %d, errno = %d\n",
152 op, errno);
153
154 CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
155 if(err < 0)
156 panic("userspace - waitpid failed, errno = %d\n",
157 errno);
158
159 regs->skas.is_user = 1;
160 save_registers(pid, regs);
161 UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
162
163 if(WIFSTOPPED(status)){
164 switch(WSTOPSIG(status)){
165 case SIGSEGV:
166 handle_segv(pid);
167 break;
168 case SIGTRAP + 0x80:
169 handle_trap(pid, regs, local_using_sysemu);
170 break;
171 case SIGTRAP:
172 relay_signal(SIGTRAP, regs);
173 break;
174 case SIGIO:
175 case SIGVTALRM:
176 case SIGILL:
177 case SIGBUS:
178 case SIGFPE:
179 case SIGWINCH:
180 user_signal(WSTOPSIG(status), regs);
181 break;
182 default:
183 printk("userspace - child stopped with signal "
184 "%d\n", WSTOPSIG(status));
185 }
186 interrupt_end();
187
188 /* Avoid -ERESTARTSYS handling in host */
189 PT_SYSCALL_NR(regs->skas.regs) = -1;
190 }
191 }
192}
193
194void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
195 void (*handler)(int))
196{
197 unsigned long flags;
198 sigjmp_buf switch_buf, fork_buf;
199
200 *switch_buf_ptr = &switch_buf;
201 *fork_buf_ptr = &fork_buf;
202
203 /* Somewhat subtle - siglongjmp restores the signal mask before doing
204 * the longjmp. This means that when jumping from one stack to another
205 * when the target stack has interrupts enabled, an interrupt may occur
206 * on the source stack. This is bad when starting up a process because
207 * it's not supposed to get timer ticks until it has been scheduled.
208 * So, we disable interrupts around the sigsetjmp to ensure that
209 * they can't happen until we get back here where they are safe.
210 */
211 flags = get_signals();
212 block_signals();
213 if(sigsetjmp(fork_buf, 1) == 0)
214 new_thread_proc(stack, handler);
215
216 remove_sigstack();
217
218 set_signals(flags);
219}
220
221void thread_wait(void *sw, void *fb)
222{
223 sigjmp_buf buf, **switch_buf = sw, *fork_buf;
224
225 *switch_buf = &buf;
226 fork_buf = fb;
227 if(sigsetjmp(buf, 1) == 0)
228 siglongjmp(*fork_buf, 1);
229}
230
231void switch_threads(void *me, void *next)
232{
233 sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
234
235 *me_ptr = &my_buf;
236 if(sigsetjmp(my_buf, 1) == 0)
237 siglongjmp(*next_buf, 1);
238}
239
240static sigjmp_buf initial_jmpbuf;
241
242/* XXX Make these percpu */
243static void (*cb_proc)(void *arg);
244static void *cb_arg;
245static sigjmp_buf *cb_back;
246
247int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
248{
249 sigjmp_buf **switch_buf = switch_buf_ptr;
250 int n;
251
252 *fork_buf_ptr = &initial_jmpbuf;
253 n = sigsetjmp(initial_jmpbuf, 1);
254 if(n == 0)
255 new_thread_proc((void *) stack, new_thread_handler);
256 else if(n == 1)
257 remove_sigstack();
258 else if(n == 2){
259 (*cb_proc)(cb_arg);
260 siglongjmp(*cb_back, 1);
261 }
262 else if(n == 3){
263 kmalloc_ok = 0;
264 return(0);
265 }
266 else if(n == 4){
267 kmalloc_ok = 0;
268 return(1);
269 }
270 siglongjmp(**switch_buf, 1);
271}
272
273void remove_sigstack(void)
274{
275 stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
276 .ss_sp = NULL,
277 .ss_size = 0 });
278
279 if(sigaltstack(&stack, NULL) != 0)
280 panic("disabling signal stack failed, errno = %d\n", errno);
281}
282
283void initial_thread_cb_skas(void (*proc)(void *), void *arg)
284{
285 sigjmp_buf here;
286
287 cb_proc = proc;
288 cb_arg = arg;
289 cb_back = &here;
290
291 block_signals();
292 if(sigsetjmp(here, 1) == 0)
293 siglongjmp(initial_jmpbuf, 2);
294 unblock_signals();
295
296 cb_proc = NULL;
297 cb_arg = NULL;
298 cb_back = NULL;
299}
300
301void halt_skas(void)
302{
303 block_signals();
304 siglongjmp(initial_jmpbuf, 3);
305}
306
307void reboot_skas(void)
308{
309 block_signals();
310 siglongjmp(initial_jmpbuf, 4);
311}
312
313void switch_mm_skas(int mm_fd)
314{
315 int err;
316
317#warning need cpu pid in switch_mm_skas
318 err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
319 if(err)
320 panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
321 errno);
322}
323
324void kill_off_processes_skas(void)
325{
326#warning need to loop over userspace_pids in kill_off_processes_skas
327 os_kill_ptraced_process(userspace_pid[0], 1);
328}
329
330/*
331 * Overrides for Emacs so that we follow Linus's tabbing style.
332 * Emacs will notice this stuff at the end of the file and automatically
333 * adjust the settings for this buffer only. This must remain at the end
334 * of the file.
335 * ---------------------------------------------------------------------------
336 * Local variables:
337 * c-file-style: "linux"
338 * End:
339 */
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
new file mode 100644
index 000000000000..5d096ea63b97
--- /dev/null
+++ b/arch/um/kernel/skas/process_kern.c
@@ -0,0 +1,213 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/slab.h"
8#include "linux/ptrace.h"
9#include "linux/proc_fs.h"
10#include "linux/file.h"
11#include "linux/errno.h"
12#include "linux/init.h"
13#include "asm/uaccess.h"
14#include "asm/atomic.h"
15#include "kern_util.h"
16#include "time_user.h"
17#include "signal_user.h"
18#include "skas.h"
19#include "os.h"
20#include "user_util.h"
21#include "tlb.h"
22#include "kern.h"
23#include "mode.h"
24#include "proc_mm.h"
25#include "registers.h"
26
27void *switch_to_skas(void *prev, void *next)
28{
29 struct task_struct *from, *to;
30
31 from = prev;
32 to = next;
33
34 /* XXX need to check runqueues[cpu].idle */
35 if(current->pid == 0)
36 switch_timers(0);
37
38 to->thread.prev_sched = from;
39 set_current(to);
40
41 switch_threads(&from->thread.mode.skas.switch_buf,
42 to->thread.mode.skas.switch_buf);
43
44 if(current->pid == 0)
45 switch_timers(1);
46
47 return(current->thread.prev_sched);
48}
49
50extern void schedule_tail(struct task_struct *prev);
51
52void new_thread_handler(int sig)
53{
54 int (*fn)(void *), n;
55 void *arg;
56
57 fn = current->thread.request.u.thread.proc;
58 arg = current->thread.request.u.thread.arg;
59 change_sig(SIGUSR1, 1);
60 thread_wait(&current->thread.mode.skas.switch_buf,
61 current->thread.mode.skas.fork_buf);
62
63 if(current->thread.prev_sched != NULL)
64 schedule_tail(current->thread.prev_sched);
65 current->thread.prev_sched = NULL;
66
67 /* The return value is 1 if the kernel thread execs a process,
68 * 0 if it just exits
69 */
70 n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
71 if(n == 1)
72 userspace(&current->thread.regs.regs);
73 else do_exit(0);
74}
75
76void new_thread_proc(void *stack, void (*handler)(int sig))
77{
78 init_new_thread_stack(stack, handler);
79 os_usr1_process(os_getpid());
80}
81
82void release_thread_skas(struct task_struct *task)
83{
84}
85
86void exit_thread_skas(void)
87{
88}
89
90void fork_handler(int sig)
91{
92 change_sig(SIGUSR1, 1);
93 thread_wait(&current->thread.mode.skas.switch_buf,
94 current->thread.mode.skas.fork_buf);
95
96 force_flush_all();
97 if(current->thread.prev_sched == NULL)
98 panic("blech");
99
100 schedule_tail(current->thread.prev_sched);
101 current->thread.prev_sched = NULL;
102
103 userspace(&current->thread.regs.regs);
104}
105
106int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
107 unsigned long stack_top, struct task_struct * p,
108 struct pt_regs *regs)
109{
110 void (*handler)(int);
111
112 if(current->thread.forking){
113 memcpy(&p->thread.regs.regs.skas,
114 &current->thread.regs.regs.skas,
115 sizeof(p->thread.regs.regs.skas));
116 REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
117 if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
118
119 handler = fork_handler;
120 }
121 else {
122 init_thread_registers(&p->thread.regs.regs);
123 p->thread.request.u.thread = current->thread.request.u.thread;
124 handler = new_thread_handler;
125 }
126
127 new_thread(p->thread_info, &p->thread.mode.skas.switch_buf,
128 &p->thread.mode.skas.fork_buf, handler);
129 return(0);
130}
131
132int new_mm(int from)
133{
134 struct proc_mm_op copy;
135 int n, fd;
136
137 fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
138 if(fd < 0)
139 return(fd);
140
141 if(from != -1){
142 copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS,
143 .u =
144 { .copy_segments = from } } );
145 n = os_write_file(fd, &copy, sizeof(copy));
146 if(n != sizeof(copy))
147 printk("new_mm : /proc/mm copy_segments failed, "
148 "err = %d\n", -n);
149 }
150
151 return(fd);
152}
153
154void init_idle_skas(void)
155{
156 cpu_tasks[current_thread->cpu].pid = os_getpid();
157 default_idle();
158}
159
160extern void start_kernel(void);
161
162static int start_kernel_proc(void *unused)
163{
164 int pid;
165
166 block_signals();
167 pid = os_getpid();
168
169 cpu_tasks[0].pid = pid;
170 cpu_tasks[0].task = current;
171#ifdef CONFIG_SMP
172 cpu_online_map = cpumask_of_cpu(0);
173#endif
174 start_kernel();
175 return(0);
176}
177
178int start_uml_skas(void)
179{
180 start_userspace(0);
181
182 init_new_thread_signals(1);
183 uml_idle_timer();
184
185 init_task.thread.request.u.thread.proc = start_kernel_proc;
186 init_task.thread.request.u.thread.arg = NULL;
187 return(start_idle_thread(init_task.thread_info,
188 &init_task.thread.mode.skas.switch_buf,
189 &init_task.thread.mode.skas.fork_buf));
190}
191
192int external_pid_skas(struct task_struct *task)
193{
194#warning Need to look up userspace_pid by cpu
195 return(userspace_pid[0]);
196}
197
198int thread_pid_skas(struct task_struct *task)
199{
200#warning Need to look up userspace_pid by cpu
201 return(userspace_pid[0]);
202}
203
204/*
205 * Overrides for Emacs so that we follow Linus's tabbing style.
206 * Emacs will notice this stuff at the end of the file and automatically
207 * adjust the settings for this buffer only. This must remain at the end
208 * of the file.
209 * ---------------------------------------------------------------------------
210 * Local variables:
211 * c-file-style: "linux"
212 * End:
213 */
diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c
new file mode 100644
index 000000000000..bdf040ce5b8e
--- /dev/null
+++ b/arch/um/kernel/skas/syscall_kern.c
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sys.h"
7#include "linux/ptrace.h"
8#include "asm/errno.h"
9#include "asm/unistd.h"
10#include "asm/ptrace.h"
11#include "asm/current.h"
12#include "sysdep/syscalls.h"
13#include "kern_util.h"
14
15extern syscall_handler_t *sys_call_table[];
16
17long execute_syscall_skas(void *r)
18{
19 struct pt_regs *regs = r;
20 long res;
21 int syscall;
22
23 current->thread.nsyscalls++;
24 nsyscalls++;
25 syscall = UPT_SYSCALL_NR(&regs->regs);
26
27 if((syscall >= NR_syscalls) || (syscall < 0))
28 res = -ENOSYS;
29 else res = EXECUTE_SYSCALL(syscall, regs);
30
31 return(res);
32}
33
34/*
35 * Overrides for Emacs so that we follow Linus's tabbing style.
36 * Emacs will notice this stuff at the end of the file and automatically
37 * adjust the settings for this buffer only. This must remain at the end
38 * of the file.
39 * ---------------------------------------------------------------------------
40 * Local variables:
41 * c-file-style: "linux"
42 * End:
43 */
diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c
new file mode 100644
index 000000000000..2828e6e37721
--- /dev/null
+++ b/arch/um/kernel/skas/syscall_user.c
@@ -0,0 +1,44 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <signal.h>
8#include "kern_util.h"
9#include "uml-config.h"
10#include "syscall_user.h"
11#include "sysdep/ptrace.h"
12#include "sysdep/sigcontext.h"
13#include "skas.h"
14
15void handle_syscall(union uml_pt_regs *regs)
16{
17 long result;
18#if UML_CONFIG_SYSCALL_DEBUG
19 int index;
20
21 index = record_syscall_start(UPT_SYSCALL_NR(regs));
22#endif
23
24 syscall_trace(regs, 0);
25 result = execute_syscall_skas(regs);
26
27 REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
28
29 syscall_trace(regs, 1);
30#if UML_CONFIG_SYSCALL_DEBUG
31 record_syscall_end(index, result);
32#endif
33}
34
35/*
36 * Overrides for Emacs so that we follow Linus's tabbing style.
37 * Emacs will notice this stuff at the end of the file and automatically
38 * adjust the settings for this buffer only. This must remain at the end
39 * of the file.
40 * ---------------------------------------------------------------------------
41 * Local variables:
42 * c-file-style: "linux"
43 * End:
44 */
diff --git a/arch/um/kernel/skas/time.c b/arch/um/kernel/skas/time.c
new file mode 100644
index 000000000000..98091494b897
--- /dev/null
+++ b/arch/um/kernel/skas/time.c
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <sys/signal.h>
7#include <sys/time.h>
8#include "time_user.h"
9#include "process.h"
10#include "user.h"
11
12void user_time_init_skas(void)
13{
14 if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
15 panic("Couldn't set SIGALRM handler");
16 if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
17 panic("Couldn't set SIGVTALRM handler");
18 set_interval(ITIMER_VIRTUAL);
19}
20
21/*
22 * Overrides for Emacs so that we follow Linus's tabbing style.
23 * Emacs will notice this stuff at the end of the file and automatically
24 * adjust the settings for this buffer only. This must remain at the end
25 * of the file.
26 * ---------------------------------------------------------------------------
27 * Local variables:
28 * c-file-style: "linux"
29 * End:
30 */
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
new file mode 100644
index 000000000000..b8c5e71763d1
--- /dev/null
+++ b/arch/um/kernel/skas/tlb.c
@@ -0,0 +1,85 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Copyright 2003 PathScale, Inc.
4 * Licensed under the GPL
5 */
6
7#include "linux/stddef.h"
8#include "linux/sched.h"
9#include "linux/mm.h"
10#include "asm/page.h"
11#include "asm/pgtable.h"
12#include "asm/mmu.h"
13#include "user_util.h"
14#include "mem_user.h"
15#include "mem.h"
16#include "skas.h"
17#include "os.h"
18#include "tlb.h"
19
20static void do_ops(int fd, struct host_vm_op *ops, int last)
21{
22 struct host_vm_op *op;
23 int i;
24
25 for(i = 0; i <= last; i++){
26 op = &ops[i];
27 switch(op->type){
28 case MMAP:
29 map(fd, op->u.mmap.addr, op->u.mmap.len,
30 op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
31 op->u.mmap.fd, op->u.mmap.offset);
32 break;
33 case MUNMAP:
34 unmap(fd, (void *) op->u.munmap.addr,
35 op->u.munmap.len);
36 break;
37 case MPROTECT:
38 protect(fd, op->u.mprotect.addr, op->u.mprotect.len,
39 op->u.mprotect.r, op->u.mprotect.w,
40 op->u.mprotect.x);
41 break;
42 default:
43 printk("Unknown op type %d in do_ops\n", op->type);
44 break;
45 }
46 }
47}
48
49static void fix_range(struct mm_struct *mm, unsigned long start_addr,
50 unsigned long end_addr, int force)
51{
52 int fd = mm->context.skas.mm_fd;
53
54 fix_range_common(mm, start_addr, end_addr, force, fd, do_ops);
55}
56
57void __flush_tlb_one_skas(unsigned long addr)
58{
59 flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE);
60}
61
62void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start,
63 unsigned long end)
64{
65 if(vma->vm_mm == NULL)
66 flush_tlb_kernel_range_common(start, end);
67 else fix_range(vma->vm_mm, start, end, 0);
68}
69
70void flush_tlb_mm_skas(struct mm_struct *mm)
71{
72 /* Don't bother flushing if this address space is about to be
73 * destroyed.
74 */
75 if(atomic_read(&mm->mm_users) == 0)
76 return;
77
78 fix_range(mm, 0, host_task_size, 0);
79 flush_tlb_kernel_range_common(start_vm, end_vm);
80}
81
82void force_flush_all_skas(void)
83{
84 fix_range(current->mm, 0, host_task_size, 1);
85}
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c
new file mode 100644
index 000000000000..8e9b46d4702e
--- /dev/null
+++ b/arch/um/kernel/skas/trap_user.c
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <signal.h>
7#include <errno.h>
8#include "sysdep/ptrace.h"
9#include "signal_user.h"
10#include "user_util.h"
11#include "kern_util.h"
12#include "task.h"
13#include "sigcontext.h"
14
15void sig_handler_common_skas(int sig, void *sc_ptr)
16{
17 struct sigcontext *sc = sc_ptr;
18 struct skas_regs *r;
19 struct signal_info *info;
20 int save_errno = errno;
21 int save_user;
22
23 /* This is done because to allow SIGSEGV to be delivered inside a SEGV
24 * handler. This can happen in copy_user, and if SEGV is disabled,
25 * the process will die.
26 * XXX Figure out why this is better than SA_NODEFER
27 */
28 if(sig == SIGSEGV)
29 change_sig(SIGSEGV, 1);
30
31 r = &TASK_REGS(get_current())->skas;
32 save_user = r->is_user;
33 r->is_user = 0;
34 r->fault_addr = SC_FAULT_ADDR(sc);
35 r->fault_type = SC_FAULT_TYPE(sc);
36 r->trap_type = SC_TRAP_TYPE(sc);
37
38 change_sig(SIGUSR1, 1);
39 info = &sig_info[sig];
40 if(!info->is_irq) unblock_signals();
41
42 (*info->handler)(sig, (union uml_pt_regs *) r);
43
44 errno = save_errno;
45 r->is_user = save_user;
46}
47
48void user_signal(int sig, union uml_pt_regs *regs)
49{
50 struct signal_info *info;
51
52 regs->skas.is_user = 1;
53 regs->skas.fault_addr = 0;
54 regs->skas.fault_type = 0;
55 regs->skas.trap_type = 0;
56 info = &sig_info[sig];
57 (*info->handler)(sig, regs);
58
59 unblock_signals();
60}
61
62/*
63 * Overrides for Emacs so that we follow Linus's tabbing style.
64 * Emacs will notice this stuff at the end of the file and automatically
65 * adjust the settings for this buffer only. This must remain at the end
66 * of the file.
67 * ---------------------------------------------------------------------------
68 * Local variables:
69 * c-file-style: "linux"
70 * End:
71 */
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
new file mode 100644
index 000000000000..7575ec489b63
--- /dev/null
+++ b/arch/um/kernel/skas/uaccess.c
@@ -0,0 +1,259 @@
1/*
2 * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/stddef.h"
7#include "linux/kernel.h"
8#include "linux/string.h"
9#include "linux/fs.h"
10#include "linux/highmem.h"
11#include "asm/page.h"
12#include "asm/pgtable.h"
13#include "asm/uaccess.h"
14#include "kern_util.h"
15#include "user_util.h"
16
17extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
18 pte_t *pte_out);
19
20static unsigned long maybe_map(unsigned long virt, int is_write)
21{
22 pte_t pte;
23 int err;
24
25 void *phys = um_virt_to_phys(current, virt, &pte);
26 int dummy_code;
27
28 if(IS_ERR(phys) || (is_write && !pte_write(pte))){
29 err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
30 if(err)
31 return(0);
32 phys = um_virt_to_phys(current, virt, NULL);
33 }
34 return((unsigned long) phys);
35}
36
37static int do_op(unsigned long addr, int len, int is_write,
38 int (*op)(unsigned long addr, int len, void *arg), void *arg)
39{
40 struct page *page;
41 int n;
42
43 addr = maybe_map(addr, is_write);
44 if(addr == -1)
45 return(-1);
46
47 page = phys_to_page(addr);
48 addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK);
49 n = (*op)(addr, len, arg);
50 kunmap(page);
51
52 return(n);
53}
54
55static void do_buffer_op(void *jmpbuf, void *arg_ptr)
56{
57 va_list args;
58 unsigned long addr;
59 int len, is_write, size, remain, n;
60 int (*op)(unsigned long, int, void *);
61 void *arg;
62 int *res;
63
64 /* Some old gccs recognize __va_copy, but not va_copy */
65 __va_copy(args, *(va_list *)arg_ptr);
66 addr = va_arg(args, unsigned long);
67 len = va_arg(args, int);
68 is_write = va_arg(args, int);
69 op = va_arg(args, void *);
70 arg = va_arg(args, void *);
71 res = va_arg(args, int *);
72 va_end(args);
73 size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
74 remain = len;
75
76 current->thread.fault_catcher = jmpbuf;
77 n = do_op(addr, size, is_write, op, arg);
78 if(n != 0){
79 *res = (n < 0 ? remain : 0);
80 goto out;
81 }
82
83 addr += size;
84 remain -= size;
85 if(remain == 0){
86 *res = 0;
87 goto out;
88 }
89
90 while(addr < ((addr + remain) & PAGE_MASK)){
91 n = do_op(addr, PAGE_SIZE, is_write, op, arg);
92 if(n != 0){
93 *res = (n < 0 ? remain : 0);
94 goto out;
95 }
96
97 addr += PAGE_SIZE;
98 remain -= PAGE_SIZE;
99 }
100 if(remain == 0){
101 *res = 0;
102 goto out;
103 }
104
105 n = do_op(addr, remain, is_write, op, arg);
106 if(n != 0)
107 *res = (n < 0 ? remain : 0);
108 else *res = 0;
109 out:
110 current->thread.fault_catcher = NULL;
111}
112
113static int buffer_op(unsigned long addr, int len, int is_write,
114 int (*op)(unsigned long addr, int len, void *arg),
115 void *arg)
116{
117 int faulted, res;
118
119 faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg,
120 &res);
121 if(!faulted)
122 return(res);
123
124 return(addr + len - (unsigned long) current->thread.fault_addr);
125}
126
127static int copy_chunk_from_user(unsigned long from, int len, void *arg)
128{
129 unsigned long *to_ptr = arg, to = *to_ptr;
130
131 memcpy((void *) to, (void *) from, len);
132 *to_ptr += len;
133 return(0);
134}
135
136int copy_from_user_skas(void *to, const void __user *from, int n)
137{
138 if(segment_eq(get_fs(), KERNEL_DS)){
139 memcpy(to, (__force void*)from, n);
140 return(0);
141 }
142
143 return(access_ok_skas(VERIFY_READ, from, n) ?
144 buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
145 n);
146}
147
148static int copy_chunk_to_user(unsigned long to, int len, void *arg)
149{
150 unsigned long *from_ptr = arg, from = *from_ptr;
151
152 memcpy((void *) to, (void *) from, len);
153 *from_ptr += len;
154 return(0);
155}
156
157int copy_to_user_skas(void __user *to, const void *from, int n)
158{
159 if(segment_eq(get_fs(), KERNEL_DS)){
160 memcpy((__force void*)to, from, n);
161 return(0);
162 }
163
164 return(access_ok_skas(VERIFY_WRITE, to, n) ?
165 buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
166 n);
167}
168
169static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
170{
171 char **to_ptr = arg, *to = *to_ptr;
172 int n;
173
174 strncpy(to, (void *) from, len);
175 n = strnlen(to, len);
176 *to_ptr += n;
177
178 if(n < len)
179 return(1);
180 return(0);
181}
182
183int strncpy_from_user_skas(char *dst, const char __user *src, int count)
184{
185 int n;
186 char *ptr = dst;
187
188 if(segment_eq(get_fs(), KERNEL_DS)){
189 strncpy(dst, (__force void*)src, count);
190 return(strnlen(dst, count));
191 }
192
193 if(!access_ok_skas(VERIFY_READ, src, 1))
194 return(-EFAULT);
195
196 n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
197 &ptr);
198 if(n != 0)
199 return(-EFAULT);
200 return(strnlen(dst, count));
201}
202
203static int clear_chunk(unsigned long addr, int len, void *unused)
204{
205 memset((void *) addr, 0, len);
206 return(0);
207}
208
209int __clear_user_skas(void __user *mem, int len)
210{
211 return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL));
212}
213
214int clear_user_skas(void __user *mem, int len)
215{
216 if(segment_eq(get_fs(), KERNEL_DS)){
217 memset((__force void*)mem, 0, len);
218 return(0);
219 }
220
221 return(access_ok_skas(VERIFY_WRITE, mem, len) ?
222 buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
223}
224
225static int strnlen_chunk(unsigned long str, int len, void *arg)
226{
227 int *len_ptr = arg, n;
228
229 n = strnlen((void *) str, len);
230 *len_ptr += n;
231
232 if(n < len)
233 return(1);
234 return(0);
235}
236
237int strnlen_user_skas(const void __user *str, int len)
238{
239 int count = 0, n;
240
241 if(segment_eq(get_fs(), KERNEL_DS))
242 return(strnlen((__force char*)str, len) + 1);
243
244 n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
245 if(n == 0)
246 return(count + 1);
247 return(-EFAULT);
248}
249
250/*
251 * Overrides for Emacs so that we follow Linus's tabbing style.
252 * Emacs will notice this stuff at the end of the file and automatically
253 * adjust the settings for this buffer only. This must remain at the end
254 * of the file.
255 * ---------------------------------------------------------------------------
256 * Local variables:
257 * c-file-style: "linux"
258 * End:
259 */
diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile
new file mode 100644
index 000000000000..17f5909d60f7
--- /dev/null
+++ b/arch/um/kernel/skas/util/Makefile
@@ -0,0 +1,4 @@
1hostprogs-y := mk_ptregs
2always := $(hostprogs-y)
3
4mk_ptregs-objs := mk_ptregs-$(SUBARCH).o
diff --git a/arch/um/kernel/skas/util/mk_ptregs-i386.c b/arch/um/kernel/skas/util/mk_ptregs-i386.c
new file mode 100644
index 000000000000..0788dd05bcac
--- /dev/null
+++ b/arch/um/kernel/skas/util/mk_ptregs-i386.c
@@ -0,0 +1,51 @@
1#include <stdio.h>
2#include <asm/ptrace.h>
3#include <asm/user.h>
4
5#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val))
6
7int main(int argc, char **argv)
8{
9 printf("/* Automatically generated by "
10 "arch/um/kernel/skas/util/mk_ptregs */\n");
11 printf("\n");
12 printf("#ifndef __SKAS_PT_REGS_\n");
13 printf("#define __SKAS_PT_REGS_\n");
14 printf("\n");
15 printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE);
16 printf("#define HOST_FP_SIZE %d\n",
17 sizeof(struct user_i387_struct) / sizeof(unsigned long));
18 printf("#define HOST_XFP_SIZE %d\n",
19 sizeof(struct user_fxsr_struct) / sizeof(unsigned long));
20
21 PRINT_REG("IP", EIP);
22 PRINT_REG("SP", UESP);
23 PRINT_REG("EFLAGS", EFL);
24 PRINT_REG("EAX", EAX);
25 PRINT_REG("EBX", EBX);
26 PRINT_REG("ECX", ECX);
27 PRINT_REG("EDX", EDX);
28 PRINT_REG("ESI", ESI);
29 PRINT_REG("EDI", EDI);
30 PRINT_REG("EBP", EBP);
31 PRINT_REG("CS", CS);
32 PRINT_REG("SS", SS);
33 PRINT_REG("DS", DS);
34 PRINT_REG("FS", FS);
35 PRINT_REG("ES", ES);
36 PRINT_REG("GS", GS);
37 printf("\n");
38 printf("#endif\n");
39 return(0);
40}
41
42/*
43 * Overrides for Emacs so that we follow Linus's tabbing style.
44 * Emacs will notice this stuff at the end of the file and automatically
45 * adjust the settings for this buffer only. This must remain at the end
46 * of the file.
47 * ---------------------------------------------------------------------------
48 * Local variables:
49 * c-file-style: "linux"
50 * End:
51 */
diff --git a/arch/um/kernel/skas/util/mk_ptregs-x86_64.c b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
new file mode 100644
index 000000000000..67aee92a70ef
--- /dev/null
+++ b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
@@ -0,0 +1,68 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#include <stdio.h>
8#define __FRAME_OFFSETS
9#include <asm/ptrace.h>
10
11#define PRINT_REG(name, val) \
12 printf("#define HOST_%s (%d / sizeof(unsigned long))\n", (name), (val))
13
14int main(int argc, char **argv)
15{
16 printf("/* Automatically generated by "
17 "arch/um/kernel/skas/util/mk_ptregs */\n");
18 printf("\n");
19 printf("#ifndef __SKAS_PT_REGS_\n");
20 printf("#define __SKAS_PT_REGS_\n");
21 printf("#define HOST_FRAME_SIZE (%d / sizeof(unsigned long))\n",
22 FRAME_SIZE);
23 PRINT_REG("RBX", RBX);
24 PRINT_REG("RCX", RCX);
25 PRINT_REG("RDI", RDI);
26 PRINT_REG("RSI", RSI);
27 PRINT_REG("RDX", RDX);
28 PRINT_REG("RBP", RBP);
29 PRINT_REG("RAX", RAX);
30 PRINT_REG("R8", R8);
31 PRINT_REG("R9", R9);
32 PRINT_REG("R10", R10);
33 PRINT_REG("R11", R11);
34 PRINT_REG("R12", R12);
35 PRINT_REG("R13", R13);
36 PRINT_REG("R14", R14);
37 PRINT_REG("R15", R15);
38 PRINT_REG("ORIG_RAX", ORIG_RAX);
39 PRINT_REG("CS", CS);
40 PRINT_REG("SS", SS);
41 PRINT_REG("EFLAGS", EFLAGS);
42#if 0
43 PRINT_REG("FS", FS);
44 PRINT_REG("GS", GS);
45 PRINT_REG("DS", DS);
46 PRINT_REG("ES", ES);
47#endif
48
49 PRINT_REG("IP", RIP);
50 PRINT_REG("SP", RSP);
51 printf("#define HOST_FP_SIZE 0\n");
52 printf("#define HOST_XFP_SIZE 0\n");
53 printf("\n");
54 printf("\n");
55 printf("#endif\n");
56 return(0);
57}
58
59/*
60 * Overrides for Emacs so that we follow Linus's tabbing style.
61 * Emacs will notice this stuff at the end of the file and automatically
62 * adjust the settings for this buffer only. This must remain at the end
63 * of the file.
64 * ---------------------------------------------------------------------------
65 * Local variables:
66 * c-file-style: "linux"
67 * End:
68 */
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
new file mode 100644
index 000000000000..72113b0a96e7
--- /dev/null
+++ b/arch/um/kernel/smp.c
@@ -0,0 +1,269 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/percpu.h"
8#include "asm/pgalloc.h"
9#include "asm/tlb.h"
10
11/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */
12DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
13
14#ifdef CONFIG_SMP
15
16#include "linux/sched.h"
17#include "linux/module.h"
18#include "linux/threads.h"
19#include "linux/interrupt.h"
20#include "linux/err.h"
21#include "linux/hardirq.h"
22#include "asm/smp.h"
23#include "asm/processor.h"
24#include "asm/spinlock.h"
25#include "user_util.h"
26#include "kern_util.h"
27#include "kern.h"
28#include "irq_user.h"
29#include "os.h"
30
31/* CPU online map, set by smp_boot_cpus */
32cpumask_t cpu_online_map = CPU_MASK_NONE;
33cpumask_t cpu_possible_map = CPU_MASK_NONE;
34
35EXPORT_SYMBOL(cpu_online_map);
36EXPORT_SYMBOL(cpu_possible_map);
37
38/* Per CPU bogomips and other parameters
39 * The only piece used here is the ipi pipe, which is set before SMP is
40 * started and never changed.
41 */
42struct cpuinfo_um cpu_data[NR_CPUS];
43
44/* A statistic, can be a little off */
45int num_reschedules_sent = 0;
46
47/* Not changed after boot */
48struct task_struct *idle_threads[NR_CPUS];
49
50void smp_send_reschedule(int cpu)
51{
52 os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1);
53 num_reschedules_sent++;
54}
55
56void smp_send_stop(void)
57{
58 int i;
59
60 printk(KERN_INFO "Stopping all CPUs...");
61 for(i = 0; i < num_online_cpus(); i++){
62 if(i == current_thread->cpu)
63 continue;
64 os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
65 }
66 printk("done\n");
67}
68
69static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
70static cpumask_t cpu_callin_map = CPU_MASK_NONE;
71
72static int idle_proc(void *cpup)
73{
74 int cpu = (int) cpup, err;
75
76 err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
77 if(err < 0)
78 panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
79
80 activate_ipi(cpu_data[cpu].ipi_pipe[0],
81 current->thread.mode.tt.extern_pid);
82
83 wmb();
84 if (cpu_test_and_set(cpu, cpu_callin_map)) {
85 printk("huh, CPU#%d already present??\n", cpu);
86 BUG();
87 }
88
89 while (!cpu_isset(cpu, smp_commenced_mask))
90 cpu_relax();
91
92 cpu_set(cpu, cpu_online_map);
93 default_idle();
94 return(0);
95}
96
97static struct task_struct *idle_thread(int cpu)
98{
99 struct task_struct *new_task;
100 unsigned char c;
101
102 current->thread.request.u.thread.proc = idle_proc;
103 current->thread.request.u.thread.arg = (void *) cpu;
104 new_task = fork_idle(cpu);
105 if(IS_ERR(new_task))
106 panic("copy_process failed in idle_thread, error = %ld",
107 PTR_ERR(new_task));
108
109 cpu_tasks[cpu] = ((struct cpu_task)
110 { .pid = new_task->thread.mode.tt.extern_pid,
111 .task = new_task } );
112 idle_threads[cpu] = new_task;
113 CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
114 sizeof(c)),
115 ({ panic("skas mode doesn't support SMP"); }));
116 return(new_task);
117}
118
119void smp_prepare_cpus(unsigned int maxcpus)
120{
121 struct task_struct *idle;
122 unsigned long waittime;
123 int err, cpu, me = smp_processor_id();
124 int i;
125
126 for (i = 0; i < ncpus; ++i)
127 cpu_set(i, cpu_possible_map);
128
129 cpu_clear(me, cpu_online_map);
130 cpu_set(me, cpu_online_map);
131 cpu_set(me, cpu_callin_map);
132
133 err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
134 if(err < 0)
135 panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
136
137 activate_ipi(cpu_data[me].ipi_pipe[0],
138 current->thread.mode.tt.extern_pid);
139
140 for(cpu = 1; cpu < ncpus; cpu++){
141 printk("Booting processor %d...\n", cpu);
142
143 idle = idle_thread(cpu);
144
145 init_idle(idle, cpu);
146 unhash_process(idle);
147
148 waittime = 200000000;
149 while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
150 cpu_relax();
151
152 if (cpu_isset(cpu, cpu_callin_map))
153 printk("done\n");
154 else printk("failed\n");
155 }
156}
157
158void smp_prepare_boot_cpu(void)
159{
160 cpu_set(smp_processor_id(), cpu_online_map);
161}
162
163int __cpu_up(unsigned int cpu)
164{
165 cpu_set(cpu, smp_commenced_mask);
166 while (!cpu_isset(cpu, cpu_online_map))
167 mb();
168 return(0);
169}
170
171int setup_profiling_timer(unsigned int multiplier)
172{
173 printk(KERN_INFO "setup_profiling_timer\n");
174 return(0);
175}
176
177void smp_call_function_slave(int cpu);
178
179void IPI_handler(int cpu)
180{
181 unsigned char c;
182 int fd;
183
184 fd = cpu_data[cpu].ipi_pipe[0];
185 while (os_read_file(fd, &c, 1) == 1) {
186 switch (c) {
187 case 'C':
188 smp_call_function_slave(cpu);
189 break;
190
191 case 'R':
192 set_tsk_need_resched(current);
193 break;
194
195 case 'S':
196 printk("CPU#%d stopping\n", cpu);
197 while(1)
198 pause();
199 break;
200
201 default:
202 printk("CPU#%d received unknown IPI [%c]!\n", cpu, c);
203 break;
204 }
205 }
206}
207
208int hard_smp_processor_id(void)
209{
210 return(pid_to_processor_id(os_getpid()));
211}
212
213static DEFINE_SPINLOCK(call_lock);
214static atomic_t scf_started;
215static atomic_t scf_finished;
216static void (*func)(void *info);
217static void *info;
218
219void smp_call_function_slave(int cpu)
220{
221 atomic_inc(&scf_started);
222 (*func)(info);
223 atomic_inc(&scf_finished);
224}
225
226int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic,
227 int wait)
228{
229 int cpus = num_online_cpus() - 1;
230 int i;
231
232 if (!cpus)
233 return 0;
234
235 /* Can deadlock when called with interrupts disabled */
236 WARN_ON(irqs_disabled());
237
238 spin_lock_bh(&call_lock);
239 atomic_set(&scf_started, 0);
240 atomic_set(&scf_finished, 0);
241 func = _func;
242 info = _info;
243
244 for_each_online_cpu(i)
245 os_write_file(cpu_data[i].ipi_pipe[1], "C", 1);
246
247 while (atomic_read(&scf_started) != cpus)
248 barrier();
249
250 if (wait)
251 while (atomic_read(&scf_finished) != cpus)
252 barrier();
253
254 spin_unlock_bh(&call_lock);
255 return 0;
256}
257
258#endif
259
260/*
261 * Overrides for Emacs so that we follow Linus's tabbing style.
262 * Emacs will notice this stuff at the end of the file and automatically
263 * adjust the settings for this buffer only. This must remain at the end
264 * of the file.
265 * ---------------------------------------------------------------------------
266 * Local variables:
267 * c-file-style: "linux"
268 * End:
269 */
diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c
new file mode 100644
index 000000000000..7fc06c85b29d
--- /dev/null
+++ b/arch/um/kernel/sys_call_table.c
@@ -0,0 +1,276 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Copyright 2003 PathScale, Inc.
4 * Licensed under the GPL
5 */
6
7#include "linux/config.h"
8#include "linux/unistd.h"
9#include "linux/sys.h"
10#include "linux/swap.h"
11#include "linux/syscalls.h"
12#include "linux/sysctl.h"
13#include "asm/signal.h"
14#include "sysdep/syscalls.h"
15#include "kern_util.h"
16
17#ifdef CONFIG_NFSD
18#define NFSSERVCTL sys_nfsservctl
19#else
20#define NFSSERVCTL sys_ni_syscall
21#endif
22
23#define LAST_GENERIC_SYSCALL __NR_keyctl
24
25#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
26#define LAST_SYSCALL LAST_GENERIC_SYSCALL
27#else
28#define LAST_SYSCALL LAST_ARCH_SYSCALL
29#endif
30
31extern syscall_handler_t sys_fork;
32extern syscall_handler_t sys_execve;
33extern syscall_handler_t um_time;
34extern syscall_handler_t um_stime;
35extern syscall_handler_t sys_pipe;
36extern syscall_handler_t sys_olduname;
37extern syscall_handler_t sys_sigaction;
38extern syscall_handler_t sys_sigsuspend;
39extern syscall_handler_t old_readdir;
40extern syscall_handler_t sys_uname;
41extern syscall_handler_t sys_ipc;
42extern syscall_handler_t sys_sigreturn;
43extern syscall_handler_t sys_clone;
44extern syscall_handler_t sys_rt_sigreturn;
45extern syscall_handler_t sys_sigaltstack;
46extern syscall_handler_t sys_vfork;
47extern syscall_handler_t old_select;
48extern syscall_handler_t sys_modify_ldt;
49extern syscall_handler_t sys_rt_sigsuspend;
50extern syscall_handler_t sys_mbind;
51extern syscall_handler_t sys_get_mempolicy;
52extern syscall_handler_t sys_set_mempolicy;
53extern syscall_handler_t sys_sys_setaltroot;
54
55syscall_handler_t *sys_call_table[] = {
56 [ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall,
57 [ __NR_exit ] = (syscall_handler_t *) sys_exit,
58 [ __NR_fork ] = (syscall_handler_t *) sys_fork,
59 [ __NR_read ] = (syscall_handler_t *) sys_read,
60 [ __NR_write ] = (syscall_handler_t *) sys_write,
61
62 /* These three are declared differently in asm/unistd.h */
63 [ __NR_open ] = (syscall_handler_t *) sys_open,
64 [ __NR_close ] = (syscall_handler_t *) sys_close,
65 [ __NR_creat ] = (syscall_handler_t *) sys_creat,
66 [ __NR_link ] = (syscall_handler_t *) sys_link,
67 [ __NR_unlink ] = (syscall_handler_t *) sys_unlink,
68 [ __NR_execve ] = (syscall_handler_t *) sys_execve,
69
70 /* declared differently in kern_util.h */
71 [ __NR_chdir ] = (syscall_handler_t *) sys_chdir,
72 [ __NR_time ] = um_time,
73 [ __NR_mknod ] = (syscall_handler_t *) sys_mknod,
74 [ __NR_chmod ] = (syscall_handler_t *) sys_chmod,
75 [ __NR_lchown ] = (syscall_handler_t *) sys_lchown16,
76 [ __NR_lseek ] = (syscall_handler_t *) sys_lseek,
77 [ __NR_getpid ] = (syscall_handler_t *) sys_getpid,
78 [ __NR_mount ] = (syscall_handler_t *) sys_mount,
79 [ __NR_setuid ] = (syscall_handler_t *) sys_setuid16,
80 [ __NR_getuid ] = (syscall_handler_t *) sys_getuid16,
81 [ __NR_ptrace ] = (syscall_handler_t *) sys_ptrace,
82 [ __NR_alarm ] = (syscall_handler_t *) sys_alarm,
83 [ __NR_pause ] = (syscall_handler_t *) sys_pause,
84 [ __NR_utime ] = (syscall_handler_t *) sys_utime,
85 [ __NR_access ] = (syscall_handler_t *) sys_access,
86 [ __NR_sync ] = (syscall_handler_t *) sys_sync,
87 [ __NR_kill ] = (syscall_handler_t *) sys_kill,
88 [ __NR_rename ] = (syscall_handler_t *) sys_rename,
89 [ __NR_mkdir ] = (syscall_handler_t *) sys_mkdir,
90 [ __NR_rmdir ] = (syscall_handler_t *) sys_rmdir,
91
92 /* Declared differently in asm/unistd.h */
93 [ __NR_dup ] = (syscall_handler_t *) sys_dup,
94 [ __NR_pipe ] = (syscall_handler_t *) sys_pipe,
95 [ __NR_times ] = (syscall_handler_t *) sys_times,
96 [ __NR_brk ] = (syscall_handler_t *) sys_brk,
97 [ __NR_setgid ] = (syscall_handler_t *) sys_setgid16,
98 [ __NR_getgid ] = (syscall_handler_t *) sys_getgid16,
99 [ __NR_geteuid ] = (syscall_handler_t *) sys_geteuid16,
100 [ __NR_getegid ] = (syscall_handler_t *) sys_getegid16,
101 [ __NR_acct ] = (syscall_handler_t *) sys_acct,
102 [ __NR_umount2 ] = (syscall_handler_t *) sys_umount,
103 [ __NR_ioctl ] = (syscall_handler_t *) sys_ioctl,
104 [ __NR_fcntl ] = (syscall_handler_t *) sys_fcntl,
105 [ __NR_setpgid ] = (syscall_handler_t *) sys_setpgid,
106 [ __NR_umask ] = (syscall_handler_t *) sys_umask,
107 [ __NR_chroot ] = (syscall_handler_t *) sys_chroot,
108 [ __NR_ustat ] = (syscall_handler_t *) sys_ustat,
109 [ __NR_dup2 ] = (syscall_handler_t *) sys_dup2,
110 [ __NR_getppid ] = (syscall_handler_t *) sys_getppid,
111 [ __NR_getpgrp ] = (syscall_handler_t *) sys_getpgrp,
112 [ __NR_setsid ] = (syscall_handler_t *) sys_setsid,
113 [ __NR_setreuid ] = (syscall_handler_t *) sys_setreuid16,
114 [ __NR_setregid ] = (syscall_handler_t *) sys_setregid16,
115 [ __NR_sethostname ] = (syscall_handler_t *) sys_sethostname,
116 [ __NR_setrlimit ] = (syscall_handler_t *) sys_setrlimit,
117 [ __NR_getrlimit ] = (syscall_handler_t *) sys_old_getrlimit,
118 [ __NR_getrusage ] = (syscall_handler_t *) sys_getrusage,
119 [ __NR_gettimeofday ] = (syscall_handler_t *) sys_gettimeofday,
120 [ __NR_settimeofday ] = (syscall_handler_t *) sys_settimeofday,
121 [ __NR_getgroups ] = (syscall_handler_t *) sys_getgroups16,
122 [ __NR_setgroups ] = (syscall_handler_t *) sys_setgroups16,
123 [ __NR_symlink ] = (syscall_handler_t *) sys_symlink,
124 [ __NR_readlink ] = (syscall_handler_t *) sys_readlink,
125 [ __NR_uselib ] = (syscall_handler_t *) sys_uselib,
126 [ __NR_swapon ] = (syscall_handler_t *) sys_swapon,
127 [ __NR_reboot ] = (syscall_handler_t *) sys_reboot,
128 [ __NR_munmap ] = (syscall_handler_t *) sys_munmap,
129 [ __NR_truncate ] = (syscall_handler_t *) sys_truncate,
130 [ __NR_ftruncate ] = (syscall_handler_t *) sys_ftruncate,
131 [ __NR_fchmod ] = (syscall_handler_t *) sys_fchmod,
132 [ __NR_fchown ] = (syscall_handler_t *) sys_fchown16,
133 [ __NR_getpriority ] = (syscall_handler_t *) sys_getpriority,
134 [ __NR_setpriority ] = (syscall_handler_t *) sys_setpriority,
135 [ __NR_statfs ] = (syscall_handler_t *) sys_statfs,
136 [ __NR_fstatfs ] = (syscall_handler_t *) sys_fstatfs,
137 [ __NR_ioperm ] = (syscall_handler_t *) sys_ni_syscall,
138 [ __NR_syslog ] = (syscall_handler_t *) sys_syslog,
139 [ __NR_setitimer ] = (syscall_handler_t *) sys_setitimer,
140 [ __NR_getitimer ] = (syscall_handler_t *) sys_getitimer,
141 [ __NR_stat ] = (syscall_handler_t *) sys_newstat,
142 [ __NR_lstat ] = (syscall_handler_t *) sys_newlstat,
143 [ __NR_fstat ] = (syscall_handler_t *) sys_newfstat,
144 [ __NR_vhangup ] = (syscall_handler_t *) sys_vhangup,
145 [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4,
146 [ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff,
147 [ __NR_sysinfo ] = (syscall_handler_t *) sys_sysinfo,
148 [ __NR_fsync ] = (syscall_handler_t *) sys_fsync,
149 [ __NR_clone ] = (syscall_handler_t *) sys_clone,
150 [ __NR_setdomainname ] = (syscall_handler_t *) sys_setdomainname,
151 [ __NR_uname ] = (syscall_handler_t *) sys_newuname,
152 [ __NR_adjtimex ] = (syscall_handler_t *) sys_adjtimex,
153 [ __NR_mprotect ] = (syscall_handler_t *) sys_mprotect,
154 [ __NR_create_module ] = (syscall_handler_t *) sys_ni_syscall,
155 [ __NR_init_module ] = (syscall_handler_t *) sys_init_module,
156 [ __NR_delete_module ] = (syscall_handler_t *) sys_delete_module,
157 [ __NR_get_kernel_syms ] = (syscall_handler_t *) sys_ni_syscall,
158 [ __NR_quotactl ] = (syscall_handler_t *) sys_quotactl,
159 [ __NR_getpgid ] = (syscall_handler_t *) sys_getpgid,
160 [ __NR_fchdir ] = (syscall_handler_t *) sys_fchdir,
161 [ __NR_sysfs ] = (syscall_handler_t *) sys_sysfs,
162 [ __NR_personality ] = (syscall_handler_t *) sys_personality,
163 [ __NR_afs_syscall ] = (syscall_handler_t *) sys_ni_syscall,
164 [ __NR_setfsuid ] = (syscall_handler_t *) sys_setfsuid16,
165 [ __NR_setfsgid ] = (syscall_handler_t *) sys_setfsgid16,
166 [ __NR_getdents ] = (syscall_handler_t *) sys_getdents,
167 [ __NR_flock ] = (syscall_handler_t *) sys_flock,
168 [ __NR_msync ] = (syscall_handler_t *) sys_msync,
169 [ __NR_readv ] = (syscall_handler_t *) sys_readv,
170 [ __NR_writev ] = (syscall_handler_t *) sys_writev,
171 [ __NR_getsid ] = (syscall_handler_t *) sys_getsid,
172 [ __NR_fdatasync ] = (syscall_handler_t *) sys_fdatasync,
173 [ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl,
174 [ __NR_mlock ] = (syscall_handler_t *) sys_mlock,
175 [ __NR_munlock ] = (syscall_handler_t *) sys_munlock,
176 [ __NR_mlockall ] = (syscall_handler_t *) sys_mlockall,
177 [ __NR_munlockall ] = (syscall_handler_t *) sys_munlockall,
178 [ __NR_sched_setparam ] = (syscall_handler_t *) sys_sched_setparam,
179 [ __NR_sched_getparam ] = (syscall_handler_t *) sys_sched_getparam,
180 [ __NR_sched_setscheduler ] = (syscall_handler_t *) sys_sched_setscheduler,
181 [ __NR_sched_getscheduler ] = (syscall_handler_t *) sys_sched_getscheduler,
182 [ __NR_sched_yield ] = (syscall_handler_t *) yield,
183 [ __NR_sched_get_priority_max ] = (syscall_handler_t *) sys_sched_get_priority_max,
184 [ __NR_sched_get_priority_min ] = (syscall_handler_t *) sys_sched_get_priority_min,
185 [ __NR_sched_rr_get_interval ] = (syscall_handler_t *) sys_sched_rr_get_interval,
186 [ __NR_nanosleep ] = (syscall_handler_t *) sys_nanosleep,
187 [ __NR_mremap ] = (syscall_handler_t *) sys_mremap,
188 [ __NR_setresuid ] = (syscall_handler_t *) sys_setresuid16,
189 [ __NR_getresuid ] = (syscall_handler_t *) sys_getresuid16,
190 [ __NR_query_module ] = (syscall_handler_t *) sys_ni_syscall,
191 [ __NR_poll ] = (syscall_handler_t *) sys_poll,
192 [ __NR_nfsservctl ] = (syscall_handler_t *) NFSSERVCTL,
193 [ __NR_setresgid ] = (syscall_handler_t *) sys_setresgid16,
194 [ __NR_getresgid ] = (syscall_handler_t *) sys_getresgid16,
195 [ __NR_prctl ] = (syscall_handler_t *) sys_prctl,
196 [ __NR_rt_sigreturn ] = (syscall_handler_t *) sys_rt_sigreturn,
197 [ __NR_rt_sigaction ] = (syscall_handler_t *) sys_rt_sigaction,
198 [ __NR_rt_sigprocmask ] = (syscall_handler_t *) sys_rt_sigprocmask,
199 [ __NR_rt_sigpending ] = (syscall_handler_t *) sys_rt_sigpending,
200 [ __NR_rt_sigtimedwait ] = (syscall_handler_t *) sys_rt_sigtimedwait,
201 [ __NR_rt_sigqueueinfo ] = (syscall_handler_t *) sys_rt_sigqueueinfo,
202 [ __NR_rt_sigsuspend ] = (syscall_handler_t *) sys_rt_sigsuspend,
203 [ __NR_pread64 ] = (syscall_handler_t *) sys_pread64,
204 [ __NR_pwrite64 ] = (syscall_handler_t *) sys_pwrite64,
205 [ __NR_chown ] = (syscall_handler_t *) sys_chown16,
206 [ __NR_getcwd ] = (syscall_handler_t *) sys_getcwd,
207 [ __NR_capget ] = (syscall_handler_t *) sys_capget,
208 [ __NR_capset ] = (syscall_handler_t *) sys_capset,
209 [ __NR_sigaltstack ] = (syscall_handler_t *) sys_sigaltstack,
210 [ __NR_sendfile ] = (syscall_handler_t *) sys_sendfile,
211 [ __NR_getpmsg ] = (syscall_handler_t *) sys_ni_syscall,
212 [ __NR_putpmsg ] = (syscall_handler_t *) sys_ni_syscall,
213 [ __NR_vfork ] = (syscall_handler_t *) sys_vfork,
214 [ __NR_getdents64 ] = (syscall_handler_t *) sys_getdents64,
215 [ __NR_gettid ] = (syscall_handler_t *) sys_gettid,
216 [ __NR_readahead ] = (syscall_handler_t *) sys_readahead,
217 [ __NR_setxattr ] = (syscall_handler_t *) sys_setxattr,
218 [ __NR_lsetxattr ] = (syscall_handler_t *) sys_lsetxattr,
219 [ __NR_fsetxattr ] = (syscall_handler_t *) sys_fsetxattr,
220 [ __NR_getxattr ] = (syscall_handler_t *) sys_getxattr,
221 [ __NR_lgetxattr ] = (syscall_handler_t *) sys_lgetxattr,
222 [ __NR_fgetxattr ] = (syscall_handler_t *) sys_fgetxattr,
223 [ __NR_listxattr ] = (syscall_handler_t *) sys_listxattr,
224 [ __NR_llistxattr ] = (syscall_handler_t *) sys_llistxattr,
225 [ __NR_flistxattr ] = (syscall_handler_t *) sys_flistxattr,
226 [ __NR_removexattr ] = (syscall_handler_t *) sys_removexattr,
227 [ __NR_lremovexattr ] = (syscall_handler_t *) sys_lremovexattr,
228 [ __NR_fremovexattr ] = (syscall_handler_t *) sys_fremovexattr,
229 [ __NR_tkill ] = (syscall_handler_t *) sys_tkill,
230 [ __NR_futex ] = (syscall_handler_t *) sys_futex,
231 [ __NR_sched_setaffinity ] = (syscall_handler_t *) sys_sched_setaffinity,
232 [ __NR_sched_getaffinity ] = (syscall_handler_t *) sys_sched_getaffinity,
233 [ __NR_io_setup ] = (syscall_handler_t *) sys_io_setup,
234 [ __NR_io_destroy ] = (syscall_handler_t *) sys_io_destroy,
235 [ __NR_io_getevents ] = (syscall_handler_t *) sys_io_getevents,
236 [ __NR_io_submit ] = (syscall_handler_t *) sys_io_submit,
237 [ __NR_io_cancel ] = (syscall_handler_t *) sys_io_cancel,
238 [ __NR_exit_group ] = (syscall_handler_t *) sys_exit_group,
239 [ __NR_lookup_dcookie ] = (syscall_handler_t *) sys_lookup_dcookie,
240 [ __NR_epoll_create ] = (syscall_handler_t *) sys_epoll_create,
241 [ __NR_epoll_ctl ] = (syscall_handler_t *) sys_epoll_ctl,
242 [ __NR_epoll_wait ] = (syscall_handler_t *) sys_epoll_wait,
243 [ __NR_remap_file_pages ] = (syscall_handler_t *) sys_remap_file_pages,
244 [ __NR_set_tid_address ] = (syscall_handler_t *) sys_set_tid_address,
245 [ __NR_timer_create ] = (syscall_handler_t *) sys_timer_create,
246 [ __NR_timer_settime ] = (syscall_handler_t *) sys_timer_settime,
247 [ __NR_timer_gettime ] = (syscall_handler_t *) sys_timer_gettime,
248 [ __NR_timer_getoverrun ] = (syscall_handler_t *) sys_timer_getoverrun,
249 [ __NR_timer_delete ] = (syscall_handler_t *) sys_timer_delete,
250 [ __NR_clock_settime ] = (syscall_handler_t *) sys_clock_settime,
251 [ __NR_clock_gettime ] = (syscall_handler_t *) sys_clock_gettime,
252 [ __NR_clock_getres ] = (syscall_handler_t *) sys_clock_getres,
253 [ __NR_clock_nanosleep ] = (syscall_handler_t *) sys_clock_nanosleep,
254 [ __NR_tgkill ] = (syscall_handler_t *) sys_tgkill,
255 [ __NR_utimes ] = (syscall_handler_t *) sys_utimes,
256 [ __NR_fadvise64 ] = (syscall_handler_t *) sys_fadvise64,
257 [ __NR_vserver ] = (syscall_handler_t *) sys_ni_syscall,
258 [ __NR_mbind ] = (syscall_handler_t *) sys_mbind,
259 [ __NR_get_mempolicy ] = (syscall_handler_t *) sys_get_mempolicy,
260 [ __NR_set_mempolicy ] = (syscall_handler_t *) sys_set_mempolicy,
261 [ __NR_mq_open ] = (syscall_handler_t *) sys_mq_open,
262 [ __NR_mq_unlink ] = (syscall_handler_t *) sys_mq_unlink,
263 [ __NR_mq_timedsend ] = (syscall_handler_t *) sys_mq_timedsend,
264 [ __NR_mq_timedreceive ] = (syscall_handler_t *) sys_mq_timedreceive,
265 [ __NR_mq_notify ] = (syscall_handler_t *) sys_mq_notify,
266 [ __NR_mq_getsetattr ] = (syscall_handler_t *) sys_mq_getsetattr,
267 [ __NR_kexec_load ] = (syscall_handler_t *) sys_ni_syscall,
268 [ __NR_waitid ] = (syscall_handler_t *) sys_waitid,
269 [ __NR_add_key ] = (syscall_handler_t *) sys_add_key,
270 [ __NR_request_key ] = (syscall_handler_t *) sys_request_key,
271 [ __NR_keyctl ] = (syscall_handler_t *) sys_keyctl,
272
273 ARCH_SYSCALLS
274 [ LAST_SYSCALL + 1 ... NR_syscalls ] =
275 (syscall_handler_t *) sys_ni_syscall
276};
diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
new file mode 100644
index 000000000000..42731e04f50f
--- /dev/null
+++ b/arch/um/kernel/syscall_kern.c
@@ -0,0 +1,176 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/file.h"
8#include "linux/smp_lock.h"
9#include "linux/mm.h"
10#include "linux/utsname.h"
11#include "linux/msg.h"
12#include "linux/shm.h"
13#include "linux/sys.h"
14#include "linux/syscalls.h"
15#include "linux/unistd.h"
16#include "linux/slab.h"
17#include "linux/utime.h"
18#include "asm/mman.h"
19#include "asm/uaccess.h"
20#include "asm/ipc.h"
21#include "kern_util.h"
22#include "user_util.h"
23#include "sysdep/syscalls.h"
24#include "mode_kern.h"
25#include "choose-mode.h"
26
27/* Unlocked, I don't care if this is a bit off */
28int nsyscalls = 0;
29
30long sys_fork(void)
31{
32 long ret;
33
34 current->thread.forking = 1;
35 ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
36 current->thread.forking = 0;
37 return(ret);
38}
39
40long sys_vfork(void)
41{
42 long ret;
43
44 current->thread.forking = 1;
45 ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL,
46 NULL);
47 current->thread.forking = 0;
48 return(ret);
49}
50
51/* common code for old and new mmaps */
52long sys_mmap2(unsigned long addr, unsigned long len,
53 unsigned long prot, unsigned long flags,
54 unsigned long fd, unsigned long pgoff)
55{
56 long error = -EBADF;
57 struct file * file = NULL;
58
59 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
60 if (!(flags & MAP_ANONYMOUS)) {
61 file = fget(fd);
62 if (!file)
63 goto out;
64 }
65
66 down_write(&current->mm->mmap_sem);
67 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
68 up_write(&current->mm->mmap_sem);
69
70 if (file)
71 fput(file);
72 out:
73 return error;
74}
75
76long old_mmap(unsigned long addr, unsigned long len,
77 unsigned long prot, unsigned long flags,
78 unsigned long fd, unsigned long offset)
79{
80 long err = -EINVAL;
81 if (offset & ~PAGE_MASK)
82 goto out;
83
84 err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
85 out:
86 return err;
87}
88/*
89 * sys_pipe() is the normal C calling standard for creating
90 * a pipe. It's not the way unix traditionally does this, though.
91 */
92long sys_pipe(unsigned long __user * fildes)
93{
94 int fd[2];
95 long error;
96
97 error = do_pipe(fd);
98 if (!error) {
99 if (copy_to_user(fildes, fd, sizeof(fd)))
100 error = -EFAULT;
101 }
102 return error;
103}
104
105
106long sys_uname(struct old_utsname * name)
107{
108 long err;
109 if (!name)
110 return -EFAULT;
111 down_read(&uts_sem);
112 err=copy_to_user(name, &system_utsname, sizeof (*name));
113 up_read(&uts_sem);
114 return err?-EFAULT:0;
115}
116
117long sys_olduname(struct oldold_utsname * name)
118{
119 long error;
120
121 if (!name)
122 return -EFAULT;
123 if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
124 return -EFAULT;
125
126 down_read(&uts_sem);
127
128 error = __copy_to_user(&name->sysname,&system_utsname.sysname,
129 __OLD_UTS_LEN);
130 error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
131 error |= __copy_to_user(&name->nodename,&system_utsname.nodename,
132 __OLD_UTS_LEN);
133 error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
134 error |= __copy_to_user(&name->release,&system_utsname.release,
135 __OLD_UTS_LEN);
136 error |= __put_user(0,name->release+__OLD_UTS_LEN);
137 error |= __copy_to_user(&name->version,&system_utsname.version,
138 __OLD_UTS_LEN);
139 error |= __put_user(0,name->version+__OLD_UTS_LEN);
140 error |= __copy_to_user(&name->machine,&system_utsname.machine,
141 __OLD_UTS_LEN);
142 error |= __put_user(0,name->machine+__OLD_UTS_LEN);
143
144 up_read(&uts_sem);
145
146 error = error ? -EFAULT : 0;
147
148 return error;
149}
150
151DEFINE_SPINLOCK(syscall_lock);
152
153static int syscall_index = 0;
154
155int next_syscall_index(int limit)
156{
157 int ret;
158
159 spin_lock(&syscall_lock);
160 ret = syscall_index;
161 if(++syscall_index == limit)
162 syscall_index = 0;
163 spin_unlock(&syscall_lock);
164 return(ret);
165}
166
167/*
168 * Overrides for Emacs so that we follow Linus's tabbing style.
169 * Emacs will notice this stuff at the end of the file and automatically
170 * adjust the settings for this buffer only. This must remain at the end
171 * of the file.
172 * ---------------------------------------------------------------------------
173 * Local variables:
174 * c-file-style: "linux"
175 * End:
176 */
diff --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c
new file mode 100644
index 000000000000..01b711e00a85
--- /dev/null
+++ b/arch/um/kernel/syscall_user.c
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <sys/time.h>
8#include "kern_util.h"
9#include "syscall_user.h"
10
11struct {
12 int syscall;
13 int pid;
14 long result;
15 struct timeval start;
16 struct timeval end;
17} syscall_record[1024];
18
19int record_syscall_start(int syscall)
20{
21 int max, index;
22
23 max = sizeof(syscall_record)/sizeof(syscall_record[0]);
24 index = next_syscall_index(max);
25
26 syscall_record[index].syscall = syscall;
27 syscall_record[index].pid = current_pid();
28 syscall_record[index].result = 0xdeadbeef;
29 gettimeofday(&syscall_record[index].start, NULL);
30 return(index);
31}
32
33void record_syscall_end(int index, long result)
34{
35 syscall_record[index].result = result;
36 gettimeofday(&syscall_record[index].end, NULL);
37}
38
39/*
40 * Overrides for Emacs so that we follow Linus's tabbing style.
41 * Emacs will notice this stuff at the end of the file and automatically
42 * adjust the settings for this buffer only. This must remain at the end
43 * of the file.
44 * ---------------------------------------------------------------------------
45 * Local variables:
46 * c-file-style: "linux"
47 * End:
48 */
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
new file mode 100644
index 000000000000..e630438f9e73
--- /dev/null
+++ b/arch/um/kernel/sysrq.c
@@ -0,0 +1,81 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/kernel.h"
8#include "linux/module.h"
9#include "linux/kallsyms.h"
10#include "asm/page.h"
11#include "asm/processor.h"
12#include "sysrq.h"
13#include "user_util.h"
14
15void show_trace(unsigned long * stack)
16{
17 /* XXX: Copy the CONFIG_FRAME_POINTER stack-walking backtrace from
18 * arch/i386/kernel/traps.c, and then move this to sys-i386/sysrq.c.*/
19 unsigned long addr;
20
21 if (!stack) {
22 stack = (unsigned long*) &stack;
23 WARN_ON(1);
24 }
25
26 printk("Call Trace: \n");
27 while (((long) stack & (THREAD_SIZE-1)) != 0) {
28 addr = *stack;
29 if (__kernel_text_address(addr)) {
30 printk("%08lx: [<%08lx>]", (unsigned long) stack, addr);
31 print_symbol(" %s", addr);
32 printk("\n");
33 }
34 stack++;
35 }
36 printk("\n");
37}
38
39/*
40 * stack dumps generator - this is used by arch-independent code.
41 * And this is identical to i386 currently.
42 */
43void dump_stack(void)
44{
45 unsigned long stack;
46
47 show_trace(&stack);
48}
49EXPORT_SYMBOL(dump_stack);
50
51/*Stolen from arch/i386/kernel/traps.c */
52static int kstack_depth_to_print = 24;
53
54/* This recently started being used in arch-independent code too, as in
55 * kernel/sched.c.*/
56void show_stack(struct task_struct *task, unsigned long *esp)
57{
58 unsigned long *stack;
59 int i;
60
61 if (esp == NULL) {
62 if (task != current) {
63 esp = (unsigned long *) KSTK_ESP(task);
64 /* Which one? No actual difference - just coding style.*/
65 //esp = (unsigned long *) PT_REGS_IP(&task->thread.regs);
66 } else {
67 esp = (unsigned long *) &esp;
68 }
69 }
70
71 stack = esp;
72 for(i = 0; i < kstack_depth_to_print; i++) {
73 if (kstack_end(stack))
74 break;
75 if (i && ((i % 8) == 0))
76 printk("\n ");
77 printk("%08lx ", *stack++);
78 }
79
80 show_trace(esp);
81}
diff --git a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c
new file mode 100644
index 000000000000..b1674bc1395d
--- /dev/null
+++ b/arch/um/kernel/tempfile.c
@@ -0,0 +1,82 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <string.h>
10#include <errno.h>
11#include <sys/param.h>
12#include "init.h"
13
14/* Modified from create_mem_file and start_debugger */
15static char *tempdir = NULL;
16
17static void __init find_tempdir(void)
18{
19 char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
20 int i;
21 char *dir = NULL;
22
23 if(tempdir != NULL) return; /* We've already been called */
24 for(i = 0; dirs[i]; i++){
25 dir = getenv(dirs[i]);
26 if((dir != NULL) && (*dir != '\0'))
27 break;
28 }
29 if((dir == NULL) || (*dir == '\0'))
30 dir = "/tmp";
31
32 tempdir = malloc(strlen(dir) + 2);
33 if(tempdir == NULL){
34 fprintf(stderr, "Failed to malloc tempdir, "
35 "errno = %d\n", errno);
36 return;
37 }
38 strcpy(tempdir, dir);
39 strcat(tempdir, "/");
40}
41
42int make_tempfile(const char *template, char **out_tempname, int do_unlink)
43{
44 char tempname[MAXPATHLEN];
45 int fd;
46
47 find_tempdir();
48 if (*template != '/')
49 strcpy(tempname, tempdir);
50 else
51 *tempname = 0;
52 strcat(tempname, template);
53 fd = mkstemp(tempname);
54 if(fd < 0){
55 fprintf(stderr, "open - cannot create %s: %s\n", tempname,
56 strerror(errno));
57 return -1;
58 }
59 if(do_unlink && (unlink(tempname) < 0)){
60 perror("unlink");
61 return -1;
62 }
63 if(out_tempname){
64 *out_tempname = strdup(tempname);
65 if(*out_tempname == NULL){
66 perror("strdup");
67 return -1;
68 }
69 }
70 return(fd);
71}
72
73/*
74 * Overrides for Emacs so that we follow Linus's tabbing style.
75 * Emacs will notice this stuff at the end of the file and automatically
76 * adjust the settings for this buffer only. This must remain at the end
77 * of the file.
78 * ---------------------------------------------------------------------------
79 * Local variables:
80 * c-file-style: "linux"
81 * End:
82 */
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
new file mode 100644
index 000000000000..c40c86a3f918
--- /dev/null
+++ b/arch/um/kernel/time.c
@@ -0,0 +1,167 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <time.h>
10#include <sys/time.h>
11#include <signal.h>
12#include <errno.h>
13#include "user_util.h"
14#include "kern_util.h"
15#include "user.h"
16#include "process.h"
17#include "signal_user.h"
18#include "time_user.h"
19#include "kern_constants.h"
20
21/* XXX This really needs to be declared and initialized in a kernel file since
22 * it's in <linux/time.h>
23 */
24extern struct timespec wall_to_monotonic;
25
26extern struct timeval xtime;
27
28struct timeval local_offset = { 0, 0 };
29
30void timer(void)
31{
32 gettimeofday(&xtime, NULL);
33 timeradd(&xtime, &local_offset, &xtime);
34}
35
36void set_interval(int timer_type)
37{
38 int usec = 1000000/hz();
39 struct itimerval interval = ((struct itimerval) { { 0, usec },
40 { 0, usec } });
41
42 if(setitimer(timer_type, &interval, NULL) == -1)
43 panic("setitimer failed - errno = %d\n", errno);
44}
45
46void enable_timer(void)
47{
48 int usec = 1000000/hz();
49 struct itimerval enable = ((struct itimerval) { { 0, usec },
50 { 0, usec }});
51 if(setitimer(ITIMER_VIRTUAL, &enable, NULL))
52 printk("enable_timer - setitimer failed, errno = %d\n",
53 errno);
54}
55
56void disable_timer(void)
57{
58 struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
59 if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) ||
60 (setitimer(ITIMER_REAL, &disable, NULL) < 0))
61 printk("disnable_timer - setitimer failed, errno = %d\n",
62 errno);
63 /* If there are signals already queued, after unblocking ignore them */
64 set_handler(SIGALRM, SIG_IGN, 0, -1);
65 set_handler(SIGVTALRM, SIG_IGN, 0, -1);
66}
67
68void switch_timers(int to_real)
69{
70 struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
71 struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() },
72 { 0, 1000000/hz() }});
73 int old, new;
74
75 if(to_real){
76 old = ITIMER_VIRTUAL;
77 new = ITIMER_REAL;
78 }
79 else {
80 old = ITIMER_REAL;
81 new = ITIMER_VIRTUAL;
82 }
83
84 if((setitimer(old, &disable, NULL) < 0) ||
85 (setitimer(new, &enable, NULL)))
86 printk("switch_timers - setitimer failed, errno = %d\n",
87 errno);
88}
89
90void uml_idle_timer(void)
91{
92 if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
93 panic("Couldn't unset SIGVTALRM handler");
94
95 set_handler(SIGALRM, (__sighandler_t) alarm_handler,
96 SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
97 set_interval(ITIMER_REAL);
98}
99
100extern int do_posix_clock_monotonic_gettime(struct timespec *tp);
101
102void time_init(void)
103{
104 struct timespec now;
105
106 if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
107 panic("Couldn't set SIGVTALRM handler");
108 set_interval(ITIMER_VIRTUAL);
109
110 do_posix_clock_monotonic_gettime(&now);
111 wall_to_monotonic.tv_sec = -now.tv_sec;
112 wall_to_monotonic.tv_nsec = -now.tv_nsec;
113}
114
115/* Declared in linux/time.h, which can't be included here */
116extern void clock_was_set(void);
117
118void do_gettimeofday(struct timeval *tv)
119{
120 unsigned long flags;
121
122 flags = time_lock();
123 gettimeofday(tv, NULL);
124 timeradd(tv, &local_offset, tv);
125 time_unlock(flags);
126 clock_was_set();
127}
128
129int do_settimeofday(struct timespec *tv)
130{
131 struct timeval now;
132 unsigned long flags;
133 struct timeval tv_in;
134
135 if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC)
136 return -EINVAL;
137
138 tv_in.tv_sec = tv->tv_sec;
139 tv_in.tv_usec = tv->tv_nsec / 1000;
140
141 flags = time_lock();
142 gettimeofday(&now, NULL);
143 timersub(&tv_in, &now, &local_offset);
144 time_unlock(flags);
145
146 return(0);
147}
148
149void idle_sleep(int secs)
150{
151 struct timespec ts;
152
153 ts.tv_sec = secs;
154 ts.tv_nsec = 0;
155 nanosleep(&ts, NULL);
156}
157
158/*
159 * Overrides for Emacs so that we follow Linus's tabbing style.
160 * Emacs will notice this stuff at the end of the file and automatically
161 * adjust the settings for this buffer only. This must remain at the end
162 * of the file.
163 * ---------------------------------------------------------------------------
164 * Local variables:
165 * c-file-style: "linux"
166 * End:
167 */
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
new file mode 100644
index 000000000000..2461cd73ca87
--- /dev/null
+++ b/arch/um/kernel/time_kern.c
@@ -0,0 +1,203 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "linux/module.h"
8#include "linux/unistd.h"
9#include "linux/stddef.h"
10#include "linux/spinlock.h"
11#include "linux/time.h"
12#include "linux/sched.h"
13#include "linux/interrupt.h"
14#include "linux/init.h"
15#include "linux/delay.h"
16#include "asm/irq.h"
17#include "asm/param.h"
18#include "asm/current.h"
19#include "kern_util.h"
20#include "user_util.h"
21#include "time_user.h"
22#include "mode.h"
23#include "os.h"
24
25u64 jiffies_64 = INITIAL_JIFFIES;
26
27EXPORT_SYMBOL(jiffies_64);
28
29int hz(void)
30{
31 return(HZ);
32}
33
34/*
35 * Scheduler clock - returns current time in nanosec units.
36 */
37unsigned long long sched_clock(void)
38{
39 return (unsigned long long)jiffies_64 * (1000000000 / HZ);
40}
41
42/* Changed at early boot */
43int timer_irq_inited = 0;
44
45static int first_tick;
46static unsigned long long prev_usecs;
47#ifdef CONFIG_UML_REAL_TIME_CLOCK
48static long long delta; /* Deviation per interval */
49#endif
50
51#define MILLION 1000000
52
53void timer_irq(union uml_pt_regs *regs)
54{
55 unsigned long long ticks = 0;
56
57 if(!timer_irq_inited){
58 /* This is to ensure that ticks don't pile up when
59 * the timer handler is suspended */
60 first_tick = 0;
61 return;
62 }
63
64 if(first_tick){
65#ifdef CONFIG_UML_REAL_TIME_CLOCK
66 /* We've had 1 tick */
67 unsigned long long usecs = os_usecs();
68
69 delta += usecs - prev_usecs;
70 prev_usecs = usecs;
71
72 /* Protect against the host clock being set backwards */
73 if(delta < 0)
74 delta = 0;
75
76 ticks += (delta * HZ) / MILLION;
77 delta -= (ticks * MILLION) / HZ;
78#else
79 ticks = 1;
80#endif
81 }
82 else {
83 prev_usecs = os_usecs();
84 first_tick = 1;
85 }
86
87 while(ticks > 0){
88 do_IRQ(TIMER_IRQ, regs);
89 ticks--;
90 }
91}
92
93void boot_timer_handler(int sig)
94{
95 struct pt_regs regs;
96
97 CHOOSE_MODE((void)
98 (UPT_SC(&regs.regs) = (struct sigcontext *) (&sig + 1)),
99 (void) (regs.regs.skas.is_user = 0));
100 do_timer(&regs);
101}
102
103irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
104{
105 unsigned long flags;
106
107 do_timer(regs);
108 write_seqlock_irqsave(&xtime_lock, flags);
109 timer();
110 write_sequnlock_irqrestore(&xtime_lock, flags);
111 return(IRQ_HANDLED);
112}
113
114long um_time(int __user *tloc)
115{
116 struct timeval now;
117
118 do_gettimeofday(&now);
119 if (tloc) {
120 if (put_user(now.tv_sec, tloc))
121 now.tv_sec = -EFAULT;
122 }
123 return now.tv_sec;
124}
125
126long um_stime(int __user *tptr)
127{
128 int value;
129 struct timespec new;
130
131 if (get_user(value, tptr))
132 return -EFAULT;
133 new.tv_sec = value;
134 new.tv_nsec = 0;
135 do_settimeofday(&new);
136 return 0;
137}
138
139void __udelay(unsigned long usecs)
140{
141 int i, n;
142
143 n = (loops_per_jiffy * HZ * usecs) / MILLION;
144 for(i=0;i<n;i++) ;
145}
146
147void __const_udelay(unsigned long usecs)
148{
149 int i, n;
150
151 n = (loops_per_jiffy * HZ * usecs) / MILLION;
152 for(i=0;i<n;i++) ;
153}
154
155void timer_handler(int sig, union uml_pt_regs *regs)
156{
157 local_irq_disable();
158 update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)), (regs)->skas.is_user));
159 local_irq_enable();
160 if(current_thread->cpu == 0)
161 timer_irq(regs);
162}
163
164static DEFINE_SPINLOCK(timer_spinlock);
165
166unsigned long time_lock(void)
167{
168 unsigned long flags;
169
170 spin_lock_irqsave(&timer_spinlock, flags);
171 return(flags);
172}
173
174void time_unlock(unsigned long flags)
175{
176 spin_unlock_irqrestore(&timer_spinlock, flags);
177}
178
179int __init timer_init(void)
180{
181 int err;
182
183 CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
184 err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
185 if(err != 0)
186 printk(KERN_ERR "timer_init : request_irq failed - "
187 "errno = %d\n", -err);
188 timer_irq_inited = 1;
189 return(0);
190}
191
192__initcall(timer_init);
193
194/*
195 * Overrides for Emacs so that we follow Linus's tabbing style.
196 * Emacs will notice this stuff at the end of the file and automatically
197 * adjust the settings for this buffer only. This must remain at the end
198 * of the file.
199 * ---------------------------------------------------------------------------
200 * Local variables:
201 * c-file-style: "linux"
202 * End:
203 */
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
new file mode 100644
index 000000000000..eda477edfdf5
--- /dev/null
+++ b/arch/um/kernel/tlb.c
@@ -0,0 +1,369 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/mm.h"
7#include "asm/page.h"
8#include "asm/pgalloc.h"
9#include "asm/tlbflush.h"
10#include "choose-mode.h"
11#include "mode_kern.h"
12#include "user_util.h"
13#include "tlb.h"
14#include "mem.h"
15#include "mem_user.h"
16#include "os.h"
17
18#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
19
20void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
21 unsigned long end_addr, int force, int data,
22 void (*do_ops)(int, struct host_vm_op *, int))
23{
24 pgd_t *npgd;
25 pud_t *npud;
26 pmd_t *npmd;
27 pte_t *npte;
28 unsigned long addr, end;
29 int r, w, x;
30 struct host_vm_op ops[16];
31 int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1;
32
33 if(mm == NULL) return;
34
35 for(addr = start_addr; addr < end_addr;){
36 npgd = pgd_offset(mm, addr);
37 if(!pgd_present(*npgd)){
38 end = ADD_ROUND(addr, PGDIR_SIZE);
39 if(end > end_addr)
40 end = end_addr;
41 if(force || pgd_newpage(*npgd)){
42 op_index = add_munmap(addr, end - addr, ops,
43 op_index, last_op, data,
44 do_ops);
45 pgd_mkuptodate(*npgd);
46 }
47 addr = end;
48 continue;
49 }
50
51 npud = pud_offset(npgd, addr);
52 if(!pud_present(*npud)){
53 end = ADD_ROUND(addr, PUD_SIZE);
54 if(end > end_addr)
55 end = end_addr;
56 if(force || pud_newpage(*npud)){
57 op_index = add_munmap(addr, end - addr, ops,
58 op_index, last_op, data,
59 do_ops);
60 pud_mkuptodate(*npud);
61 }
62 addr = end;
63 continue;
64 }
65
66 npmd = pmd_offset(npud, addr);
67 if(!pmd_present(*npmd)){
68 end = ADD_ROUND(addr, PMD_SIZE);
69 if(end > end_addr)
70 end = end_addr;
71 if(force || pmd_newpage(*npmd)){
72 op_index = add_munmap(addr, end - addr, ops,
73 op_index, last_op, data,
74 do_ops);
75 pmd_mkuptodate(*npmd);
76 }
77 addr = end;
78 continue;
79 }
80
81 npte = pte_offset_kernel(npmd, addr);
82 r = pte_read(*npte);
83 w = pte_write(*npte);
84 x = pte_exec(*npte);
85 if(!pte_dirty(*npte))
86 w = 0;
87 if(!pte_young(*npte)){
88 r = 0;
89 w = 0;
90 }
91 if(force || pte_newpage(*npte)){
92 if(pte_present(*npte))
93 op_index = add_mmap(addr,
94 pte_val(*npte) & PAGE_MASK,
95 PAGE_SIZE, r, w, x, ops,
96 op_index, last_op, data,
97 do_ops);
98 else op_index = add_munmap(addr, PAGE_SIZE, ops,
99 op_index, last_op, data,
100 do_ops);
101 }
102 else if(pte_newprot(*npte))
103 op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
104 op_index, last_op, data,
105 do_ops);
106
107 *npte = pte_mkuptodate(*npte);
108 addr += PAGE_SIZE;
109 }
110 (*do_ops)(data, ops, op_index);
111}
112
113int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
114{
115 struct mm_struct *mm;
116 pgd_t *pgd;
117 pud_t *pud;
118 pmd_t *pmd;
119 pte_t *pte;
120 unsigned long addr, last;
121 int updated = 0, err;
122
123 mm = &init_mm;
124 for(addr = start; addr < end;){
125 pgd = pgd_offset(mm, addr);
126 if(!pgd_present(*pgd)){
127 last = ADD_ROUND(addr, PGDIR_SIZE);
128 if(last > end)
129 last = end;
130 if(pgd_newpage(*pgd)){
131 updated = 1;
132 err = os_unmap_memory((void *) addr,
133 last - addr);
134 if(err < 0)
135 panic("munmap failed, errno = %d\n",
136 -err);
137 }
138 addr = last;
139 continue;
140 }
141
142 pud = pud_offset(pgd, addr);
143 if(!pud_present(*pud)){
144 last = ADD_ROUND(addr, PUD_SIZE);
145 if(last > end)
146 last = end;
147 if(pud_newpage(*pud)){
148 updated = 1;
149 err = os_unmap_memory((void *) addr,
150 last - addr);
151 if(err < 0)
152 panic("munmap failed, errno = %d\n",
153 -err);
154 }
155 addr = last;
156 continue;
157 }
158
159 pmd = pmd_offset(pud, addr);
160 if(!pmd_present(*pmd)){
161 last = ADD_ROUND(addr, PMD_SIZE);
162 if(last > end)
163 last = end;
164 if(pmd_newpage(*pmd)){
165 updated = 1;
166 err = os_unmap_memory((void *) addr,
167 last - addr);
168 if(err < 0)
169 panic("munmap failed, errno = %d\n",
170 -err);
171 }
172 addr = last;
173 continue;
174 }
175
176 pte = pte_offset_kernel(pmd, addr);
177 if(!pte_present(*pte) || pte_newpage(*pte)){
178 updated = 1;
179 err = os_unmap_memory((void *) addr,
180 PAGE_SIZE);
181 if(err < 0)
182 panic("munmap failed, errno = %d\n",
183 -err);
184 if(pte_present(*pte))
185 map_memory(addr,
186 pte_val(*pte) & PAGE_MASK,
187 PAGE_SIZE, 1, 1, 1);
188 }
189 else if(pte_newprot(*pte)){
190 updated = 1;
191 protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
192 }
193 addr += PAGE_SIZE;
194 }
195 return(updated);
196}
197
198void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
199{
200 address &= PAGE_MASK;
201 flush_tlb_range(vma, address, address + PAGE_SIZE);
202}
203
204void flush_tlb_all(void)
205{
206 flush_tlb_mm(current->mm);
207}
208
209void flush_tlb_kernel_range(unsigned long start, unsigned long end)
210{
211 CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
212 flush_tlb_kernel_range_common, start, end);
213}
214
215void flush_tlb_kernel_vm(void)
216{
217 CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
218 flush_tlb_kernel_range_common(start_vm, end_vm));
219}
220
221void __flush_tlb_one(unsigned long addr)
222{
223 CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
224}
225
226void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
227 unsigned long end)
228{
229 CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
230 end);
231}
232
233void flush_tlb_mm(struct mm_struct *mm)
234{
235 CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
236}
237
238void force_flush_all(void)
239{
240 CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
241}
242
243pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
244{
245 return(pgd_offset(mm, address));
246}
247
248pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address)
249{
250 return(pud_offset(pgd, address));
251}
252
253pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address)
254{
255 return(pmd_offset(pud, address));
256}
257
258pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
259{
260 return(pte_offset_kernel(pmd, address));
261}
262
263pte_t *addr_pte(struct task_struct *task, unsigned long addr)
264{
265 pgd_t *pgd = pgd_offset(task->mm, addr);
266 pud_t *pud = pud_offset(pgd, addr);
267 pmd_t *pmd = pmd_offset(pud, addr);
268
269 return(pte_offset_map(pmd, addr));
270}
271
272int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
273 int r, int w, int x, struct host_vm_op *ops, int index,
274 int last_filled, int data,
275 void (*do_ops)(int, struct host_vm_op *, int))
276{
277 __u64 offset;
278 struct host_vm_op *last;
279 int fd;
280
281 fd = phys_mapping(phys, &offset);
282 if(index != -1){
283 last = &ops[index];
284 if((last->type == MMAP) &&
285 (last->u.mmap.addr + last->u.mmap.len == virt) &&
286 (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
287 (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
288 (last->u.mmap.offset + last->u.mmap.len == offset)){
289 last->u.mmap.len += len;
290 return(index);
291 }
292 }
293
294 if(index == last_filled){
295 (*do_ops)(data, ops, last_filled);
296 index = -1;
297 }
298
299 ops[++index] = ((struct host_vm_op) { .type = MMAP,
300 .u = { .mmap = {
301 .addr = virt,
302 .len = len,
303 .r = r,
304 .w = w,
305 .x = x,
306 .fd = fd,
307 .offset = offset }
308 } });
309 return(index);
310}
311
312int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
313 int index, int last_filled, int data,
314 void (*do_ops)(int, struct host_vm_op *, int))
315{
316 struct host_vm_op *last;
317
318 if(index != -1){
319 last = &ops[index];
320 if((last->type == MUNMAP) &&
321 (last->u.munmap.addr + last->u.mmap.len == addr)){
322 last->u.munmap.len += len;
323 return(index);
324 }
325 }
326
327 if(index == last_filled){
328 (*do_ops)(data, ops, last_filled);
329 index = -1;
330 }
331
332 ops[++index] = ((struct host_vm_op) { .type = MUNMAP,
333 .u = { .munmap = {
334 .addr = addr,
335 .len = len } } });
336 return(index);
337}
338
339int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
340 struct host_vm_op *ops, int index, int last_filled, int data,
341 void (*do_ops)(int, struct host_vm_op *, int))
342{
343 struct host_vm_op *last;
344
345 if(index != -1){
346 last = &ops[index];
347 if((last->type == MPROTECT) &&
348 (last->u.mprotect.addr + last->u.mprotect.len == addr) &&
349 (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
350 (last->u.mprotect.x == x)){
351 last->u.mprotect.len += len;
352 return(index);
353 }
354 }
355
356 if(index == last_filled){
357 (*do_ops)(data, ops, last_filled);
358 index = -1;
359 }
360
361 ops[++index] = ((struct host_vm_op) { .type = MPROTECT,
362 .u = { .mprotect = {
363 .addr = addr,
364 .len = len,
365 .r = r,
366 .w = w,
367 .x = x } } });
368 return(index);
369}
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
new file mode 100644
index 000000000000..47e766e6ba10
--- /dev/null
+++ b/arch/um/kernel/trap_kern.c
@@ -0,0 +1,251 @@
1/*
2 * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "asm/errno.h"
8#include "linux/sched.h"
9#include "linux/mm.h"
10#include "linux/spinlock.h"
11#include "linux/config.h"
12#include "linux/init.h"
13#include "linux/ptrace.h"
14#include "asm/semaphore.h"
15#include "asm/pgtable.h"
16#include "asm/pgalloc.h"
17#include "asm/tlbflush.h"
18#include "asm/a.out.h"
19#include "asm/current.h"
20#include "asm/irq.h"
21#include "user_util.h"
22#include "kern_util.h"
23#include "kern.h"
24#include "chan_kern.h"
25#include "mconsole_kern.h"
26#include "2_5compat.h"
27#include "mem.h"
28#include "mem_kern.h"
29
30int handle_page_fault(unsigned long address, unsigned long ip,
31 int is_write, int is_user, int *code_out)
32{
33 struct mm_struct *mm = current->mm;
34 struct vm_area_struct *vma;
35 pgd_t *pgd;
36 pud_t *pud;
37 pmd_t *pmd;
38 pte_t *pte;
39 unsigned long page;
40 int err = -EFAULT;
41
42 *code_out = SEGV_MAPERR;
43 down_read(&mm->mmap_sem);
44 vma = find_vma(mm, address);
45 if(!vma)
46 goto out;
47 else if(vma->vm_start <= address)
48 goto good_area;
49 else if(!(vma->vm_flags & VM_GROWSDOWN))
50 goto out;
51 else if(!ARCH_IS_STACKGROW(address))
52 goto out;
53 else if(expand_stack(vma, address))
54 goto out;
55
56 good_area:
57 *code_out = SEGV_ACCERR;
58 if(is_write && !(vma->vm_flags & VM_WRITE))
59 goto out;
60 page = address & PAGE_MASK;
61 pgd = pgd_offset(mm, page);
62 pud = pud_offset(pgd, page);
63 pmd = pmd_offset(pud, page);
64 do {
65 survive:
66 switch (handle_mm_fault(mm, vma, address, is_write)){
67 case VM_FAULT_MINOR:
68 current->min_flt++;
69 break;
70 case VM_FAULT_MAJOR:
71 current->maj_flt++;
72 break;
73 case VM_FAULT_SIGBUS:
74 err = -EACCES;
75 goto out;
76 case VM_FAULT_OOM:
77 err = -ENOMEM;
78 goto out_of_memory;
79 default:
80 BUG();
81 }
82 pgd = pgd_offset(mm, page);
83 pud = pud_offset(pgd, page);
84 pmd = pmd_offset(pud, page);
85 pte = pte_offset_kernel(pmd, page);
86 } while(!pte_present(*pte));
87 err = 0;
88 *pte = pte_mkyoung(*pte);
89 if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
90 flush_tlb_page(vma, page);
91 out:
92 up_read(&mm->mmap_sem);
93 return(err);
94
95/*
96 * We ran out of memory, or some other thing happened to us that made
97 * us unable to handle the page fault gracefully.
98 */
99out_of_memory:
100 if (current->pid == 1) {
101 up_read(&mm->mmap_sem);
102 yield();
103 down_read(&mm->mmap_sem);
104 goto survive;
105 }
106 goto out;
107}
108
109LIST_HEAD(physmem_remappers);
110
111void register_remapper(struct remapper *info)
112{
113 list_add(&info->list, &physmem_remappers);
114}
115
116static int check_remapped_addr(unsigned long address, int is_write)
117{
118 struct remapper *remapper;
119 struct list_head *ele;
120 __u64 offset;
121 int fd;
122
123 fd = phys_mapping(__pa(address), &offset);
124 if(fd == -1)
125 return(0);
126
127 list_for_each(ele, &physmem_remappers){
128 remapper = list_entry(ele, struct remapper, list);
129 if((*remapper->proc)(fd, address, is_write, offset))
130 return(1);
131 }
132
133 return(0);
134}
135
136unsigned long segv(unsigned long address, unsigned long ip, int is_write,
137 int is_user, void *sc)
138{
139 struct siginfo si;
140 void *catcher;
141 int err;
142
143 if(!is_user && (address >= start_vm) && (address < end_vm)){
144 flush_tlb_kernel_vm();
145 return(0);
146 }
147 else if(check_remapped_addr(address & PAGE_MASK, is_write))
148 return(0);
149 else if(current->mm == NULL)
150 panic("Segfault with no mm");
151 err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
152
153 catcher = current->thread.fault_catcher;
154 if(!err)
155 return(0);
156 else if(catcher != NULL){
157 current->thread.fault_addr = (void *) address;
158 do_longjmp(catcher, 1);
159 }
160 else if(current->thread.fault_addr != NULL)
161 panic("fault_addr set but no fault catcher");
162 else if(arch_fixup(ip, sc))
163 return(0);
164
165 if(!is_user)
166 panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
167 address, ip);
168
169 if(err == -EACCES){
170 si.si_signo = SIGBUS;
171 si.si_errno = 0;
172 si.si_code = BUS_ADRERR;
173 si.si_addr = (void *)address;
174 force_sig_info(SIGBUS, &si, current);
175 }
176 else if(err == -ENOMEM){
177 printk("VM: killing process %s\n", current->comm);
178 do_exit(SIGKILL);
179 }
180 else {
181 si.si_signo = SIGSEGV;
182 si.si_addr = (void *) address;
183 current->thread.cr2 = address;
184 current->thread.err = is_write;
185 force_sig_info(SIGSEGV, &si, current);
186 }
187 return(0);
188}
189
190void bad_segv(unsigned long address, unsigned long ip, int is_write)
191{
192 struct siginfo si;
193
194 si.si_signo = SIGSEGV;
195 si.si_code = SEGV_ACCERR;
196 si.si_addr = (void *) address;
197 current->thread.cr2 = address;
198 current->thread.err = is_write;
199 force_sig_info(SIGSEGV, &si, current);
200}
201
202void relay_signal(int sig, union uml_pt_regs *regs)
203{
204 if(arch_handle_signal(sig, regs)) return;
205 if(!UPT_IS_USER(regs))
206 panic("Kernel mode signal %d", sig);
207 force_sig(sig, current);
208}
209
210void bus_handler(int sig, union uml_pt_regs *regs)
211{
212 if(current->thread.fault_catcher != NULL)
213 do_longjmp(current->thread.fault_catcher, 1);
214 else relay_signal(sig, regs);
215}
216
217void winch(int sig, union uml_pt_regs *regs)
218{
219 do_IRQ(WINCH_IRQ, regs);
220}
221
222void trap_init(void)
223{
224}
225
226DEFINE_SPINLOCK(trap_lock);
227
228static int trap_index = 0;
229
230int next_trap_index(int limit)
231{
232 int ret;
233
234 spin_lock(&trap_lock);
235 ret = trap_index;
236 if(++trap_index == limit)
237 trap_index = 0;
238 spin_unlock(&trap_lock);
239 return(ret);
240}
241
242/*
243 * Overrides for Emacs so that we follow Linus's tabbing style.
244 * Emacs will notice this stuff at the end of the file and automatically
245 * adjust the settings for this buffer only. This must remain at the end
246 * of the file.
247 * ---------------------------------------------------------------------------
248 * Local variables:
249 * c-file-style: "linux"
250 * End:
251 */
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
new file mode 100644
index 000000000000..50a4042a509f
--- /dev/null
+++ b/arch/um/kernel/trap_user.c
@@ -0,0 +1,120 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <errno.h>
8#include <setjmp.h>
9#include <signal.h>
10#include <sys/time.h>
11#include <sys/wait.h>
12#include <asm/page.h>
13#include <asm/unistd.h>
14#include <asm/ptrace.h>
15#include "init.h"
16#include "sysdep/ptrace.h"
17#include "sigcontext.h"
18#include "sysdep/sigcontext.h"
19#include "irq_user.h"
20#include "signal_user.h"
21#include "time_user.h"
22#include "task.h"
23#include "mode.h"
24#include "choose-mode.h"
25#include "kern_util.h"
26#include "user_util.h"
27#include "os.h"
28
29void kill_child_dead(int pid)
30{
31 kill(pid, SIGKILL);
32 kill(pid, SIGCONT);
33 do {
34 int n;
35 CATCH_EINTR(n = waitpid(pid, NULL, 0));
36 if (n > 0)
37 kill(pid, SIGCONT);
38 else
39 break;
40 } while(1);
41}
42
43/* Unlocked - don't care if this is a bit off */
44int nsegfaults = 0;
45
46struct {
47 unsigned long address;
48 int is_write;
49 int pid;
50 unsigned long sp;
51 int is_user;
52} segfault_record[1024];
53
54void segv_handler(int sig, union uml_pt_regs *regs)
55{
56 int index, max;
57
58 if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){
59 bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs),
60 UPT_FAULT_WRITE(regs));
61 return;
62 }
63 max = sizeof(segfault_record)/sizeof(segfault_record[0]);
64 index = next_trap_index(max);
65
66 nsegfaults++;
67 segfault_record[index].address = UPT_FAULT_ADDR(regs);
68 segfault_record[index].pid = os_getpid();
69 segfault_record[index].is_write = UPT_FAULT_WRITE(regs);
70 segfault_record[index].sp = UPT_SP(regs);
71 segfault_record[index].is_user = UPT_IS_USER(regs);
72 segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs),
73 UPT_IS_USER(regs), regs);
74}
75
76void usr2_handler(int sig, union uml_pt_regs *regs)
77{
78 CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0);
79}
80
81struct signal_info sig_info[] = {
82 [ SIGTRAP ] { .handler = relay_signal,
83 .is_irq = 0 },
84 [ SIGFPE ] { .handler = relay_signal,
85 .is_irq = 0 },
86 [ SIGILL ] { .handler = relay_signal,
87 .is_irq = 0 },
88 [ SIGWINCH ] { .handler = winch,
89 .is_irq = 1 },
90 [ SIGBUS ] { .handler = bus_handler,
91 .is_irq = 0 },
92 [ SIGSEGV] { .handler = segv_handler,
93 .is_irq = 0 },
94 [ SIGIO ] { .handler = sigio_handler,
95 .is_irq = 1 },
96 [ SIGVTALRM ] { .handler = timer_handler,
97 .is_irq = 1 },
98 [ SIGALRM ] { .handler = timer_handler,
99 .is_irq = 1 },
100 [ SIGUSR2 ] { .handler = usr2_handler,
101 .is_irq = 0 },
102};
103
104void do_longjmp(void *b, int val)
105{
106 sigjmp_buf *buf = b;
107
108 siglongjmp(*buf, val);
109}
110
111/*
112 * Overrides for Emacs so that we follow Linus's tabbing style.
113 * Emacs will notice this stuff at the end of the file and automatically
114 * adjust the settings for this buffer only. This must remain at the end
115 * of the file.
116 * ---------------------------------------------------------------------------
117 * Local variables:
118 * c-file-style: "linux"
119 * End:
120 */
diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
new file mode 100644
index 000000000000..3d5177df3504
--- /dev/null
+++ b/arch/um/kernel/tt/Makefile
@@ -0,0 +1,28 @@
1#
2# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
3# Licensed under the GPL
4#
5
6extra-y := unmap_fin.o
7clean-files := unmap_tmp.o
8
9obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
10 syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
11 uaccess.o uaccess_user.o
12
13obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
14
15USER_OBJS := gdb.o time.o tracer.o
16
17include arch/um/scripts/Makefile.rules
18
19UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
20UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
21
22#XXX: partially copied from arch/um/scripts/Makefile.rules
23$(obj)/unmap.o: c_flags = -Wp,-MD,$(depfile) $(UNMAP_CFLAGS)
24
25$(obj)/unmap_fin.o : $(obj)/unmap.o
26 $(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a)
27 $(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo
28
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
new file mode 100644
index 000000000000..065b504a653b
--- /dev/null
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -0,0 +1,87 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "linux/mm.h"
8#include "asm/signal.h"
9#include "asm/ptrace.h"
10#include "asm/uaccess.h"
11#include "asm/pgalloc.h"
12#include "asm/tlbflush.h"
13#include "user_util.h"
14#include "kern_util.h"
15#include "irq_user.h"
16#include "time_user.h"
17#include "signal_user.h"
18#include "mem_user.h"
19#include "os.h"
20#include "tlb.h"
21#include "mode.h"
22
23static int exec_tramp(void *sig_stack)
24{
25 init_new_thread_stack(sig_stack, NULL);
26 init_new_thread_signals(1);
27 os_stop_process(os_getpid());
28 return(0);
29}
30
31void flush_thread_tt(void)
32{
33 unsigned long stack;
34 int new_pid;
35
36 stack = alloc_stack(0, 0);
37 if(stack == 0){
38 printk(KERN_ERR
39 "flush_thread : failed to allocate temporary stack\n");
40 do_exit(SIGKILL);
41 }
42
43 new_pid = start_fork_tramp(current->thread_info, stack, 0, exec_tramp);
44 if(new_pid < 0){
45 printk(KERN_ERR
46 "flush_thread : new thread failed, errno = %d\n",
47 -new_pid);
48 do_exit(SIGKILL);
49 }
50
51 if(current_thread->cpu == 0)
52 forward_interrupts(new_pid);
53 current->thread.request.op = OP_EXEC;
54 current->thread.request.u.exec.pid = new_pid;
55 unprotect_stack((unsigned long) current_thread);
56 os_usr1_process(os_getpid());
57 change_sig(SIGUSR1, 1);
58
59 change_sig(SIGUSR1, 0);
60 enable_timer();
61 free_page(stack);
62 protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
63 task_protections((unsigned long) current_thread);
64 force_flush_all();
65 unblock_signals();
66}
67
68void start_thread_tt(struct pt_regs *regs, unsigned long eip,
69 unsigned long esp)
70{
71 set_fs(USER_DS);
72 flush_tlb_mm(current->mm);
73 PT_REGS_IP(regs) = eip;
74 PT_REGS_SP(regs) = esp;
75 PT_FIX_EXEC_STACK(esp);
76}
77
78/*
79 * Overrides for Emacs so that we follow Linus's tabbing style.
80 * Emacs will notice this stuff at the end of the file and automatically
81 * adjust the settings for this buffer only. This must remain at the end
82 * of the file.
83 * ---------------------------------------------------------------------------
84 * Local variables:
85 * c-file-style: "linux"
86 * End:
87 */
diff --git a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c
new file mode 100644
index 000000000000..a92c02ff2ce3
--- /dev/null
+++ b/arch/um/kernel/tt/exec_user.c
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <unistd.h>
8#include <stdlib.h>
9#include <sched.h>
10#include <errno.h>
11#include <sys/wait.h>
12#include <signal.h>
13#include "user_util.h"
14#include "kern_util.h"
15#include "user.h"
16#include "ptrace_user.h"
17#include "os.h"
18
19void do_exec(int old_pid, int new_pid)
20{
21 unsigned long regs[FRAME_SIZE];
22 int err;
23
24 if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
25 (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
26 tracer_panic("do_exec failed to attach proc - errno = %d",
27 errno);
28
29 CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
30 if (err < 0)
31 tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
32 errno);
33
34 if(ptrace_getregs(old_pid, regs) < 0)
35 tracer_panic("do_exec failed to get registers - errno = %d",
36 errno);
37
38 os_kill_ptraced_process(old_pid, 0);
39
40 if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
41 tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno);
42
43 if(ptrace_setregs(new_pid, regs) < 0)
44 tracer_panic("do_exec failed to start new proc - errno = %d",
45 errno);
46}
47
48/*
49 * Overrides for Emacs so that we follow Linus's tabbing style.
50 * Emacs will notice this stuff at the end of the file and automatically
51 * adjust the settings for this buffer only. This must remain at the end
52 * of the file.
53 * ---------------------------------------------------------------------------
54 * Local variables:
55 * c-file-style: "linux"
56 * End:
57 */
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
new file mode 100644
index 000000000000..19a0ad7b35b3
--- /dev/null
+++ b/arch/um/kernel/tt/gdb.c
@@ -0,0 +1,278 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <errno.h>
9#include <string.h>
10#include <signal.h>
11#include <sys/types.h>
12#include "ptrace_user.h"
13#include "uml-config.h"
14#include "kern_constants.h"
15#include "chan_user.h"
16#include "init.h"
17#include "user.h"
18#include "debug.h"
19#include "kern_util.h"
20#include "user_util.h"
21#include "tt.h"
22#include "sysdep/thread.h"
23
24extern int debugger_pid;
25extern int debugger_fd;
26extern int debugger_parent;
27
28int detach(int pid, int sig)
29{
30 return(ptrace(PTRACE_DETACH, pid, 0, sig));
31}
32
33int attach(int pid)
34{
35 int err;
36
37 err = ptrace(PTRACE_ATTACH, pid, 0, 0);
38 if(err < 0) return(-errno);
39 else return(err);
40}
41
42int cont(int pid)
43{
44 return(ptrace(PTRACE_CONT, pid, 0, 0));
45}
46
47#ifdef UML_CONFIG_PT_PROXY
48
49int debugger_signal(int status, pid_t pid)
50{
51 return(debugger_proxy(status, pid));
52}
53
54void child_signal(pid_t pid, int status)
55{
56 child_proxy(pid, status);
57}
58
59static void gdb_announce(char *dev_name, int dev)
60{
61 printf("gdb assigned device '%s'\n", dev_name);
62}
63
64static struct chan_opts opts = {
65 .announce = gdb_announce,
66 .xterm_title = "UML kernel debugger",
67 .raw = 0,
68 .tramp_stack = 0,
69 .in_kernel = 0,
70};
71
72/* Accessed by the tracing thread, which automatically serializes access */
73static void *xterm_data;
74static int xterm_fd;
75
76extern void *xterm_init(char *, int, struct chan_opts *);
77extern int xterm_open(int, int, int, void *, char **);
78extern void xterm_close(int, void *);
79
80int open_gdb_chan(void)
81{
82 char stack[UM_KERN_PAGE_SIZE], *dummy;
83
84 opts.tramp_stack = (unsigned long) stack;
85 xterm_data = xterm_init("", 0, &opts);
86 xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy);
87 return(xterm_fd);
88}
89
90static void exit_debugger_cb(void *unused)
91{
92 if(debugger_pid != -1){
93 if(gdb_pid != -1){
94 fake_child_exit();
95 gdb_pid = -1;
96 }
97 else kill_child_dead(debugger_pid);
98 debugger_pid = -1;
99 if(debugger_parent != -1)
100 detach(debugger_parent, SIGINT);
101 }
102 if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
103}
104
105static void exit_debugger(void)
106{
107 initial_thread_cb(exit_debugger_cb, NULL);
108}
109
110__uml_exitcall(exit_debugger);
111
112struct gdb_data {
113 char *str;
114 int err;
115};
116
117static void config_gdb_cb(void *arg)
118{
119 struct gdb_data *data = arg;
120 void *task;
121 int pid;
122
123 data->err = -1;
124 if(debugger_pid != -1) exit_debugger_cb(NULL);
125 if(!strncmp(data->str, "pid,", strlen("pid,"))){
126 data->str += strlen("pid,");
127 pid = strtoul(data->str, NULL, 0);
128 task = cpu_tasks[0].task;
129 debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0);
130 if(debugger_pid != -1){
131 data->err = 0;
132 gdb_pid = pid;
133 }
134 return;
135 }
136 data->err = 0;
137 debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
138 init_proxy(debugger_pid, 0, 0);
139}
140
141int gdb_config(char *str)
142{
143 struct gdb_data data;
144
145 if(*str++ != '=') return(-1);
146 data.str = str;
147 initial_thread_cb(config_gdb_cb, &data);
148 return(data.err);
149}
150
151void remove_gdb_cb(void *unused)
152{
153 exit_debugger_cb(NULL);
154}
155
156int gdb_remove(char *unused)
157{
158 initial_thread_cb(remove_gdb_cb, NULL);
159 return(0);
160}
161
162void signal_usr1(int sig)
163{
164 if(debugger_pid != -1){
165 printf("The debugger is already running\n");
166 return;
167 }
168 debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
169 init_proxy(debugger_pid, 0, 0);
170}
171
172int init_ptrace_proxy(int idle_pid, int startup, int stop)
173{
174 int pid, status;
175
176 pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
177 status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
178 if(pid < 0){
179 cont(idle_pid);
180 return(-1);
181 }
182 init_proxy(pid, 1, status);
183 return(pid);
184}
185
186int attach_debugger(int idle_pid, int pid, int stop)
187{
188 int status = 0, err;
189
190 err = attach(pid);
191 if(err < 0){
192 printf("Failed to attach pid %d, errno = %d\n", pid, -err);
193 return(-1);
194 }
195 if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
196 init_proxy(pid, 1, status);
197 return(pid);
198}
199
200#ifdef notdef /* Put this back in when it does something useful */
201static int __init uml_gdb_init_setup(char *line, int *add)
202{
203 gdb_init = uml_strdup(line);
204 return 0;
205}
206
207__uml_setup("gdb=", uml_gdb_init_setup,
208"gdb=<channel description>\n\n"
209);
210#endif
211
212static int __init uml_gdb_pid_setup(char *line, int *add)
213{
214 gdb_pid = strtoul(line, NULL, 0);
215 *add = 0;
216 return 0;
217}
218
219__uml_setup("gdb-pid=", uml_gdb_pid_setup,
220"gdb-pid=<pid>\n"
221" gdb-pid is used to attach an external debugger to UML. This may be\n"
222" an already-running gdb or a debugger-like process like strace.\n\n"
223);
224
225#else
226
227int debugger_signal(int status, pid_t pid){ return(0); }
228void child_signal(pid_t pid, int status){ }
229int init_ptrace_proxy(int idle_pid, int startup, int stop)
230{
231 printf("debug requested when CONFIG_PT_PROXY is off\n");
232 kill_child_dead(idle_pid);
233 exit(1);
234}
235
236void signal_usr1(int sig)
237{
238 printf("debug requested when CONFIG_PT_PROXY is off\n");
239}
240
241int attach_debugger(int idle_pid, int pid, int stop)
242{
243 printf("attach_debugger called when CONFIG_PT_PROXY "
244 "is off\n");
245 return(-1);
246}
247
248int config_gdb(char *str)
249{
250 return(-1);
251}
252
253int remove_gdb(void)
254{
255 return(-1);
256}
257
258int init_parent_proxy(int pid)
259{
260 return(-1);
261}
262
263void debugger_parent_signal(int status, int pid)
264{
265}
266
267#endif
268
269/*
270 * Overrides for Emacs so that we follow Linus's tabbing style.
271 * Emacs will notice this stuff at the end of the file and automatically
272 * adjust the settings for this buffer only. This must remain at the end
273 * of the file.
274 * ---------------------------------------------------------------------------
275 * Local variables:
276 * c-file-style: "linux"
277 * End:
278 */
diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
new file mode 100644
index 000000000000..93fb121f86af
--- /dev/null
+++ b/arch/um/kernel/tt/gdb_kern.c
@@ -0,0 +1,40 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/init.h"
7#include "linux/config.h"
8#include "mconsole_kern.h"
9
10#ifdef CONFIG_MCONSOLE
11
12extern int gdb_config(char *str);
13extern int gdb_remove(char *unused);
14
15static struct mc_device gdb_mc = {
16 .name = "gdb",
17 .config = gdb_config,
18 .remove = gdb_remove,
19};
20
21int gdb_mc_init(void)
22{
23 mconsole_register_dev(&gdb_mc);
24 return(0);
25}
26
27__initcall(gdb_mc_init);
28
29#endif
30
31/*
32 * Overrides for Emacs so that we follow Linus's tabbing style.
33 * Emacs will notice this stuff at the end of the file and automatically
34 * adjust the settings for this buffer only. This must remain at the end
35 * of the file.
36 * ---------------------------------------------------------------------------
37 * Local variables:
38 * c-file-style: "linux"
39 * End:
40 */
diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h
new file mode 100644
index 000000000000..8eff674107ca
--- /dev/null
+++ b/arch/um/kernel/tt/include/debug.h
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and
3 * Lars Brinkhoff.
4 * Licensed under the GPL
5 */
6
7#ifndef __DEBUG_H
8#define __DEBUG_H
9
10extern int debugger_proxy(int status, pid_t pid);
11extern void child_proxy(pid_t pid, int status);
12extern void init_proxy (pid_t pid, int waiting, int status);
13extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
14extern void fake_child_exit(void);
15extern int gdb_config(char *str);
16extern int gdb_remove(char *unused);
17
18#endif
19
20/*
21 * Overrides for Emacs so that we follow Linus's tabbing style.
22 * Emacs will notice this stuff at the end of the file and automatically
23 * adjust the settings for this buffer only. This must remain at the end
24 * of the file.
25 * ---------------------------------------------------------------------------
26 * Local variables:
27 * c-file-style: "linux"
28 * End:
29 */
diff --git a/arch/um/kernel/tt/include/mmu-tt.h b/arch/um/kernel/tt/include/mmu-tt.h
new file mode 100644
index 000000000000..0440510ab3fe
--- /dev/null
+++ b/arch/um/kernel/tt/include/mmu-tt.h
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TT_MMU_H
7#define __TT_MMU_H
8
9struct mmu_context_tt {
10};
11
12#endif
13
14/*
15 * Overrides for Emacs so that we follow Linus's tabbing style.
16 * Emacs will notice this stuff at the end of the file and automatically
17 * adjust the settings for this buffer only. This must remain at the end
18 * of the file.
19 * ---------------------------------------------------------------------------
20 * Local variables:
21 * c-file-style: "linux"
22 * End:
23 */
diff --git a/arch/um/kernel/tt/include/mode-tt.h b/arch/um/kernel/tt/include/mode-tt.h
new file mode 100644
index 000000000000..efe462019069
--- /dev/null
+++ b/arch/um/kernel/tt/include/mode-tt.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MODE_TT_H__
7#define __MODE_TT_H__
8
9#include "sysdep/ptrace.h"
10
11enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
12
13extern int tracing_pid;
14
15extern int tracer(int (*init_proc)(void *), void *sp);
16extern void user_time_init_tt(void);
17extern void sig_handler_common_tt(int sig, void *sc);
18extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
19extern void reboot_tt(void);
20extern void halt_tt(void);
21extern int is_tracer_winch(int pid, int fd, void *data);
22extern void kill_off_processes_tt(void);
23
24#endif
25
26/*
27 * Overrides for Emacs so that we follow Linus's tabbing style.
28 * Emacs will notice this stuff at the end of the file and automatically
29 * adjust the settings for this buffer only. This must remain at the end
30 * of the file.
31 * ---------------------------------------------------------------------------
32 * Local variables:
33 * c-file-style: "linux"
34 * End:
35 */
diff --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h
new file mode 100644
index 000000000000..28aaab3448fa
--- /dev/null
+++ b/arch/um/kernel/tt/include/mode_kern-tt.h
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TT_MODE_KERN_H__
7#define __TT_MODE_KERN_H__
8
9#include "linux/sched.h"
10#include "asm/page.h"
11#include "asm/ptrace.h"
12#include "asm/uaccess.h"
13
14extern void *switch_to_tt(void *prev, void *next);
15extern void flush_thread_tt(void);
16extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
17 unsigned long esp);
18extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
19 unsigned long stack_top, struct task_struct *p,
20 struct pt_regs *regs);
21extern void release_thread_tt(struct task_struct *task);
22extern void exit_thread_tt(void);
23extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
24extern void init_idle_tt(void);
25extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
26extern void flush_tlb_kernel_vm_tt(void);
27extern void __flush_tlb_one_tt(unsigned long addr);
28extern void flush_tlb_range_tt(struct vm_area_struct *vma,
29 unsigned long start, unsigned long end);
30extern void flush_tlb_mm_tt(struct mm_struct *mm);
31extern void force_flush_all_tt(void);
32extern long execute_syscall_tt(void *r);
33extern void before_mem_tt(unsigned long brk_start);
34extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
35 unsigned long *task_size_out);
36extern int start_uml_tt(void);
37extern int external_pid_tt(struct task_struct *task);
38extern int thread_pid_tt(struct task_struct *task);
39
40#define kmem_end_tt (host_task_size - ABOVE_KMEM)
41
42#endif
43
44/*
45 * Overrides for Emacs so that we follow Linus's tabbing style.
46 * Emacs will notice this stuff at the end of the file and automatically
47 * adjust the settings for this buffer only. This must remain at the end
48 * of the file.
49 * ---------------------------------------------------------------------------
50 * Local variables:
51 * c-file-style: "linux"
52 * End:
53 */
diff --git a/arch/um/kernel/tt/include/tt.h b/arch/um/kernel/tt/include/tt.h
new file mode 100644
index 000000000000..c667b67af405
--- /dev/null
+++ b/arch/um/kernel/tt/include/tt.h
@@ -0,0 +1,46 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TT_H__
7#define __TT_H__
8
9#include "sysdep/ptrace.h"
10
11extern int gdb_pid;
12extern int debug;
13extern int debug_stop;
14extern int debug_trace;
15
16extern int honeypot;
17
18extern int fork_tramp(void *sig_stack);
19extern int do_proc_op(void *t, int proc_id);
20extern int tracer(int (*init_proc)(void *), void *sp);
21extern void attach_process(int pid);
22extern void tracer_panic(char *format, ...);
23extern void set_init_pid(int pid);
24extern int set_user_mode(void *task);
25extern void set_tracing(void *t, int tracing);
26extern int is_tracing(void *task);
27extern void syscall_handler(int sig, union uml_pt_regs *regs);
28extern void exit_kernel(int pid, void *task);
29extern void do_syscall(void *task, int pid, int local_using_sysemu);
30extern void do_sigtrap(void *task);
31extern int is_valid_pid(int pid);
32extern void remap_data(void *segment_start, void *segment_end, int w);
33extern long execute_syscall_tt(void *r);
34
35#endif
36
37/*
38 * Overrides for Emacs so that we follow Linus's tabbing style.
39 * Emacs will notice this stuff at the end of the file and automatically
40 * adjust the settings for this buffer only. This must remain at the end
41 * of the file.
42 * ---------------------------------------------------------------------------
43 * Local variables:
44 * c-file-style: "linux"
45 * End:
46 */
diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h
new file mode 100644
index 000000000000..f0bad010cebd
--- /dev/null
+++ b/arch/um/kernel/tt/include/uaccess-tt.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TT_UACCESS_H
7#define __TT_UACCESS_H
8
9#include "linux/string.h"
10#include "linux/sched.h"
11#include "asm/processor.h"
12#include "asm/errno.h"
13#include "asm/current.h"
14#include "asm/a.out.h"
15#include "uml_uaccess.h"
16
17#define ABOVE_KMEM (16 * 1024 * 1024)
18
19extern unsigned long end_vm;
20extern unsigned long uml_physmem;
21
22#define under_task_size(addr, size) \
23 (((unsigned long) (addr) < TASK_SIZE) && \
24 (((unsigned long) (addr) + (size)) < TASK_SIZE))
25
26#define is_stack(addr, size) \
27 (((unsigned long) (addr) < STACK_TOP) && \
28 ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
29 (((unsigned long) (addr) + (size)) <= STACK_TOP))
30
31#define access_ok_tt(type, addr, size) \
32 ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
33 (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
34 (under_task_size(addr, size) || is_stack(addr, size))))
35
36static inline int verify_area_tt(int type, const void * addr,
37 unsigned long size)
38{
39 return(access_ok_tt(type, addr, size) ? 0 : -EFAULT);
40}
41
42extern unsigned long get_fault_addr(void);
43
44extern int __do_copy_from_user(void *to, const void *from, int n,
45 void **fault_addr, void **fault_catcher);
46extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
47 void **fault_addr, void **fault_catcher);
48extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
49 void **fault_catcher);
50extern int __do_strnlen_user(const char *str, unsigned long n,
51 void **fault_addr, void **fault_catcher);
52
53extern int copy_from_user_tt(void *to, const void *from, int n);
54extern int copy_to_user_tt(void *to, const void *from, int n);
55extern int strncpy_from_user_tt(char *dst, const char *src, int count);
56extern int __clear_user_tt(void *mem, int len);
57extern int clear_user_tt(void *mem, int len);
58extern int strnlen_user_tt(const void *str, int len);
59
60#endif
61
62/*
63 * Overrides for Emacs so that we follow Linus's tabbing style.
64 * Emacs will notice this stuff at the end of the file and automatically
65 * adjust the settings for this buffer only. This must remain at the end
66 * of the file.
67 * ---------------------------------------------------------------------------
68 * Local variables:
69 * c-file-style: "linux"
70 * End:
71 */
diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c
new file mode 100644
index 000000000000..92ec85d67c7c
--- /dev/null
+++ b/arch/um/kernel/tt/ksyms.c
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/module.h"
7#include "asm/uaccess.h"
8#include "mode.h"
9
10EXPORT_SYMBOL(__do_copy_from_user);
11EXPORT_SYMBOL(__do_copy_to_user);
12EXPORT_SYMBOL(__do_strncpy_from_user);
13EXPORT_SYMBOL(__do_strnlen_user);
14EXPORT_SYMBOL(__do_clear_user);
15
16EXPORT_SYMBOL(tracing_pid);
17EXPORT_SYMBOL(honeypot);
18
19/*
20 * Overrides for Emacs so that we follow Linus's tabbing style.
21 * Emacs will notice this stuff at the end of the file and automatically
22 * adjust the settings for this buffer only. This must remain at the end
23 * of the file.
24 * ---------------------------------------------------------------------------
25 * Local variables:
26 * c-file-style: "linux"
27 * End:
28 */
diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
new file mode 100644
index 000000000000..74346a04a2b2
--- /dev/null
+++ b/arch/um/kernel/tt/mem.c
@@ -0,0 +1,51 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/stddef.h"
7#include "linux/config.h"
8#include "linux/mm.h"
9#include "asm/uaccess.h"
10#include "mem_user.h"
11#include "kern_util.h"
12#include "user_util.h"
13#include "kern.h"
14#include "tt.h"
15
16void before_mem_tt(unsigned long brk_start)
17{
18 if(debug)
19 remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
20 remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
21 remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
22}
23
24#ifdef CONFIG_HOST_2G_2G
25#define TOP 0x80000000
26#else
27#define TOP 0xc0000000
28#endif
29
30#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
31#define START (TOP - SIZE)
32
33unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
34 unsigned long *task_size_out)
35{
36 /* Round up to the nearest 4M */
37 *host_size_out = ROUND_4M((unsigned long) &arg);
38 *task_size_out = START;
39 return(START);
40}
41
42/*
43 * Overrides for Emacs so that we follow Linus's tabbing style.
44 * Emacs will notice this stuff at the end of the file and automatically
45 * adjust the settings for this buffer only. This must remain at the end
46 * of the file.
47 * ---------------------------------------------------------------------------
48 * Local variables:
49 * c-file-style: "linux"
50 * End:
51 */
diff --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c
new file mode 100644
index 000000000000..3085267459b1
--- /dev/null
+++ b/arch/um/kernel/tt/mem_user.c
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <stdio.h>
8#include <unistd.h>
9#include <string.h>
10#include <errno.h>
11#include <sys/mman.h>
12#include "tt.h"
13#include "mem_user.h"
14#include "user_util.h"
15
16void remap_data(void *segment_start, void *segment_end, int w)
17{
18 void *addr;
19 unsigned long size;
20 int data, prot;
21
22 if(w) prot = PROT_WRITE;
23 else prot = 0;
24 prot |= PROT_READ | PROT_EXEC;
25 size = (unsigned long) segment_end -
26 (unsigned long) segment_start;
27 data = create_mem_file(size);
28 addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
29 if(addr == MAP_FAILED){
30 perror("mapping new data segment");
31 exit(1);
32 }
33 memcpy(addr, segment_start, size);
34 if(switcheroo(data, prot, addr, segment_start, size) < 0){
35 printf("switcheroo failed\n");
36 exit(1);
37 }
38}
39
40/*
41 * Overrides for Emacs so that we follow Linus's tabbing style.
42 * Emacs will notice this stuff at the end of the file and automatically
43 * adjust the settings for this buffer only. This must remain at the end
44 * of the file.
45 * ---------------------------------------------------------------------------
46 * Local variables:
47 * c-file-style: "linux"
48 * End:
49 */
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
new file mode 100644
index 000000000000..f19f7c18febe
--- /dev/null
+++ b/arch/um/kernel/tt/process_kern.c
@@ -0,0 +1,476 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/signal.h"
8#include "linux/kernel.h"
9#include "linux/interrupt.h"
10#include "linux/ptrace.h"
11#include "asm/system.h"
12#include "asm/pgalloc.h"
13#include "asm/ptrace.h"
14#include "asm/tlbflush.h"
15#include "irq_user.h"
16#include "signal_user.h"
17#include "kern_util.h"
18#include "user_util.h"
19#include "os.h"
20#include "kern.h"
21#include "sigcontext.h"
22#include "time_user.h"
23#include "mem_user.h"
24#include "tlb.h"
25#include "mode.h"
26#include "init.h"
27#include "tt.h"
28
29void *switch_to_tt(void *prev, void *next, void *last)
30{
31 struct task_struct *from, *to, *prev_sched;
32 unsigned long flags;
33 int err, vtalrm, alrm, prof, cpu;
34 char c;
35 /* jailing and SMP are incompatible, so this doesn't need to be
36 * made per-cpu
37 */
38 static int reading;
39
40 from = prev;
41 to = next;
42
43 to->thread.prev_sched = from;
44
45 cpu = from->thread_info->cpu;
46 if(cpu == 0)
47 forward_interrupts(to->thread.mode.tt.extern_pid);
48#ifdef CONFIG_SMP
49 forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid);
50#endif
51 local_irq_save(flags);
52
53 vtalrm = change_sig(SIGVTALRM, 0);
54 alrm = change_sig(SIGALRM, 0);
55 prof = change_sig(SIGPROF, 0);
56
57 forward_pending_sigio(to->thread.mode.tt.extern_pid);
58
59 c = 0;
60 set_current(to);
61
62 reading = 0;
63 err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
64 if(err != sizeof(c))
65 panic("write of switch_pipe failed, err = %d", -err);
66
67 reading = 1;
68 if((from->exit_state == EXIT_ZOMBIE) ||
69 (from->exit_state == EXIT_DEAD))
70 os_kill_process(os_getpid(), 0);
71
72 err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
73 if(err != sizeof(c))
74 panic("read of switch_pipe failed, errno = %d", -err);
75
76 /* If the process that we have just scheduled away from has exited,
77 * then it needs to be killed here. The reason is that, even though
78 * it will kill itself when it next runs, that may be too late. Its
79 * stack will be freed, possibly before then, and if that happens,
80 * we have a use-after-free situation. So, it gets killed here
81 * in case it has not already killed itself.
82 */
83 prev_sched = current->thread.prev_sched;
84 if((prev_sched->exit_state == EXIT_ZOMBIE) ||
85 (prev_sched->exit_state == EXIT_DEAD))
86 os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
87
88 change_sig(SIGVTALRM, vtalrm);
89 change_sig(SIGALRM, alrm);
90 change_sig(SIGPROF, prof);
91
92 arch_switch();
93
94 flush_tlb_all();
95 local_irq_restore(flags);
96
97 return(current->thread.prev_sched);
98}
99
100void release_thread_tt(struct task_struct *task)
101{
102 int pid = task->thread.mode.tt.extern_pid;
103
104 if(os_getpid() != pid)
105 os_kill_process(pid, 0);
106}
107
108void exit_thread_tt(void)
109{
110 os_close_file(current->thread.mode.tt.switch_pipe[0]);
111 os_close_file(current->thread.mode.tt.switch_pipe[1]);
112}
113
114void suspend_new_thread(int fd)
115{
116 int err;
117 char c;
118
119 os_stop_process(os_getpid());
120 err = os_read_file(fd, &c, sizeof(c));
121 if(err != sizeof(c))
122 panic("read failed in suspend_new_thread, err = %d", -err);
123}
124
125void schedule_tail(task_t *prev);
126
127static void new_thread_handler(int sig)
128{
129 unsigned long disable;
130 int (*fn)(void *);
131 void *arg;
132
133 fn = current->thread.request.u.thread.proc;
134 arg = current->thread.request.u.thread.arg;
135
136 UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
137 disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
138 (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
139 SC_SIGMASK(UPT_SC(&current->thread.regs.regs)) &= ~disable;
140
141 suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
142
143 force_flush_all();
144 if(current->thread.prev_sched != NULL)
145 schedule_tail(current->thread.prev_sched);
146 current->thread.prev_sched = NULL;
147
148 init_new_thread_signals(1);
149 enable_timer();
150 free_page(current->thread.temp_stack);
151 set_cmdline("(kernel thread)");
152
153 change_sig(SIGUSR1, 1);
154 change_sig(SIGVTALRM, 1);
155 change_sig(SIGPROF, 1);
156 local_irq_enable();
157 if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
158 do_exit(0);
159
160 /* XXX No set_user_mode here because a newly execed process will
161 * immediately segfault on its non-existent IP, coming straight back
162 * to the signal handler, which will call set_user_mode on its way
163 * out. This should probably change since it's confusing.
164 */
165}
166
167static int new_thread_proc(void *stack)
168{
169 /* local_irq_disable is needed to block out signals until this thread is
170 * properly scheduled. Otherwise, the tracing thread will get mighty
171 * upset about any signals that arrive before that.
172 * This has the complication that it sets the saved signal mask in
173 * the sigcontext to block signals. This gets restored when this
174 * thread (or a descendant, since they get a copy of this sigcontext)
175 * returns to userspace.
176 * So, this is compensated for elsewhere.
177 * XXX There is still a small window until local_irq_disable() actually
178 * finishes where signals are possible - shouldn't be a problem in
179 * practice since SIGIO hasn't been forwarded here yet, and the
180 * local_irq_disable should finish before a SIGVTALRM has time to be
181 * delivered.
182 */
183
184 local_irq_disable();
185 init_new_thread_stack(stack, new_thread_handler);
186 os_usr1_process(os_getpid());
187 change_sig(SIGUSR1, 1);
188 return(0);
189}
190
191/* Signal masking - signals are blocked at the start of fork_tramp. They
192 * are re-enabled when finish_fork_handler is entered by fork_tramp hitting
193 * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off,
194 * so it is blocked before it's called. They are re-enabled on sigreturn
195 * despite the fact that they were blocked when the SIGUSR1 was issued because
196 * copy_thread copies the parent's sigcontext, including the signal mask
197 * onto the signal frame.
198 */
199
200void finish_fork_handler(int sig)
201{
202 UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
203 suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
204
205 force_flush_all();
206 if(current->thread.prev_sched != NULL)
207 schedule_tail(current->thread.prev_sched);
208 current->thread.prev_sched = NULL;
209
210 enable_timer();
211 change_sig(SIGVTALRM, 1);
212 local_irq_enable();
213 if(current->mm != current->parent->mm)
214 protect_memory(uml_reserved, high_physmem - uml_reserved, 1,
215 1, 0, 1);
216 task_protections((unsigned long) current_thread);
217
218 free_page(current->thread.temp_stack);
219 local_irq_disable();
220 change_sig(SIGUSR1, 0);
221 set_user_mode(current);
222}
223
224int fork_tramp(void *stack)
225{
226 local_irq_disable();
227 arch_init_thread();
228 init_new_thread_stack(stack, finish_fork_handler);
229
230 os_usr1_process(os_getpid());
231 change_sig(SIGUSR1, 1);
232 return(0);
233}
234
235int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
236 unsigned long stack_top, struct task_struct * p,
237 struct pt_regs *regs)
238{
239 int (*tramp)(void *);
240 int new_pid, err;
241 unsigned long stack;
242
243 if(current->thread.forking)
244 tramp = fork_tramp;
245 else {
246 tramp = new_thread_proc;
247 p->thread.request.u.thread = current->thread.request.u.thread;
248 }
249
250 err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
251 if(err < 0){
252 printk("copy_thread : pipe failed, err = %d\n", -err);
253 return(err);
254 }
255
256 stack = alloc_stack(0, 0);
257 if(stack == 0){
258 printk(KERN_ERR "copy_thread : failed to allocate "
259 "temporary stack\n");
260 return(-ENOMEM);
261 }
262
263 clone_flags &= CLONE_VM;
264 p->thread.temp_stack = stack;
265 new_pid = start_fork_tramp(p->thread_info, stack, clone_flags, tramp);
266 if(new_pid < 0){
267 printk(KERN_ERR "copy_thread : clone failed - errno = %d\n",
268 -new_pid);
269 return(new_pid);
270 }
271
272 if(current->thread.forking){
273 sc_to_sc(UPT_SC(&p->thread.regs.regs),
274 UPT_SC(&current->thread.regs.regs));
275 SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
276 if(sp != 0) SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
277 }
278 p->thread.mode.tt.extern_pid = new_pid;
279
280 current->thread.request.op = OP_FORK;
281 current->thread.request.u.fork.pid = new_pid;
282 os_usr1_process(os_getpid());
283
284 /* Enable the signal and then disable it to ensure that it is handled
285 * here, and nowhere else.
286 */
287 change_sig(SIGUSR1, 1);
288
289 change_sig(SIGUSR1, 0);
290 err = 0;
291 return(err);
292}
293
294void reboot_tt(void)
295{
296 current->thread.request.op = OP_REBOOT;
297 os_usr1_process(os_getpid());
298 change_sig(SIGUSR1, 1);
299}
300
301void halt_tt(void)
302{
303 current->thread.request.op = OP_HALT;
304 os_usr1_process(os_getpid());
305 change_sig(SIGUSR1, 1);
306}
307
308void kill_off_processes_tt(void)
309{
310 struct task_struct *p;
311 int me;
312
313 me = os_getpid();
314 for_each_process(p){
315 if(p->thread.mode.tt.extern_pid != me)
316 os_kill_process(p->thread.mode.tt.extern_pid, 0);
317 }
318 if(init_task.thread.mode.tt.extern_pid != me)
319 os_kill_process(init_task.thread.mode.tt.extern_pid, 0);
320}
321
322void initial_thread_cb_tt(void (*proc)(void *), void *arg)
323{
324 if(os_getpid() == tracing_pid){
325 (*proc)(arg);
326 }
327 else {
328 current->thread.request.op = OP_CB;
329 current->thread.request.u.cb.proc = proc;
330 current->thread.request.u.cb.arg = arg;
331 os_usr1_process(os_getpid());
332 change_sig(SIGUSR1, 1);
333
334 change_sig(SIGUSR1, 0);
335 }
336}
337
338int do_proc_op(void *t, int proc_id)
339{
340 struct task_struct *task;
341 struct thread_struct *thread;
342 int op, pid;
343
344 task = t;
345 thread = &task->thread;
346 op = thread->request.op;
347 switch(op){
348 case OP_NONE:
349 case OP_TRACE_ON:
350 break;
351 case OP_EXEC:
352 pid = thread->request.u.exec.pid;
353 do_exec(thread->mode.tt.extern_pid, pid);
354 thread->mode.tt.extern_pid = pid;
355 cpu_tasks[task->thread_info->cpu].pid = pid;
356 break;
357 case OP_FORK:
358 attach_process(thread->request.u.fork.pid);
359 break;
360 case OP_CB:
361 (*thread->request.u.cb.proc)(thread->request.u.cb.arg);
362 break;
363 case OP_REBOOT:
364 case OP_HALT:
365 break;
366 default:
367 tracer_panic("Bad op in do_proc_op");
368 break;
369 }
370 thread->request.op = OP_NONE;
371 return(op);
372}
373
374void init_idle_tt(void)
375{
376 default_idle();
377}
378
379extern void start_kernel(void);
380
381static int start_kernel_proc(void *unused)
382{
383 int pid;
384
385 block_signals();
386 pid = os_getpid();
387
388 cpu_tasks[0].pid = pid;
389 cpu_tasks[0].task = current;
390#ifdef CONFIG_SMP
391 cpu_online_map = cpumask_of_cpu(0);
392#endif
393 if(debug) os_stop_process(pid);
394 start_kernel();
395 return(0);
396}
397
398void set_tracing(void *task, int tracing)
399{
400 ((struct task_struct *) task)->thread.mode.tt.tracing = tracing;
401}
402
403int is_tracing(void *t)
404{
405 return (((struct task_struct *) t)->thread.mode.tt.tracing);
406}
407
408int set_user_mode(void *t)
409{
410 struct task_struct *task;
411
412 task = t ? t : current;
413 if(task->thread.mode.tt.tracing)
414 return(1);
415 task->thread.request.op = OP_TRACE_ON;
416 os_usr1_process(os_getpid());
417 return(0);
418}
419
420void set_init_pid(int pid)
421{
422 int err;
423
424 init_task.thread.mode.tt.extern_pid = pid;
425 err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
426 if(err)
427 panic("Can't create switch pipe for init_task, errno = %d",
428 -err);
429}
430
431int start_uml_tt(void)
432{
433 void *sp;
434 int pages;
435
436 pages = (1 << CONFIG_KERNEL_STACK_ORDER);
437 sp = (void *) ((unsigned long) init_task.thread_info) +
438 pages * PAGE_SIZE - sizeof(unsigned long);
439 return(tracer(start_kernel_proc, sp));
440}
441
442int external_pid_tt(struct task_struct *task)
443{
444 return(task->thread.mode.tt.extern_pid);
445}
446
447int thread_pid_tt(struct task_struct *task)
448{
449 return(task->thread.mode.tt.extern_pid);
450}
451
452int is_valid_pid(int pid)
453{
454 struct task_struct *task;
455
456 read_lock(&tasklist_lock);
457 for_each_process(task){
458 if(task->thread.mode.tt.extern_pid == pid){
459 read_unlock(&tasklist_lock);
460 return(1);
461 }
462 }
463 read_unlock(&tasklist_lock);
464 return(0);
465}
466
467/*
468 * Overrides for Emacs so that we follow Linus's tabbing style.
469 * Emacs will notice this stuff at the end of the file and automatically
470 * adjust the settings for this buffer only. This must remain at the end
471 * of the file.
472 * ---------------------------------------------------------------------------
473 * Local variables:
474 * c-file-style: "linux"
475 * End:
476 */
diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile
new file mode 100644
index 000000000000..3ad5b774de59
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/Makefile
@@ -0,0 +1,10 @@
1#
2# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6obj-y = proxy.o ptrace.o sysdep.o wait.o
7
8USER_OBJS := $(obj-y)
9
10include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
new file mode 100644
index 000000000000..58800c50b10e
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/proxy.c
@@ -0,0 +1,377 @@
1/**********************************************************************
2proxy.c
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6
7Jeff Dike (jdike@karaya.com) : Modified for integration into uml
8**********************************************************************/
9
10/* XXX This file shouldn't refer to CONFIG_* */
11
12#include <errno.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <signal.h>
17#include <string.h>
18#include <termios.h>
19#include <sys/wait.h>
20#include <sys/types.h>
21#include <sys/ioctl.h>
22#include <asm/unistd.h>
23#include "ptrace_user.h"
24
25#include "ptproxy.h"
26#include "sysdep.h"
27#include "wait.h"
28
29#include "user_util.h"
30#include "user.h"
31#include "os.h"
32#include "tempfile.h"
33
34static int debugger_wait(debugger_state *debugger, int *status, int options,
35 int (*syscall)(debugger_state *debugger, pid_t child),
36 int (*normal_return)(debugger_state *debugger,
37 pid_t unused),
38 int (*wait_return)(debugger_state *debugger,
39 pid_t unused))
40{
41 if(debugger->real_wait){
42 debugger->handle_trace = normal_return;
43 syscall_continue(debugger->pid);
44 debugger->real_wait = 0;
45 return(1);
46 }
47 debugger->wait_status_ptr = status;
48 debugger->wait_options = options;
49 if((debugger->debugee != NULL) && debugger->debugee->event){
50 syscall_continue(debugger->pid);
51 wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
52 NULL);
53 (*wait_return)(debugger, -1);
54 return(0);
55 }
56 else if(debugger->wait_options & WNOHANG){
57 syscall_cancel(debugger->pid, 0);
58 debugger->handle_trace = syscall;
59 return(0);
60 }
61 else {
62 syscall_pause(debugger->pid);
63 debugger->handle_trace = wait_return;
64 debugger->waiting = 1;
65 }
66 return(1);
67}
68
69/*
70 * Handle debugger trap, i.e. syscall.
71 */
72
73int debugger_syscall(debugger_state *debugger, pid_t child)
74{
75 long arg1, arg2, arg3, arg4, arg5, result;
76 int syscall, ret = 0;
77
78 syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,
79 &arg5);
80
81 switch(syscall){
82 case __NR_execve:
83 /* execve never returns */
84 debugger->handle_trace = debugger_syscall;
85 break;
86
87 case __NR_ptrace:
88 if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
89 if(!debugger->debugee->in_context)
90 child = debugger->debugee->pid;
91 result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
92 &ret);
93 syscall_cancel(debugger->pid, result);
94 debugger->handle_trace = debugger_syscall;
95 return(ret);
96
97#ifdef __NR_waitpid
98 case __NR_waitpid:
99#endif
100 case __NR_wait4:
101 if(!debugger_wait(debugger, (int *) arg2, arg3,
102 debugger_syscall, debugger_normal_return,
103 proxy_wait_return))
104 return(0);
105 break;
106
107 case __NR_kill:
108 if(!debugger->debugee->in_context)
109 child = debugger->debugee->pid;
110 if(arg1 == debugger->debugee->pid){
111 result = kill(child, arg2);
112 syscall_cancel(debugger->pid, result);
113 debugger->handle_trace = debugger_syscall;
114 return(0);
115 }
116 else debugger->handle_trace = debugger_normal_return;
117 break;
118
119 default:
120 debugger->handle_trace = debugger_normal_return;
121 }
122
123 syscall_continue(debugger->pid);
124 return(0);
125}
126
127/* Used by the tracing thread */
128static debugger_state parent;
129static int parent_syscall(debugger_state *debugger, int pid);
130
131int init_parent_proxy(int pid)
132{
133 parent = ((debugger_state) { .pid = pid,
134 .wait_options = 0,
135 .wait_status_ptr = NULL,
136 .waiting = 0,
137 .real_wait = 0,
138 .expecting_child = 0,
139 .handle_trace = parent_syscall,
140 .debugee = NULL } );
141 return(0);
142}
143
144int parent_normal_return(debugger_state *debugger, pid_t unused)
145{
146 debugger->handle_trace = parent_syscall;
147 syscall_continue(debugger->pid);
148 return(0);
149}
150
151static int parent_syscall(debugger_state *debugger, int pid)
152{
153 long arg1, arg2, arg3, arg4, arg5;
154 int syscall;
155
156 syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
157
158 if((syscall == __NR_wait4)
159#ifdef __NR_waitpid
160 || (syscall == __NR_waitpid)
161#endif
162 ){
163 debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
164 parent_normal_return, parent_wait_return);
165 }
166 else ptrace(PTRACE_SYSCALL, pid, 0, 0);
167 return(0);
168}
169
170int debugger_normal_return(debugger_state *debugger, pid_t unused)
171{
172 debugger->handle_trace = debugger_syscall;
173 syscall_continue(debugger->pid);
174 return(0);
175}
176
177void debugger_cancelled_return(debugger_state *debugger, int result)
178{
179 debugger->handle_trace = debugger_syscall;
180 syscall_set_result(debugger->pid, result);
181 syscall_continue(debugger->pid);
182}
183
184/* Used by the tracing thread */
185static debugger_state debugger;
186static debugee_state debugee;
187
188void init_proxy (pid_t debugger_pid, int stopped, int status)
189{
190 debugger.pid = debugger_pid;
191 debugger.handle_trace = debugger_syscall;
192 debugger.debugee = &debugee;
193 debugger.waiting = 0;
194 debugger.real_wait = 0;
195 debugger.expecting_child = 0;
196
197 debugee.pid = 0;
198 debugee.traced = 0;
199 debugee.stopped = stopped;
200 debugee.event = 0;
201 debugee.zombie = 0;
202 debugee.died = 0;
203 debugee.wait_status = status;
204 debugee.in_context = 1;
205}
206
207int debugger_proxy(int status, int pid)
208{
209 int ret = 0, sig;
210
211 if(WIFSTOPPED(status)){
212 sig = WSTOPSIG(status);
213 if (sig == SIGTRAP)
214 ret = (*debugger.handle_trace)(&debugger, pid);
215
216 else if(sig == SIGCHLD){
217 if(debugger.expecting_child){
218 ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
219 debugger.expecting_child = 0;
220 }
221 else if(debugger.waiting)
222 real_wait_return(&debugger);
223 else {
224 ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
225 debugger.real_wait = 1;
226 }
227 }
228 else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
229 }
230 else if(WIFEXITED(status)){
231 tracer_panic("debugger (pid %d) exited with status %d",
232 debugger.pid, WEXITSTATUS(status));
233 }
234 else if(WIFSIGNALED(status)){
235 tracer_panic("debugger (pid %d) exited with signal %d",
236 debugger.pid, WTERMSIG(status));
237 }
238 else {
239 tracer_panic("proxy got unknown status (0x%x) on debugger "
240 "(pid %d)", status, debugger.pid);
241 }
242 return(ret);
243}
244
245void child_proxy(pid_t pid, int status)
246{
247 debugee.event = 1;
248 debugee.wait_status = status;
249
250 if(WIFSTOPPED(status)){
251 debugee.stopped = 1;
252 debugger.expecting_child = 1;
253 kill(debugger.pid, SIGCHLD);
254 }
255 else if(WIFEXITED(status) || WIFSIGNALED(status)){
256 debugee.zombie = 1;
257 debugger.expecting_child = 1;
258 kill(debugger.pid, SIGCHLD);
259 }
260 else panic("proxy got unknown status (0x%x) on child (pid %d)",
261 status, pid);
262}
263
264void debugger_parent_signal(int status, int pid)
265{
266 int sig;
267
268 if(WIFSTOPPED(status)){
269 sig = WSTOPSIG(status);
270 if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
271 else ptrace(PTRACE_SYSCALL, pid, 0, sig);
272 }
273}
274
275void fake_child_exit(void)
276{
277 int status, pid;
278
279 child_proxy(1, W_EXITCODE(0, 0));
280 while(debugger.waiting == 1){
281 CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
282 if(pid != debugger.pid){
283 printk("fake_child_exit - waitpid failed, "
284 "errno = %d\n", errno);
285 return;
286 }
287 debugger_proxy(status, debugger.pid);
288 }
289 CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
290 if(pid != debugger.pid){
291 printk("fake_child_exit - waitpid failed, "
292 "errno = %d\n", errno);
293 return;
294 }
295 if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
296 printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
297 errno);
298}
299
300char gdb_init_string[] =
301"att 1 \n\
302b panic \n\
303b stop \n\
304handle SIGWINCH nostop noprint pass \n\
305";
306
307int start_debugger(char *prog, int startup, int stop, int *fd_out)
308{
309 int slave, child;
310
311 slave = open_gdb_chan();
312 child = fork();
313 if(child == 0){
314 char *tempname = NULL;
315 int fd;
316
317 if(setsid() < 0) perror("setsid");
318 if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) ||
319 (dup2(slave, 2) < 0)){
320 printk("start_debugger : dup2 failed, errno = %d\n",
321 errno);
322 exit(1);
323 }
324 if(ioctl(0, TIOCSCTTY, 0) < 0){
325 printk("start_debugger : TIOCSCTTY failed, "
326 "errno = %d\n", errno);
327 exit(1);
328 }
329 if(tcsetpgrp (1, os_getpid()) < 0){
330 printk("start_debugger : tcsetpgrp failed, "
331 "errno = %d\n", errno);
332#ifdef notdef
333 exit(1);
334#endif
335 }
336 fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
337 if(fd < 0){
338 printk("start_debugger : make_tempfile failed,"
339 "err = %d\n", -fd);
340 exit(1);
341 }
342 os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
343 if(startup){
344 if(stop){
345 os_write_file(fd, "b start_kernel\n",
346 strlen("b start_kernel\n"));
347 }
348 os_write_file(fd, "c\n", strlen("c\n"));
349 }
350 if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
351 printk("start_debugger : PTRACE_TRACEME failed, "
352 "errno = %d\n", errno);
353 exit(1);
354 }
355 execlp("gdb", "gdb", "--command", tempname, prog, NULL);
356 printk("start_debugger : exec of gdb failed, errno = %d\n",
357 errno);
358 }
359 if(child < 0){
360 printk("start_debugger : fork for gdb failed, errno = %d\n",
361 errno);
362 return(-1);
363 }
364 *fd_out = slave;
365 return(child);
366}
367
368/*
369 * Overrides for Emacs so that we follow Linus's tabbing style.
370 * Emacs will notice this stuff at the end of the file and automatically
371 * adjust the settings for this buffer only. This must remain at the end
372 * of the file.
373 * ---------------------------------------------------------------------------
374 * Local variables:
375 * c-file-style: "linux"
376 * End:
377 */
diff --git a/arch/um/kernel/tt/ptproxy/ptproxy.h b/arch/um/kernel/tt/ptproxy/ptproxy.h
new file mode 100644
index 000000000000..5eb0285b1968
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/ptproxy.h
@@ -0,0 +1,61 @@
1/**********************************************************************
2ptproxy.h
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6**********************************************************************/
7
8#ifndef __PTPROXY_H
9#define __PTPROXY_H
10
11#include <sys/types.h>
12
13typedef struct debugger debugger_state;
14typedef struct debugee debugee_state;
15
16struct debugger
17{
18 pid_t pid;
19 int wait_options;
20 int *wait_status_ptr;
21 unsigned int waiting : 1;
22 unsigned int real_wait : 1;
23 unsigned int expecting_child : 1;
24 int (*handle_trace) (debugger_state *, pid_t);
25
26 debugee_state *debugee;
27};
28
29struct debugee
30{
31 pid_t pid;
32 int wait_status;
33 unsigned int died : 1;
34 unsigned int event : 1;
35 unsigned int stopped : 1;
36 unsigned int trace_singlestep : 1;
37 unsigned int trace_syscall : 1;
38 unsigned int traced : 1;
39 unsigned int zombie : 1;
40 unsigned int in_context : 1;
41};
42
43extern int debugger_syscall(debugger_state *debugger, pid_t pid);
44extern int debugger_normal_return (debugger_state *debugger, pid_t unused);
45
46extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t,
47 int *strace_out);
48extern void debugger_cancelled_return(debugger_state *debugger, int result);
49
50#endif
51
52/*
53 * Overrides for Emacs so that we follow Linus's tabbing style.
54 * Emacs will notice this stuff at the end of the file and automatically
55 * adjust the settings for this buffer only. This must remain at the end
56 * of the file.
57 * ---------------------------------------------------------------------------
58 * Local variables:
59 * c-file-style: "linux"
60 * End:
61 */
diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
new file mode 100644
index 000000000000..528a5fc8d887
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/ptrace.c
@@ -0,0 +1,237 @@
1/**********************************************************************
2ptrace.c
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6
7Jeff Dike (jdike@karaya.com) : Modified for integration into uml
8**********************************************************************/
9
10#include <errno.h>
11#include <unistd.h>
12#include <signal.h>
13#include <sys/types.h>
14#include <sys/time.h>
15#include <sys/wait.h>
16
17#include "ptproxy.h"
18#include "debug.h"
19#include "user_util.h"
20#include "kern_util.h"
21#include "ptrace_user.h"
22#include "tt.h"
23
24long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
25 long arg3, long arg4, pid_t child, int *ret)
26{
27 sigset_t relay;
28 long result;
29 int status;
30
31 *ret = 0;
32 if(debugger->debugee->died) return(-ESRCH);
33
34 switch(arg1){
35 case PTRACE_ATTACH:
36 if(debugger->debugee->traced) return(-EPERM);
37
38 debugger->debugee->pid = arg2;
39 debugger->debugee->traced = 1;
40
41 if(is_valid_pid(arg2) && (arg2 != child)){
42 debugger->debugee->in_context = 0;
43 kill(arg2, SIGSTOP);
44 debugger->debugee->event = 1;
45 debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
46 }
47 else {
48 debugger->debugee->in_context = 1;
49 if(debugger->debugee->stopped)
50 child_proxy(child, W_STOPCODE(SIGSTOP));
51 else kill(child, SIGSTOP);
52 }
53
54 return(0);
55
56 case PTRACE_DETACH:
57 if(!debugger->debugee->traced) return(-EPERM);
58
59 debugger->debugee->traced = 0;
60 debugger->debugee->pid = 0;
61 if(!debugger->debugee->in_context)
62 kill(child, SIGCONT);
63
64 return(0);
65
66 case PTRACE_CONT:
67 if(!debugger->debugee->in_context) return(-EPERM);
68 *ret = PTRACE_CONT;
69 return(ptrace(PTRACE_CONT, child, arg3, arg4));
70
71#ifdef UM_HAVE_GETFPREGS
72 case PTRACE_GETFPREGS:
73 {
74 long regs[FP_FRAME_SIZE];
75 int i, result;
76
77 result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
78 if(result == -1) return(-errno);
79
80 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
81 ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
82 regs[i]);
83 return(result);
84 }
85#endif
86
87#ifdef UM_HAVE_GETFPXREGS
88 case PTRACE_GETFPXREGS:
89 {
90 long regs[FPX_FRAME_SIZE];
91 int i, result;
92
93 result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
94 if(result == -1) return(-errno);
95
96 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
97 ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
98 regs[i]);
99 return(result);
100 }
101#endif
102
103#ifdef UM_HAVE_GETREGS
104 case PTRACE_GETREGS:
105 {
106 long regs[FRAME_SIZE];
107 int i, result;
108
109 result = ptrace(PTRACE_GETREGS, child, 0, regs);
110 if(result == -1) return(-errno);
111
112 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
113 ptrace (PTRACE_POKEDATA, debugger->pid,
114 arg4 + 4 * i, regs[i]);
115 return(result);
116 }
117 break;
118#endif
119
120 case PTRACE_KILL:
121 result = ptrace(PTRACE_KILL, child, arg3, arg4);
122 if(result == -1) return(-errno);
123
124 return(result);
125
126 case PTRACE_PEEKDATA:
127 case PTRACE_PEEKTEXT:
128 case PTRACE_PEEKUSR:
129 /* The value being read out could be -1, so we have to
130 * check errno to see if there's an error, and zero it
131 * beforehand so we're not faked out by an old error
132 */
133
134 errno = 0;
135 result = ptrace(arg1, child, arg3, 0);
136 if((result == -1) && (errno != 0)) return(-errno);
137
138 result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
139 if(result == -1) return(-errno);
140
141 return(result);
142
143 case PTRACE_POKEDATA:
144 case PTRACE_POKETEXT:
145 case PTRACE_POKEUSR:
146 result = ptrace(arg1, child, arg3, arg4);
147 if(result == -1) return(-errno);
148
149 if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4);
150 return(result);
151
152#ifdef UM_HAVE_SETFPREGS
153 case PTRACE_SETFPREGS:
154 {
155 long regs[FP_FRAME_SIZE];
156 int i;
157
158 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
159 regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
160 arg4 + 4 * i, 0);
161 result = ptrace(PTRACE_SETFPREGS, child, 0, regs);
162 if(result == -1) return(-errno);
163
164 return(result);
165 }
166#endif
167
168#ifdef UM_HAVE_SETFPXREGS
169 case PTRACE_SETFPXREGS:
170 {
171 long regs[FPX_FRAME_SIZE];
172 int i;
173
174 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
175 regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
176 arg4 + 4 * i, 0);
177 result = ptrace(PTRACE_SETFPXREGS, child, 0, regs);
178 if(result == -1) return(-errno);
179
180 return(result);
181 }
182#endif
183
184#ifdef UM_HAVE_SETREGS
185 case PTRACE_SETREGS:
186 {
187 long regs[FRAME_SIZE];
188 int i;
189
190 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
191 regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid,
192 arg4 + 4 * i, 0);
193 result = ptrace(PTRACE_SETREGS, child, 0, regs);
194 if(result == -1) return(-errno);
195
196 return(result);
197 }
198#endif
199
200 case PTRACE_SINGLESTEP:
201 if(!debugger->debugee->in_context) return(-EPERM);
202 sigemptyset(&relay);
203 sigaddset(&relay, SIGSEGV);
204 sigaddset(&relay, SIGILL);
205 sigaddset(&relay, SIGBUS);
206 result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
207 if(result == -1) return(-errno);
208
209 status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP,
210 &relay);
211 child_proxy(child, status);
212 return(result);
213
214 case PTRACE_SYSCALL:
215 if(!debugger->debugee->in_context) return(-EPERM);
216 result = ptrace(PTRACE_SYSCALL, child, arg3, arg4);
217 if(result == -1) return(-errno);
218
219 *ret = PTRACE_SYSCALL;
220 return(result);
221
222 case PTRACE_TRACEME:
223 default:
224 return(-EINVAL);
225 }
226}
227
228/*
229 * Overrides for Emacs so that we follow Linus's tabbing style.
230 * Emacs will notice this stuff at the end of the file and automatically
231 * adjust the settings for this buffer only. This must remain at the end
232 * of the file.
233 * ---------------------------------------------------------------------------
234 * Local variables:
235 * c-file-style: "linux"
236 * End:
237 */
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
new file mode 100644
index 000000000000..a5f0e01e214e
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/sysdep.c
@@ -0,0 +1,70 @@
1/**********************************************************************
2sysdep.c
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6**********************************************************************/
7
8#include <stdio.h>
9#include <string.h>
10#include <stdlib.h>
11#include <signal.h>
12#include <errno.h>
13#include <sys/types.h>
14#include <linux/unistd.h>
15#include "ptrace_user.h"
16#include "user_util.h"
17#include "user.h"
18
19int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4,
20 long *arg5)
21{
22 *arg1 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG1_OFFSET, 0);
23 *arg2 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG2_OFFSET, 0);
24 *arg3 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG3_OFFSET, 0);
25 *arg4 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG4_OFFSET, 0);
26 *arg5 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG5_OFFSET, 0);
27 return(ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0));
28}
29
30void syscall_cancel(pid_t pid, int result)
31{
32 if((ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
33 __NR_getpid) < 0) ||
34 (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
35 (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
36 (ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
37 (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
38 printk("ptproxy: couldn't cancel syscall: errno = %d\n",
39 errno);
40}
41
42void syscall_set_result(pid_t pid, long result)
43{
44 ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result);
45}
46
47void syscall_continue(pid_t pid)
48{
49 ptrace(PTRACE_SYSCALL, pid, 0, 0);
50}
51
52int syscall_pause(pid_t pid)
53{
54 if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
55 printk("syscall_change - ptrace failed, errno = %d\n", errno);
56 return(-1);
57 }
58 return(0);
59}
60
61/*
62 * Overrides for Emacs so that we follow Linus's tabbing style.
63 * Emacs will notice this stuff at the end of the file and automatically
64 * adjust the settings for this buffer only. This must remain at the end
65 * of the file.
66 * ---------------------------------------------------------------------------
67 * Local variables:
68 * c-file-style: "linux"
69 * End:
70 */
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.h b/arch/um/kernel/tt/ptproxy/sysdep.h
new file mode 100644
index 000000000000..735f488049aa
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/sysdep.h
@@ -0,0 +1,25 @@
1/**********************************************************************
2sysdep.h
3
4Copyright (C) 1999 Lars Brinkhoff.
5Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
6See the file COPYING for licensing terms and conditions.
7**********************************************************************/
8
9extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3,
10 long *arg4, long *arg5);
11extern void syscall_cancel (pid_t pid, long result);
12extern void syscall_set_result (pid_t pid, long result);
13extern void syscall_continue (pid_t pid);
14extern int syscall_pause(pid_t pid);
15
16/*
17 * Overrides for Emacs so that we follow Linus's tabbing style.
18 * Emacs will notice this stuff at the end of the file and automatically
19 * adjust the settings for this buffer only. This must remain at the end
20 * of the file.
21 * ---------------------------------------------------------------------------
22 * Local variables:
23 * c-file-style: "linux"
24 * End:
25 */
diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
new file mode 100644
index 000000000000..12f6319d8d76
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/wait.c
@@ -0,0 +1,86 @@
1/**********************************************************************
2wait.c
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6
7**********************************************************************/
8
9#include <errno.h>
10#include <signal.h>
11#include <sys/wait.h>
12
13#include "ptproxy.h"
14#include "sysdep.h"
15#include "wait.h"
16#include "user_util.h"
17#include "ptrace_user.h"
18#include "sysdep/ptrace.h"
19#include "sysdep/sigcontext.h"
20
21int proxy_wait_return(struct debugger *debugger, pid_t unused)
22{
23 debugger->waiting = 0;
24
25 if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){
26 debugger_cancelled_return(debugger, -ECHILD);
27 return(0);
28 }
29
30 if(debugger->debugee->zombie && debugger->debugee->event)
31 debugger->debugee->died = 1;
32
33 if(debugger->debugee->event){
34 debugger->debugee->event = 0;
35 ptrace(PTRACE_POKEDATA, debugger->pid,
36 debugger->wait_status_ptr,
37 debugger->debugee->wait_status);
38 /* if (wait4)
39 ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */
40 debugger_cancelled_return(debugger, debugger->debugee->pid);
41 return(0);
42 }
43
44 /* pause will return -EINTR, which happens to be right for wait */
45 debugger_normal_return(debugger, -1);
46 return(0);
47}
48
49int parent_wait_return(struct debugger *debugger, pid_t unused)
50{
51 return(debugger_normal_return(debugger, -1));
52}
53
54int real_wait_return(struct debugger *debugger)
55{
56 unsigned long ip;
57 int pid;
58
59 pid = debugger->pid;
60
61 ip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
62 IP_RESTART_SYSCALL(ip);
63
64 if(ptrace(PTRACE_POKEUSR, pid, PT_IP_OFFSET, ip) < 0)
65 tracer_panic("real_wait_return : Failed to restart system "
66 "call, errno = %d\n", errno);
67
68 if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
69 (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
70 (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
71 debugger_normal_return(debugger, -1))
72 tracer_panic("real_wait_return : gdb failed to wait, "
73 "errno = %d\n", errno);
74 return(0);
75}
76
77/*
78 * Overrides for Emacs so that we follow Linus's tabbing style.
79 * Emacs will notice this stuff at the end of the file and automatically
80 * adjust the settings for this buffer only. This must remain at the end
81 * of the file.
82 * ---------------------------------------------------------------------------
83 * Local variables:
84 * c-file-style: "linux"
85 * End:
86 */
diff --git a/arch/um/kernel/tt/ptproxy/wait.h b/arch/um/kernel/tt/ptproxy/wait.h
new file mode 100644
index 000000000000..542e73ee2cee
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/wait.h
@@ -0,0 +1,15 @@
1/**********************************************************************
2wait.h
3
4Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
5terms and conditions.
6**********************************************************************/
7
8#ifndef __PTPROXY_WAIT_H
9#define __PTPROXY_WAIT_H
10
11extern int proxy_wait_return(struct debugger *debugger, pid_t unused);
12extern int real_wait_return(struct debugger *debugger);
13extern int parent_wait_return(struct debugger *debugger, pid_t unused);
14
15#endif
diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
new file mode 100644
index 000000000000..2650a628719e
--- /dev/null
+++ b/arch/um/kernel/tt/syscall_kern.c
@@ -0,0 +1,47 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/types.h"
7#include "linux/utime.h"
8#include "linux/sys.h"
9#include "linux/ptrace.h"
10#include "asm/unistd.h"
11#include "asm/ptrace.h"
12#include "asm/uaccess.h"
13#include "asm/stat.h"
14#include "sysdep/syscalls.h"
15#include "kern_util.h"
16
17extern syscall_handler_t *sys_call_table[];
18
19long execute_syscall_tt(void *r)
20{
21 struct pt_regs *regs = r;
22 long res;
23 int syscall;
24
25#ifdef CONFIG_SYSCALL_DEBUG
26 current->thread.nsyscalls++;
27 nsyscalls++;
28#endif
29 syscall = UPT_SYSCALL_NR(&regs->regs);
30
31 if((syscall >= NR_syscalls) || (syscall < 0))
32 res = -ENOSYS;
33 else res = EXECUTE_SYSCALL(syscall, regs);
34
35 return(res);
36}
37
38/*
39 * Overrides for Emacs so that we follow Linus's tabbing style.
40 * Emacs will notice this stuff at the end of the file and automatically
41 * adjust the settings for this buffer only. This must remain at the end
42 * of the file.
43 * ---------------------------------------------------------------------------
44 * Local variables:
45 * c-file-style: "linux"
46 * End:
47 */
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
new file mode 100644
index 000000000000..e4e7e9c2224c
--- /dev/null
+++ b/arch/um/kernel/tt/syscall_user.c
@@ -0,0 +1,90 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <signal.h>
8#include <errno.h>
9#include <asm/unistd.h>
10#include "sysdep/ptrace.h"
11#include "sigcontext.h"
12#include "ptrace_user.h"
13#include "task.h"
14#include "user_util.h"
15#include "kern_util.h"
16#include "syscall_user.h"
17#include "tt.h"
18
19
20void syscall_handler_tt(int sig, union uml_pt_regs *regs)
21{
22 void *sc;
23 long result;
24 int syscall;
25#ifdef UML_CONFIG_DEBUG_SYSCALL
26 int index;
27#endif
28
29 syscall = UPT_SYSCALL_NR(regs);
30 sc = UPT_SC(regs);
31 SC_START_SYSCALL(sc);
32
33#ifdef UML_CONFIG_DEBUG_SYSCALL
34 index = record_syscall_start(syscall);
35#endif
36 syscall_trace(regs, 0);
37 result = execute_syscall_tt(regs);
38
39 /* regs->sc may have changed while the system call ran (there may
40 * have been an interrupt or segfault), so it needs to be refreshed.
41 */
42 UPT_SC(regs) = sc;
43
44 SC_SET_SYSCALL_RETURN(sc, result);
45
46 syscall_trace(regs, 1);
47#ifdef UML_CONFIG_DEBUG_SYSCALL
48 record_syscall_end(index, result);
49#endif
50}
51
52void do_sigtrap(void *task)
53{
54 UPT_SYSCALL_NR(TASK_REGS(task)) = -1;
55}
56
57void do_syscall(void *task, int pid, int local_using_sysemu)
58{
59 unsigned long proc_regs[FRAME_SIZE];
60
61 if(ptrace_getregs(pid, proc_regs) < 0)
62 tracer_panic("Couldn't read registers");
63
64 UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs);
65
66 if(((unsigned long *) PT_IP(proc_regs) >= &_stext) &&
67 ((unsigned long *) PT_IP(proc_regs) <= &_etext))
68 tracer_panic("I'm tracing myself and I can't get out");
69
70 /* advanced sysemu mode set syscall number to -1 automatically */
71 if (local_using_sysemu==2)
72 return;
73
74 /* syscall number -1 in sysemu skips syscall restarting in host */
75 if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
76 local_using_sysemu ? -1 : __NR_getpid) < 0)
77 tracer_panic("do_syscall : Nullifying syscall failed, "
78 "errno = %d", errno);
79}
80
81/*
82 * Overrides for Emacs so that we follow Linus's tabbing style.
83 * Emacs will notice this stuff at the end of the file and automatically
84 * adjust the settings for this buffer only. This must remain at the end
85 * of the file.
86 * ---------------------------------------------------------------------------
87 * Local variables:
88 * c-file-style: "linux"
89 * End:
90 */
diff --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c
new file mode 100644
index 000000000000..8565b71b07cd
--- /dev/null
+++ b/arch/um/kernel/tt/time.c
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <signal.h>
7#include <sys/time.h>
8#include <time_user.h>
9#include "process.h"
10#include "user.h"
11
12void user_time_init_tt(void)
13{
14 if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
15 panic("Couldn't set SIGVTALRM handler");
16 set_interval(ITIMER_VIRTUAL);
17}
18
19/*
20 * Overrides for Emacs so that we follow Linus's tabbing style.
21 * Emacs will notice this stuff at the end of the file and automatically
22 * adjust the settings for this buffer only. This must remain at the end
23 * of the file.
24 * ---------------------------------------------------------------------------
25 * Local variables:
26 * c-file-style: "linux"
27 * End:
28 */
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
new file mode 100644
index 000000000000..203216ad86f1
--- /dev/null
+++ b/arch/um/kernel/tt/tlb.c
@@ -0,0 +1,149 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Copyright 2003 PathScale, Inc.
4 * Licensed under the GPL
5 */
6
7#include "linux/stddef.h"
8#include "linux/kernel.h"
9#include "linux/sched.h"
10#include "linux/mm.h"
11#include "asm/page.h"
12#include "asm/pgtable.h"
13#include "asm/uaccess.h"
14#include "asm/tlbflush.h"
15#include "user_util.h"
16#include "mem_user.h"
17#include "os.h"
18#include "tlb.h"
19
20static void do_ops(int unused, struct host_vm_op *ops, int last)
21{
22 struct host_vm_op *op;
23 int i;
24
25 for(i = 0; i <= last; i++){
26 op = &ops[i];
27 switch(op->type){
28 case MMAP:
29 os_map_memory((void *) op->u.mmap.addr, op->u.mmap.fd,
30 op->u.mmap.offset, op->u.mmap.len,
31 op->u.mmap.r, op->u.mmap.w,
32 op->u.mmap.x);
33 break;
34 case MUNMAP:
35 os_unmap_memory((void *) op->u.munmap.addr,
36 op->u.munmap.len);
37 break;
38 case MPROTECT:
39 protect_memory(op->u.mprotect.addr, op->u.munmap.len,
40 op->u.mprotect.r, op->u.mprotect.w,
41 op->u.mprotect.x, 1);
42 break;
43 default:
44 printk("Unknown op type %d in do_ops\n", op->type);
45 break;
46 }
47 }
48}
49
50static void fix_range(struct mm_struct *mm, unsigned long start_addr,
51 unsigned long end_addr, int force)
52{
53 if((current->thread.mode.tt.extern_pid != -1) &&
54 (current->thread.mode.tt.extern_pid != os_getpid()))
55 panic("fix_range fixing wrong address space, current = 0x%p",
56 current);
57
58 fix_range_common(mm, start_addr, end_addr, force, 0, do_ops);
59}
60
61atomic_t vmchange_seq = ATOMIC_INIT(1);
62
63void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end)
64{
65 if(flush_tlb_kernel_range_common(start, end))
66 atomic_inc(&vmchange_seq);
67}
68
69static void protect_vm_page(unsigned long addr, int w, int must_succeed)
70{
71 int err;
72
73 err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed);
74 if(err == 0) return;
75 else if((err == -EFAULT) || (err == -ENOMEM)){
76 flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
77 protect_vm_page(addr, w, 1);
78 }
79 else panic("protect_vm_page : protect failed, errno = %d\n", err);
80}
81
82void mprotect_kernel_vm(int w)
83{
84 struct mm_struct *mm;
85 pgd_t *pgd;
86 pud_t *pud;
87 pmd_t *pmd;
88 pte_t *pte;
89 unsigned long addr;
90
91 mm = &init_mm;
92 for(addr = start_vm; addr < end_vm;){
93 pgd = pgd_offset(mm, addr);
94 pud = pud_offset(pgd, addr);
95 pmd = pmd_offset(pud, addr);
96 if(pmd_present(*pmd)){
97 pte = pte_offset_kernel(pmd, addr);
98 if(pte_present(*pte)) protect_vm_page(addr, w, 0);
99 addr += PAGE_SIZE;
100 }
101 else addr += PMD_SIZE;
102 }
103}
104
105void flush_tlb_kernel_vm_tt(void)
106{
107 flush_tlb_kernel_range(start_vm, end_vm);
108}
109
110void __flush_tlb_one_tt(unsigned long addr)
111{
112 flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
113}
114
115void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start,
116 unsigned long end)
117{
118 if(vma->vm_mm != current->mm) return;
119
120 /* Assumes that the range start ... end is entirely within
121 * either process memory or kernel vm
122 */
123 if((start >= start_vm) && (start < end_vm)){
124 if(flush_tlb_kernel_range_common(start, end))
125 atomic_inc(&vmchange_seq);
126 }
127 else fix_range(vma->vm_mm, start, end, 0);
128}
129
130void flush_tlb_mm_tt(struct mm_struct *mm)
131{
132 unsigned long seq;
133
134 if(mm != current->mm) return;
135
136 fix_range(mm, 0, STACK_TOP, 0);
137
138 seq = atomic_read(&vmchange_seq);
139 if(current->thread.mode.tt.vm_seq == seq)
140 return;
141 current->thread.mode.tt.vm_seq = seq;
142 flush_tlb_kernel_range_common(start_vm, end_vm);
143}
144
145void force_flush_all_tt(void)
146{
147 fix_range(current->mm, 0, STACK_TOP, 1);
148 flush_tlb_kernel_range_common(start_vm, end_vm);
149}
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
new file mode 100644
index 000000000000..7b5d937e5955
--- /dev/null
+++ b/arch/um/kernel/tt/tracer.c
@@ -0,0 +1,480 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdarg.h>
9#include <unistd.h>
10#include <signal.h>
11#include <errno.h>
12#include <sched.h>
13#include <string.h>
14#include <sys/mman.h>
15#include <sys/time.h>
16#include <sys/wait.h>
17#include "user.h"
18#include "sysdep/ptrace.h"
19#include "sigcontext.h"
20#include "sysdep/sigcontext.h"
21#include "os.h"
22#include "signal_user.h"
23#include "user_util.h"
24#include "mem_user.h"
25#include "process.h"
26#include "kern_util.h"
27#include "chan_user.h"
28#include "ptrace_user.h"
29#include "mode.h"
30#include "tt.h"
31
32static int tracer_winch[2];
33
34int is_tracer_winch(int pid, int fd, void *data)
35{
36 if(pid != tracing_pid)
37 return(0);
38
39 register_winch_irq(tracer_winch[0], fd, -1, data);
40 return(1);
41}
42
43static void tracer_winch_handler(int sig)
44{
45 int n;
46 char c = 1;
47
48 n = os_write_file(tracer_winch[1], &c, sizeof(c));
49 if(n != sizeof(c))
50 printk("tracer_winch_handler - write failed, err = %d\n", -n);
51}
52
53/* Called only by the tracing thread during initialization */
54
55static void setup_tracer_winch(void)
56{
57 int err;
58
59 err = os_pipe(tracer_winch, 1, 1);
60 if(err < 0){
61 printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
62 return;
63 }
64 signal(SIGWINCH, tracer_winch_handler);
65}
66
67void attach_process(int pid)
68{
69 if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
70 (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
71 tracer_panic("OP_FORK failed to attach pid");
72 wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
73 if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
74 tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno);
75 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
76 tracer_panic("OP_FORK failed to continue process");
77}
78
79void tracer_panic(char *format, ...)
80{
81 va_list ap;
82
83 va_start(ap, format);
84 vprintf(format, ap);
85 va_end(ap);
86 printf("\n");
87 while(1) pause();
88}
89
90static void tracer_segv(int sig, struct sigcontext sc)
91{
92 printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
93 SC_FAULT_ADDR(&sc), SC_IP(&sc));
94 while(1)
95 pause();
96}
97
98/* Changed early in boot, and then only read */
99int debug = 0;
100int debug_stop = 1;
101int debug_parent = 0;
102int honeypot = 0;
103
104static int signal_tramp(void *arg)
105{
106 int (*proc)(void *);
107
108 if(honeypot && munmap((void *) (host_task_size - 0x10000000),
109 0x10000000))
110 panic("Unmapping stack failed");
111 if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
112 panic("ptrace PTRACE_TRACEME failed");
113 os_stop_process(os_getpid());
114 change_sig(SIGWINCH, 0);
115 signal(SIGUSR1, SIG_IGN);
116 change_sig(SIGCHLD, 0);
117 signal(SIGSEGV, (__sighandler_t) sig_handler);
118 set_cmdline("(idle thread)");
119 set_init_pid(os_getpid());
120 proc = arg;
121 return((*proc)(NULL));
122}
123
124static void sleeping_process_signal(int pid, int sig)
125{
126 switch(sig){
127 /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is
128 * right because the process must be in the kernel already.
129 */
130 case SIGCONT:
131 case SIGTSTP:
132 if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
133 tracer_panic("sleeping_process_signal : Failed to "
134 "continue pid %d, signal = %d, "
135 "errno = %d\n", pid, sig, errno);
136 break;
137
138 /* This happens when the debugger (e.g. strace) is doing system call
139 * tracing on the kernel. During a context switch, the current task
140 * will be set to the incoming process and the outgoing process will
141 * hop into write and then read. Since it's not the current process
142 * any more, the trace of those will land here. So, we need to just
143 * PTRACE_SYSCALL it.
144 */
145 case (SIGTRAP + 0x80):
146 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
147 tracer_panic("sleeping_process_signal : Failed to "
148 "PTRACE_SYSCALL pid %d, errno = %d\n",
149 pid, errno);
150 break;
151 case SIGSTOP:
152 break;
153 default:
154 tracer_panic("sleeping process %d got unexpected "
155 "signal : %d\n", pid, sig);
156 break;
157 }
158}
159
160/* Accessed only by the tracing thread */
161int debugger_pid = -1;
162int debugger_parent = -1;
163int debugger_fd = -1;
164int gdb_pid = -1;
165
166struct {
167 int pid;
168 int signal;
169 unsigned long addr;
170 struct timeval time;
171} signal_record[1024][32];
172
173int signal_index[32];
174int nsignals = 0;
175int debug_trace = 0;
176extern int io_nsignals, io_count, intr_count;
177
178extern void signal_usr1(int sig);
179
180int tracing_pid = -1;
181
182int tracer(int (*init_proc)(void *), void *sp)
183{
184 void *task = NULL;
185 int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
186 int proc_id = 0, n, err, old_tracing = 0, strace = 0;
187 int local_using_sysemu = 0;
188#ifdef UML_CONFIG_SYSCALL_DEBUG
189 unsigned long eip = 0;
190 int last_index;
191#endif
192 signal(SIGPIPE, SIG_IGN);
193 setup_tracer_winch();
194 tracing_pid = os_getpid();
195 printf("tracing thread pid = %d\n", tracing_pid);
196
197 pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
198 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
199 if(n < 0){
200 printf("waitpid on idle thread failed, errno = %d\n", errno);
201 exit(1);
202 }
203 if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) {
204 printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno);
205 exit(1);
206 }
207 if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
208 printf("Failed to continue idle thread, errno = %d\n", errno);
209 exit(1);
210 }
211
212 signal(SIGSEGV, (sighandler_t) tracer_segv);
213 signal(SIGUSR1, signal_usr1);
214 if(debug_trace){
215 printf("Tracing thread pausing to be attached\n");
216 stop();
217 }
218 if(debug){
219 if(gdb_pid != -1)
220 debugger_pid = attach_debugger(pid, gdb_pid, 1);
221 else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
222 if(debug_parent){
223 debugger_parent = os_process_parent(debugger_pid);
224 init_parent_proxy(debugger_parent);
225 err = attach(debugger_parent);
226 if(err){
227 printf("Failed to attach debugger parent %d, "
228 "errno = %d\n", debugger_parent, -err);
229 debugger_parent = -1;
230 }
231 else {
232 if(ptrace(PTRACE_SYSCALL, debugger_parent,
233 0, 0) < 0){
234 printf("Failed to continue debugger "
235 "parent, errno = %d\n", errno);
236 debugger_parent = -1;
237 }
238 }
239 }
240 }
241 set_cmdline("(tracing thread)");
242 while(1){
243 CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
244 if(pid <= 0){
245 if(errno != ECHILD){
246 printf("wait failed - errno = %d\n", errno);
247 }
248 continue;
249 }
250 if(pid == debugger_pid){
251 int cont = 0;
252
253 if(WIFEXITED(status) || WIFSIGNALED(status))
254 debugger_pid = -1;
255 /* XXX Figure out how to deal with gdb and SMP */
256 else cont = debugger_signal(status, cpu_tasks[0].pid);
257 if(cont == PTRACE_SYSCALL) strace = 1;
258 continue;
259 }
260 else if(pid == debugger_parent){
261 debugger_parent_signal(status, pid);
262 continue;
263 }
264 nsignals++;
265 if(WIFEXITED(status)) ;
266#ifdef notdef
267 {
268 printf("Child %d exited with status %d\n", pid,
269 WEXITSTATUS(status));
270 }
271#endif
272 else if(WIFSIGNALED(status)){
273 sig = WTERMSIG(status);
274 if(sig != 9){
275 printf("Child %d exited with signal %d\n", pid,
276 sig);
277 }
278 }
279 else if(WIFSTOPPED(status)){
280 proc_id = pid_to_processor_id(pid);
281 sig = WSTOPSIG(status);
282#ifdef UML_CONFIG_SYSCALL_DEBUG
283 if(signal_index[proc_id] == 1024){
284 signal_index[proc_id] = 0;
285 last_index = 1023;
286 }
287 else last_index = signal_index[proc_id] - 1;
288 if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
289 (sig == SIGALRM)) &&
290 (signal_record[proc_id][last_index].signal == sig)&&
291 (signal_record[proc_id][last_index].pid == pid))
292 signal_index[proc_id] = last_index;
293 signal_record[proc_id][signal_index[proc_id]].pid = pid;
294 gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
295 eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
296 signal_record[proc_id][signal_index[proc_id]].addr = eip;
297 signal_record[proc_id][signal_index[proc_id]++].signal = sig;
298#endif
299 if(proc_id == -1){
300 sleeping_process_signal(pid, sig);
301 continue;
302 }
303
304 task = cpu_tasks[proc_id].task;
305 tracing = is_tracing(task);
306 old_tracing = tracing;
307
308 /* Assume: no syscall, when coming from user */
309 if ( tracing )
310 do_sigtrap(task);
311
312 switch(sig){
313 case SIGUSR1:
314 sig = 0;
315 op = do_proc_op(task, proc_id);
316 switch(op){
317 /*
318 * This is called when entering user mode; after
319 * this, we start intercepting syscalls.
320 *
321 * In fact, a process is started in kernel mode,
322 * so with is_tracing() == 0 (and that is reset
323 * when executing syscalls, since UML kernel has
324 * the right to do syscalls);
325 */
326 case OP_TRACE_ON:
327 arch_leave_kernel(task, pid);
328 tracing = 1;
329 break;
330 case OP_REBOOT:
331 case OP_HALT:
332 unmap_physmem();
333 kmalloc_ok = 0;
334 os_kill_ptraced_process(pid, 0);
335 /* Now let's reap remaining zombies */
336 errno = 0;
337 do {
338 waitpid(-1, &status,
339 WUNTRACED);
340 } while (errno != ECHILD);
341 return(op == OP_REBOOT);
342 case OP_NONE:
343 printf("Detaching pid %d\n", pid);
344 detach(pid, SIGSTOP);
345 continue;
346 default:
347 break;
348 }
349 /* OP_EXEC switches host processes on us,
350 * we want to continue the new one.
351 */
352 pid = cpu_tasks[proc_id].pid;
353 break;
354 case (SIGTRAP + 0x80):
355 if(!tracing && (debugger_pid != -1)){
356 child_signal(pid, status & 0x7fff);
357 continue;
358 }
359 tracing = 0;
360 /* local_using_sysemu has been already set
361 * below, since if we are here, is_tracing() on
362 * the traced task was 1, i.e. the process had
363 * already run through one iteration of the
364 * loop which executed a OP_TRACE_ON request.*/
365 do_syscall(task, pid, local_using_sysemu);
366 sig = SIGUSR2;
367 break;
368 case SIGTRAP:
369 if(!tracing && (debugger_pid != -1)){
370 child_signal(pid, status);
371 continue;
372 }
373 tracing = 0;
374 break;
375 case SIGPROF:
376 if(tracing) sig = 0;
377 break;
378 case SIGCHLD:
379 case SIGHUP:
380 sig = 0;
381 break;
382 case SIGSEGV:
383 case SIGIO:
384 case SIGALRM:
385 case SIGVTALRM:
386 case SIGFPE:
387 case SIGBUS:
388 case SIGILL:
389 case SIGWINCH:
390
391 default:
392 tracing = 0;
393 break;
394 }
395 set_tracing(task, tracing);
396
397 if(!tracing && old_tracing)
398 arch_enter_kernel(task, pid);
399
400 if(!tracing && (debugger_pid != -1) && (sig != 0) &&
401 (sig != SIGALRM) && (sig != SIGVTALRM) &&
402 (sig != SIGSEGV) && (sig != SIGTRAP) &&
403 (sig != SIGUSR2) && (sig != SIGIO) &&
404 (sig != SIGFPE)){
405 child_signal(pid, status);
406 continue;
407 }
408
409 local_using_sysemu = get_using_sysemu();
410
411 if(tracing)
412 cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu,
413 singlestepping(task));
414 else if((debugger_pid != -1) && strace)
415 cont_type = PTRACE_SYSCALL;
416 else
417 cont_type = PTRACE_CONT;
418
419 if(ptrace(cont_type, pid, 0, sig) != 0){
420 tracer_panic("ptrace failed to continue "
421 "process - errno = %d\n",
422 errno);
423 }
424 }
425 }
426 return(0);
427}
428
429static int __init uml_debug_setup(char *line, int *add)
430{
431 char *next;
432
433 debug = 1;
434 *add = 0;
435 if(*line != '=') return(0);
436 line++;
437
438 while(line != NULL){
439 next = strchr(line, ',');
440 if(next) *next++ = '\0';
441
442 if(!strcmp(line, "go")) debug_stop = 0;
443 else if(!strcmp(line, "parent")) debug_parent = 1;
444 else printf("Unknown debug option : '%s'\n", line);
445
446 line = next;
447 }
448 return(0);
449}
450
451__uml_setup("debug", uml_debug_setup,
452"debug\n"
453" Starts up the kernel under the control of gdb. See the \n"
454" kernel debugging tutorial and the debugging session pages\n"
455" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
456);
457
458static int __init uml_debugtrace_setup(char *line, int *add)
459{
460 debug_trace = 1;
461 return 0;
462}
463__uml_setup("debugtrace", uml_debugtrace_setup,
464"debugtrace\n"
465" Causes the tracing thread to pause until it is attached by a\n"
466" debugger and continued. This is mostly for debugging crashes\n"
467" early during boot, and should be pretty much obsoleted by\n"
468" the debug switch.\n\n"
469);
470
471/*
472 * Overrides for Emacs so that we follow Linus's tabbing style.
473 * Emacs will notice this stuff at the end of the file and automatically
474 * adjust the settings for this buffer only. This must remain at the end
475 * of the file.
476 * ---------------------------------------------------------------------------
477 * Local variables:
478 * c-file-style: "linux"
479 * End:
480 */
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c
new file mode 100644
index 000000000000..92a3820ca543
--- /dev/null
+++ b/arch/um/kernel/tt/trap_user.c
@@ -0,0 +1,60 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <errno.h>
8#include <signal.h>
9#include "sysdep/ptrace.h"
10#include "signal_user.h"
11#include "user_util.h"
12#include "kern_util.h"
13#include "task.h"
14#include "tt.h"
15
16void sig_handler_common_tt(int sig, void *sc_ptr)
17{
18 struct sigcontext *sc = sc_ptr;
19 struct tt_regs save_regs, *r;
20 struct signal_info *info;
21 int save_errno = errno, is_user;
22
23 /* This is done because to allow SIGSEGV to be delivered inside a SEGV
24 * handler. This can happen in copy_user, and if SEGV is disabled,
25 * the process will die.
26 */
27 if(sig == SIGSEGV)
28 change_sig(SIGSEGV, 1);
29
30 r = &TASK_REGS(get_current())->tt;
31 save_regs = *r;
32 is_user = user_context(SC_SP(sc));
33 r->sc = sc;
34 if(sig != SIGUSR2)
35 r->syscall = -1;
36
37 info = &sig_info[sig];
38 if(!info->is_irq) unblock_signals();
39
40 (*info->handler)(sig, (union uml_pt_regs *) r);
41
42 if(is_user){
43 interrupt_end();
44 block_signals();
45 set_user_mode(NULL);
46 }
47 *r = save_regs;
48 errno = save_errno;
49}
50
51/*
52 * Overrides for Emacs so that we follow Linus's tabbing style.
53 * Emacs will notice this stuff at the end of the file and automatically
54 * adjust the settings for this buffer only. This must remain at the end
55 * of the file.
56 * ---------------------------------------------------------------------------
57 * Local variables:
58 * c-file-style: "linux"
59 * End:
60 */
diff --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c
new file mode 100644
index 000000000000..a72aa632972f
--- /dev/null
+++ b/arch/um/kernel/tt/uaccess.c
@@ -0,0 +1,73 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "asm/uaccess.h"
8
9int copy_from_user_tt(void *to, const void __user *from, int n)
10{
11 if(!access_ok_tt(VERIFY_READ, from, n))
12 return(n);
13
14 return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
15 &current->thread.fault_catcher));
16}
17
18int copy_to_user_tt(void __user *to, const void *from, int n)
19{
20 if(!access_ok_tt(VERIFY_WRITE, to, n))
21 return(n);
22
23 return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
24 &current->thread.fault_catcher));
25}
26
27int strncpy_from_user_tt(char *dst, const char __user *src, int count)
28{
29 int n;
30
31 if(!access_ok_tt(VERIFY_READ, src, 1))
32 return(-EFAULT);
33
34 n = __do_strncpy_from_user(dst, src, count,
35 &current->thread.fault_addr,
36 &current->thread.fault_catcher);
37 if(n < 0) return(-EFAULT);
38 return(n);
39}
40
41int __clear_user_tt(void __user *mem, int len)
42{
43 return(__do_clear_user(mem, len,
44 &current->thread.fault_addr,
45 &current->thread.fault_catcher));
46}
47
48int clear_user_tt(void __user *mem, int len)
49{
50 if(!access_ok_tt(VERIFY_WRITE, mem, len))
51 return(len);
52
53 return(__do_clear_user(mem, len, &current->thread.fault_addr,
54 &current->thread.fault_catcher));
55}
56
57int strnlen_user_tt(const void __user *str, int len)
58{
59 return(__do_strnlen_user(str, len,
60 &current->thread.fault_addr,
61 &current->thread.fault_catcher));
62}
63
64/*
65 * Overrides for Emacs so that we follow Linus's tabbing style.
66 * Emacs will notice this stuff at the end of the file and automatically
67 * adjust the settings for this buffer only. This must remain at the end
68 * of the file.
69 * ---------------------------------------------------------------------------
70 * Local variables:
71 * c-file-style: "linux"
72 * End:
73 */
diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
new file mode 100644
index 000000000000..f01475512ecb
--- /dev/null
+++ b/arch/um/kernel/tt/uaccess_user.c
@@ -0,0 +1,98 @@
1/*
2 * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
3 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
4 * Licensed under the GPL
5 */
6
7#include <setjmp.h>
8#include <string.h>
9#include "user_util.h"
10#include "uml_uaccess.h"
11#include "task.h"
12#include "kern_util.h"
13
14int __do_copy_from_user(void *to, const void *from, int n,
15 void **fault_addr, void **fault_catcher)
16{
17 struct tt_regs save = TASK_REGS(get_current())->tt;
18 unsigned long fault;
19 int faulted;
20
21 fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
22 __do_copy, &faulted);
23 TASK_REGS(get_current())->tt = save;
24
25 if(!faulted) return(0);
26 else return(n - (fault - (unsigned long) from));
27}
28
29static void __do_strncpy(void *dst, const void *src, int count)
30{
31 strncpy(dst, src, count);
32}
33
34int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
35 void **fault_addr, void **fault_catcher)
36{
37 struct tt_regs save = TASK_REGS(get_current())->tt;
38 unsigned long fault;
39 int faulted;
40
41 fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
42 __do_strncpy, &faulted);
43 TASK_REGS(get_current())->tt = save;
44
45 if(!faulted) return(strlen(dst));
46 else return(-1);
47}
48
49static void __do_clear(void *to, const void *from, int n)
50{
51 memset(to, 0, n);
52}
53
54int __do_clear_user(void *mem, unsigned long len,
55 void **fault_addr, void **fault_catcher)
56{
57 struct tt_regs save = TASK_REGS(get_current())->tt;
58 unsigned long fault;
59 int faulted;
60
61 fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
62 __do_clear, &faulted);
63 TASK_REGS(get_current())->tt = save;
64
65 if(!faulted) return(0);
66 else return(len - (fault - (unsigned long) mem));
67}
68
69int __do_strnlen_user(const char *str, unsigned long n,
70 void **fault_addr, void **fault_catcher)
71{
72 struct tt_regs save = TASK_REGS(get_current())->tt;
73 int ret;
74 unsigned long *faddrp = (unsigned long *)fault_addr;
75 sigjmp_buf jbuf;
76
77 *fault_catcher = &jbuf;
78 if(sigsetjmp(jbuf, 1) == 0)
79 ret = strlen(str) + 1;
80 else ret = *faddrp - (unsigned long) str;
81
82 *fault_addr = NULL;
83 *fault_catcher = NULL;
84
85 TASK_REGS(get_current())->tt = save;
86 return ret;
87}
88
89/*
90 * Overrides for Emacs so that we follow Linus's tabbing style.
91 * Emacs will notice this stuff at the end of the file and automatically
92 * adjust the settings for this buffer only. This must remain at the end
93 * of the file.
94 * ---------------------------------------------------------------------------
95 * Local variables:
96 * c-file-style: "linux"
97 * End:
98 */
diff --git a/arch/um/kernel/tt/unmap.c b/arch/um/kernel/tt/unmap.c
new file mode 100644
index 000000000000..3f7aecdbe532
--- /dev/null
+++ b/arch/um/kernel/tt/unmap.c
@@ -0,0 +1,31 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <sys/mman.h>
7
8int switcheroo(int fd, int prot, void *from, void *to, int size)
9{
10 if(munmap(to, size) < 0){
11 return(-1);
12 }
13 if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){
14 return(-1);
15 }
16 if(munmap(from, size) < 0){
17 return(-1);
18 }
19 return(0);
20}
21
22/*
23 * Overrides for Emacs so that we follow Linus's tabbing style.
24 * Emacs will notice this stuff at the end of the file and automatically
25 * adjust the settings for this buffer only. This must remain at the end
26 * of the file.
27 * ---------------------------------------------------------------------------
28 * Local variables:
29 * c-file-style: "linux"
30 * End:
31 */
diff --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c
new file mode 100644
index 000000000000..9ada656f68ce
--- /dev/null
+++ b/arch/um/kernel/tty_log.c
@@ -0,0 +1,230 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and
3 * geoffrey hing <ghing@net.ohio-state.edu>
4 * Licensed under the GPL
5 */
6
7#include <errno.h>
8#include <string.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <sys/time.h>
13#include "init.h"
14#include "user.h"
15#include "kern_util.h"
16#include "os.h"
17
18#define TTY_LOG_DIR "./"
19
20/* Set early in boot and then unchanged */
21static char *tty_log_dir = TTY_LOG_DIR;
22static int tty_log_fd = -1;
23
24#define TTY_LOG_OPEN 1
25#define TTY_LOG_CLOSE 2
26#define TTY_LOG_WRITE 3
27#define TTY_LOG_EXEC 4
28
29#define TTY_READ 1
30#define TTY_WRITE 2
31
32struct tty_log_buf {
33 int what;
34 unsigned long tty;
35 int len;
36 int direction;
37 unsigned long sec;
38 unsigned long usec;
39};
40
41int open_tty_log(void *tty, void *current_tty)
42{
43 struct timeval tv;
44 struct tty_log_buf data;
45 char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
46 int fd;
47
48 gettimeofday(&tv, NULL);
49 if(tty_log_fd != -1){
50 data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN,
51 .tty = (unsigned long) tty,
52 .len = sizeof(current_tty),
53 .direction = 0,
54 .sec = tv.tv_sec,
55 .usec = tv.tv_usec } );
56 os_write_file(tty_log_fd, &data, sizeof(data));
57 os_write_file(tty_log_fd, &current_tty, data.len);
58 return(tty_log_fd);
59 }
60
61 sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec,
62 (unsigned int) tv.tv_usec);
63
64 fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))),
65 0644);
66 if(fd < 0){
67 printk("open_tty_log : couldn't open '%s', errno = %d\n",
68 buf, -fd);
69 }
70 return(fd);
71}
72
73void close_tty_log(int fd, void *tty)
74{
75 struct tty_log_buf data;
76 struct timeval tv;
77
78 if(tty_log_fd != -1){
79 gettimeofday(&tv, NULL);
80 data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE,
81 .tty = (unsigned long) tty,
82 .len = 0,
83 .direction = 0,
84 .sec = tv.tv_sec,
85 .usec = tv.tv_usec } );
86 os_write_file(tty_log_fd, &data, sizeof(data));
87 return;
88 }
89 os_close_file(fd);
90}
91
92static int log_chunk(int fd, const char *buf, int len)
93{
94 int total = 0, try, missed, n;
95 char chunk[64];
96
97 while(len > 0){
98 try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
99 missed = copy_from_user_proc(chunk, (char *) buf, try);
100 try -= missed;
101 n = os_write_file(fd, chunk, try);
102 if(n != try) {
103 if(n < 0)
104 return(n);
105 return(-EIO);
106 }
107 if(missed != 0)
108 return(-EFAULT);
109
110 len -= try;
111 total += try;
112 buf += try;
113 }
114
115 return(total);
116}
117
118int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
119{
120 struct timeval tv;
121 struct tty_log_buf data;
122 int direction;
123
124 if(fd == tty_log_fd){
125 gettimeofday(&tv, NULL);
126 direction = is_read ? TTY_READ : TTY_WRITE;
127 data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE,
128 .tty = (unsigned long) tty,
129 .len = len,
130 .direction = direction,
131 .sec = tv.tv_sec,
132 .usec = tv.tv_usec } );
133 os_write_file(tty_log_fd, &data, sizeof(data));
134 }
135
136 return(log_chunk(fd, buf, len));
137}
138
139void log_exec(char **argv, void *tty)
140{
141 struct timeval tv;
142 struct tty_log_buf data;
143 char **ptr,*arg;
144 int len;
145
146 if(tty_log_fd == -1) return;
147
148 gettimeofday(&tv, NULL);
149
150 len = 0;
151 for(ptr = argv; ; ptr++){
152 if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
153 return;
154 if(arg == NULL) break;
155 len += strlen_user_proc(arg);
156 }
157
158 data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC,
159 .tty = (unsigned long) tty,
160 .len = len,
161 .direction = 0,
162 .sec = tv.tv_sec,
163 .usec = tv.tv_usec } );
164 os_write_file(tty_log_fd, &data, sizeof(data));
165
166 for(ptr = argv; ; ptr++){
167 if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
168 return;
169 if(arg == NULL) break;
170 log_chunk(tty_log_fd, arg, strlen_user_proc(arg));
171 }
172}
173
174extern void register_tty_logger(int (*opener)(void *, void *),
175 int (*writer)(int, const char *, int,
176 void *, int),
177 void (*closer)(int, void *));
178
179static int register_logger(void)
180{
181 register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
182 return(0);
183}
184
185__uml_initcall(register_logger);
186
187static int __init set_tty_log_dir(char *name, int *add)
188{
189 tty_log_dir = name;
190 return 0;
191}
192
193__uml_setup("tty_log_dir=", set_tty_log_dir,
194"tty_log_dir=<directory>\n"
195" This is used to specify the directory where the logs of all pty\n"
196" data from this UML machine will be written.\n\n"
197);
198
199static int __init set_tty_log_fd(char *name, int *add)
200{
201 char *end;
202
203 tty_log_fd = strtoul(name, &end, 0);
204 if((*end != '\0') || (end == name)){
205 printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
206 tty_log_fd = -1;
207 }
208
209 *add = 0;
210 return 0;
211}
212
213__uml_setup("tty_log_fd=", set_tty_log_fd,
214"tty_log_fd=<fd>\n"
215" This is used to specify a preconfigured file descriptor to which all\n"
216" tty data will be written. Preconfigure the descriptor with something\n"
217" like '10>tty_log tty_log_fd=10'.\n\n"
218);
219
220
221/*
222 * Overrides for Emacs so that we follow Linus's tabbing style.
223 * Emacs will notice this stuff at the end of the file and automatically
224 * adjust the settings for this buffer only. This must remain at the end
225 * of the file.
226 * ---------------------------------------------------------------------------
227 * Local variables:
228 * c-file-style: "linux"
229 * End:
230 */
diff --git a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/uaccess_user.c
new file mode 100644
index 000000000000..d035257ed0af
--- /dev/null
+++ b/arch/um/kernel/uaccess_user.c
@@ -0,0 +1,64 @@
1/*
2 * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
3 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
4 * Licensed under the GPL
5 */
6
7#include <setjmp.h>
8#include <string.h>
9
10/* These are here rather than tt/uaccess.c because skas mode needs them in
11 * order to do SIGBUS recovery when a tmpfs mount runs out of room.
12 */
13
14unsigned long __do_user_copy(void *to, const void *from, int n,
15 void **fault_addr, void **fault_catcher,
16 void (*op)(void *to, const void *from,
17 int n), int *faulted_out)
18{
19 unsigned long *faddrp = (unsigned long *) fault_addr, ret;
20
21 sigjmp_buf jbuf;
22 *fault_catcher = &jbuf;
23 if(sigsetjmp(jbuf, 1) == 0){
24 (*op)(to, from, n);
25 ret = 0;
26 *faulted_out = 0;
27 }
28 else {
29 ret = *faddrp;
30 *faulted_out = 1;
31 }
32 *fault_addr = NULL;
33 *fault_catcher = NULL;
34 return ret;
35}
36
37void __do_copy(void *to, const void *from, int n)
38{
39 memcpy(to, from, n);
40}
41
42
43int __do_copy_to_user(void *to, const void *from, int n,
44 void **fault_addr, void **fault_catcher)
45{
46 unsigned long fault;
47 int faulted;
48
49 fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
50 __do_copy, &faulted);
51 if(!faulted) return(0);
52 else return(n - (fault - (unsigned long) to));
53}
54
55/*
56 * Overrides for Emacs so that we follow Linus's tabbing style.
57 * Emacs will notice this stuff at the end of the file and automatically
58 * adjust the settings for this buffer only. This must remain at the end
59 * of the file.
60 * ---------------------------------------------------------------------------
61 * Local variables:
62 * c-file-style: "linux"
63 * End:
64 */
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
new file mode 100644
index 000000000000..5c49d88eed3d
--- /dev/null
+++ b/arch/um/kernel/um_arch.c
@@ -0,0 +1,467 @@
1/*
2 * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/kernel.h"
8#include "linux/sched.h"
9#include "linux/notifier.h"
10#include "linux/mm.h"
11#include "linux/types.h"
12#include "linux/tty.h"
13#include "linux/init.h"
14#include "linux/bootmem.h"
15#include "linux/spinlock.h"
16#include "linux/utsname.h"
17#include "linux/sysrq.h"
18#include "linux/seq_file.h"
19#include "linux/delay.h"
20#include "linux/module.h"
21#include "asm/page.h"
22#include "asm/pgtable.h"
23#include "asm/ptrace.h"
24#include "asm/elf.h"
25#include "asm/user.h"
26#include "ubd_user.h"
27#include "asm/current.h"
28#include "asm/setup.h"
29#include "user_util.h"
30#include "kern_util.h"
31#include "kern.h"
32#include "mem_user.h"
33#include "mem.h"
34#include "umid.h"
35#include "initrd.h"
36#include "init.h"
37#include "os.h"
38#include "choose-mode.h"
39#include "mode_kern.h"
40#include "mode.h"
41
42#define DEFAULT_COMMAND_LINE "root=98:0"
43
44/* Changed in linux_main and setup_arch, which run before SMP is started */
45char command_line[COMMAND_LINE_SIZE] = { 0 };
46
47void add_arg(char *arg)
48{
49 if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
50 printf("add_arg: Too many command line arguments!\n");
51 exit(1);
52 }
53 if(strlen(command_line) > 0)
54 strcat(command_line, " ");
55 strcat(command_line, arg);
56}
57
58struct cpuinfo_um boot_cpu_data = {
59 .loops_per_jiffy = 0,
60 .ipi_pipe = { -1, -1 }
61};
62
63unsigned long thread_saved_pc(struct task_struct *task)
64{
65 return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
66 task)));
67}
68
69static int show_cpuinfo(struct seq_file *m, void *v)
70{
71 int index = 0;
72
73#ifdef CONFIG_SMP
74 index = (struct cpuinfo_um *) v - cpu_data;
75 if (!cpu_online(index))
76 return 0;
77#endif
78
79 seq_printf(m, "processor\t: %d\n", index);
80 seq_printf(m, "vendor_id\t: User Mode Linux\n");
81 seq_printf(m, "model name\t: UML\n");
82 seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
83 seq_printf(m, "host\t\t: %s\n", host_info);
84 seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
85 loops_per_jiffy/(500000/HZ),
86 (loops_per_jiffy/(5000/HZ)) % 100);
87
88 return(0);
89}
90
91static void *c_start(struct seq_file *m, loff_t *pos)
92{
93 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
94}
95
96static void *c_next(struct seq_file *m, void *v, loff_t *pos)
97{
98 ++*pos;
99 return c_start(m, pos);
100}
101
102static void c_stop(struct seq_file *m, void *v)
103{
104}
105
106struct seq_operations cpuinfo_op = {
107 .start = c_start,
108 .next = c_next,
109 .stop = c_stop,
110 .show = show_cpuinfo,
111};
112
113pte_t * __bad_pagetable(void)
114{
115 panic("Someone should implement __bad_pagetable");
116 return(NULL);
117}
118
119/* Set in linux_main */
120unsigned long host_task_size;
121unsigned long task_size;
122
123unsigned long uml_start;
124
125/* Set in early boot */
126unsigned long uml_physmem;
127unsigned long uml_reserved;
128unsigned long start_vm;
129unsigned long end_vm;
130int ncpus = 1;
131
132#ifdef CONFIG_MODE_TT
133/* Pointer set in linux_main, the array itself is private to each thread,
134 * and changed at address space creation time so this poses no concurrency
135 * problems.
136 */
137static char *argv1_begin = NULL;
138static char *argv1_end = NULL;
139#endif
140
141/* Set in early boot */
142static int have_root __initdata = 0;
143long physmem_size = 32 * 1024 * 1024;
144
145void set_cmdline(char *cmd)
146{
147#ifdef CONFIG_MODE_TT
148 char *umid, *ptr;
149
150 if(CHOOSE_MODE(honeypot, 0)) return;
151
152 umid = get_umid(1);
153 if(umid != NULL){
154 snprintf(argv1_begin,
155 (argv1_end - argv1_begin) * sizeof(*ptr),
156 "(%s) ", umid);
157 ptr = &argv1_begin[strlen(argv1_begin)];
158 }
159 else ptr = argv1_begin;
160
161 snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
162 memset(argv1_begin + strlen(argv1_begin), '\0',
163 argv1_end - argv1_begin - strlen(argv1_begin));
164#endif
165}
166
167static char *usage_string =
168"User Mode Linux v%s\n"
169" available at http://user-mode-linux.sourceforge.net/\n\n";
170
171static int __init uml_version_setup(char *line, int *add)
172{
173 printf("%s\n", system_utsname.release);
174 exit(0);
175
176 return 0;
177}
178
179__uml_setup("--version", uml_version_setup,
180"--version\n"
181" Prints the version number of the kernel.\n\n"
182);
183
184static int __init uml_root_setup(char *line, int *add)
185{
186 have_root = 1;
187 return 0;
188}
189
190__uml_setup("root=", uml_root_setup,
191"root=<file containing the root fs>\n"
192" This is actually used by the generic kernel in exactly the same\n"
193" way as in any other kernel. If you configure a number of block\n"
194" devices and want to boot off something other than ubd0, you \n"
195" would use something like:\n"
196" root=/dev/ubd5\n\n"
197);
198
199#ifdef CONFIG_SMP
200static int __init uml_ncpus_setup(char *line, int *add)
201{
202 if (!sscanf(line, "%d", &ncpus)) {
203 printf("Couldn't parse [%s]\n", line);
204 return -1;
205 }
206
207 return 0;
208}
209
210__uml_setup("ncpus=", uml_ncpus_setup,
211"ncpus=<# of desired CPUs>\n"
212" This tells an SMP kernel how many virtual processors to start.\n\n"
213);
214#endif
215
216static int force_tt = 0;
217
218#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
219#define DEFAULT_TT 0
220
221static int __init mode_tt_setup(char *line, int *add)
222{
223 force_tt = 1;
224 return(0);
225}
226
227#else
228#ifdef CONFIG_MODE_SKAS
229
230#define DEFAULT_TT 0
231
232static int __init mode_tt_setup(char *line, int *add)
233{
234 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
235 return(0);
236}
237
238#else
239#ifdef CONFIG_MODE_TT
240
241#define DEFAULT_TT 1
242
243static int __init mode_tt_setup(char *line, int *add)
244{
245 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
246 return(0);
247}
248
249#else
250
251#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled
252
253#endif
254#endif
255#endif
256
257__uml_setup("mode=tt", mode_tt_setup,
258"mode=tt\n"
259" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
260" forces UML to run in tt (tracing thread) mode. It is not the default\n"
261" because it's slower and less secure than skas mode.\n\n"
262);
263
264int mode_tt = DEFAULT_TT;
265
266static int __init Usage(char *line, int *add)
267{
268 const char **p;
269
270 printf(usage_string, system_utsname.release);
271 p = &__uml_help_start;
272 while (p < &__uml_help_end) {
273 printf("%s", *p);
274 p++;
275 }
276 exit(0);
277
278 return 0;
279}
280
281__uml_setup("--help", Usage,
282"--help\n"
283" Prints this message.\n\n"
284);
285
286static int __init uml_checksetup(char *line, int *add)
287{
288 struct uml_param *p;
289
290 p = &__uml_setup_start;
291 while(p < &__uml_setup_end) {
292 int n;
293
294 n = strlen(p->str);
295 if(!strncmp(line, p->str, n)){
296 if (p->setup_func(line + n, add)) return 1;
297 }
298 p++;
299 }
300 return 0;
301}
302
303static void __init uml_postsetup(void)
304{
305 initcall_t *p;
306
307 p = &__uml_postsetup_start;
308 while(p < &__uml_postsetup_end){
309 (*p)();
310 p++;
311 }
312 return;
313}
314
315/* Set during early boot */
316unsigned long brk_start;
317unsigned long end_iomem;
318EXPORT_SYMBOL(end_iomem);
319
320#define MIN_VMALLOC (32 * 1024 * 1024)
321
322int linux_main(int argc, char **argv)
323{
324 unsigned long avail, diff;
325 unsigned long virtmem_size, max_physmem;
326 unsigned int i, add;
327
328 for (i = 1; i < argc; i++){
329 if((i == 1) && (argv[i][0] == ' ')) continue;
330 add = 1;
331 uml_checksetup(argv[i], &add);
332 if (add)
333 add_arg(argv[i]);
334 }
335 if(have_root == 0)
336 add_arg(DEFAULT_COMMAND_LINE);
337
338 mode_tt = force_tt ? 1 : !can_do_skas();
339#ifndef CONFIG_MODE_TT
340 if (mode_tt) {
341 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
342 * can_do_skas() returned 0, and the message is correct. */
343 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
344 exit(1);
345 }
346#endif
347 uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
348 &host_task_size, &task_size);
349
350 /* Need to check this early because mmapping happens before the
351 * kernel is running.
352 */
353 check_tmpexec();
354
355 brk_start = (unsigned long) sbrk(0);
356 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
357 /* Increase physical memory size for exec-shield users
358 so they actually get what they asked for. This should
359 add zero for non-exec shield users */
360
361 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
362 if(diff > 1024 * 1024){
363 printf("Adding %ld bytes to physical memory to account for "
364 "exec-shield gap\n", diff);
365 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
366 }
367
368 uml_physmem = uml_start;
369
370 /* Reserve up to 4M after the current brk */
371 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
372
373 setup_machinename(system_utsname.machine);
374
375#ifdef CONFIG_MODE_TT
376 argv1_begin = argv[1];
377 argv1_end = &argv[1][strlen(argv[1])];
378#endif
379
380 highmem = 0;
381 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
382 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
383
384 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
385 * so this makes sure that's true for highmem
386 */
387 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
388 if(physmem_size + iomem_size > max_physmem){
389 highmem = physmem_size + iomem_size - max_physmem;
390 physmem_size -= highmem;
391#ifndef CONFIG_HIGHMEM
392 highmem = 0;
393 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
394 "to %ld bytes\n", physmem_size);
395#endif
396 }
397
398 high_physmem = uml_physmem + physmem_size;
399 end_iomem = high_physmem + iomem_size;
400 high_memory = (void *) end_iomem;
401
402 start_vm = VMALLOC_START;
403
404 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
405 if(init_maps(physmem_size, iomem_size, highmem)){
406 printf("Failed to allocate mem_map for %ld bytes of physical "
407 "memory and %ld bytes of highmem\n", physmem_size,
408 highmem);
409 exit(1);
410 }
411
412 virtmem_size = physmem_size;
413 avail = get_kmem_end() - start_vm;
414 if(physmem_size > avail) virtmem_size = avail;
415 end_vm = start_vm + virtmem_size;
416
417 if(virtmem_size < physmem_size)
418 printf("Kernel virtual memory size shrunk to %ld bytes\n",
419 virtmem_size);
420
421 uml_postsetup();
422
423 task_protections((unsigned long) &init_thread_info);
424 os_flush_stdout();
425
426 return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
427}
428
429extern int uml_exitcode;
430
431static int panic_exit(struct notifier_block *self, unsigned long unused1,
432 void *unused2)
433{
434 bust_spinlocks(1);
435 show_regs(&(current->thread.regs));
436 bust_spinlocks(0);
437 uml_exitcode = 1;
438 machine_halt();
439 return(0);
440}
441
442static struct notifier_block panic_exit_notifier = {
443 .notifier_call = panic_exit,
444 .next = NULL,
445 .priority = 0
446};
447
448void __init setup_arch(char **cmdline_p)
449{
450 notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
451 paging_init();
452 strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
453 *cmdline_p = command_line;
454 setup_hostinfo();
455}
456
457void __init check_bugs(void)
458{
459 arch_check_bugs();
460 check_ptrace();
461 check_sigio();
462 check_devanon();
463}
464
465void apply_alternatives(void *start, void *end)
466{
467}
diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
new file mode 100644
index 000000000000..186c28885016
--- /dev/null
+++ b/arch/um/kernel/umid.c
@@ -0,0 +1,325 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <unistd.h>
8#include <errno.h>
9#include <string.h>
10#include <stdlib.h>
11#include <dirent.h>
12#include <signal.h>
13#include <sys/stat.h>
14#include <sys/param.h>
15#include "user.h"
16#include "umid.h"
17#include "init.h"
18#include "os.h"
19#include "user_util.h"
20#include "choose-mode.h"
21
22#define UMID_LEN 64
23#define UML_DIR "~/.uml/"
24
25/* Changed by set_umid and make_umid, which are run early in boot */
26static char umid[UMID_LEN] = { 0 };
27
28/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */
29static char *uml_dir = UML_DIR;
30
31/* Changed by set_umid */
32static int umid_is_random = 1;
33static int umid_inited = 0;
34
35static int make_umid(int (*printer)(const char *fmt, ...));
36
37static int __init set_umid(char *name, int is_random,
38 int (*printer)(const char *fmt, ...))
39{
40 if(umid_inited){
41 (*printer)("Unique machine name can't be set twice\n");
42 return(-1);
43 }
44
45 if(strlen(name) > UMID_LEN - 1)
46 (*printer)("Unique machine name is being truncated to %d "
47 "characters\n", UMID_LEN);
48 strlcpy(umid, name, sizeof(umid));
49
50 umid_is_random = is_random;
51 umid_inited = 1;
52 return 0;
53}
54
55static int __init set_umid_arg(char *name, int *add)
56{
57 *add = 0;
58 return(set_umid(name, 0, printf));
59}
60
61__uml_setup("umid=", set_umid_arg,
62"umid=<name>\n"
63" This is used to assign a unique identity to this UML machine and\n"
64" is used for naming the pid file and management console socket.\n\n"
65);
66
67int __init umid_file_name(char *name, char *buf, int len)
68{
69 int n;
70
71 if(!umid_inited && make_umid(printk)) return(-1);
72
73 n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
74 if(n > len){
75 printk("umid_file_name : buffer too short\n");
76 return(-1);
77 }
78
79 sprintf(buf, "%s%s/%s", uml_dir, umid, name);
80 return(0);
81}
82
83extern int tracing_pid;
84
85static int __init create_pid_file(void)
86{
87 char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
88 char pid[sizeof("nnnnn\0")];
89 int fd, n;
90
91 if(umid_file_name("pid", file, sizeof(file))) return 0;
92
93 fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))),
94 0644);
95 if(fd < 0){
96 printf("Open of machine pid file \"%s\" failed: %s\n",
97 file, strerror(-fd));
98 return 0;
99 }
100
101 sprintf(pid, "%d\n", os_getpid());
102 n = os_write_file(fd, pid, strlen(pid));
103 if(n != strlen(pid))
104 printf("Write of pid file failed - err = %d\n", -n);
105 os_close_file(fd);
106 return 0;
107}
108
109static int actually_do_remove(char *dir)
110{
111 DIR *directory;
112 struct dirent *ent;
113 int len;
114 char file[256];
115
116 directory = opendir(dir);
117 if(directory == NULL){
118 printk("actually_do_remove : couldn't open directory '%s', "
119 "errno = %d\n", dir, errno);
120 return(1);
121 }
122 while((ent = readdir(directory)) != NULL){
123 if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
124 continue;
125 len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1;
126 if(len > sizeof(file)){
127 printk("Not deleting '%s' from '%s' - name too long\n",
128 ent->d_name, dir);
129 continue;
130 }
131 sprintf(file, "%s/%s", dir, ent->d_name);
132 if(unlink(file) < 0){
133 printk("actually_do_remove : couldn't remove '%s' "
134 "from '%s', errno = %d\n", ent->d_name, dir,
135 errno);
136 return(1);
137 }
138 }
139 if(rmdir(dir) < 0){
140 printk("actually_do_remove : couldn't rmdir '%s', "
141 "errno = %d\n", dir, errno);
142 return(1);
143 }
144 return(0);
145}
146
147void remove_umid_dir(void)
148{
149 char dir[strlen(uml_dir) + UMID_LEN + 1];
150 if(!umid_inited) return;
151
152 sprintf(dir, "%s%s", uml_dir, umid);
153 actually_do_remove(dir);
154}
155
156char *get_umid(int only_if_set)
157{
158 if(only_if_set && umid_is_random) return(NULL);
159 return(umid);
160}
161
162int not_dead_yet(char *dir)
163{
164 char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
165 char pid[sizeof("nnnnn\0")], *end;
166 int dead, fd, p, n;
167
168 sprintf(file, "%s/pid", dir);
169 dead = 0;
170 fd = os_open_file(file, of_read(OPENFLAGS()), 0);
171 if(fd < 0){
172 if(fd != -ENOENT){
173 printk("not_dead_yet : couldn't open pid file '%s', "
174 "err = %d\n", file, -fd);
175 return(1);
176 }
177 dead = 1;
178 }
179 if(fd > 0){
180 n = os_read_file(fd, pid, sizeof(pid));
181 if(n < 0){
182 printk("not_dead_yet : couldn't read pid file '%s', "
183 "err = %d\n", file, -n);
184 return(1);
185 }
186 p = strtoul(pid, &end, 0);
187 if(end == pid){
188 printk("not_dead_yet : couldn't parse pid file '%s', "
189 "errno = %d\n", file, errno);
190 dead = 1;
191 }
192 if(((kill(p, 0) < 0) && (errno == ESRCH)) ||
193 (p == CHOOSE_MODE(tracing_pid, os_getpid())))
194 dead = 1;
195 }
196 if(!dead) return(1);
197 return(actually_do_remove(dir));
198}
199
200static int __init set_uml_dir(char *name, int *add)
201{
202 if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
203 uml_dir = malloc(strlen(name) + 2);
204 if(uml_dir == NULL){
205 printf("Failed to malloc uml_dir - error = %d\n",
206 errno);
207 uml_dir = name;
208 /* Return 0 here because do_initcalls doesn't look at
209 * the return value.
210 */
211 return(0);
212 }
213 sprintf(uml_dir, "%s/", name);
214 }
215 else uml_dir = name;
216 return(0);
217}
218
219static int __init make_uml_dir(void)
220{
221 char dir[MAXPATHLEN + 1] = { '\0' };
222 int len;
223
224 if(*uml_dir == '~'){
225 char *home = getenv("HOME");
226
227 if(home == NULL){
228 printf("make_uml_dir : no value in environment for "
229 "$HOME\n");
230 exit(1);
231 }
232 strlcpy(dir, home, sizeof(dir));
233 uml_dir++;
234 }
235 len = strlen(dir);
236 strncat(dir, uml_dir, sizeof(dir) - len);
237 len = strlen(dir);
238 if((len > 0) && (len < sizeof(dir) - 1) && (dir[len - 1] != '/')){
239 dir[len] = '/';
240 dir[len + 1] = '\0';
241 }
242
243 uml_dir = malloc(strlen(dir) + 1);
244 if(uml_dir == NULL){
245 printf("make_uml_dir : malloc failed, errno = %d\n", errno);
246 exit(1);
247 }
248 strcpy(uml_dir, dir);
249
250 if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
251 printf("Failed to mkdir %s: %s\n", uml_dir, strerror(errno));
252 return(-1);
253 }
254 return 0;
255}
256
257static int __init make_umid(int (*printer)(const char *fmt, ...))
258{
259 int fd, err;
260 char tmp[strlen(uml_dir) + UMID_LEN + 1];
261
262 strlcpy(tmp, uml_dir, sizeof(tmp));
263
264 if(!umid_inited){
265 strcat(tmp, "XXXXXX");
266 fd = mkstemp(tmp);
267 if(fd < 0){
268 (*printer)("make_umid - mkstemp(%s) failed: %s\n",
269 tmp,strerror(errno));
270 return(1);
271 }
272
273 os_close_file(fd);
274 /* There's a nice tiny little race between this unlink and
275 * the mkdir below. It'd be nice if there were a mkstemp
276 * for directories.
277 */
278 unlink(tmp);
279 set_umid(&tmp[strlen(uml_dir)], 1, printer);
280 }
281
282 sprintf(tmp, "%s%s", uml_dir, umid);
283
284 err = mkdir(tmp, 0777);
285 if(err < 0){
286 if(errno == EEXIST){
287 if(not_dead_yet(tmp)){
288 (*printer)("umid '%s' is in use\n", umid);
289 return(-1);
290 }
291 err = mkdir(tmp, 0777);
292 }
293 }
294 if(err < 0){
295 (*printer)("Failed to create %s - errno = %d\n", umid, errno);
296 return(-1);
297 }
298
299 return(0);
300}
301
302__uml_setup("uml_dir=", set_uml_dir,
303"uml_dir=<directory>\n"
304" The location to place the pid and umid files.\n\n"
305);
306
307static int __init make_umid_setup(void)
308{
309 /* one function with the ordering we need ... */
310 make_uml_dir();
311 make_umid(printf);
312 return create_pid_file();
313}
314__uml_postsetup(make_umid_setup);
315
316/*
317 * Overrides for Emacs so that we follow Linus's tabbing style.
318 * Emacs will notice this stuff at the end of the file and automatically
319 * adjust the settings for this buffer only. This must remain at the end
320 * of the file.
321 * ---------------------------------------------------------------------------
322 * Local variables:
323 * c-file-style: "linux"
324 * End:
325 */
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
new file mode 100644
index 000000000000..76eadb309189
--- /dev/null
+++ b/arch/um/kernel/uml.lds.S
@@ -0,0 +1,106 @@
1#include <asm-generic/vmlinux.lds.h>
2
3OUTPUT_FORMAT(ELF_FORMAT)
4OUTPUT_ARCH(ELF_ARCH)
5ENTRY(_start)
6jiffies = jiffies_64;
7
8SECTIONS
9{
10 /*This must contain the right address - not quite the default ELF one.*/
11 PROVIDE (__executable_start = START);
12 . = START + SIZEOF_HEADERS;
13
14 /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
15 * is remapped.*/
16 __binary_start = .;
17#ifdef MODE_TT
18 .thread_private : {
19 __start_thread_private = .;
20 errno = .;
21 . += 4;
22 arch/um/kernel/tt/unmap_fin.o (.data)
23 __end_thread_private = .;
24 }
25 . = ALIGN(4096);
26 .remap : { arch/um/kernel/tt/unmap_fin.o (.text) }
27
28 /* We want it only if we are in MODE_TT. In both cases, however, when MODE_TT
29 * is off the resulting binary segfaults.*/
30
31 . = ALIGN(4096); /* Init code and data */
32#endif
33
34 _stext = .;
35 __init_begin = .;
36 .init.text : {
37 _sinittext = .;
38 *(.init.text)
39 _einittext = .;
40 }
41 . = ALIGN(4096);
42 .text :
43 {
44 *(.text)
45 SCHED_TEXT
46 LOCK_TEXT
47 *(.fixup)
48 /* .gnu.warning sections are handled specially by elf32.em. */
49 *(.gnu.warning)
50 *(.gnu.linkonce.t*)
51 }
52
53 #include "asm/common.lds.S"
54
55 init.data : { *(init.data) }
56 .data :
57 {
58 . = ALIGN(KERNEL_STACK_SIZE); /* init_task */
59 *(.data.init_task)
60 *(.data)
61 *(.gnu.linkonce.d*)
62 CONSTRUCTORS
63 }
64 .data1 : { *(.data1) }
65 .ctors :
66 {
67 *(.ctors)
68 }
69 .dtors :
70 {
71 *(.dtors)
72 }
73
74 .got : { *(.got.plt) *(.got) }
75 .dynamic : { *(.dynamic) }
76 /* We want the small data sections together, so single-instruction offsets
77 can access them all, and initialized data all before uninitialized, so
78 we can shorten the on-disk segment size. */
79 .sdata : { *(.sdata) }
80 _edata = .;
81 PROVIDE (edata = .);
82 . = ALIGN(0x1000);
83 .sbss :
84 {
85 __bss_start = .;
86 PROVIDE(_bss_start = .);
87 *(.sbss)
88 *(.scommon)
89 }
90 .bss :
91 {
92 *(.dynbss)
93 *(.bss)
94 *(COMMON)
95 }
96 _end = . ;
97 PROVIDE (end = .);
98 /* Stabs debugging sections. */
99 .stab 0 : { *(.stab) }
100 .stabstr 0 : { *(.stabstr) }
101 .stab.excl 0 : { *(.stab.excl) }
102 .stab.exclstr 0 : { *(.stab.exclstr) }
103 .stab.index 0 : { *(.stab.index) }
104 .stab.indexstr 0 : { *(.stab.indexstr) }
105 .comment 0 : { *(.comment) }
106}
diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c
new file mode 100644
index 000000000000..954ff67cc8b3
--- /dev/null
+++ b/arch/um/kernel/user_util.c
@@ -0,0 +1,173 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <limits.h>
10#include <setjmp.h>
11#include <sys/mman.h>
12#include <sys/stat.h>
13#include <sys/utsname.h>
14#include <sys/param.h>
15#include <sys/time.h>
16#include "asm/types.h"
17#include <ctype.h>
18#include <signal.h>
19#include <wait.h>
20#include <errno.h>
21#include <stdarg.h>
22#include <sched.h>
23#include <termios.h>
24#include <string.h>
25#include "user_util.h"
26#include "kern_util.h"
27#include "user.h"
28#include "mem_user.h"
29#include "init.h"
30#include "helper.h"
31#include "ptrace_user.h"
32#include "uml-config.h"
33
34void stop(void)
35{
36 while(1) sleep(1000000);
37}
38
39void stack_protections(unsigned long address)
40{
41 int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
42
43 if(mprotect((void *) address, page_size(), prot) < 0)
44 panic("protecting stack failed, errno = %d", errno);
45}
46
47void task_protections(unsigned long address)
48{
49 unsigned long guard = address + page_size();
50 unsigned long stack = guard + page_size();
51 int prot = 0, pages;
52
53#ifdef notdef
54 if(mprotect((void *) stack, page_size(), prot) < 0)
55 panic("protecting guard page failed, errno = %d", errno);
56#endif
57 pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
58 prot = PROT_READ | PROT_WRITE | PROT_EXEC;
59 if(mprotect((void *) stack, pages * page_size(), prot) < 0)
60 panic("protecting stack failed, errno = %d", errno);
61}
62
63int wait_for_stop(int pid, int sig, int cont_type, void *relay)
64{
65 sigset_t *relay_signals = relay;
66 int status, ret;
67
68 while(1){
69 CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED));
70 if((ret < 0) ||
71 !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
72 if(ret < 0){
73 printk("wait failed, errno = %d\n",
74 errno);
75 }
76 else if(WIFEXITED(status))
77 printk("process %d exited with status %d\n",
78 pid, WEXITSTATUS(status));
79 else if(WIFSIGNALED(status))
80 printk("process %d exited with signal %d\n",
81 pid, WTERMSIG(status));
82 else if((WSTOPSIG(status) == SIGVTALRM) ||
83 (WSTOPSIG(status) == SIGALRM) ||
84 (WSTOPSIG(status) == SIGIO) ||
85 (WSTOPSIG(status) == SIGPROF) ||
86 (WSTOPSIG(status) == SIGCHLD) ||
87 (WSTOPSIG(status) == SIGWINCH) ||
88 (WSTOPSIG(status) == SIGINT)){
89 ptrace(cont_type, pid, 0, WSTOPSIG(status));
90 continue;
91 }
92 else if((relay_signals != NULL) &&
93 sigismember(relay_signals, WSTOPSIG(status))){
94 ptrace(cont_type, pid, 0, WSTOPSIG(status));
95 continue;
96 }
97 else printk("process %d stopped with signal %d\n",
98 pid, WSTOPSIG(status));
99 panic("wait_for_stop failed to wait for %d to stop "
100 "with %d\n", pid, sig);
101 }
102 return(status);
103 }
104}
105
106int raw(int fd)
107{
108 struct termios tt;
109 int err;
110
111 CATCH_EINTR(err = tcgetattr(fd, &tt));
112 if (err < 0) {
113 printk("tcgetattr failed, errno = %d\n", errno);
114 return(-errno);
115 }
116
117 cfmakeraw(&tt);
118
119 CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt));
120 if (err < 0) {
121 printk("tcsetattr failed, errno = %d\n", errno);
122 return(-errno);
123 }
124
125 /* XXX tcsetattr could have applied only some changes
126 * (and cfmakeraw() is a set of changes) */
127 return(0);
128}
129
130void setup_machinename(char *machine_out)
131{
132 struct utsname host;
133
134 uname(&host);
135 strcpy(machine_out, host.machine);
136}
137
138char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1];
139
140void setup_hostinfo(void)
141{
142 struct utsname host;
143
144 uname(&host);
145 sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename,
146 host.release, host.version, host.machine);
147}
148
149int setjmp_wrapper(void (*proc)(void *, void *), ...)
150{
151 va_list args;
152 sigjmp_buf buf;
153 int n;
154
155 n = sigsetjmp(buf, 1);
156 if(n == 0){
157 va_start(args, proc);
158 (*proc)(&buf, &args);
159 }
160 va_end(args);
161 return(n);
162}
163
164/*
165 * Overrides for Emacs so that we follow Linus's tabbing style.
166 * Emacs will notice this stuff at the end of the file and automatically
167 * adjust the settings for this buffer only. This must remain at the end
168 * of the file.
169 * ---------------------------------------------------------------------------
170 * Local variables:
171 * c-file-style: "linux"
172 * End:
173 */