aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
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
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')
-rw-r--r--arch/um/Kconfig320
-rw-r--r--arch/um/Kconfig.debug53
-rw-r--r--arch/um/Kconfig_char208
-rw-r--r--arch/um/Kconfig_i38624
-rw-r--r--arch/um/Kconfig_net180
-rw-r--r--arch/um/Kconfig_scsi58
-rw-r--r--arch/um/Kconfig_x86_6415
-rw-r--r--arch/um/Makefile210
-rw-r--r--arch/um/Makefile-i38644
-rw-r--r--arch/um/Makefile-ia641
-rw-r--r--arch/um/Makefile-os-Linux8
-rw-r--r--arch/um/Makefile-ppc9
-rw-r--r--arch/um/Makefile-skas14
-rw-r--r--arch/um/Makefile-tt5
-rw-r--r--arch/um/Makefile-x86_6432
-rw-r--r--arch/um/config.release333
-rw-r--r--arch/um/defconfig417
-rw-r--r--arch/um/drivers/Makefile46
-rw-r--r--arch/um/drivers/chan_kern.c577
-rw-r--r--arch/um/drivers/chan_user.c210
-rw-r--r--arch/um/drivers/cow.h42
-rw-r--r--arch/um/drivers/cow_sys.h48
-rw-r--r--arch/um/drivers/cow_user.c378
-rw-r--r--arch/um/drivers/daemon.h35
-rw-r--r--arch/um/drivers/daemon_kern.c108
-rw-r--r--arch/um/drivers/daemon_user.c197
-rw-r--r--arch/um/drivers/fd.c108
-rw-r--r--arch/um/drivers/harddog_kern.c190
-rw-r--r--arch/um/drivers/harddog_user.c143
-rw-r--r--arch/um/drivers/hostaudio_kern.c352
-rw-r--r--arch/um/drivers/line.c681
-rw-r--r--arch/um/drivers/mcast.h30
-rw-r--r--arch/um/drivers/mcast_kern.c143
-rw-r--r--arch/um/drivers/mcast_user.c177
-rw-r--r--arch/um/drivers/mconsole_kern.c619
-rw-r--r--arch/um/drivers/mconsole_user.c215
-rw-r--r--arch/um/drivers/mmapper_kern.c150
-rw-r--r--arch/um/drivers/net_kern.c896
-rw-r--r--arch/um/drivers/net_user.c255
-rw-r--r--arch/um/drivers/null.c56
-rw-r--r--arch/um/drivers/pcap_kern.c123
-rw-r--r--arch/um/drivers/pcap_user.c143
-rw-r--r--arch/um/drivers/pcap_user.h31
-rw-r--r--arch/um/drivers/port.h30
-rw-r--r--arch/um/drivers/port_kern.c309
-rw-r--r--arch/um/drivers/port_user.c225
-rw-r--r--arch/um/drivers/pty.c162
-rw-r--r--arch/um/drivers/random.c122
-rw-r--r--arch/um/drivers/slip.h39
-rw-r--r--arch/um/drivers/slip_kern.c109
-rw-r--r--arch/um/drivers/slip_proto.h93
-rw-r--r--arch/um/drivers/slip_user.c280
-rw-r--r--arch/um/drivers/slirp.h51
-rw-r--r--arch/um/drivers/slirp_kern.c135
-rw-r--r--arch/um/drivers/slirp_user.c201
-rw-r--r--arch/um/drivers/ssl.c251
-rw-r--r--arch/um/drivers/ssl.h23
-rw-r--r--arch/um/drivers/stderr_console.c45
-rw-r--r--arch/um/drivers/stdio_console.c205
-rw-r--r--arch/um/drivers/stdio_console.h21
-rw-r--r--arch/um/drivers/tty.c92
-rw-r--r--arch/um/drivers/ubd_kern.c1669
-rw-r--r--arch/um/drivers/ubd_user.c75
-rw-r--r--arch/um/drivers/xterm.c225
-rw-r--r--arch/um/drivers/xterm.h22
-rw-r--r--arch/um/drivers/xterm_kern.c93
-rw-r--r--arch/um/include/2_5compat.h24
-rw-r--r--arch/um/include/chan_kern.h60
-rw-r--r--arch/um/include/chan_user.h67
-rw-r--r--arch/um/include/choose-mode.h42
-rw-r--r--arch/um/include/elf_user.h19
-rw-r--r--arch/um/include/frame_kern.h32
-rw-r--r--arch/um/include/helper.h27
-rw-r--r--arch/um/include/init.h132
-rw-r--r--arch/um/include/initrd.h22
-rw-r--r--arch/um/include/irq_kern.h28
-rw-r--r--arch/um/include/irq_user.h36
-rw-r--r--arch/um/include/kern.h49
-rw-r--r--arch/um/include/kern_util.h125
-rw-r--r--arch/um/include/line.h108
-rw-r--r--arch/um/include/mconsole.h103
-rw-r--r--arch/um/include/mconsole_kern.h62
-rw-r--r--arch/um/include/mem.h28
-rw-r--r--arch/um/include/mem_kern.h30
-rw-r--r--arch/um/include/mem_user.h83
-rw-r--r--arch/um/include/mode.h30
-rw-r--r--arch/um/include/mode_kern.h30
-rw-r--r--arch/um/include/net_kern.h82
-rw-r--r--arch/um/include/net_user.h66
-rw-r--r--arch/um/include/os.h183
-rw-r--r--arch/um/include/process.h25
-rw-r--r--arch/um/include/ptrace_user.h60
-rw-r--r--arch/um/include/registers.h29
-rw-r--r--arch/um/include/sigcontext.h25
-rw-r--r--arch/um/include/sigio.h28
-rw-r--r--arch/um/include/signal_kern.h22
-rw-r--r--arch/um/include/signal_user.h28
-rw-r--r--arch/um/include/skas_ptrace.h36
-rw-r--r--arch/um/include/syscall_user.h23
-rw-r--r--arch/um/include/sysdep-i386/checksum.h219
-rw-r--r--arch/um/include/sysdep-i386/ptrace.h241
-rw-r--r--arch/um/include/sysdep-i386/ptrace_user.h62
-rw-r--r--arch/um/include/sysdep-i386/sigcontext.h49
-rw-r--r--arch/um/include/sysdep-i386/signal.h25
-rw-r--r--arch/um/include/sysdep-i386/syscalls.h123
-rw-r--r--arch/um/include/sysdep-ia64/ptrace.h26
-rw-r--r--arch/um/include/sysdep-ia64/sigcontext.h20
-rw-r--r--arch/um/include/sysdep-ia64/syscalls.h20
-rw-r--r--arch/um/include/sysdep-ppc/ptrace.h104
-rw-r--r--arch/um/include/sysdep-ppc/sigcontext.h62
-rw-r--r--arch/um/include/sysdep-ppc/syscalls.h53
-rw-r--r--arch/um/include/sysdep-x86_64/checksum.h151
-rw-r--r--arch/um/include/sysdep-x86_64/ptrace.h264
-rw-r--r--arch/um/include/sysdep-x86_64/ptrace_user.h69
-rw-r--r--arch/um/include/sysdep-x86_64/sigcontext.h49
-rw-r--r--arch/um/include/sysdep-x86_64/signal.h27
-rw-r--r--arch/um/include/sysdep-x86_64/syscalls.h91
-rw-r--r--arch/um/include/sysrq.h6
-rw-r--r--arch/um/include/tempfile.h21
-rw-r--r--arch/um/include/time_user.h18
-rw-r--r--arch/um/include/tlb.h67
-rw-r--r--arch/um/include/ubd_user.h26
-rw-r--r--arch/um/include/um_mmu.h40
-rw-r--r--arch/um/include/um_uaccess.h125
-rw-r--r--arch/um/include/umid.h22
-rw-r--r--arch/um/include/uml_uaccess.h28
-rw-r--r--arch/um/include/user.h32
-rw-r--r--arch/um/include/user_util.h106
-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
-rw-r--r--arch/um/os-Linux/Makefile13
-rw-r--r--arch/um/os-Linux/drivers/Makefile13
-rw-r--r--arch/um/os-Linux/drivers/etap.h27
-rw-r--r--arch/um/os-Linux/drivers/ethertap_kern.c119
-rw-r--r--arch/um/os-Linux/drivers/ethertap_user.c240
-rw-r--r--arch/um/os-Linux/drivers/tuntap.h32
-rw-r--r--arch/um/os-Linux/drivers/tuntap_kern.c104
-rw-r--r--arch/um/os-Linux/drivers/tuntap_user.c225
-rw-r--r--arch/um/os-Linux/elf_aux.c66
-rw-r--r--arch/um/os-Linux/file.c680
-rw-r--r--arch/um/os-Linux/include/file.h22
-rw-r--r--arch/um/os-Linux/process.c171
-rw-r--r--arch/um/os-Linux/signal.c48
-rw-r--r--arch/um/os-Linux/sys-i386/Makefile10
-rw-r--r--arch/um/os-Linux/sys-i386/registers.c132
-rw-r--r--arch/um/os-Linux/sys-x86_64/Makefile10
-rw-r--r--arch/um/os-Linux/sys-x86_64/registers.c81
-rw-r--r--arch/um/os-Linux/time.c21
-rw-r--r--arch/um/os-Linux/tty.c61
-rw-r--r--arch/um/os-Linux/user_syms.c95
-rw-r--r--arch/um/os-Linux/util/Makefile4
-rw-r--r--arch/um/os-Linux/util/mk_user_constants.c29
-rw-r--r--arch/um/scripts/Makefile.rules13
-rw-r--r--arch/um/sys-i386/Makefile29
-rw-r--r--arch/um/sys-i386/bugs.c222
-rw-r--r--arch/um/sys-i386/checksum.S460
-rw-r--r--arch/um/sys-i386/delay.c14
-rw-r--r--arch/um/sys-i386/fault.c42
-rw-r--r--arch/um/sys-i386/ksyms.c17
-rw-r--r--arch/um/sys-i386/ldt.c98
-rw-r--r--arch/um/sys-i386/ptrace.c369
-rw-r--r--arch/um/sys-i386/ptrace_user.c131
-rw-r--r--arch/um/sys-i386/sigcontext.c71
-rw-r--r--arch/um/sys-i386/signal.c382
-rw-r--r--arch/um/sys-i386/syscalls.c210
-rw-r--r--arch/um/sys-i386/sysrq.c35
-rw-r--r--arch/um/sys-i386/util/Makefile8
-rw-r--r--arch/um/sys-i386/util/mk_sc.c52
-rw-r--r--arch/um/sys-i386/util/mk_thread_kern.c22
-rw-r--r--arch/um/sys-i386/util/mk_thread_user.c30
-rw-r--r--arch/um/sys-ia64/Makefile11
-rw-r--r--arch/um/sys-ppc/Makefile69
-rw-r--r--arch/um/sys-ppc/misc.S116
-rw-r--r--arch/um/sys-ppc/miscthings.c53
-rw-r--r--arch/um/sys-ppc/ptrace.c28
-rw-r--r--arch/um/sys-ppc/ptrace_user.c39
-rw-r--r--arch/um/sys-ppc/sigcontext.c15
-rw-r--r--arch/um/sys-ppc/sysrq.c43
-rw-r--r--arch/um/sys-x86_64/Makefile37
-rw-r--r--arch/um/sys-x86_64/bugs.c122
-rw-r--r--arch/um/sys-x86_64/delay.c26
-rw-r--r--arch/um/sys-x86_64/fault.c23
-rw-r--r--arch/um/sys-x86_64/mem.c25
-rw-r--r--arch/um/sys-x86_64/ptrace.c138
-rw-r--r--arch/um/sys-x86_64/ptrace_user.c51
-rw-r--r--arch/um/sys-x86_64/sigcontext.c39
-rw-r--r--arch/um/sys-x86_64/signal.c276
-rw-r--r--arch/um/sys-x86_64/syscalls.c186
-rw-r--r--arch/um/sys-x86_64/sysrq.c49
-rw-r--r--arch/um/sys-x86_64/util/Makefile10
-rw-r--r--arch/um/sys-x86_64/util/mk_sc.c58
-rw-r--r--arch/um/sys-x86_64/util/mk_thread_kern.c21
-rw-r--r--arch/um/sys-x86_64/util/mk_thread_user.c30
-rw-r--r--arch/um/util/Makefile8
-rw-r--r--arch/um/util/mk_constants_kern.c28
-rw-r--r--arch/um/util/mk_constants_user.c28
-rw-r--r--arch/um/util/mk_task_kern.c17
-rw-r--r--arch/um/util/mk_task_user.c30
295 files changed, 35908 insertions, 0 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
new file mode 100644
index 000000000000..9a23df182123
--- /dev/null
+++ b/arch/um/Kconfig
@@ -0,0 +1,320 @@
1# UML uses the generic IRQ sugsystem
2config GENERIC_HARDIRQS
3 bool
4 default y
5
6config UML
7 bool
8 default y
9
10# XXX: does UM have a mmu/swap?
11config MMU
12 bool
13 default y
14
15mainmenu "Linux/Usermode Kernel Configuration"
16
17config ISA
18 bool
19
20config SBUS
21 bool
22
23config PCI
24 bool
25
26config UID16
27 bool
28 default y
29
30config RWSEM_GENERIC_SPINLOCK
31 bool
32 default y
33
34config GENERIC_CALIBRATE_DELAY
35 bool
36 default y
37
38menu "UML-specific options"
39
40config MODE_TT
41 bool "Tracing thread support"
42 default y
43 help
44 This option controls whether tracing thread support is compiled
45 into UML. Normally, this should be set to Y. If you intend to
46 use only skas mode (and the host has the skas patch applied to it),
47 then it is OK to say N here.
48
49config STATIC_LINK
50 bool "Force a static link"
51 default n
52 depends on !MODE_TT
53 help
54 If CONFIG_MODE_TT is disabled, then this option gives you the ability
55 to force a static link of UML. Normally, if only skas mode is built
56 in to UML, it will be linked as a shared binary. This is inconvenient
57 for use in a chroot jail. So, if you intend to run UML inside a
58 chroot, and you disable CONFIG_MODE_TT, you probably want to say Y
59 here.
60
61config MODE_SKAS
62 bool "Separate Kernel Address Space support"
63 default y
64 help
65 This option controls whether skas (separate kernel address space)
66 support is compiled in. If you have applied the skas patch to the
67 host, then you certainly want to say Y here (and consider saying N
68 to CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this
69 option will shrink the UML binary slightly.
70
71source "arch/um/Kconfig_arch"
72
73config LD_SCRIPT_STATIC
74 bool
75 default y
76 depends on MODE_TT || STATIC_LINK
77
78config LD_SCRIPT_DYN
79 bool
80 default y
81 depends on !LD_SCRIPT_STATIC
82
83config NET
84 bool "Networking support"
85 help
86 Unless you really know what you are doing, you should say Y here.
87 The reason is that some programs need kernel networking support even
88 when running on a stand-alone machine that isn't connected to any
89 other computer. If you are upgrading from an older kernel, you
90 should consider updating your networking tools too because changes
91 in the kernel and the tools often go hand in hand. The tools are
92 contained in the package net-tools, the location and version number
93 of which are given in <file:Documentation/Changes>.
94
95 For a general introduction to Linux networking, it is highly
96 recommended to read the NET-HOWTO, available from
97 <http://www.tldp.org/docs.html#howto>.
98
99
100source "fs/Kconfig.binfmt"
101
102config HOSTFS
103 tristate "Host filesystem"
104 help
105 While the User-Mode Linux port uses its own root file system for
106 booting and normal file access, this module lets the UML user
107 access files stored on the host. It does not require any
108 network connection between the Host and UML. An example use of
109 this might be:
110
111 mount none /tmp/fromhost -t hostfs -o /tmp/umlshare
112
113 where /tmp/fromhost is an empty directory inside UML and
114 /tmp/umlshare is a directory on the host with files the UML user
115 wishes to access.
116
117 For more information, see
118 <http://user-mode-linux.sourceforge.net/hostfs.html>.
119
120 If you'd like to be able to work with files stored on the host,
121 say Y or M here; otherwise say N.
122
123config HPPFS
124 tristate "HoneyPot ProcFS (EXPERIMENTAL)"
125 depends on BROKEN
126 help
127 hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
128 entries to be overridden, removed, or fabricated from the host.
129 Its purpose is to allow a UML to appear to be a physical machine
130 by removing or changing anything in /proc which gives away the
131 identity of a UML.
132
133 See <http://user-mode-linux.sf.net/hppfs.html> for more information.
134
135 You only need this if you are setting up a UML honeypot. Otherwise,
136 it is safe to say 'N' here.
137
138 If you are actively using it, please ask for it to be fixed. In this
139 moment, it does not work on 2.6 (it works somehow on 2.4).
140
141config MCONSOLE
142 bool "Management console"
143 default y
144 help
145 The user mode linux management console is a low-level interface to
146 the kernel, somewhat like the i386 SysRq interface. Since there is
147 a full-blown operating system running under every user mode linux
148 instance, there is much greater flexibility possible than with the
149 SysRq mechanism.
150
151 If you answer 'Y' to this option, to use this feature, you need the
152 mconsole client (called uml_mconsole) which is present in CVS in
153 2.4.5-9um and later (path /tools/mconsole), and is also in the
154 distribution RPM package in 2.4.6 and later.
155
156 It is safe to say 'Y' here.
157
158config MAGIC_SYSRQ
159 bool "Magic SysRq key"
160 depends on MCONSOLE
161 ---help---
162 If you say Y here, you will have some control over the system even
163 if the system crashes for example during kernel debugging (e.g., you
164 will be able to flush the buffer cache to disk, reboot the system
165 immediately or dump some status information). A key for each of the
166 possible requests is provided.
167
168 This is the feature normally accomplished by pressing a key
169 while holding SysRq (Alt+PrintScreen).
170
171 On UML, this is accomplished by sending a "sysrq" command with
172 mconsole, followed by the letter for the requested command.
173
174 The keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
175 unless you really know what this hack does.
176
177config HOST_2G_2G
178 bool "2G/2G host address space split"
179 default n
180 help
181 This is needed when the host on which you run has a 2G/2G memory
182 split, instead of the customary 3G/1G.
183
184 Note that to enable such a host
185 configuration, which makes sense only in some cases, you need special
186 host patches.
187
188 So, if you do not know what to do here, say 'N'.
189
190config SMP
191 bool "Symmetric multi-processing support (EXPERIMENTAL)"
192 default n
193 depends on MODE_TT && EXPERIMENTAL
194 help
195 This option enables UML SMP support.
196 It is NOT related to having a real SMP box. Not directly, at least.
197
198 UML implements virtual SMP by allowing as many processes to run
199 simultaneously on the host as there are virtual processors configured.
200
201 Obviously, if the host is a uniprocessor, those processes will
202 timeshare, but, inside UML, will appear to be running simultaneously.
203 If the host is a multiprocessor, then UML processes may run
204 simultaneously, depending on the host scheduler.
205
206 This, however, is supported only in TT mode. So, if you use the SKAS
207 patch on your host, switching to TT mode and enabling SMP usually gives
208 you worse performances.
209 Also, since the support for SMP has been under-developed, there could
210 be some bugs being exposed by enabling SMP.
211
212 If you don't know what to do, say N.
213
214config NR_CPUS
215 int "Maximum number of CPUs (2-32)"
216 range 2 32
217 depends on SMP
218 default "32"
219
220config NEST_LEVEL
221 int "Nesting level"
222 default "0"
223 help
224 This is set to the number of layers of UMLs that this UML will be run
225 in. Normally, this is zero, meaning that it will run directly on the
226 host. Setting it to one will build a UML that can run inside a UML
227 that is running on the host. Generally, if you intend this UML to run
228 inside another UML, set CONFIG_NEST_LEVEL to one more than the host
229 UML.
230
231 Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to
232 greater than one, then the guest UML should have its CONFIG_NEST_LEVEL
233 set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS.
234 Only change this if you are running nested UMLs.
235
236config KERNEL_HALF_GIGS
237 int "Kernel address space size (in .5G units)"
238 default "1"
239 help
240 This determines the amount of address space that UML will allocate for
241 its own, measured in half Gigabyte units. The default is 1.
242 Change this only if you need to boot UML with an unusually large amount
243 of physical memory.
244
245config HIGHMEM
246 bool "Highmem support"
247
248config KERNEL_STACK_ORDER
249 int "Kernel stack size order"
250 default 2
251 help
252 This option determines the size of UML kernel stacks. They will
253 be 1 << order pages. The default is OK unless you're running Valgrind
254 on UML, in which case, set this to 3.
255
256config UML_REAL_TIME_CLOCK
257 bool "Real-time Clock"
258 default y
259 help
260 This option makes UML time deltas match wall clock deltas. This should
261 normally be enabled. The exception would be if you are debugging with
262 UML and spend long times with UML stopped at a breakpoint. In this
263 case, when UML is restarted, it will call the timer enough times to make
264 up for the time spent at the breakpoint. This could result in a
265 noticable lag. If this is a problem, then disable this option.
266
267endmenu
268
269source "init/Kconfig"
270
271source "drivers/base/Kconfig"
272
273source "arch/um/Kconfig_char"
274
275source "drivers/block/Kconfig"
276
277config NETDEVICES
278 bool
279 default NET
280
281source "arch/um/Kconfig_net"
282
283source "net/Kconfig"
284
285source "fs/Kconfig"
286
287source "security/Kconfig"
288
289source "crypto/Kconfig"
290
291source "lib/Kconfig"
292
293menu "SCSI support"
294depends on BROKEN
295
296config SCSI
297 tristate "SCSI support"
298
299# This gives us free_dma, which scsi.c wants.
300config GENERIC_ISA_DMA
301 bool
302 depends on SCSI
303 default y
304
305source "arch/um/Kconfig_scsi"
306
307endmenu
308
309source "drivers/md/Kconfig"
310
311if BROKEN
312 source "drivers/mtd/Kconfig"
313endif
314
315#This is just to shut up some Kconfig warnings, so no prompt.
316config INPUT
317 bool
318 default n
319
320source "arch/um/Kconfig.debug"
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug
new file mode 100644
index 000000000000..b89989de364d
--- /dev/null
+++ b/arch/um/Kconfig.debug
@@ -0,0 +1,53 @@
1menu "Kernel hacking"
2
3source "lib/Kconfig.debug"
4
5config FRAME_POINTER
6 bool
7 default y if DEBUG_INFO
8
9config PT_PROXY
10 bool "Enable ptrace proxy"
11 depends on XTERM_CHAN && DEBUG_INFO && MODE_TT
12 help
13 This option enables a debugging interface which allows gdb to debug
14 the kernel without needing to actually attach to kernel threads.
15 If you want to do kernel debugging, say Y here; otherwise say N.
16
17config GPROF
18 bool "Enable gprof support"
19 depends on DEBUG_INFO && MODE_SKAS && !MODE_TT
20 help
21 This allows profiling of a User-Mode Linux kernel with the gprof
22 utility.
23
24 See <http://user-mode-linux.sourceforge.net/gprof.html> for more
25 details.
26
27 If you're involved in UML kernel development and want to use gprof,
28 say Y. If you're unsure, say N.
29
30config GCOV
31 bool "Enable gcov support"
32 depends on DEBUG_INFO && MODE_SKAS
33 help
34 This option allows developers to retrieve coverage data from a UML
35 session.
36
37 See <http://user-mode-linux.sourceforge.net/gprof.html> for more
38 details.
39
40 If you're involved in UML kernel development and want to use gcov,
41 say Y. If you're unsure, say N.
42
43config SYSCALL_DEBUG
44 bool "Enable system call debugging"
45 default N
46 depends on DEBUG_INFO
47 help
48 This adds some system debugging to UML, including keeping a ring buffer
49 with recent system calls and some global and per-task statistics.
50
51 If unsure, say N
52
53endmenu
diff --git a/arch/um/Kconfig_char b/arch/um/Kconfig_char
new file mode 100644
index 000000000000..3e50fdb67626
--- /dev/null
+++ b/arch/um/Kconfig_char
@@ -0,0 +1,208 @@
1
2menu "Character Devices"
3
4config STDERR_CONSOLE
5 bool "stderr console"
6 default y
7 help
8 console driver which dumps all printk messages to stderr.
9
10config STDIO_CONSOLE
11 bool
12 default y
13
14config SSL
15 bool "Virtual serial line"
16 help
17 The User-Mode Linux environment allows you to create virtual serial
18 lines on the UML that are usually made to show up on the host as
19 ttys or ptys.
20
21 See <http://user-mode-linux.sourceforge.net/input.html> for more
22 information and command line examples of how to use this facility.
23
24 Unless you have a specific reason for disabling this, say Y.
25
26config NULL_CHAN
27 bool "null channel support"
28 help
29 This option enables support for attaching UML consoles and serial
30 lines to a device similar to /dev/null. Data written to it disappears
31 and there is never any data to be read.
32
33config PORT_CHAN
34 bool "port channel support"
35 help
36 This option enables support for attaching UML consoles and serial
37 lines to host portals. They may be accessed with 'telnet <host>
38 <port number>'. Any number of consoles and serial lines may be
39 attached to a single portal, although what UML device you get when
40 you telnet to that portal will be unpredictable.
41 It is safe to say 'Y' here.
42
43config PTY_CHAN
44 bool "pty channel support"
45 help
46 This option enables support for attaching UML consoles and serial
47 lines to host pseudo-terminals. Access to both traditional
48 pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled
49 with this option. The assignment of UML devices to host devices
50 will be announced in the kernel message log.
51 It is safe to say 'Y' here.
52
53config TTY_CHAN
54 bool "tty channel support"
55 help
56 This option enables support for attaching UML consoles and serial
57 lines to host terminals. Access to both virtual consoles
58 (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and
59 /dev/pts/*) are controlled by this option.
60 It is safe to say 'Y' here.
61
62config XTERM_CHAN
63 bool "xterm channel support"
64 help
65 This option enables support for attaching UML consoles and serial
66 lines to xterms. Each UML device so assigned will be brought up in
67 its own xterm.
68 If you disable this option, then CONFIG_PT_PROXY will be disabled as
69 well, since UML's gdb currently requires an xterm.
70 It is safe to say 'Y' here.
71
72config NOCONFIG_CHAN
73 bool
74 default !(XTERM_CHAN && TTY_CHAN && PTY_CHAN && PORT_CHAN && NULL_CHAN)
75
76config CON_ZERO_CHAN
77 string "Default main console channel initialization"
78 default "fd:0,fd:1"
79 help
80 This is the string describing the channel to which the main console
81 will be attached by default. This value can be overridden from the
82 command line. The default value is "fd:0,fd:1", which attaches the
83 main console to stdin and stdout.
84 It is safe to leave this unchanged.
85
86config CON_CHAN
87 string "Default console channel initialization"
88 default "xterm"
89 help
90 This is the string describing the channel to which all consoles
91 except the main console will be attached by default. This value can
92 be overridden from the command line. The default value is "xterm",
93 which brings them up in xterms.
94 It is safe to leave this unchanged, although you may wish to change
95 this if you expect the UML that you build to be run in environments
96 which don't have X or xterm available.
97
98config SSL_CHAN
99 string "Default serial line channel initialization"
100 default "pty"
101 help
102 This is the string describing the channel to which the serial lines
103 will be attached by default. This value can be overridden from the
104 command line. The default value is "pty", which attaches them to
105 traditional pseudo-terminals.
106 It is safe to leave this unchanged, although you may wish to change
107 this if you expect the UML that you build to be run in environments
108 which don't have a set of /dev/pty* devices.
109
110config UNIX98_PTYS
111 bool "Unix98 PTY support"
112 ---help---
113 A pseudo terminal (PTY) is a software device consisting of two
114 halves: a master and a slave. The slave device behaves identical to
115 a physical terminal; the master device is used by a process to
116 read data from and write data to the slave, thereby emulating a
117 terminal. Typical programs for the master side are telnet servers
118 and xterms.
119
120 Linux has traditionally used the BSD-like names /dev/ptyxx for
121 masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
122 has a number of problems. The GNU C library glibc 2.1 and later,
123 however, supports the Unix98 naming standard: in order to acquire a
124 pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
125 terminal is then made available to the process and the pseudo
126 terminal slave can be accessed as /dev/pts/<number>. What was
127 traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
128
129 All modern Linux systems use the Unix98 ptys. Say Y unless
130 you're on an embedded system and want to conserve memory.
131
132config LEGACY_PTYS
133 bool "Legacy (BSD) PTY support"
134 default y
135 ---help---
136 A pseudo terminal (PTY) is a software device consisting of two
137 halves: a master and a slave. The slave device behaves identical to
138 a physical terminal; the master device is used by a process to
139 read data from and write data to the slave, thereby emulating a
140 terminal. Typical programs for the master side are telnet servers
141 and xterms.
142
143 Linux has traditionally used the BSD-like names /dev/ptyxx
144 for masters and /dev/ttyxx for slaves of pseudo
145 terminals. This scheme has a number of problems, including
146 security. This option enables these legacy devices; on most
147 systems, it is safe to say N.
148
149
150config LEGACY_PTY_COUNT
151 int "Maximum number of legacy PTY in use"
152 depends on LEGACY_PTYS
153 default "256"
154 ---help---
155 The maximum number of legacy PTYs that can be used at any one time.
156 The default is 256, and should be more than enough. Embedded
157 systems may want to reduce this to save memory.
158
159 When not in use, each legacy PTY occupies 12 bytes on 32-bit
160 architectures and 24 bytes on 64-bit architectures.
161
162config WATCHDOG
163 bool "Watchdog Timer Support"
164
165config WATCHDOG_NOWAYOUT
166 bool "Disable watchdog shutdown on close"
167 depends on WATCHDOG
168
169config SOFT_WATCHDOG
170 tristate "Software Watchdog"
171 depends on WATCHDOG
172
173config UML_WATCHDOG
174 tristate "UML watchdog"
175 depends on WATCHDOG
176
177config UML_SOUND
178 tristate "Sound support"
179 help
180 This option enables UML sound support. If enabled, it will pull in
181 soundcore and the UML hostaudio relay, which acts as a intermediary
182 between the host's dsp and mixer devices and the UML sound system.
183 It is safe to say 'Y' here.
184
185config SOUND
186 tristate
187 default UML_SOUND
188
189config HOSTAUDIO
190 tristate
191 default UML_SOUND
192
193config UML_RANDOM
194 tristate "Hardware random number generator"
195 help
196 This option enables UML's "hardware" random number generator. It
197 attaches itself to the host's /dev/random, supplying as much entropy
198 as the host has, rather than the small amount the UML gets from its
199 own drivers. It registers itself as a standard hardware random number
200 generator, major 10, minor 183, and the canonical device name is
201 /dev/hwrng.
202 The way to make use of this is to install the rng-tools package
203 (check your distro, or download from
204 http://sourceforge.net/projects/gkernel/). rngd periodically reads
205 /dev/hwrng and injects the entropy into /dev/random.
206
207endmenu
208
diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig_i386
new file mode 100644
index 000000000000..203c242201b6
--- /dev/null
+++ b/arch/um/Kconfig_i386
@@ -0,0 +1,24 @@
1config 64_BIT
2 bool
3 default n
4
5config TOP_ADDR
6 hex
7 default 0xc0000000 if !HOST_2G_2G
8 default 0x80000000 if HOST_2G_2G
9
10config 3_LEVEL_PGTABLES
11 bool "Three-level pagetables"
12 default n
13 help
14 Three-level pagetables will let UML have more than 4G of physical
15 memory. All the memory that can't be mapped directly will be treated
16 as high memory.
17
18config ARCH_HAS_SC_SIGNALS
19 bool
20 default y
21
22config ARCH_REUSE_HOST_VSYSCALL_AREA
23 bool
24 default y
diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig_net
new file mode 100644
index 000000000000..1c2f9a70d91d
--- /dev/null
+++ b/arch/um/Kconfig_net
@@ -0,0 +1,180 @@
1
2menu "UML Network Devices"
3 depends on NET
4
5# UML virtual driver
6config UML_NET
7 bool "Virtual network device"
8 help
9 While the User-Mode port cannot directly talk to any physical
10 hardware devices, this choice and the following transport options
11 provide one or more virtual network devices through which the UML
12 kernels can talk to each other, the host, and with the host's help,
13 machines on the outside world.
14
15 For more information, including explanations of the networking and
16 sample configurations, see
17 <http://user-mode-linux.sourceforge.net/networking.html>.
18
19 If you'd like to be able to enable networking in the User-Mode
20 linux environment, say Y; otherwise say N. Note that you must
21 enable at least one of the following transport options to actually
22 make use of UML networking.
23
24config UML_NET_ETHERTAP
25 bool "Ethertap transport"
26 depends on UML_NET
27 help
28 The Ethertap User-Mode Linux network transport allows a single
29 running UML to exchange packets with its host over one of the
30 host's Ethertap devices, such as /dev/tap0. Additional running
31 UMLs can use additional Ethertap devices, one per running UML.
32 While the UML believes it's on a (multi-device, broadcast) virtual
33 Ethernet network, it's in fact communicating over a point-to-point
34 link with the host.
35
36 To use this, your host kernel must have support for Ethertap
37 devices. Also, if your host kernel is 2.4.x, it must have
38 CONFIG_NETLINK_DEV configured as Y or M.
39
40 For more information, see
41 <http://user-mode-linux.sourceforge.net/networking.html> That site
42 has examples of the UML command line to use to enable Ethertap
43 networking.
44
45 If you'd like to set up an IP network with the host and/or the
46 outside world, say Y to this, the Daemon Transport and/or the
47 Slip Transport. You'll need at least one of them, but may choose
48 more than one without conflict. If you don't need UML networking,
49 say N.
50
51config UML_NET_TUNTAP
52 bool "TUN/TAP transport"
53 depends on UML_NET
54 help
55 The UML TUN/TAP network transport allows a UML instance to exchange
56 packets with the host over a TUN/TAP device. This option will only
57 work with a 2.4 host, unless you've applied the TUN/TAP patch to
58 your 2.2 host kernel.
59
60 To use this transport, your host kernel must have support for TUN/TAP
61 devices, either built-in or as a module.
62
63config UML_NET_SLIP
64 bool "SLIP transport"
65 depends on UML_NET
66 help
67 The slip User-Mode Linux network transport allows a running UML to
68 network with its host over a point-to-point link. Unlike Ethertap,
69 which can carry any Ethernet frame (and hence even non-IP packets),
70 the slip transport can only carry IP packets.
71
72 To use this, your host must support slip devices.
73
74 For more information, see
75 <http://user-mode-linux.sourceforge.net/networking.html>. That site
76 has examples of the UML command line to use to enable slip
77 networking, and details of a few quirks with it.
78
79 The Ethertap Transport is preferred over slip because of its
80 limitations. If you prefer slip, however, say Y here. Otherwise
81 choose the Multicast transport (to network multiple UMLs on
82 multiple hosts), Ethertap (to network with the host and the
83 outside world), and/or the Daemon transport (to network multiple
84 UMLs on a single host). You may choose more than one without
85 conflict. If you don't need UML networking, say N.
86
87config UML_NET_DAEMON
88 bool "Daemon transport"
89 depends on UML_NET
90 help
91 This User-Mode Linux network transport allows one or more running
92 UMLs on a single host to communicate with each other, but not to
93 the host.
94
95 To use this form of networking, you'll need to run the UML
96 networking daemon on the host.
97
98 For more information, see
99 <http://user-mode-linux.sourceforge.net/networking.html> That site
100 has examples of the UML command line to use to enable Daemon
101 networking.
102
103 If you'd like to set up a network with other UMLs on a single host,
104 say Y. If you need a network between UMLs on multiple physical
105 hosts, choose the Multicast Transport. To set up a network with
106 the host and/or other IP machines, say Y to the Ethertap or Slip
107 transports. You'll need at least one of them, but may choose
108 more than one without conflict. If you don't need UML networking,
109 say N.
110
111config UML_NET_MCAST
112 bool "Multicast transport"
113 depends on UML_NET
114 help
115 This Multicast User-Mode Linux network transport allows multiple
116 UMLs (even ones running on different host machines!) to talk to
117 each other over a virtual ethernet network. However, it requires
118 at least one UML with one of the other transports to act as a
119 bridge if any of them need to be able to talk to their hosts or any
120 other IP machines.
121
122 To use this, your host kernel(s) must support IP Multicasting.
123
124 For more information, see
125 <http://user-mode-linux.sourceforge.net/networking.html> That site
126 has examples of the UML command line to use to enable Multicast
127 networking, and notes about the security of this approach.
128
129 If you need UMLs on multiple physical hosts to communicate as if
130 they shared an Ethernet network, say Y. If you need to communicate
131 with other IP machines, make sure you select one of the other
132 transports (possibly in addition to Multicast; they're not
133 exclusive). If you don't need to network UMLs say N to each of
134 the transports.
135
136config UML_NET_PCAP
137 bool "pcap transport"
138 depends on UML_NET && BROKEN
139 help
140 The pcap transport makes a pcap packet stream on the host look
141 like an ethernet device inside UML. This is useful for making
142 UML act as a network monitor for the host. You must have libcap
143 installed in order to build the pcap transport into UML.
144
145 For more information, see
146 <http://user-mode-linux.sourceforge.net/networking.html> That site
147 has examples of the UML command line to use to enable this option.
148
149 If you intend to use UML as a network monitor for the host, say
150 Y here. Otherwise, say N.
151
152config UML_NET_SLIRP
153 bool "SLiRP transport"
154 depends on UML_NET
155 help
156 The SLiRP User-Mode Linux network transport allows a running UML
157 to network by invoking a program that can handle SLIP encapsulated
158 packets. This is commonly (but not limited to) the application
159 known as SLiRP, a program that can re-socket IP packets back onto
160 the host on which it is run. Only IP packets are supported,
161 unlike other network transports that can handle all Ethernet
162 frames. In general, slirp allows the UML the same IP connectivity
163 to the outside world that the host user is permitted, and unlike
164 other transports, SLiRP works without the need of root level
165 privleges, setuid binaries, or SLIP devices on the host. This
166 also means not every type of connection is possible, but most
167 situations can be accomodated with carefully crafted slirp
168 commands that can be passed along as part of the network device's
169 setup string. The effect of this transport on the UML is similar
170 that of a host behind a firewall that masquerades all network
171 connections passing through it (but is less secure).
172
173 To use this you should first have slirp compiled somewhere
174 accessible on the host, and have read its documentation. If you
175 don't need UML networking, say N.
176
177 Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
178
179endmenu
180
diff --git a/arch/um/Kconfig_scsi b/arch/um/Kconfig_scsi
new file mode 100644
index 000000000000..c291c942b1a8
--- /dev/null
+++ b/arch/um/Kconfig_scsi
@@ -0,0 +1,58 @@
1comment "SCSI support type (disk, tape, CD-ROM)"
2 depends on SCSI
3
4config BLK_DEV_SD
5 tristate "SCSI disk support"
6 depends on SCSI
7
8config SD_EXTRA_DEVS
9 int "Maximum number of SCSI disks that can be loaded as modules"
10 depends on BLK_DEV_SD
11 default "40"
12
13config CHR_DEV_ST
14 tristate "SCSI tape support"
15 depends on SCSI
16
17config BLK_DEV_SR
18 tristate "SCSI CD-ROM support"
19 depends on SCSI
20
21config BLK_DEV_SR_VENDOR
22 bool "Enable vendor-specific extensions (for SCSI CDROM)"
23 depends on BLK_DEV_SR
24
25config SR_EXTRA_DEVS
26 int "Maximum number of CDROM devices that can be loaded as modules"
27 depends on BLK_DEV_SR
28 default "2"
29
30config CHR_DEV_SG
31 tristate "SCSI generic support"
32 depends on SCSI
33
34comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs"
35 depends on SCSI
36
37#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
38config SCSI_DEBUG_QUEUES
39 bool "Enable extra checks in new queueing code"
40 depends on SCSI
41
42#fi
43config SCSI_MULTI_LUN
44 bool "Probe all LUNs on each SCSI device"
45 depends on SCSI
46
47config SCSI_CONSTANTS
48 bool "Verbose SCSI error reporting (kernel size +=12K)"
49 depends on SCSI
50
51config SCSI_LOGGING
52 bool "SCSI logging facility"
53 depends on SCSI
54
55config SCSI_DEBUG
56 tristate "SCSI debugging host simulator (EXPERIMENTAL)"
57 depends on SCSI
58
diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64
new file mode 100644
index 000000000000..768dc6626a8d
--- /dev/null
+++ b/arch/um/Kconfig_x86_64
@@ -0,0 +1,15 @@
1config 64_BIT
2 bool
3 default y
4
5config 3_LEVEL_PGTABLES
6 bool
7 default y
8
9config ARCH_HAS_SC_SIGNALS
10 bool
11 default n
12
13config ARCH_REUSE_HOST_VSYSCALL_AREA
14 bool
15 default n
diff --git a/arch/um/Makefile b/arch/um/Makefile
new file mode 100644
index 000000000000..97bca6b5ca95
--- /dev/null
+++ b/arch/um/Makefile
@@ -0,0 +1,210 @@
1#
2# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6ARCH_DIR := arch/um
7OS := $(shell uname -s)
8# We require bash because the vmlinux link and loader script cpp use bash
9# features.
10SHELL := /bin/bash
11
12filechk_gen_header = $<
13
14core-y += $(ARCH_DIR)/kernel/ \
15 $(ARCH_DIR)/drivers/ \
16 $(ARCH_DIR)/os-$(OS)/
17
18# Have to precede the include because the included Makefiles reference them.
19SYMLINK_HEADERS := archparam.h system.h sigcontext.h processor.h ptrace.h \
20 arch-signal.h module.h vm-flags.h
21SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header))
22
23# XXX: The "os" symlink is only used by arch/um/include/os.h, which includes
24# ../os/include/file.h
25#
26# These are cleaned up during mrproper. Please DO NOT fix it again, this is
27# the Correct Thing(tm) to do!
28ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
29 $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
30
31GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h
32
33um-modes-$(CONFIG_MODE_TT) += tt
34um-modes-$(CONFIG_MODE_SKAS) += skas
35
36MODE_INCLUDE += $(foreach mode,$(um-modes-y),\
37 -I$(srctree)/$(ARCH_DIR)/kernel/$(mode)/include)
38
39MAKEFILES-INCL += $(foreach mode,$(um-modes-y),\
40 $(srctree)/$(ARCH_DIR)/Makefile-$(mode))
41
42ifneq ($(MAKEFILES-INCL),)
43 include $(MAKEFILES-INCL)
44endif
45
46ARCH_INCLUDE := -I$(ARCH_DIR)/include
47SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH)
48
49include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
50
51core-y += $(SUBARCH_CORE)
52libs-y += $(SUBARCH_LIBS)
53
54# -Derrno=kernel_errno - This turns all kernel references to errno into
55# kernel_errno to separate them from the libc errno. This allows -fno-common
56# in CFLAGS. Otherwise, it would cause ld to complain about the two different
57# errnos.
58
59CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
60 $(ARCH_INCLUDE) $(MODE_INCLUDE)
61
62USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
63USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
64 $(MODE_INCLUDE) $(ARCH_USER_CFLAGS)
65CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask
66CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
67
68#This will adjust *FLAGS accordingly to the platform.
69include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS)
70
71# These are needed for clean and mrproper, since in that case .config is not
72# included; the values here are meaningless
73
74CONFIG_NEST_LEVEL ?= 0
75CONFIG_KERNEL_HALF_GIGS ?= 0
76
77SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
78
79ifeq ($(CONFIG_MODE_SKAS), y)
80$(SYS_HEADERS) : $(ARCH_DIR)/include/skas_ptregs.h
81endif
82
83.PHONY: linux
84
85all: linux
86
87linux: vmlinux
88 ln -f $< $@
89
90define archhelp
91 echo '* linux - Binary kernel image (./linux) - for backward'
92 echo ' compatibility only, this creates a hard link to the'
93 echo ' real kernel binary, the the "vmlinux" binary you'
94 echo ' find in the kernel root.'
95endef
96
97$(shell cd $(ARCH_DIR) && ln -sf Kconfig_$(SUBARCH) Kconfig_arch)
98
99prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) \
100 $(ARCH_DIR)/kernel/vmlinux.lds.S
101
102LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static
103LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib
104
105LD_SCRIPT-$(CONFIG_LD_SCRIPT_STATIC) := uml.lds.S
106LD_SCRIPT-$(CONFIG_LD_SCRIPT_DYN) := dyn.lds.S
107
108CPP_MODE-$(CONFIG_MODE_TT) := -DMODE_TT
109CONFIG_KERNEL_STACK_ORDER ?= 2
110STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
111
112ifndef START
113 START = $$(($(TOP_ADDR) - $(SIZE)))
114endif
115
116CPPFLAGS_vmlinux.lds = $(shell echo -U$(SUBARCH) \
117 -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
118 -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE-y) \
119 -DKERNEL_STACK_SIZE=$(STACK_SIZE))
120
121#The wrappers will select whether using "malloc" or the kernel allocator.
122LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
123
124CFLAGS_vmlinux = $(LINK-y) $(LINK_WRAPS)
125define cmd_vmlinux__
126 $(CC) $(CFLAGS_vmlinux) -o $@ \
127 -Wl,-T,$(vmlinux-lds) $(vmlinux-init) \
128 -Wl,--start-group $(vmlinux-main) -Wl,--end-group \
129 -L/usr/lib -lutil \
130 $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) \
131 FORCE ,$^) ; rm -f linux
132endef
133
134#When cleaning we don't include .config, so we don't include
135#TT or skas makefiles and don't clean skas_ptregs.h.
136CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \
137 $(GEN_HEADERS) $(ARCH_DIR)/include/skas_ptregs.h
138
139MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \
140 $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os \
141 $(ARCH_DIR)/Kconfig_arch
142
143archclean:
144 $(Q)$(MAKE) $(clean)=$(ARCH_DIR)/util
145 @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
146 -o -name '*.gcov' \) -type f -print | xargs rm -f
147
148#We need to re-preprocess this when the symlink dest changes.
149#So we touch it when needed.
150$(ARCH_DIR)/kernel/vmlinux.lds.S: FORCE
151 $(Q)if [ "$(shell readlink $@)" != "$(LD_SCRIPT-y)" ]; then \
152 echo ' SYMLINK $@'; \
153 ln -sf $(LD_SCRIPT-y) $@; \
154 touch $@; \
155 fi;
156
157$(SYMLINK_HEADERS):
158 @echo ' SYMLINK $@'
159 $(Q)cd $(TOPDIR)/$(dir $@) ; \
160 ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@)
161
162include/asm-um/arch:
163 @echo ' SYMLINK $@'
164 $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch
165
166$(ARCH_DIR)/include/sysdep:
167 @echo ' SYMLINK $@'
168 $(Q)cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep
169
170$(ARCH_DIR)/os:
171 @echo ' SYMLINK $@'
172 $(Q)cd $(ARCH_DIR) && ln -sf os-$(OS) os
173
174# Generated files
175define filechk_umlconfig
176 sed 's/ CONFIG/ UML_CONFIG/'
177endef
178
179$(ARCH_DIR)/include/uml-config.h : include/linux/autoconf.h
180 $(call filechk,umlconfig)
181
182$(ARCH_DIR)/include/task.h: $(ARCH_DIR)/util/mk_task
183 $(call filechk,gen_header)
184
185$(ARCH_DIR)/include/user_constants.h: $(ARCH_DIR)/os/util/mk_user_constants
186 $(call filechk,gen_header)
187
188$(ARCH_DIR)/include/kern_constants.h: $(ARCH_DIR)/util/mk_constants
189 $(call filechk,gen_header)
190
191$(ARCH_DIR)/include/skas_ptregs.h: $(ARCH_DIR)/kernel/skas/util/mk_ptregs
192 $(call filechk,gen_header)
193
194$(ARCH_DIR)/os/util/mk_user_constants: $(ARCH_DIR)/os/util FORCE ;
195
196$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants: $(ARCH_DIR)/include/user_constants.h $(ARCH_DIR)/util \
197 FORCE ;
198
199$(ARCH_DIR)/kernel/skas/util/mk_ptregs: $(ARCH_DIR)/kernel/skas/util FORCE ;
200
201$(ARCH_DIR)/util: scripts_basic $(SYS_DIR)/sc.h FORCE
202 $(Q)$(MAKE) $(build)=$@
203
204$(ARCH_DIR)/kernel/skas/util: scripts_basic FORCE
205 $(Q)$(MAKE) $(build)=$@
206
207$(ARCH_DIR)/os/util: scripts_basic FORCE
208 $(Q)$(MAKE) $(build)=$@
209
210export SUBARCH USER_CFLAGS OS
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
new file mode 100644
index 000000000000..97b223bfa78e
--- /dev/null
+++ b/arch/um/Makefile-i386
@@ -0,0 +1,44 @@
1SUBARCH_CORE := arch/um/sys-i386/
2
3TOP_ADDR := $(CONFIG_TOP_ADDR)
4
5ifeq ($(CONFIG_MODE_SKAS),y)
6 ifneq ($(CONFIG_MODE_TT),y)
7 START := 0x8048000
8 endif
9endif
10
11CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
12ARCH_USER_CFLAGS :=
13
14ifneq ($(CONFIG_GPROF),y)
15ARCH_CFLAGS += -DUM_FASTCALL
16endif
17
18ELF_ARCH := $(SUBARCH)
19ELF_FORMAT := elf32-$(SUBARCH)
20
21OBJCOPYFLAGS := -O binary -R .note -R .comment -S
22
23SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/util
24
25SYS_HEADERS := $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h
26
27prepare: $(SYS_HEADERS)
28
29$(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
30 $(call filechk,gen_header)
31
32$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
33 $(call filechk,gen_header)
34
35$(SYS_UTIL_DIR)/mk_sc: scripts_basic FORCE
36 $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
37
38$(SYS_UTIL_DIR)/mk_thread: scripts_basic $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE
39 $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
40
41$(SYS_UTIL_DIR): scripts_basic include/asm FORCE
42 $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR)
43
44CLEAN_FILES += $(SYS_HEADERS)
diff --git a/arch/um/Makefile-ia64 b/arch/um/Makefile-ia64
new file mode 100644
index 000000000000..f84dc23b0f6e
--- /dev/null
+++ b/arch/um/Makefile-ia64
@@ -0,0 +1 @@
START_ADDR = 0x1000000000000000
diff --git a/arch/um/Makefile-os-Linux b/arch/um/Makefile-os-Linux
new file mode 100644
index 000000000000..0c0f9a1cbbad
--- /dev/null
+++ b/arch/um/Makefile-os-Linux
@@ -0,0 +1,8 @@
1#
2# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6# To get a definition of F_SETSIG
7USER_CFLAGS += -D_GNU_SOURCE -D_LARGEFILE64_SOURCE
8CFLAGS += -D_LARGEFILE64_SOURCE
diff --git a/arch/um/Makefile-ppc b/arch/um/Makefile-ppc
new file mode 100644
index 000000000000..66fd2003e165
--- /dev/null
+++ b/arch/um/Makefile-ppc
@@ -0,0 +1,9 @@
1ifeq ($(CONFIG_HOST_2G_2G), y)
2START_ADDR = 0x80000000
3else
4START_ADDR = 0xc0000000
5endif
6ARCH_CFLAGS = -U__powerpc__ -D__UM_PPC__
7
8# The arch is ppc, but the elf32 name is powerpc
9ELF_SUBARCH = powerpc
diff --git a/arch/um/Makefile-skas b/arch/um/Makefile-skas
new file mode 100644
index 000000000000..fd18ec572271
--- /dev/null
+++ b/arch/um/Makefile-skas
@@ -0,0 +1,14 @@
1#
2# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6GPROF_OPT += -pg
7GCOV_OPT += -fprofile-arcs -ftest-coverage
8
9CFLAGS-$(CONFIG_GCOV) += $(GCOV_OPT)
10CFLAGS-$(CONFIG_GPROF) += $(GPROF_OPT)
11LINK-$(CONFIG_GCOV) += $(GCOV_OPT)
12LINK-$(CONFIG_GPROF) += $(GPROF_OPT)
13
14GEN_HEADERS += $(ARCH_DIR)/include/skas_ptregs.h
diff --git a/arch/um/Makefile-tt b/arch/um/Makefile-tt
new file mode 100644
index 000000000000..03f7b10cfd0b
--- /dev/null
+++ b/arch/um/Makefile-tt
@@ -0,0 +1,5 @@
1#
2# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
new file mode 100644
index 000000000000..a77971133e91
--- /dev/null
+++ b/arch/um/Makefile-x86_64
@@ -0,0 +1,32 @@
1# Copyright 2003 - 2004 Pathscale, Inc
2# Released under the GPL
3
4SUBARCH_LIBS := arch/um/sys-x86_64/
5START := 0x60000000
6
7CFLAGS += -U__$(SUBARCH)__ -fno-builtin
8ARCH_USER_CFLAGS := -D__x86_64__
9
10ELF_ARCH := i386:x86-64
11ELF_FORMAT := elf64-x86-64
12
13SYS_UTIL_DIR := $(ARCH_DIR)/sys-x86_64/util
14SYS_DIR := $(ARCH_DIR)/include/sysdep-x86_64
15
16SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h
17
18prepare: $(SYS_HEADERS)
19
20$(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
21 $(call filechk,gen_header)
22
23$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
24 $(call filechk,gen_header)
25
26$(SYS_UTIL_DIR)/mk_sc: scripts_basic FORCE
27 $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
28
29$(SYS_UTIL_DIR)/mk_thread: scripts_basic $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE
30 $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
31
32CLEAN_FILES += $(SYS_HEADERS)
diff --git a/arch/um/config.release b/arch/um/config.release
new file mode 100644
index 000000000000..fc68bcb9294e
--- /dev/null
+++ b/arch/um/config.release
@@ -0,0 +1,333 @@
1#
2# Automatically generated make config: don't edit
3#
4CONFIG_USERMODE=y
5# CONFIG_ISA is not set
6# CONFIG_SBUS is not set
7# CONFIG_PCI is not set
8CONFIG_UID16=y
9CONFIG_RWSEM_XCHGADD_ALGORITHM=y
10
11#
12# Code maturity level options
13#
14CONFIG_EXPERIMENTAL=y
15
16#
17# General Setup
18#
19CONFIG_STDIO_CONSOLE=y
20CONFIG_NET=y
21CONFIG_SYSVIPC=y
22CONFIG_BSD_PROCESS_ACCT=y
23CONFIG_SYSCTL=y
24CONFIG_BINFMT_AOUT=y
25CONFIG_BINFMT_ELF=y
26CONFIG_BINFMT_MISC=y
27CONFIG_UNIX98_PTYS=y
28CONFIG_UNIX98_PTY_COUNT=256
29CONFIG_SSL=y
30CONFIG_HOSTFS=y
31CONFIG_MCONSOLE=y
32CONFIG_MAGIC_SYSRQ=y
33# CONFIG_HOST_2G_2G is not set
34# CONFIG_UML_SMP is not set
35# CONFIG_SMP is not set
36CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
37CONFIG_CON_CHAN="xterm"
38CONFIG_SSL_CHAN="pty"
39CONFIG_NEST_LEVEL=0
40CONFIG_KERNEL_HALF_GIGS=1
41
42#
43# Loadable module support
44#
45CONFIG_MODULES=y
46CONFIG_KMOD=y
47
48#
49# Devices
50#
51CONFIG_BLK_DEV_UBD=y
52# CONFIG_BLK_DEV_UBD_SYNC is not set
53CONFIG_BLK_DEV_LOOP=y
54CONFIG_BLK_DEV_NBD=y
55CONFIG_BLK_DEV_RAM=y
56CONFIG_BLK_DEV_RAM_SIZE=4096
57CONFIG_BLK_DEV_INITRD=y
58# CONFIG_MMAPPER is not set
59CONFIG_UML_SOUND=y
60CONFIG_SOUND=y
61CONFIG_HOSTAUDIO=y
62# CONFIG_UML_WATCHDOG is not set
63# CONFIG_TTY_LOG is not set
64CONFIG_FD_CHAN=y
65# CONFIG_NULL_CHAN is not set
66CONFIG_PORT_CHAN=y
67CONFIG_PTY_CHAN=y
68CONFIG_TTY_CHAN=y
69CONFIG_XTERM_CHAN=y
70
71#
72# Networking options
73#
74CONFIG_PACKET=y
75CONFIG_PACKET_MMAP=y
76# CONFIG_NETLINK_DEV is not set
77# CONFIG_NETFILTER is not set
78# CONFIG_FILTER is not set
79CONFIG_UNIX=y
80CONFIG_INET=y
81# CONFIG_IP_MULTICAST is not set
82# CONFIG_IP_ADVANCED_ROUTER is not set
83# CONFIG_IP_PNP is not set
84# CONFIG_NET_IPIP is not set
85# CONFIG_NET_IPGRE is not set
86# CONFIG_ARPD is not set
87# CONFIG_INET_ECN is not set
88# CONFIG_SYN_COOKIES is not set
89# CONFIG_IPV6 is not set
90# CONFIG_KHTTPD is not set
91# CONFIG_ATM is not set
92# CONFIG_VLAN_8021Q is not set
93
94#
95#
96#
97# CONFIG_IPX is not set
98# CONFIG_ATALK is not set
99# CONFIG_DECNET is not set
100# CONFIG_BRIDGE is not set
101# CONFIG_X25 is not set
102# CONFIG_LAPB is not set
103# CONFIG_LLC is not set
104# CONFIG_NET_DIVERT is not set
105# CONFIG_ECONET is not set
106# CONFIG_WAN_ROUTER is not set
107# CONFIG_NET_HW_FLOWCONTROL is not set
108
109#
110# QoS and/or fair queueing
111#
112# CONFIG_NET_SCHED is not set
113
114#
115# Network device support
116#
117CONFIG_UML_NET=y
118CONFIG_UML_NET_ETHERTAP=y
119CONFIG_UML_NET_TUNTAP=y
120CONFIG_UML_NET_SLIP=y
121CONFIG_UML_NET_DAEMON=y
122CONFIG_UML_NET_MCAST=y
123CONFIG_NETDEVICES=y
124
125#
126# ARCnet devices
127#
128# CONFIG_ARCNET is not set
129CONFIG_DUMMY=y
130CONFIG_BONDING=m
131CONFIG_EQUALIZER=m
132CONFIG_TUN=y
133# CONFIG_ETHERTAP is not set
134
135#
136# Ethernet (10 or 100Mbit)
137#
138# CONFIG_NET_ETHERNET is not set
139
140#
141# Ethernet (1000 Mbit)
142#
143# CONFIG_ACENIC is not set
144# CONFIG_DL2K is not set
145# CONFIG_MYRI_SBUS is not set
146# CONFIG_NS83820 is not set
147# CONFIG_HAMACHI is not set
148# CONFIG_YELLOWFIN is not set
149# CONFIG_SK98LIN is not set
150# CONFIG_FDDI is not set
151# CONFIG_HIPPI is not set
152CONFIG_PLIP=m
153CONFIG_PPP=m
154CONFIG_PPP_MULTILINK=y
155# CONFIG_PPP_FILTER is not set
156# CONFIG_PPP_ASYNC is not set
157CONFIG_PPP_SYNC_TTY=m
158CONFIG_PPP_DEFLATE=m
159CONFIG_PPP_BSDCOMP=m
160CONFIG_PPPOE=m
161CONFIG_SLIP=m
162CONFIG_SLIP_COMPRESSED=y
163CONFIG_SLIP_SMART=y
164# CONFIG_SLIP_MODE_SLIP6 is not set
165
166#
167# Wireless LAN (non-hamradio)
168#
169# CONFIG_NET_RADIO is not set
170
171#
172# Token Ring devices
173#
174# CONFIG_TR is not set
175# CONFIG_NET_FC is not set
176# CONFIG_RCPCI is not set
177CONFIG_SHAPER=m
178
179#
180# Wan interfaces
181#
182# CONFIG_WAN is not set
183
184#
185# File systems
186#
187CONFIG_QUOTA=y
188CONFIG_AUTOFS_FS=m
189CONFIG_AUTOFS4_FS=m
190CONFIG_REISERFS_FS=m
191# CONFIG_REISERFS_CHECK is not set
192# CONFIG_REISERFS_PROC_INFO is not set
193CONFIG_ADFS_FS=m
194# CONFIG_ADFS_FS_RW is not set
195CONFIG_AFFS_FS=m
196CONFIG_HFS_FS=m
197CONFIG_BFS_FS=m
198CONFIG_EXT3_FS=y
199CONFIG_JBD=y
200# CONFIG_JBD_DEBUG is not set
201CONFIG_FAT_FS=y
202CONFIG_MSDOS_FS=y
203CONFIG_UMSDOS_FS=y
204CONFIG_VFAT_FS=y
205CONFIG_EFS_FS=m
206# CONFIG_JFFS_FS is not set
207# CONFIG_JFFS2_FS is not set
208CONFIG_CRAMFS=m
209CONFIG_TMPFS=y
210CONFIG_RAMFS=m
211CONFIG_ISO9660_FS=y
212# CONFIG_JOLIET is not set
213# CONFIG_ZISOFS is not set
214CONFIG_MINIX_FS=m
215CONFIG_VXFS_FS=m
216# CONFIG_NTFS_FS is not set
217# CONFIG_NTFS_RW is not set
218CONFIG_HPFS_FS=m
219CONFIG_PROC_FS=y
220CONFIG_DEVFS_FS=y
221CONFIG_DEVFS_MOUNT=y
222# CONFIG_DEVFS_DEBUG is not set
223CONFIG_DEVPTS_FS=y
224CONFIG_QNX4FS_FS=m
225# CONFIG_QNX4FS_RW is not set
226CONFIG_ROMFS_FS=m
227CONFIG_EXT2_FS=y
228CONFIG_SYSV_FS=m
229CONFIG_UDF_FS=m
230CONFIG_UFS_FS=m
231# CONFIG_UFS_FS_WRITE is not set
232
233#
234# Network File Systems
235#
236# CONFIG_CODA_FS is not set
237# CONFIG_INTERMEZZO_FS is not set
238CONFIG_NFS_FS=y
239CONFIG_NFS_V3=y
240# CONFIG_ROOT_NFS is not set
241CONFIG_NFSD=y
242CONFIG_NFSD_V3=y
243CONFIG_SUNRPC=y
244CONFIG_LOCKD=y
245CONFIG_LOCKD_V4=y
246# CONFIG_SMB_FS is not set
247# CONFIG_NCP_FS is not set
248# CONFIG_NCPFS_PACKET_SIGNING is not set
249# CONFIG_NCPFS_IOCTL_LOCKING is not set
250# CONFIG_NCPFS_STRONG is not set
251# CONFIG_NCPFS_NFS_NS is not set
252# CONFIG_NCPFS_OS2_NS is not set
253# CONFIG_NCPFS_SMALLDOS is not set
254# CONFIG_NCPFS_NLS is not set
255# CONFIG_NCPFS_EXTRAS is not set
256# CONFIG_ZISOFS_FS is not set
257CONFIG_ZLIB_FS_INFLATE=m
258
259#
260# Partition Types
261#
262# CONFIG_PARTITION_ADVANCED is not set
263CONFIG_MSDOS_PARTITION=y
264# CONFIG_SMB_NLS is not set
265CONFIG_NLS=y
266
267#
268# Native Language Support
269#
270CONFIG_NLS_DEFAULT="iso8859-1"
271# CONFIG_NLS_CODEPAGE_437 is not set
272# CONFIG_NLS_CODEPAGE_737 is not set
273# CONFIG_NLS_CODEPAGE_775 is not set
274# CONFIG_NLS_CODEPAGE_850 is not set
275# CONFIG_NLS_CODEPAGE_852 is not set
276# CONFIG_NLS_CODEPAGE_855 is not set
277# CONFIG_NLS_CODEPAGE_857 is not set
278# CONFIG_NLS_CODEPAGE_860 is not set
279# CONFIG_NLS_CODEPAGE_861 is not set
280# CONFIG_NLS_CODEPAGE_862 is not set
281# CONFIG_NLS_CODEPAGE_863 is not set
282# CONFIG_NLS_CODEPAGE_864 is not set
283# CONFIG_NLS_CODEPAGE_865 is not set
284# CONFIG_NLS_CODEPAGE_866 is not set
285# CONFIG_NLS_CODEPAGE_869 is not set
286# CONFIG_NLS_CODEPAGE_936 is not set
287# CONFIG_NLS_CODEPAGE_950 is not set
288# CONFIG_NLS_CODEPAGE_932 is not set
289# CONFIG_NLS_CODEPAGE_949 is not set
290# CONFIG_NLS_CODEPAGE_874 is not set
291# CONFIG_NLS_ISO8859_8 is not set
292# CONFIG_NLS_CODEPAGE_1250 is not set
293# CONFIG_NLS_CODEPAGE_1251 is not set
294# CONFIG_NLS_ISO8859_1 is not set
295# CONFIG_NLS_ISO8859_2 is not set
296# CONFIG_NLS_ISO8859_3 is not set
297# CONFIG_NLS_ISO8859_4 is not set
298# CONFIG_NLS_ISO8859_5 is not set
299# CONFIG_NLS_ISO8859_6 is not set
300# CONFIG_NLS_ISO8859_7 is not set
301# CONFIG_NLS_ISO8859_9 is not set
302# CONFIG_NLS_ISO8859_13 is not set
303# CONFIG_NLS_ISO8859_14 is not set
304# CONFIG_NLS_ISO8859_15 is not set
305# CONFIG_NLS_KOI8_R is not set
306# CONFIG_NLS_KOI8_U is not set
307# CONFIG_NLS_UTF8 is not set
308
309#
310# Multi-device support (RAID and LVM)
311#
312# CONFIG_MD is not set
313# CONFIG_BLK_DEV_MD is not set
314# CONFIG_MD_LINEAR is not set
315# CONFIG_MD_RAID0 is not set
316# CONFIG_MD_RAID1 is not set
317# CONFIG_MD_RAID5 is not set
318# CONFIG_MD_MULTIPATH is not set
319# CONFIG_BLK_DEV_LVM is not set
320
321#
322# Memory Technology Devices (MTD)
323#
324# CONFIG_MTD is not set
325
326#
327# Kernel hacking
328#
329# CONFIG_DEBUG_SLAB is not set
330# CONFIG_DEBUG_INFO is not set
331# CONFIG_PT_PROXY is not set
332# CONFIG_GPROF is not set
333# CONFIG_GCOV is not set
diff --git a/arch/um/defconfig b/arch/um/defconfig
new file mode 100644
index 000000000000..fc3075c589d8
--- /dev/null
+++ b/arch/um/defconfig
@@ -0,0 +1,417 @@
1#
2# Automatically generated make config: don't edit
3# Linux kernel version: 2.6.12-rc1-bk1
4# Sun Mar 20 16:53:00 2005
5#
6CONFIG_GENERIC_HARDIRQS=y
7CONFIG_UML=y
8CONFIG_MMU=y
9CONFIG_UID16=y
10CONFIG_RWSEM_GENERIC_SPINLOCK=y
11CONFIG_GENERIC_CALIBRATE_DELAY=y
12
13#
14# UML-specific options
15#
16CONFIG_MODE_TT=y
17CONFIG_MODE_SKAS=y
18# CONFIG_64_BIT is not set
19CONFIG_TOP_ADDR=0xc0000000
20# CONFIG_3_LEVEL_PGTABLES is not set
21CONFIG_ARCH_HAS_SC_SIGNALS=y
22CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
23CONFIG_LD_SCRIPT_STATIC=y
24CONFIG_NET=y
25CONFIG_BINFMT_ELF=y
26CONFIG_BINFMT_MISC=m
27CONFIG_HOSTFS=y
28CONFIG_MCONSOLE=y
29# CONFIG_MAGIC_SYSRQ is not set
30# CONFIG_HOST_2G_2G is not set
31# CONFIG_SMP is not set
32CONFIG_NEST_LEVEL=0
33CONFIG_KERNEL_HALF_GIGS=1
34# CONFIG_HIGHMEM is not set
35CONFIG_KERNEL_STACK_ORDER=2
36CONFIG_UML_REAL_TIME_CLOCK=y
37
38#
39# Code maturity level options
40#
41CONFIG_EXPERIMENTAL=y
42CONFIG_CLEAN_COMPILE=y
43CONFIG_BROKEN_ON_SMP=y
44
45#
46# General setup
47#
48CONFIG_LOCALVERSION=""
49CONFIG_SWAP=y
50CONFIG_SYSVIPC=y
51CONFIG_POSIX_MQUEUE=y
52CONFIG_BSD_PROCESS_ACCT=y
53# CONFIG_BSD_PROCESS_ACCT_V3 is not set
54CONFIG_SYSCTL=y
55# CONFIG_AUDIT is not set
56# CONFIG_HOTPLUG is not set
57CONFIG_KOBJECT_UEVENT=y
58CONFIG_IKCONFIG=y
59CONFIG_IKCONFIG_PROC=y
60# CONFIG_EMBEDDED is not set
61CONFIG_KALLSYMS=y
62# CONFIG_KALLSYMS_ALL is not set
63CONFIG_KALLSYMS_EXTRA_PASS=y
64CONFIG_BASE_FULL=y
65CONFIG_FUTEX=y
66CONFIG_EPOLL=y
67CONFIG_SHMEM=y
68CONFIG_CC_ALIGN_FUNCTIONS=0
69CONFIG_CC_ALIGN_LABELS=0
70CONFIG_CC_ALIGN_LOOPS=0
71CONFIG_CC_ALIGN_JUMPS=0
72# CONFIG_TINY_SHMEM is not set
73CONFIG_BASE_SMALL=0
74
75#
76# Loadable module support
77#
78CONFIG_MODULES=y
79CONFIG_MODULE_UNLOAD=y
80# CONFIG_MODULE_FORCE_UNLOAD is not set
81CONFIG_OBSOLETE_MODPARM=y
82# CONFIG_MODULE_SRCVERSION_ALL is not set
83CONFIG_KMOD=y
84
85#
86# Generic Driver Options
87#
88CONFIG_STANDALONE=y
89CONFIG_PREVENT_FIRMWARE_BUILD=y
90# CONFIG_FW_LOADER is not set
91# CONFIG_DEBUG_DRIVER is not set
92
93#
94# Character Devices
95#
96CONFIG_STDERR_CONSOLE=y
97CONFIG_STDIO_CONSOLE=y
98CONFIG_SSL=y
99CONFIG_NULL_CHAN=y
100CONFIG_PORT_CHAN=y
101CONFIG_PTY_CHAN=y
102CONFIG_TTY_CHAN=y
103CONFIG_XTERM_CHAN=y
104# CONFIG_NOCONFIG_CHAN is not set
105CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
106CONFIG_CON_CHAN="xterm"
107CONFIG_SSL_CHAN="pty"
108CONFIG_UNIX98_PTYS=y
109CONFIG_LEGACY_PTYS=y
110CONFIG_LEGACY_PTY_COUNT=256
111# CONFIG_WATCHDOG is not set
112CONFIG_UML_SOUND=m
113CONFIG_SOUND=m
114CONFIG_HOSTAUDIO=m
115CONFIG_UML_RANDOM=y
116
117#
118# Block devices
119#
120CONFIG_BLK_DEV_UBD=y
121CONFIG_BLK_DEV_UBD_SYNC=y
122CONFIG_BLK_DEV_COW_COMMON=y
123CONFIG_BLK_DEV_LOOP=m
124# CONFIG_BLK_DEV_CRYPTOLOOP is not set
125CONFIG_BLK_DEV_NBD=m
126# CONFIG_BLK_DEV_RAM is not set
127CONFIG_BLK_DEV_RAM_COUNT=16
128CONFIG_INITRAMFS_SOURCE=""
129# CONFIG_LBD is not set
130
131#
132# IO Schedulers
133#
134CONFIG_IOSCHED_NOOP=y
135CONFIG_IOSCHED_AS=y
136CONFIG_IOSCHED_DEADLINE=y
137CONFIG_IOSCHED_CFQ=y
138# CONFIG_ATA_OVER_ETH is not set
139CONFIG_NETDEVICES=y
140
141#
142# UML Network Devices
143#
144CONFIG_UML_NET=y
145CONFIG_UML_NET_ETHERTAP=y
146CONFIG_UML_NET_TUNTAP=y
147CONFIG_UML_NET_SLIP=y
148CONFIG_UML_NET_DAEMON=y
149CONFIG_UML_NET_MCAST=y
150CONFIG_UML_NET_SLIRP=y
151
152#
153# Networking support
154#
155
156#
157# Networking options
158#
159CONFIG_PACKET=y
160CONFIG_PACKET_MMAP=y
161# CONFIG_NETLINK_DEV is not set
162CONFIG_UNIX=y
163# CONFIG_NET_KEY is not set
164CONFIG_INET=y
165# CONFIG_IP_MULTICAST is not set
166# CONFIG_IP_ADVANCED_ROUTER is not set
167# CONFIG_IP_PNP is not set
168# CONFIG_NET_IPIP is not set
169# CONFIG_NET_IPGRE is not set
170# CONFIG_ARPD is not set
171# CONFIG_SYN_COOKIES is not set
172# CONFIG_INET_AH is not set
173# CONFIG_INET_ESP is not set
174# CONFIG_INET_IPCOMP is not set
175# CONFIG_INET_TUNNEL is not set
176CONFIG_IP_TCPDIAG=y
177# CONFIG_IP_TCPDIAG_IPV6 is not set
178# CONFIG_IPV6 is not set
179# CONFIG_NETFILTER is not set
180
181#
182# SCTP Configuration (EXPERIMENTAL)
183#
184# CONFIG_IP_SCTP is not set
185# CONFIG_ATM is not set
186# CONFIG_BRIDGE is not set
187# CONFIG_VLAN_8021Q is not set
188# CONFIG_DECNET is not set
189# CONFIG_LLC2 is not set
190# CONFIG_IPX is not set
191# CONFIG_ATALK is not set
192# CONFIG_X25 is not set
193# CONFIG_LAPB is not set
194# CONFIG_NET_DIVERT is not set
195# CONFIG_ECONET is not set
196# CONFIG_WAN_ROUTER is not set
197
198#
199# QoS and/or fair queueing
200#
201# CONFIG_NET_SCHED is not set
202# CONFIG_NET_CLS_ROUTE is not set
203
204#
205# Network testing
206#
207# CONFIG_NET_PKTGEN is not set
208# CONFIG_NETPOLL is not set
209# CONFIG_NET_POLL_CONTROLLER is not set
210# CONFIG_HAMRADIO is not set
211# CONFIG_IRDA is not set
212# CONFIG_BT is not set
213CONFIG_DUMMY=m
214# CONFIG_BONDING is not set
215# CONFIG_EQUALIZER is not set
216CONFIG_TUN=m
217
218#
219# Wan interfaces
220#
221# CONFIG_WAN is not set
222CONFIG_PPP=m
223# CONFIG_PPP_MULTILINK is not set
224# CONFIG_PPP_FILTER is not set
225# CONFIG_PPP_ASYNC is not set
226# CONFIG_PPP_SYNC_TTY is not set
227# CONFIG_PPP_DEFLATE is not set
228# CONFIG_PPP_BSDCOMP is not set
229# CONFIG_PPPOE is not set
230CONFIG_SLIP=m
231# CONFIG_SLIP_COMPRESSED is not set
232# CONFIG_SLIP_SMART is not set
233# CONFIG_SLIP_MODE_SLIP6 is not set
234# CONFIG_SHAPER is not set
235# CONFIG_NETCONSOLE is not set
236
237#
238# File systems
239#
240CONFIG_EXT2_FS=y
241# CONFIG_EXT2_FS_XATTR is not set
242CONFIG_EXT3_FS=y
243# CONFIG_EXT3_FS_XATTR is not set
244CONFIG_JBD=y
245# CONFIG_JBD_DEBUG is not set
246CONFIG_REISERFS_FS=y
247# CONFIG_REISERFS_CHECK is not set
248# CONFIG_REISERFS_PROC_INFO is not set
249# CONFIG_REISERFS_FS_XATTR is not set
250# CONFIG_JFS_FS is not set
251
252#
253# XFS support
254#
255# CONFIG_XFS_FS is not set
256# CONFIG_MINIX_FS is not set
257# CONFIG_ROMFS_FS is not set
258CONFIG_QUOTA=y
259# CONFIG_QFMT_V1 is not set
260# CONFIG_QFMT_V2 is not set
261CONFIG_QUOTACTL=y
262CONFIG_DNOTIFY=y
263CONFIG_AUTOFS_FS=m
264CONFIG_AUTOFS4_FS=m
265
266#
267# CD-ROM/DVD Filesystems
268#
269CONFIG_ISO9660_FS=m
270CONFIG_JOLIET=y
271# CONFIG_ZISOFS is not set
272# CONFIG_UDF_FS is not set
273
274#
275# DOS/FAT/NT Filesystems
276#
277# CONFIG_MSDOS_FS is not set
278# CONFIG_VFAT_FS is not set
279# CONFIG_NTFS_FS is not set
280
281#
282# Pseudo filesystems
283#
284CONFIG_PROC_FS=y
285CONFIG_PROC_KCORE=y
286CONFIG_SYSFS=y
287# CONFIG_DEVFS_FS is not set
288# CONFIG_DEVPTS_FS_XATTR is not set
289CONFIG_TMPFS=y
290# CONFIG_TMPFS_XATTR is not set
291# CONFIG_HUGETLB_PAGE is not set
292CONFIG_RAMFS=y
293
294#
295# Miscellaneous filesystems
296#
297# CONFIG_ADFS_FS is not set
298# CONFIG_AFFS_FS is not set
299# CONFIG_HFS_FS is not set
300# CONFIG_HFSPLUS_FS is not set
301# CONFIG_BEFS_FS is not set
302# CONFIG_BFS_FS is not set
303# CONFIG_EFS_FS is not set
304# CONFIG_CRAMFS is not set
305# CONFIG_VXFS_FS is not set
306# CONFIG_HPFS_FS is not set
307# CONFIG_QNX4FS_FS is not set
308# CONFIG_SYSV_FS is not set
309# CONFIG_UFS_FS is not set
310
311#
312# Network File Systems
313#
314# CONFIG_NFS_FS is not set
315# CONFIG_NFSD is not set
316# CONFIG_SMB_FS is not set
317# CONFIG_CIFS is not set
318# CONFIG_NCP_FS is not set
319# CONFIG_CODA_FS is not set
320# CONFIG_AFS_FS is not set
321
322#
323# Partition Types
324#
325# CONFIG_PARTITION_ADVANCED is not set
326CONFIG_MSDOS_PARTITION=y
327
328#
329# Native Language Support
330#
331CONFIG_NLS=y
332CONFIG_NLS_DEFAULT="iso8859-1"
333# CONFIG_NLS_CODEPAGE_437 is not set
334# CONFIG_NLS_CODEPAGE_737 is not set
335# CONFIG_NLS_CODEPAGE_775 is not set
336# CONFIG_NLS_CODEPAGE_850 is not set
337# CONFIG_NLS_CODEPAGE_852 is not set
338# CONFIG_NLS_CODEPAGE_855 is not set
339# CONFIG_NLS_CODEPAGE_857 is not set
340# CONFIG_NLS_CODEPAGE_860 is not set
341# CONFIG_NLS_CODEPAGE_861 is not set
342# CONFIG_NLS_CODEPAGE_862 is not set
343# CONFIG_NLS_CODEPAGE_863 is not set
344# CONFIG_NLS_CODEPAGE_864 is not set
345# CONFIG_NLS_CODEPAGE_865 is not set
346# CONFIG_NLS_CODEPAGE_866 is not set
347# CONFIG_NLS_CODEPAGE_869 is not set
348# CONFIG_NLS_CODEPAGE_936 is not set
349# CONFIG_NLS_CODEPAGE_950 is not set
350# CONFIG_NLS_CODEPAGE_932 is not set
351# CONFIG_NLS_CODEPAGE_949 is not set
352# CONFIG_NLS_CODEPAGE_874 is not set
353# CONFIG_NLS_ISO8859_8 is not set
354# CONFIG_NLS_CODEPAGE_1250 is not set
355# CONFIG_NLS_CODEPAGE_1251 is not set
356# CONFIG_NLS_ASCII is not set
357# CONFIG_NLS_ISO8859_1 is not set
358# CONFIG_NLS_ISO8859_2 is not set
359# CONFIG_NLS_ISO8859_3 is not set
360# CONFIG_NLS_ISO8859_4 is not set
361# CONFIG_NLS_ISO8859_5 is not set
362# CONFIG_NLS_ISO8859_6 is not set
363# CONFIG_NLS_ISO8859_7 is not set
364# CONFIG_NLS_ISO8859_9 is not set
365# CONFIG_NLS_ISO8859_13 is not set
366# CONFIG_NLS_ISO8859_14 is not set
367# CONFIG_NLS_ISO8859_15 is not set
368# CONFIG_NLS_KOI8_R is not set
369# CONFIG_NLS_KOI8_U is not set
370# CONFIG_NLS_UTF8 is not set
371
372#
373# Security options
374#
375# CONFIG_KEYS is not set
376# CONFIG_SECURITY is not set
377
378#
379# Cryptographic options
380#
381# CONFIG_CRYPTO is not set
382
383#
384# Hardware crypto devices
385#
386
387#
388# Library routines
389#
390# CONFIG_CRC_CCITT is not set
391CONFIG_CRC32=m
392# CONFIG_LIBCRC32C is not set
393
394#
395# Multi-device support (RAID and LVM)
396#
397# CONFIG_MD is not set
398# CONFIG_INPUT is not set
399
400#
401# Kernel hacking
402#
403# CONFIG_PRINTK_TIME is not set
404CONFIG_DEBUG_KERNEL=y
405CONFIG_LOG_BUF_SHIFT=14
406# CONFIG_SCHEDSTATS is not set
407# CONFIG_DEBUG_SLAB is not set
408# CONFIG_DEBUG_SPINLOCK is not set
409# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
410# CONFIG_DEBUG_KOBJECT is not set
411CONFIG_DEBUG_INFO=y
412# CONFIG_DEBUG_FS is not set
413CONFIG_FRAME_POINTER=y
414CONFIG_PT_PROXY=y
415# CONFIG_GPROF is not set
416# CONFIG_GCOV is not set
417# CONFIG_SYSCALL_DEBUG is not set
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
new file mode 100644
index 000000000000..323f72c64cd2
--- /dev/null
+++ b/arch/um/drivers/Makefile
@@ -0,0 +1,46 @@
1#
2# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6# pcap is broken in 2.5 because kbuild doesn't allow pcap.a to be linked
7# in to pcap.o
8
9slip-objs := slip_kern.o slip_user.o
10slirp-objs := slirp_kern.o slirp_user.o
11daemon-objs := daemon_kern.o daemon_user.o
12mcast-objs := mcast_kern.o mcast_user.o
13#pcap-objs := pcap_kern.o pcap_user.o $(PCAP)
14net-objs := net_kern.o net_user.o
15mconsole-objs := mconsole_kern.o mconsole_user.o
16hostaudio-objs := hostaudio_kern.o
17ubd-objs := ubd_kern.o ubd_user.o
18port-objs := port_kern.o port_user.o
19harddog-objs := harddog_kern.o harddog_user.o
20
21obj-y := stdio_console.o fd.o chan_kern.o chan_user.o line.o
22obj-$(CONFIG_SSL) += ssl.o
23obj-$(CONFIG_STDERR_CONSOLE) += stderr_console.o
24
25obj-$(CONFIG_UML_NET_SLIP) += slip.o
26obj-$(CONFIG_UML_NET_SLIRP) += slirp.o
27obj-$(CONFIG_UML_NET_DAEMON) += daemon.o
28obj-$(CONFIG_UML_NET_MCAST) += mcast.o
29#obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP)
30obj-$(CONFIG_UML_NET) += net.o
31obj-$(CONFIG_MCONSOLE) += mconsole.o
32obj-$(CONFIG_MMAPPER) += mmapper_kern.o
33obj-$(CONFIG_BLK_DEV_UBD) += ubd.o
34obj-$(CONFIG_HOSTAUDIO) += hostaudio.o
35obj-$(CONFIG_NULL_CHAN) += null.o
36obj-$(CONFIG_PORT_CHAN) += port.o
37obj-$(CONFIG_PTY_CHAN) += pty.o
38obj-$(CONFIG_TTY_CHAN) += tty.o
39obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
40obj-$(CONFIG_UML_WATCHDOG) += harddog.o
41obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
42obj-$(CONFIG_UML_RANDOM) += random.o
43
44USER_OBJS := fd.o null.o pty.o tty.o xterm.o
45
46include arch/um/scripts/Makefile.rules
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
new file mode 100644
index 000000000000..1f77deb3fd23
--- /dev/null
+++ b/arch/um/drivers/chan_kern.c
@@ -0,0 +1,577 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <linux/stddef.h>
7#include <linux/kernel.h>
8#include <linux/list.h>
9#include <linux/slab.h>
10#include <linux/tty.h>
11#include <linux/string.h>
12#include <linux/tty_flip.h>
13#include <asm/irq.h>
14#include "chan_kern.h"
15#include "user_util.h"
16#include "kern.h"
17#include "irq_user.h"
18#include "sigio.h"
19#include "line.h"
20#include "os.h"
21
22#ifdef CONFIG_NOCONFIG_CHAN
23static void *not_configged_init(char *str, int device, struct chan_opts *opts)
24{
25 printk(KERN_ERR "Using a channel type which is configured out of "
26 "UML\n");
27 return(NULL);
28}
29
30static int not_configged_open(int input, int output, int primary, void *data,
31 char **dev_out)
32{
33 printk(KERN_ERR "Using a channel type which is configured out of "
34 "UML\n");
35 return(-ENODEV);
36}
37
38static void not_configged_close(int fd, void *data)
39{
40 printk(KERN_ERR "Using a channel type which is configured out of "
41 "UML\n");
42}
43
44static int not_configged_read(int fd, char *c_out, void *data)
45{
46 printk(KERN_ERR "Using a channel type which is configured out of "
47 "UML\n");
48 return(-EIO);
49}
50
51static int not_configged_write(int fd, const char *buf, int len, void *data)
52{
53 printk(KERN_ERR "Using a channel type which is configured out of "
54 "UML\n");
55 return(-EIO);
56}
57
58static int not_configged_console_write(int fd, const char *buf, int len,
59 void *data)
60{
61 printk(KERN_ERR "Using a channel type which is configured out of "
62 "UML\n");
63 return(-EIO);
64}
65
66static int not_configged_window_size(int fd, void *data, unsigned short *rows,
67 unsigned short *cols)
68{
69 printk(KERN_ERR "Using a channel type which is configured out of "
70 "UML\n");
71 return(-ENODEV);
72}
73
74static void not_configged_free(void *data)
75{
76 printk(KERN_ERR "Using a channel type which is configured out of "
77 "UML\n");
78}
79
80static struct chan_ops not_configged_ops = {
81 .init = not_configged_init,
82 .open = not_configged_open,
83 .close = not_configged_close,
84 .read = not_configged_read,
85 .write = not_configged_write,
86 .console_write = not_configged_console_write,
87 .window_size = not_configged_window_size,
88 .free = not_configged_free,
89 .winch = 0,
90};
91#endif /* CONFIG_NOCONFIG_CHAN */
92
93void generic_close(int fd, void *unused)
94{
95 os_close_file(fd);
96}
97
98int generic_read(int fd, char *c_out, void *unused)
99{
100 int n;
101
102 n = os_read_file(fd, c_out, sizeof(*c_out));
103
104 if(n == -EAGAIN)
105 return(0);
106 else if(n == 0)
107 return(-EIO);
108 return(n);
109}
110
111/* XXX Trivial wrapper around os_write_file */
112
113int generic_write(int fd, const char *buf, int n, void *unused)
114{
115 return(os_write_file(fd, buf, n));
116}
117
118int generic_window_size(int fd, void *unused, unsigned short *rows_out,
119 unsigned short *cols_out)
120{
121 int rows, cols;
122 int ret;
123
124 ret = os_window_size(fd, &rows, &cols);
125 if(ret < 0)
126 return(ret);
127
128 ret = ((*rows_out != rows) || (*cols_out != cols));
129
130 *rows_out = rows;
131 *cols_out = cols;
132
133 return(ret);
134}
135
136void generic_free(void *data)
137{
138 kfree(data);
139}
140
141static void tty_receive_char(struct tty_struct *tty, char ch)
142{
143 if(tty == NULL) return;
144
145 if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
146 if(ch == STOP_CHAR(tty)){
147 stop_tty(tty);
148 return;
149 }
150 else if(ch == START_CHAR(tty)){
151 start_tty(tty);
152 return;
153 }
154 }
155
156 if((tty->flip.flag_buf_ptr == NULL) ||
157 (tty->flip.char_buf_ptr == NULL))
158 return;
159 tty_insert_flip_char(tty, ch, TTY_NORMAL);
160}
161
162static int open_one_chan(struct chan *chan, int input, int output, int primary)
163{
164 int fd;
165
166 if(chan->opened) return(0);
167 if(chan->ops->open == NULL) fd = 0;
168 else fd = (*chan->ops->open)(input, output, primary, chan->data,
169 &chan->dev);
170 if(fd < 0) return(fd);
171 chan->fd = fd;
172
173 chan->opened = 1;
174 return(0);
175}
176
177int open_chan(struct list_head *chans)
178{
179 struct list_head *ele;
180 struct chan *chan;
181 int ret, err = 0;
182
183 list_for_each(ele, chans){
184 chan = list_entry(ele, struct chan, list);
185 ret = open_one_chan(chan, chan->input, chan->output,
186 chan->primary);
187 if(chan->primary) err = ret;
188 }
189 return(err);
190}
191
192void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
193{
194 struct list_head *ele;
195 struct chan *chan;
196
197 list_for_each(ele, chans){
198 chan = list_entry(ele, struct chan, list);
199 if(chan->primary && chan->output && chan->ops->winch){
200 register_winch(chan->fd, tty);
201 return;
202 }
203 }
204}
205
206void enable_chan(struct list_head *chans, struct tty_struct *tty)
207{
208 struct list_head *ele;
209 struct chan *chan;
210
211 list_for_each(ele, chans){
212 chan = list_entry(ele, struct chan, list);
213 if(!chan->opened) continue;
214
215 line_setup_irq(chan->fd, chan->input, chan->output, tty);
216 }
217}
218
219void close_chan(struct list_head *chans)
220{
221 struct chan *chan;
222
223 /* Close in reverse order as open in case more than one of them
224 * refers to the same device and they save and restore that device's
225 * state. Then, the first one opened will have the original state,
226 * so it must be the last closed.
227 */
228 list_for_each_entry_reverse(chan, chans, list) {
229 if(!chan->opened) continue;
230 if(chan->ops->close != NULL)
231 (*chan->ops->close)(chan->fd, chan->data);
232 chan->opened = 0;
233 chan->fd = -1;
234 }
235}
236
237int write_chan(struct list_head *chans, const char *buf, int len,
238 int write_irq)
239{
240 struct list_head *ele;
241 struct chan *chan = NULL;
242 int n, ret = 0;
243
244 list_for_each(ele, chans) {
245 chan = list_entry(ele, struct chan, list);
246 if (!chan->output || (chan->ops->write == NULL))
247 continue;
248 n = chan->ops->write(chan->fd, buf, len, chan->data);
249 if (chan->primary) {
250 ret = n;
251 if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
252 reactivate_fd(chan->fd, write_irq);
253 }
254 }
255 return(ret);
256}
257
258int console_write_chan(struct list_head *chans, const char *buf, int len)
259{
260 struct list_head *ele;
261 struct chan *chan;
262 int n, ret = 0;
263
264 list_for_each(ele, chans){
265 chan = list_entry(ele, struct chan, list);
266 if(!chan->output || (chan->ops->console_write == NULL))
267 continue;
268 n = chan->ops->console_write(chan->fd, buf, len, chan->data);
269 if(chan->primary) ret = n;
270 }
271 return(ret);
272}
273
274int console_open_chan(struct line *line, struct console *co, struct chan_opts *opts)
275{
276 if (!list_empty(&line->chan_list))
277 return 0;
278
279 if (0 != parse_chan_pair(line->init_str, &line->chan_list,
280 line->init_pri, co->index, opts))
281 return -1;
282 if (0 != open_chan(&line->chan_list))
283 return -1;
284 printk("Console initialized on /dev/%s%d\n",co->name,co->index);
285 return 0;
286}
287
288int chan_window_size(struct list_head *chans, unsigned short *rows_out,
289 unsigned short *cols_out)
290{
291 struct list_head *ele;
292 struct chan *chan;
293
294 list_for_each(ele, chans){
295 chan = list_entry(ele, struct chan, list);
296 if(chan->primary){
297 if(chan->ops->window_size == NULL) return(0);
298 return(chan->ops->window_size(chan->fd, chan->data,
299 rows_out, cols_out));
300 }
301 }
302 return(0);
303}
304
305void free_one_chan(struct chan *chan)
306{
307 list_del(&chan->list);
308 if(chan->ops->free != NULL)
309 (*chan->ops->free)(chan->data);
310 free_irq_by_fd(chan->fd);
311 if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
312 kfree(chan);
313}
314
315void free_chan(struct list_head *chans)
316{
317 struct list_head *ele, *next;
318 struct chan *chan;
319
320 list_for_each_safe(ele, next, chans){
321 chan = list_entry(ele, struct chan, list);
322 free_one_chan(chan);
323 }
324}
325
326static int one_chan_config_string(struct chan *chan, char *str, int size,
327 char **error_out)
328{
329 int n = 0;
330
331 if(chan == NULL){
332 CONFIG_CHUNK(str, size, n, "none", 1);
333 return(n);
334 }
335
336 CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
337
338 if(chan->dev == NULL){
339 CONFIG_CHUNK(str, size, n, "", 1);
340 return(n);
341 }
342
343 CONFIG_CHUNK(str, size, n, ":", 0);
344 CONFIG_CHUNK(str, size, n, chan->dev, 0);
345
346 return(n);
347}
348
349static int chan_pair_config_string(struct chan *in, struct chan *out,
350 char *str, int size, char **error_out)
351{
352 int n;
353
354 n = one_chan_config_string(in, str, size, error_out);
355 str += n;
356 size -= n;
357
358 if(in == out){
359 CONFIG_CHUNK(str, size, n, "", 1);
360 return(n);
361 }
362
363 CONFIG_CHUNK(str, size, n, ",", 1);
364 n = one_chan_config_string(out, str, size, error_out);
365 str += n;
366 size -= n;
367 CONFIG_CHUNK(str, size, n, "", 1);
368
369 return(n);
370}
371
372int chan_config_string(struct list_head *chans, char *str, int size,
373 char **error_out)
374{
375 struct list_head *ele;
376 struct chan *chan, *in = NULL, *out = NULL;
377
378 list_for_each(ele, chans){
379 chan = list_entry(ele, struct chan, list);
380 if(!chan->primary)
381 continue;
382 if(chan->input)
383 in = chan;
384 if(chan->output)
385 out = chan;
386 }
387
388 return(chan_pair_config_string(in, out, str, size, error_out));
389}
390
391struct chan_type {
392 char *key;
393 struct chan_ops *ops;
394};
395
396struct chan_type chan_table[] = {
397 { "fd", &fd_ops },
398
399#ifdef CONFIG_NULL_CHAN
400 { "null", &null_ops },
401#else
402 { "null", &not_configged_ops },
403#endif
404
405#ifdef CONFIG_PORT_CHAN
406 { "port", &port_ops },
407#else
408 { "port", &not_configged_ops },
409#endif
410
411#ifdef CONFIG_PTY_CHAN
412 { "pty", &pty_ops },
413 { "pts", &pts_ops },
414#else
415 { "pty", &not_configged_ops },
416 { "pts", &not_configged_ops },
417#endif
418
419#ifdef CONFIG_TTY_CHAN
420 { "tty", &tty_ops },
421#else
422 { "tty", &not_configged_ops },
423#endif
424
425#ifdef CONFIG_XTERM_CHAN
426 { "xterm", &xterm_ops },
427#else
428 { "xterm", &not_configged_ops },
429#endif
430};
431
432static struct chan *parse_chan(char *str, int pri, int device,
433 struct chan_opts *opts)
434{
435 struct chan_type *entry;
436 struct chan_ops *ops;
437 struct chan *chan;
438 void *data;
439 int i;
440
441 ops = NULL;
442 data = NULL;
443 for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){
444 entry = &chan_table[i];
445 if(!strncmp(str, entry->key, strlen(entry->key))){
446 ops = entry->ops;
447 str += strlen(entry->key);
448 break;
449 }
450 }
451 if(ops == NULL){
452 printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n",
453 str);
454 return(NULL);
455 }
456 if(ops->init == NULL) return(NULL);
457 data = (*ops->init)(str, device, opts);
458 if(data == NULL) return(NULL);
459
460 chan = kmalloc(sizeof(*chan), GFP_KERNEL);
461 if(chan == NULL) return(NULL);
462 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
463 .primary = 1,
464 .input = 0,
465 .output = 0,
466 .opened = 0,
467 .fd = -1,
468 .pri = pri,
469 .ops = ops,
470 .data = data });
471 return(chan);
472}
473
474int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
475 struct chan_opts *opts)
476{
477 struct chan *new, *chan;
478 char *in, *out;
479
480 if(!list_empty(chans)){
481 chan = list_entry(chans->next, struct chan, list);
482 if(chan->pri >= pri) return(0);
483 free_chan(chans);
484 INIT_LIST_HEAD(chans);
485 }
486
487 out = strchr(str, ',');
488 if(out != NULL){
489 in = str;
490 *out = '\0';
491 out++;
492 new = parse_chan(in, pri, device, opts);
493 if(new == NULL) return(-1);
494 new->input = 1;
495 list_add(&new->list, chans);
496
497 new = parse_chan(out, pri, device, opts);
498 if(new == NULL) return(-1);
499 list_add(&new->list, chans);
500 new->output = 1;
501 }
502 else {
503 new = parse_chan(str, pri, device, opts);
504 if(new == NULL) return(-1);
505 list_add(&new->list, chans);
506 new->input = 1;
507 new->output = 1;
508 }
509 return(0);
510}
511
512int chan_out_fd(struct list_head *chans)
513{
514 struct list_head *ele;
515 struct chan *chan;
516
517 list_for_each(ele, chans){
518 chan = list_entry(ele, struct chan, list);
519 if(chan->primary && chan->output)
520 return(chan->fd);
521 }
522 return(-1);
523}
524
525void chan_interrupt(struct list_head *chans, struct work_struct *task,
526 struct tty_struct *tty, int irq)
527{
528 struct list_head *ele, *next;
529 struct chan *chan;
530 int err;
531 char c;
532
533 list_for_each_safe(ele, next, chans){
534 chan = list_entry(ele, struct chan, list);
535 if(!chan->input || (chan->ops->read == NULL)) continue;
536 do {
537 if((tty != NULL) &&
538 (tty->flip.count >= TTY_FLIPBUF_SIZE)){
539 schedule_work(task);
540 goto out;
541 }
542 err = chan->ops->read(chan->fd, &c, chan->data);
543 if(err > 0)
544 tty_receive_char(tty, c);
545 } while(err > 0);
546
547 if(err == 0) reactivate_fd(chan->fd, irq);
548 if(err == -EIO){
549 if(chan->primary){
550 if(tty != NULL)
551 tty_hangup(tty);
552 line_disable(tty, irq);
553 close_chan(chans);
554 free_chan(chans);
555 return;
556 }
557 else {
558 if(chan->ops->close != NULL)
559 chan->ops->close(chan->fd, chan->data);
560 free_one_chan(chan);
561 }
562 }
563 }
564 out:
565 if(tty) tty_flip_buffer_push(tty);
566}
567
568/*
569 * Overrides for Emacs so that we follow Linus's tabbing style.
570 * Emacs will notice this stuff at the end of the file and automatically
571 * adjust the settings for this buffer only. This must remain at the end
572 * of the file.
573 * ---------------------------------------------------------------------------
574 * Local variables:
575 * c-file-style: "linux"
576 * End:
577 */
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
new file mode 100644
index 000000000000..583b8e137c33
--- /dev/null
+++ b/arch/um/drivers/chan_user.c
@@ -0,0 +1,210 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <stdlib.h>
8#include <errno.h>
9#include <termios.h>
10#include <string.h>
11#include <signal.h>
12#include <sys/stat.h>
13#include <sys/ioctl.h>
14#include <sys/socket.h>
15#include "kern_util.h"
16#include "user_util.h"
17#include "chan_user.h"
18#include "user.h"
19#include "helper.h"
20#include "os.h"
21#include "choose-mode.h"
22#include "mode.h"
23
24int generic_console_write(int fd, const char *buf, int n, void *unused)
25{
26 struct termios save, new;
27 int err;
28
29 if(isatty(fd)){
30 CATCH_EINTR(err = tcgetattr(fd, &save));
31 if (err)
32 goto error;
33 new = save;
34 /* The terminal becomes a bit less raw, to handle \n also as
35 * "Carriage Return", not only as "New Line". Otherwise, the new
36 * line won't start at the first column.*/
37 new.c_oflag |= OPOST;
38 CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new));
39 if (err)
40 goto error;
41 }
42 err = generic_write(fd, buf, n, NULL);
43 /* Restore raw mode, in any case; we *must* ignore any error apart
44 * EINTR, except for debug.*/
45 if(isatty(fd))
46 CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save));
47 return(err);
48error:
49 return(-errno);
50}
51
52/*
53 * UML SIGWINCH handling
54 *
55 * The point of this is to handle SIGWINCH on consoles which have host ttys and
56 * relay them inside UML to whatever might be running on the console and cares
57 * about the window size (since SIGWINCH notifies about terminal size changes).
58 *
59 * So, we have a separate thread for each host tty attached to a UML device
60 * (side-issue - I'm annoyed that one thread can't have multiple controlling
61 * ttys for purposed of handling SIGWINCH, but I imagine there are other reasons
62 * that doesn't make any sense).
63 *
64 * SIGWINCH can't be received synchronously, so you have to set up to receive it
65 * as a signal. That being the case, if you are going to wait for it, it is
66 * convenient to sit in a pause() and wait for the signal to bounce you out of
67 * it (see below for how we make sure to exit only on SIGWINCH).
68 */
69
70static void winch_handler(int sig)
71{
72}
73
74struct winch_data {
75 int pty_fd;
76 int pipe_fd;
77 int close_me;
78};
79
80static int winch_thread(void *arg)
81{
82 struct winch_data *data = arg;
83 sigset_t sigs;
84 int pty_fd, pipe_fd;
85 int count, err;
86 char c = 1;
87
88 os_close_file(data->close_me);
89 pty_fd = data->pty_fd;
90 pipe_fd = data->pipe_fd;
91 count = os_write_file(pipe_fd, &c, sizeof(c));
92 if(count != sizeof(c))
93 printk("winch_thread : failed to write synchronization "
94 "byte, err = %d\n", -count);
95
96 /* We are not using SIG_IGN on purpose, so don't fix it as I thought to
97 * do! If using SIG_IGN, the pause() call below would not stop on
98 * SIGWINCH. */
99
100 signal(SIGWINCH, winch_handler);
101 sigfillset(&sigs);
102 sigdelset(&sigs, SIGWINCH);
103 /* Block anything else than SIGWINCH. */
104 if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){
105 printk("winch_thread : sigprocmask failed, errno = %d\n",
106 errno);
107 exit(1);
108 }
109
110 if(setsid() < 0){
111 printk("winch_thread : setsid failed, errno = %d\n", errno);
112 exit(1);
113 }
114
115 err = os_new_tty_pgrp(pty_fd, os_getpid());
116 if(err < 0){
117 printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err);
118 exit(1);
119 }
120
121 /* These are synchronization calls between various UML threads on the
122 * host - since they are not different kernel threads, we cannot use
123 * kernel semaphores. We don't use SysV semaphores because they are
124 * persistant. */
125 count = os_read_file(pipe_fd, &c, sizeof(c));
126 if(count != sizeof(c))
127 printk("winch_thread : failed to read synchronization byte, "
128 "err = %d\n", -count);
129
130 while(1){
131 /* This will be interrupted by SIGWINCH only, since other signals
132 * are blocked.*/
133 pause();
134
135 count = os_write_file(pipe_fd, &c, sizeof(c));
136 if(count != sizeof(c))
137 printk("winch_thread : write failed, err = %d\n",
138 -count);
139 }
140}
141
142static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
143{
144 struct winch_data data;
145 unsigned long stack;
146 int fds[2], pid, n, err;
147 char c;
148
149 err = os_pipe(fds, 1, 1);
150 if(err < 0){
151 printk("winch_tramp : os_pipe failed, err = %d\n", -err);
152 return(err);
153 }
154
155 data = ((struct winch_data) { .pty_fd = fd,
156 .pipe_fd = fds[1],
157 .close_me = fds[0] } );
158 pid = run_helper_thread(winch_thread, &data, 0, &stack, 0);
159 if(pid < 0){
160 printk("fork of winch_thread failed - errno = %d\n", errno);
161 return(pid);
162 }
163
164 os_close_file(fds[1]);
165 *fd_out = fds[0];
166 n = os_read_file(fds[0], &c, sizeof(c));
167 if(n != sizeof(c)){
168 printk("winch_tramp : failed to read synchronization byte\n");
169 printk("read failed, err = %d\n", -n);
170 printk("fd %d will not support SIGWINCH\n", fd);
171 *fd_out = -1;
172 }
173 return(pid);
174}
175
176void register_winch(int fd, struct tty_struct *tty)
177{
178 int pid, thread, thread_fd;
179 int count;
180 char c = 1;
181
182 if(!isatty(fd))
183 return;
184
185 pid = tcgetpgrp(fd);
186 if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd,
187 tty) && (pid == -1)){
188 thread = winch_tramp(fd, tty, &thread_fd);
189 if(fd != -1){
190 register_winch_irq(thread_fd, fd, thread, tty);
191
192 count = os_write_file(thread_fd, &c, sizeof(c));
193 if(count != sizeof(c))
194 printk("register_winch : failed to write "
195 "synchronization byte, err = %d\n",
196 -count);
197 }
198 }
199}
200
201/*
202 * Overrides for Emacs so that we follow Linus's tabbing style.
203 * Emacs will notice this stuff at the end of the file and automatically
204 * adjust the settings for this buffer only. This must remain at the end
205 * of the file.
206 * ---------------------------------------------------------------------------
207 * Local variables:
208 * c-file-style: "linux"
209 * End:
210 */
diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h
new file mode 100644
index 000000000000..4fcbe8b1b77e
--- /dev/null
+++ b/arch/um/drivers/cow.h
@@ -0,0 +1,42 @@
1#ifndef __COW_H__
2#define __COW_H__
3
4#include <asm/types.h>
5
6#if __BYTE_ORDER == __BIG_ENDIAN
7# define ntohll(x) (x)
8# define htonll(x) (x)
9#elif __BYTE_ORDER == __LITTLE_ENDIAN
10# define ntohll(x) bswap_64(x)
11# define htonll(x) bswap_64(x)
12#else
13#error "__BYTE_ORDER not defined"
14#endif
15
16extern int init_cow_file(int fd, char *cow_file, char *backing_file,
17 int sectorsize, int alignment, int *bitmap_offset_out,
18 unsigned long *bitmap_len_out, int *data_offset_out);
19
20extern int file_reader(__u64 offset, char *buf, int len, void *arg);
21extern int read_cow_header(int (*reader)(__u64, char *, int, void *),
22 void *arg, __u32 *version_out,
23 char **backing_file_out, time_t *mtime_out,
24 unsigned long long *size_out, int *sectorsize_out,
25 __u32 *align_out, int *bitmap_offset_out);
26
27extern int write_cow_header(char *cow_file, int fd, char *backing_file,
28 int sectorsize, int alignment,
29 unsigned long long *size);
30
31extern void cow_sizes(int version, __u64 size, int sectorsize, int align,
32 int bitmap_offset, unsigned long *bitmap_len_out,
33 int *data_offset_out);
34
35#endif
36
37/*
38 * ---------------------------------------------------------------------------
39 * Local variables:
40 * c-file-style: "linux"
41 * End:
42 */
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
new file mode 100644
index 000000000000..c83fc5d68936
--- /dev/null
+++ b/arch/um/drivers/cow_sys.h
@@ -0,0 +1,48 @@
1#ifndef __COW_SYS_H__
2#define __COW_SYS_H__
3
4#include "kern_util.h"
5#include "user_util.h"
6#include "os.h"
7#include "user.h"
8
9static inline void *cow_malloc(int size)
10{
11 return(um_kmalloc(size));
12}
13
14static inline void cow_free(void *ptr)
15{
16 kfree(ptr);
17}
18
19#define cow_printf printk
20
21static inline char *cow_strdup(char *str)
22{
23 return(uml_strdup(str));
24}
25
26static inline int cow_seek_file(int fd, unsigned long long offset)
27{
28 return(os_seek_file(fd, offset));
29}
30
31static inline int cow_file_size(char *file, unsigned long long *size_out)
32{
33 return(os_file_size(file, size_out));
34}
35
36static inline int cow_write_file(int fd, char *buf, int size)
37{
38 return(os_write_file(fd, buf, size));
39}
40
41#endif
42
43/*
44 * ---------------------------------------------------------------------------
45 * Local variables:
46 * c-file-style: "linux"
47 * End:
48 */
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c
new file mode 100644
index 000000000000..a8ce6fc3ef26
--- /dev/null
+++ b/arch/um/drivers/cow_user.c
@@ -0,0 +1,378 @@
1#include <stddef.h>
2#include <string.h>
3#include <errno.h>
4/* _XOPEN_SOURCE is needed for pread, but we define _GNU_SOURCE, which defines
5 * that.
6 */
7#include <unistd.h>
8#include <byteswap.h>
9#include <sys/time.h>
10#include <sys/param.h>
11#include <sys/user.h>
12#include <netinet/in.h>
13
14#include "os.h"
15
16#include "cow.h"
17#include "cow_sys.h"
18
19#define PATH_LEN_V1 256
20
21struct cow_header_v1 {
22 int magic;
23 int version;
24 char backing_file[PATH_LEN_V1];
25 time_t mtime;
26 __u64 size;
27 int sectorsize;
28};
29
30#define PATH_LEN_V2 MAXPATHLEN
31
32struct cow_header_v2 {
33 __u32 magic;
34 __u32 version;
35 char backing_file[PATH_LEN_V2];
36 time_t mtime;
37 __u64 size;
38 int sectorsize;
39};
40
41/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in
42 * case other systems have different values for MAXPATHLEN
43 */
44#define PATH_LEN_V3 4096
45
46/* Changes from V2 -
47 * PATH_LEN_V3 as described above
48 * Explicitly specify field bit lengths for systems with different
49 * lengths for the usual C types. Not sure whether char or
50 * time_t should be changed, this can be changed later without
51 * breaking compatibility
52 * Add alignment field so that different alignments can be used for the
53 * bitmap and data
54 * Add cow_format field to allow for the possibility of different ways
55 * of specifying the COW blocks. For now, the only value is 0,
56 * for the traditional COW bitmap.
57 * Move the backing_file field to the end of the header. This allows
58 * for the possibility of expanding it into the padding required
59 * by the bitmap alignment.
60 * The bitmap and data portions of the file will be aligned as specified
61 * by the alignment field. This is to allow COW files to be
62 * put on devices with restrictions on access alignments, such as
63 * /dev/raw, with a 512 byte alignment restriction. This also
64 * allows the data to be more aligned more strictly than on
65 * sector boundaries. This is needed for ubd-mmap, which needs
66 * the data to be page aligned.
67 * Fixed (finally!) the rounding bug
68 */
69
70struct cow_header_v3 {
71 __u32 magic;
72 __u32 version;
73 __u32 mtime;
74 __u64 size;
75 __u32 sectorsize;
76 __u32 alignment;
77 __u32 cow_format;
78 char backing_file[PATH_LEN_V3];
79};
80
81/* COW format definitions - for now, we have only the usual COW bitmap */
82#define COW_BITMAP 0
83
84union cow_header {
85 struct cow_header_v1 v1;
86 struct cow_header_v2 v2;
87 struct cow_header_v3 v3;
88};
89
90#define COW_MAGIC 0x4f4f4f4d /* MOOO */
91#define COW_VERSION 3
92
93#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
94#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
95
96void cow_sizes(int version, __u64 size, int sectorsize, int align,
97 int bitmap_offset, unsigned long *bitmap_len_out,
98 int *data_offset_out)
99{
100 if(version < 3){
101 *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
102
103 *data_offset_out = bitmap_offset + *bitmap_len_out;
104 *data_offset_out = (*data_offset_out + sectorsize - 1) /
105 sectorsize;
106 *data_offset_out *= sectorsize;
107 }
108 else {
109 *bitmap_len_out = DIV_ROUND(size, sectorsize);
110 *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
111
112 *data_offset_out = bitmap_offset + *bitmap_len_out;
113 *data_offset_out = ROUND_UP(*data_offset_out, align);
114 }
115}
116
117static int absolutize(char *to, int size, char *from)
118{
119 char save_cwd[256], *slash;
120 int remaining;
121
122 if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
123 cow_printf("absolutize : unable to get cwd - errno = %d\n",
124 errno);
125 return(-1);
126 }
127 slash = strrchr(from, '/');
128 if(slash != NULL){
129 *slash = '\0';
130 if(chdir(from)){
131 *slash = '/';
132 cow_printf("absolutize : Can't cd to '%s' - "
133 "errno = %d\n", from, errno);
134 return(-1);
135 }
136 *slash = '/';
137 if(getcwd(to, size) == NULL){
138 cow_printf("absolutize : unable to get cwd of '%s' - "
139 "errno = %d\n", from, errno);
140 return(-1);
141 }
142 remaining = size - strlen(to);
143 if(strlen(slash) + 1 > remaining){
144 cow_printf("absolutize : unable to fit '%s' into %d "
145 "chars\n", from, size);
146 return(-1);
147 }
148 strcat(to, slash);
149 }
150 else {
151 if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
152 cow_printf("absolutize : unable to fit '%s' into %d "
153 "chars\n", from, size);
154 return(-1);
155 }
156 strcpy(to, save_cwd);
157 strcat(to, "/");
158 strcat(to, from);
159 }
160 chdir(save_cwd);
161 return(0);
162}
163
164int write_cow_header(char *cow_file, int fd, char *backing_file,
165 int sectorsize, int alignment, unsigned long long *size)
166{
167 struct cow_header_v3 *header;
168 unsigned long modtime;
169 int err;
170
171 err = cow_seek_file(fd, 0);
172 if(err < 0){
173 cow_printf("write_cow_header - lseek failed, err = %d\n", -err);
174 goto out;
175 }
176
177 err = -ENOMEM;
178 header = cow_malloc(sizeof(*header));
179 if(header == NULL){
180 cow_printf("Failed to allocate COW V3 header\n");
181 goto out;
182 }
183 header->magic = htonl(COW_MAGIC);
184 header->version = htonl(COW_VERSION);
185
186 err = -EINVAL;
187 if(strlen(backing_file) > sizeof(header->backing_file) - 1){
188 cow_printf("Backing file name \"%s\" is too long - names are "
189 "limited to %d characters\n", backing_file,
190 sizeof(header->backing_file) - 1);
191 goto out_free;
192 }
193
194 if(absolutize(header->backing_file, sizeof(header->backing_file),
195 backing_file))
196 goto out_free;
197
198 err = os_file_modtime(header->backing_file, &modtime);
199 if(err < 0){
200 cow_printf("Backing file '%s' mtime request failed, "
201 "err = %d\n", header->backing_file, -err);
202 goto out_free;
203 }
204
205 err = cow_file_size(header->backing_file, size);
206 if(err < 0){
207 cow_printf("Couldn't get size of backing file '%s', "
208 "err = %d\n", header->backing_file, -err);
209 goto out_free;
210 }
211
212 header->mtime = htonl(modtime);
213 header->size = htonll(*size);
214 header->sectorsize = htonl(sectorsize);
215 header->alignment = htonl(alignment);
216 header->cow_format = COW_BITMAP;
217
218 err = os_write_file(fd, header, sizeof(*header));
219 if(err != sizeof(*header)){
220 cow_printf("Write of header to new COW file '%s' failed, "
221 "err = %d\n", cow_file, -err);
222 goto out_free;
223 }
224 err = 0;
225 out_free:
226 cow_free(header);
227 out:
228 return(err);
229}
230
231int file_reader(__u64 offset, char *buf, int len, void *arg)
232{
233 int fd = *((int *) arg);
234
235 return(pread(fd, buf, len, offset));
236}
237
238/* XXX Need to sanity-check the values read from the header */
239
240int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
241 __u32 *version_out, char **backing_file_out,
242 time_t *mtime_out, unsigned long long *size_out,
243 int *sectorsize_out, __u32 *align_out,
244 int *bitmap_offset_out)
245{
246 union cow_header *header;
247 char *file;
248 int err, n;
249 unsigned long version, magic;
250
251 header = cow_malloc(sizeof(*header));
252 if(header == NULL){
253 cow_printf("read_cow_header - Failed to allocate header\n");
254 return(-ENOMEM);
255 }
256 err = -EINVAL;
257 n = (*reader)(0, (char *) header, sizeof(*header), arg);
258 if(n < offsetof(typeof(header->v1), backing_file)){
259 cow_printf("read_cow_header - short header\n");
260 goto out;
261 }
262
263 magic = header->v1.magic;
264 if(magic == COW_MAGIC) {
265 version = header->v1.version;
266 }
267 else if(magic == ntohl(COW_MAGIC)){
268 version = ntohl(header->v1.version);
269 }
270 /* No error printed because the non-COW case comes through here */
271 else goto out;
272
273 *version_out = version;
274
275 if(version == 1){
276 if(n < sizeof(header->v1)){
277 cow_printf("read_cow_header - failed to read V1 "
278 "header\n");
279 goto out;
280 }
281 *mtime_out = header->v1.mtime;
282 *size_out = header->v1.size;
283 *sectorsize_out = header->v1.sectorsize;
284 *bitmap_offset_out = sizeof(header->v1);
285 *align_out = *sectorsize_out;
286 file = header->v1.backing_file;
287 }
288 else if(version == 2){
289 if(n < sizeof(header->v2)){
290 cow_printf("read_cow_header - failed to read V2 "
291 "header\n");
292 goto out;
293 }
294 *mtime_out = ntohl(header->v2.mtime);
295 *size_out = ntohll(header->v2.size);
296 *sectorsize_out = ntohl(header->v2.sectorsize);
297 *bitmap_offset_out = sizeof(header->v2);
298 *align_out = *sectorsize_out;
299 file = header->v2.backing_file;
300 }
301 else if(version == 3){
302 if(n < sizeof(header->v3)){
303 cow_printf("read_cow_header - failed to read V2 "
304 "header\n");
305 goto out;
306 }
307 *mtime_out = ntohl(header->v3.mtime);
308 *size_out = ntohll(header->v3.size);
309 *sectorsize_out = ntohl(header->v3.sectorsize);
310 *align_out = ntohl(header->v3.alignment);
311 *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out);
312 file = header->v3.backing_file;
313 }
314 else {
315 cow_printf("read_cow_header - invalid COW version\n");
316 goto out;
317 }
318 err = -ENOMEM;
319 *backing_file_out = cow_strdup(file);
320 if(*backing_file_out == NULL){
321 cow_printf("read_cow_header - failed to allocate backing "
322 "file\n");
323 goto out;
324 }
325 err = 0;
326 out:
327 cow_free(header);
328 return(err);
329}
330
331int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
332 int alignment, int *bitmap_offset_out,
333 unsigned long *bitmap_len_out, int *data_offset_out)
334{
335 unsigned long long size, offset;
336 char zero = 0;
337 int err;
338
339 err = write_cow_header(cow_file, fd, backing_file, sectorsize,
340 alignment, &size);
341 if(err)
342 goto out;
343
344 *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
345 cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
346 bitmap_len_out, data_offset_out);
347
348 offset = *data_offset_out + size - sizeof(zero);
349 err = cow_seek_file(fd, offset);
350 if(err < 0){
351 cow_printf("cow bitmap lseek failed : err = %d\n", -err);
352 goto out;
353 }
354
355 /* does not really matter how much we write it is just to set EOF
356 * this also sets the entire COW bitmap
357 * to zero without having to allocate it
358 */
359 err = cow_write_file(fd, &zero, sizeof(zero));
360 if(err != sizeof(zero)){
361 cow_printf("Write of bitmap to new COW file '%s' failed, "
362 "err = %d\n", cow_file, -err);
363 err = -EINVAL;
364 goto out;
365 }
366
367 return(0);
368
369 out:
370 return(err);
371}
372
373/*
374 * ---------------------------------------------------------------------------
375 * Local variables:
376 * c-file-style: "linux"
377 * End:
378 */
diff --git a/arch/um/drivers/daemon.h b/arch/um/drivers/daemon.h
new file mode 100644
index 000000000000..7326c42f7ef9
--- /dev/null
+++ b/arch/um/drivers/daemon.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "net_user.h"
7
8#define SWITCH_VERSION 3
9
10struct daemon_data {
11 char *sock_type;
12 char *ctl_sock;
13 void *ctl_addr;
14 void *data_addr;
15 void *local_addr;
16 int fd;
17 int control;
18 void *dev;
19};
20
21extern struct net_user_info daemon_user_info;
22
23extern int daemon_user_write(int fd, void *buf, int len,
24 struct daemon_data *pri);
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/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
new file mode 100644
index 000000000000..30d285b266af
--- /dev/null
+++ b/arch/um/drivers/daemon_kern.c
@@ -0,0 +1,108 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
3 * James Leu (jleu@mindspring.net).
4 * Copyright (C) 2001 by various other people who didn't put their name here.
5 * Licensed under the GPL.
6 */
7
8#include "linux/kernel.h"
9#include "linux/init.h"
10#include "linux/netdevice.h"
11#include "linux/etherdevice.h"
12#include "net_kern.h"
13#include "net_user.h"
14#include "daemon.h"
15
16struct daemon_init {
17 char *sock_type;
18 char *ctl_sock;
19};
20
21void daemon_init(struct net_device *dev, void *data)
22{
23 struct uml_net_private *pri;
24 struct daemon_data *dpri;
25 struct daemon_init *init = data;
26
27 pri = dev->priv;
28 dpri = (struct daemon_data *) pri->user;
29 dpri->sock_type = init->sock_type;
30 dpri->ctl_sock = init->ctl_sock;
31 dpri->fd = -1;
32 dpri->control = -1;
33 dpri->dev = dev;
34
35 printk("daemon backend (uml_switch version %d) - %s:%s",
36 SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock);
37 printk("\n");
38}
39
40static int daemon_read(int fd, struct sk_buff **skb,
41 struct uml_net_private *lp)
42{
43 *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
44 if(*skb == NULL) return(-ENOMEM);
45 return(net_recvfrom(fd, (*skb)->mac.raw,
46 (*skb)->dev->mtu + ETH_HEADER_OTHER));
47}
48
49static int daemon_write(int fd, struct sk_buff **skb,
50 struct uml_net_private *lp)
51{
52 return(daemon_user_write(fd, (*skb)->data, (*skb)->len,
53 (struct daemon_data *) &lp->user));
54}
55
56static struct net_kern_info daemon_kern_info = {
57 .init = daemon_init,
58 .protocol = eth_protocol,
59 .read = daemon_read,
60 .write = daemon_write,
61};
62
63int daemon_setup(char *str, char **mac_out, void *data)
64{
65 struct daemon_init *init = data;
66 char *remain;
67
68 *init = ((struct daemon_init)
69 { .sock_type = "unix",
70 .ctl_sock = "/tmp/uml.ctl" });
71
72 remain = split_if_spec(str, mac_out, &init->sock_type, &init->ctl_sock,
73 NULL);
74 if(remain != NULL)
75 printk(KERN_WARNING "daemon_setup : Ignoring data socket "
76 "specification\n");
77
78 return(1);
79}
80
81static struct transport daemon_transport = {
82 .list = LIST_HEAD_INIT(daemon_transport.list),
83 .name = "daemon",
84 .setup = daemon_setup,
85 .user = &daemon_user_info,
86 .kern = &daemon_kern_info,
87 .private_size = sizeof(struct daemon_data),
88 .setup_size = sizeof(struct daemon_init),
89};
90
91static int register_daemon(void)
92{
93 register_transport(&daemon_transport);
94 return(1);
95}
96
97__initcall(register_daemon);
98
99/*
100 * Overrides for Emacs so that we follow Linus's tabbing style.
101 * Emacs will notice this stuff at the end of the file and automatically
102 * adjust the settings for this buffer only. This must remain at the end
103 * of the file.
104 * ---------------------------------------------------------------------------
105 * Local variables:
106 * c-file-style: "linux"
107 * End:
108 */
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
new file mode 100644
index 000000000000..cf15b4a8b517
--- /dev/null
+++ b/arch/um/drivers/daemon_user.c
@@ -0,0 +1,197 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
3 * James Leu (jleu@mindspring.net).
4 * Copyright (C) 2001 by various other people who didn't put their name here.
5 * Licensed under the GPL.
6 */
7
8#include <errno.h>
9#include <unistd.h>
10#include <stdint.h>
11#include <sys/socket.h>
12#include <sys/un.h>
13#include <sys/time.h>
14#include "net_user.h"
15#include "daemon.h"
16#include "kern_util.h"
17#include "user_util.h"
18#include "user.h"
19#include "os.h"
20
21#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
22
23enum request_type { REQ_NEW_CONTROL };
24
25#define SWITCH_MAGIC 0xfeedface
26
27struct request_v3 {
28 uint32_t magic;
29 uint32_t version;
30 enum request_type type;
31 struct sockaddr_un sock;
32};
33
34static struct sockaddr_un *new_addr(void *name, int len)
35{
36 struct sockaddr_un *sun;
37
38 sun = um_kmalloc(sizeof(struct sockaddr_un));
39 if(sun == NULL){
40 printk("new_addr: allocation of sockaddr_un failed\n");
41 return(NULL);
42 }
43 sun->sun_family = AF_UNIX;
44 memcpy(sun->sun_path, name, len);
45 return(sun);
46}
47
48static int connect_to_switch(struct daemon_data *pri)
49{
50 struct sockaddr_un *ctl_addr = pri->ctl_addr;
51 struct sockaddr_un *local_addr = pri->local_addr;
52 struct sockaddr_un *sun;
53 struct request_v3 req;
54 int fd, n, err;
55
56 pri->control = socket(AF_UNIX, SOCK_STREAM, 0);
57 if(pri->control < 0){
58 printk("daemon_open : control socket failed, errno = %d\n",
59 errno);
60 return(-errno);
61 }
62
63 if(connect(pri->control, (struct sockaddr *) ctl_addr,
64 sizeof(*ctl_addr)) < 0){
65 printk("daemon_open : control connect failed, errno = %d\n",
66 errno);
67 err = -errno;
68 goto out;
69 }
70
71 fd = socket(AF_UNIX, SOCK_DGRAM, 0);
72 if(fd < 0){
73 printk("daemon_open : data socket failed, errno = %d\n",
74 errno);
75 err = -errno;
76 goto out;
77 }
78 if(bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0){
79 printk("daemon_open : data bind failed, errno = %d\n",
80 errno);
81 err = -errno;
82 goto out_close;
83 }
84
85 sun = um_kmalloc(sizeof(struct sockaddr_un));
86 if(sun == NULL){
87 printk("new_addr: allocation of sockaddr_un failed\n");
88 err = -ENOMEM;
89 goto out_close;
90 }
91
92 req.magic = SWITCH_MAGIC;
93 req.version = SWITCH_VERSION;
94 req.type = REQ_NEW_CONTROL;
95 req.sock = *local_addr;
96 n = os_write_file(pri->control, &req, sizeof(req));
97 if(n != sizeof(req)){
98 printk("daemon_open : control setup request failed, err = %d\n",
99 -n);
100 err = -ENOTCONN;
101 goto out;
102 }
103
104 n = os_read_file(pri->control, sun, sizeof(*sun));
105 if(n != sizeof(*sun)){
106 printk("daemon_open : read of data socket failed, err = %d\n",
107 -n);
108 err = -ENOTCONN;
109 goto out_close;
110 }
111
112 pri->data_addr = sun;
113 return(fd);
114
115 out_close:
116 os_close_file(fd);
117 out:
118 os_close_file(pri->control);
119 return(err);
120}
121
122static void daemon_user_init(void *data, void *dev)
123{
124 struct daemon_data *pri = data;
125 struct timeval tv;
126 struct {
127 char zero;
128 int pid;
129 int usecs;
130 } name;
131
132 if(!strcmp(pri->sock_type, "unix"))
133 pri->ctl_addr = new_addr(pri->ctl_sock,
134 strlen(pri->ctl_sock) + 1);
135 name.zero = 0;
136 name.pid = os_getpid();
137 gettimeofday(&tv, NULL);
138 name.usecs = tv.tv_usec;
139 pri->local_addr = new_addr(&name, sizeof(name));
140 pri->dev = dev;
141 pri->fd = connect_to_switch(pri);
142 if(pri->fd < 0){
143 kfree(pri->local_addr);
144 pri->local_addr = NULL;
145 }
146}
147
148static int daemon_open(void *data)
149{
150 struct daemon_data *pri = data;
151 return(pri->fd);
152}
153
154static void daemon_remove(void *data)
155{
156 struct daemon_data *pri = data;
157
158 os_close_file(pri->fd);
159 os_close_file(pri->control);
160 if(pri->data_addr != NULL) kfree(pri->data_addr);
161 if(pri->ctl_addr != NULL) kfree(pri->ctl_addr);
162 if(pri->local_addr != NULL) kfree(pri->local_addr);
163}
164
165int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
166{
167 struct sockaddr_un *data_addr = pri->data_addr;
168
169 return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
170}
171
172static int daemon_set_mtu(int mtu, void *data)
173{
174 return(mtu);
175}
176
177struct net_user_info daemon_user_info = {
178 .init = daemon_user_init,
179 .open = daemon_open,
180 .close = NULL,
181 .remove = daemon_remove,
182 .set_mtu = daemon_set_mtu,
183 .add_address = NULL,
184 .delete_address = NULL,
185 .max_packet = MAX_PACKET - ETH_HEADER_OTHER
186};
187
188/*
189 * Overrides for Emacs so that we follow Linus's tabbing style.
190 * Emacs will notice this stuff at the end of the file and automatically
191 * adjust the settings for this buffer only. This must remain at the end
192 * of the file.
193 * ---------------------------------------------------------------------------
194 * Local variables:
195 * c-file-style: "linux"
196 * End:
197 */
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
new file mode 100644
index 000000000000..f0b888f66e05
--- /dev/null
+++ b/arch/um/drivers/fd.c
@@ -0,0 +1,108 @@
1/*
2 * Copyright (C) 2001 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 <termios.h>
10#include <errno.h>
11#include "user.h"
12#include "user_util.h"
13#include "chan_user.h"
14
15struct fd_chan {
16 int fd;
17 int raw;
18 struct termios tt;
19 char str[sizeof("1234567890\0")];
20};
21
22static void *fd_init(char *str, int device, struct chan_opts *opts)
23{
24 struct fd_chan *data;
25 char *end;
26 int n;
27
28 if(*str != ':'){
29 printk("fd_init : channel type 'fd' must specify a file "
30 "descriptor\n");
31 return(NULL);
32 }
33 str++;
34 n = strtoul(str, &end, 0);
35 if((*end != '\0') || (end == str)){
36 printk("fd_init : couldn't parse file descriptor '%s'\n", str);
37 return(NULL);
38 }
39 data = um_kmalloc(sizeof(*data));
40 if(data == NULL) return(NULL);
41 *data = ((struct fd_chan) { .fd = n,
42 .raw = opts->raw });
43 return(data);
44}
45
46static int fd_open(int input, int output, int primary, void *d, char **dev_out)
47{
48 struct fd_chan *data = d;
49 int err;
50
51 if(data->raw && isatty(data->fd)){
52 CATCH_EINTR(err = tcgetattr(data->fd, &data->tt));
53 if(err)
54 return(err);
55
56 err = raw(data->fd);
57 if(err)
58 return(err);
59 }
60 sprintf(data->str, "%d", data->fd);
61 *dev_out = data->str;
62 return(data->fd);
63}
64
65static void fd_close(int fd, void *d)
66{
67 struct fd_chan *data = d;
68 int err;
69
70 if(data->raw && isatty(fd)){
71 CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt));
72 if(err)
73 printk("Failed to restore terminal state - "
74 "errno = %d\n", -err);
75 data->raw = 0;
76 }
77}
78
79static int fd_console_write(int fd, const char *buf, int n, void *d)
80{
81 struct fd_chan *data = d;
82
83 return(generic_console_write(fd, buf, n, &data->tt));
84}
85
86struct chan_ops fd_ops = {
87 .type = "fd",
88 .init = fd_init,
89 .open = fd_open,
90 .close = fd_close,
91 .read = generic_read,
92 .write = generic_write,
93 .console_write = fd_console_write,
94 .window_size = generic_window_size,
95 .free = generic_free,
96 .winch = 1,
97};
98
99/*
100 * Overrides for Emacs so that we follow Linus's tabbing style.
101 * Emacs will notice this stuff at the end of the file and automatically
102 * adjust the settings for this buffer only. This must remain at the end
103 * of the file.
104 * ---------------------------------------------------------------------------
105 * Local variables:
106 * c-file-style: "linux"
107 * End:
108 */
diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c
new file mode 100644
index 000000000000..147ec19f6bb9
--- /dev/null
+++ b/arch/um/drivers/harddog_kern.c
@@ -0,0 +1,190 @@
1/* UML hardware watchdog, shamelessly stolen from:
2 *
3 * SoftDog 0.05: A Software Watchdog Device
4 *
5 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
6 * http://www.redhat.com
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
14 * warranty for any of this software. This material is provided
15 * "AS-IS" and at no charge.
16 *
17 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
18 *
19 * Software only watchdog driver. Unlike its big brother the WDT501P
20 * driver this won't always recover a failed machine.
21 *
22 * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
23 * Modularised.
24 * Added soft_margin; use upon insmod to change the timer delay.
25 * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
26 * minors.
27 *
28 * 19980911 Alan Cox
29 * Made SMP safe for 2.3.x
30 *
31 * 20011127 Joel Becker (jlbec@evilplan.org>
32 * Added soft_noboot; Allows testing the softdog trigger without
33 * requiring a recompile.
34 * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
35 */
36
37#include <linux/module.h>
38#include <linux/config.h>
39#include <linux/types.h>
40#include <linux/kernel.h>
41#include <linux/fs.h>
42#include <linux/mm.h>
43#include <linux/miscdevice.h>
44#include <linux/watchdog.h>
45#include <linux/reboot.h>
46#include <linux/smp_lock.h>
47#include <linux/init.h>
48#include <asm/uaccess.h>
49#include "helper.h"
50#include "mconsole.h"
51
52MODULE_LICENSE("GPL");
53
54/* Locked by the BKL in harddog_open and harddog_release */
55static int timer_alive;
56static int harddog_in_fd = -1;
57static int harddog_out_fd = -1;
58
59/*
60 * Allow only one person to hold it open
61 */
62
63extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock);
64
65static int harddog_open(struct inode *inode, struct file *file)
66{
67 int err;
68 char *sock = NULL;
69
70 lock_kernel();
71 if(timer_alive)
72 return -EBUSY;
73#ifdef CONFIG_HARDDOG_NOWAYOUT
74 __module_get(THIS_MODULE);
75#endif
76
77#ifdef CONFIG_MCONSOLE
78 sock = mconsole_notify_socket();
79#endif
80 err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock);
81 if(err) return(err);
82
83 timer_alive = 1;
84 unlock_kernel();
85 return nonseekable_open(inode, file);
86}
87
88extern void stop_watchdog(int in_fd, int out_fd);
89
90static int harddog_release(struct inode *inode, struct file *file)
91{
92 /*
93 * Shut off the timer.
94 */
95 lock_kernel();
96
97 stop_watchdog(harddog_in_fd, harddog_out_fd);
98 harddog_in_fd = -1;
99 harddog_out_fd = -1;
100
101 timer_alive=0;
102 unlock_kernel();
103 return 0;
104}
105
106extern int ping_watchdog(int fd);
107
108static ssize_t harddog_write(struct file *file, const char *data, size_t len,
109 loff_t *ppos)
110{
111 /*
112 * Refresh the timer.
113 */
114 if(len)
115 return(ping_watchdog(harddog_out_fd));
116 return 0;
117}
118
119static int harddog_ioctl(struct inode *inode, struct file *file,
120 unsigned int cmd, unsigned long arg)
121{
122 static struct watchdog_info ident = {
123 WDIOC_SETTIMEOUT,
124 0,
125 "UML Hardware Watchdog"
126 };
127 switch (cmd) {
128 default:
129 return -ENOTTY;
130 case WDIOC_GETSUPPORT:
131 if(copy_to_user((struct harddog_info *)arg, &ident,
132 sizeof(ident)))
133 return -EFAULT;
134 return 0;
135 case WDIOC_GETSTATUS:
136 case WDIOC_GETBOOTSTATUS:
137 return put_user(0,(int *)arg);
138 case WDIOC_KEEPALIVE:
139 return(ping_watchdog(harddog_out_fd));
140 }
141}
142
143static struct file_operations harddog_fops = {
144 .owner = THIS_MODULE,
145 .write = harddog_write,
146 .ioctl = harddog_ioctl,
147 .open = harddog_open,
148 .release = harddog_release,
149};
150
151static struct miscdevice harddog_miscdev = {
152 .minor = WATCHDOG_MINOR,
153 .name = "watchdog",
154 .fops = &harddog_fops,
155};
156
157static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n";
158
159static int __init harddog_init(void)
160{
161 int ret;
162
163 ret = misc_register(&harddog_miscdev);
164
165 if (ret)
166 return ret;
167
168 printk(banner);
169
170 return(0);
171}
172
173static void __exit harddog_exit(void)
174{
175 misc_deregister(&harddog_miscdev);
176}
177
178module_init(harddog_init);
179module_exit(harddog_exit);
180
181/*
182 * Overrides for Emacs so that we follow Linus's tabbing style.
183 * Emacs will notice this stuff at the end of the file and automatically
184 * adjust the settings for this buffer only. This must remain at the end
185 * of the file.
186 * ---------------------------------------------------------------------------
187 * Local variables:
188 * c-file-style: "linux"
189 * End:
190 */
diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c
new file mode 100644
index 000000000000..d934181b8d4c
--- /dev/null
+++ b/arch/um/drivers/harddog_user.c
@@ -0,0 +1,143 @@
1/*
2 * Copyright (C) 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 "user_util.h"
10#include "user.h"
11#include "helper.h"
12#include "mconsole.h"
13#include "os.h"
14#include "choose-mode.h"
15#include "mode.h"
16
17struct dog_data {
18 int stdin;
19 int stdout;
20 int close_me[2];
21};
22
23static void pre_exec(void *d)
24{
25 struct dog_data *data = d;
26
27 dup2(data->stdin, 0);
28 dup2(data->stdout, 1);
29 dup2(data->stdout, 2);
30 os_close_file(data->stdin);
31 os_close_file(data->stdout);
32 os_close_file(data->close_me[0]);
33 os_close_file(data->close_me[1]);
34}
35
36int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
37{
38 struct dog_data data;
39 int in_fds[2], out_fds[2], pid, n, err;
40 char pid_buf[sizeof("nnnnn\0")], c;
41 char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL };
42 char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL,
43 NULL };
44 char **args = NULL;
45
46 err = os_pipe(in_fds, 1, 0);
47 if(err < 0){
48 printk("harddog_open - os_pipe failed, err = %d\n", -err);
49 goto out;
50 }
51
52 err = os_pipe(out_fds, 1, 0);
53 if(err < 0){
54 printk("harddog_open - os_pipe failed, err = %d\n", -err);
55 goto out_close_in;
56 }
57
58 data.stdin = out_fds[0];
59 data.stdout = in_fds[1];
60 data.close_me[0] = out_fds[1];
61 data.close_me[1] = in_fds[0];
62
63 if(sock != NULL){
64 mconsole_args[2] = sock;
65 args = mconsole_args;
66 }
67 else {
68 /* XXX The os_getpid() is not SMP correct */
69 sprintf(pid_buf, "%d", CHOOSE_MODE(tracing_pid, os_getpid()));
70 args = pid_args;
71 }
72
73 pid = run_helper(pre_exec, &data, args, NULL);
74
75 os_close_file(out_fds[0]);
76 os_close_file(in_fds[1]);
77
78 if(pid < 0){
79 err = -pid;
80 printk("harddog_open - run_helper failed, errno = %d\n", -err);
81 goto out_close_out;
82 }
83
84 n = os_read_file(in_fds[0], &c, sizeof(c));
85 if(n == 0){
86 printk("harddog_open - EOF on watchdog pipe\n");
87 helper_wait(pid);
88 err = -EIO;
89 goto out_close_out;
90 }
91 else if(n < 0){
92 printk("harddog_open - read of watchdog pipe failed, "
93 "err = %d\n", -n);
94 helper_wait(pid);
95 err = n;
96 goto out_close_out;
97 }
98 *in_fd_ret = in_fds[0];
99 *out_fd_ret = out_fds[1];
100 return(0);
101
102 out_close_in:
103 os_close_file(in_fds[0]);
104 os_close_file(in_fds[1]);
105 out_close_out:
106 os_close_file(out_fds[0]);
107 os_close_file(out_fds[1]);
108 out:
109 return(err);
110}
111
112void stop_watchdog(int in_fd, int out_fd)
113{
114 os_close_file(in_fd);
115 os_close_file(out_fd);
116}
117
118int ping_watchdog(int fd)
119{
120 int n;
121 char c = '\n';
122
123 n = os_write_file(fd, &c, sizeof(c));
124 if(n != sizeof(c)){
125 printk("ping_watchdog - write failed, err = %d\n", -n);
126 if(n < 0)
127 return(n);
128 return(-EIO);
129 }
130 return 1;
131
132}
133
134/*
135 * Overrides for Emacs so that we follow Linus's tabbing style.
136 * Emacs will notice this stuff at the end of the file and automatically
137 * adjust the settings for this buffer only. This must remain at the end
138 * of the file.
139 * ---------------------------------------------------------------------------
140 * Local variables:
141 * c-file-style: "linux"
142 * End:
143 */
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
new file mode 100644
index 000000000000..d5742783e19d
--- /dev/null
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -0,0 +1,352 @@
1/*
2 * Copyright (C) 2002 Steve Schmidtke
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/module.h"
8#include "linux/init.h"
9#include "linux/slab.h"
10#include "linux/fs.h"
11#include "linux/sound.h"
12#include "linux/soundcard.h"
13#include "asm/uaccess.h"
14#include "kern_util.h"
15#include "init.h"
16#include "os.h"
17
18struct hostaudio_state {
19 int fd;
20};
21
22struct hostmixer_state {
23 int fd;
24};
25
26#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
27#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
28
29/* Only changed from linux_main at boot time */
30char *dsp = HOSTAUDIO_DEV_DSP;
31char *mixer = HOSTAUDIO_DEV_MIXER;
32
33#define DSP_HELP \
34" This is used to specify the host dsp device to the hostaudio driver.\n" \
35" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
36
37#define MIXER_HELP \
38" This is used to specify the host mixer device to the hostaudio driver.\n"\
39" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
40
41#ifndef MODULE
42static int set_dsp(char *name, int *add)
43{
44 dsp = name;
45 return(0);
46}
47
48__uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP);
49
50static int set_mixer(char *name, int *add)
51{
52 mixer = name;
53 return(0);
54}
55
56__uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
57
58#else /*MODULE*/
59
60MODULE_PARM(dsp, "s");
61MODULE_PARM_DESC(dsp, DSP_HELP);
62
63MODULE_PARM(mixer, "s");
64MODULE_PARM_DESC(mixer, MIXER_HELP);
65
66#endif
67
68/* /dev/dsp file operations */
69
70static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count,
71 loff_t *ppos)
72{
73 struct hostaudio_state *state = file->private_data;
74 void *kbuf;
75 int err;
76
77#ifdef DEBUG
78 printk("hostaudio: read called, count = %d\n", count);
79#endif
80
81 kbuf = kmalloc(count, GFP_KERNEL);
82 if(kbuf == NULL)
83 return(-ENOMEM);
84
85 err = os_read_file(state->fd, kbuf, count);
86 if(err < 0)
87 goto out;
88
89 if(copy_to_user(buffer, kbuf, err))
90 err = -EFAULT;
91
92 out:
93 kfree(kbuf);
94 return(err);
95}
96
97static ssize_t hostaudio_write(struct file *file, const char *buffer,
98 size_t count, loff_t *ppos)
99{
100 struct hostaudio_state *state = file->private_data;
101 void *kbuf;
102 int err;
103
104#ifdef DEBUG
105 printk("hostaudio: write called, count = %d\n", count);
106#endif
107
108 kbuf = kmalloc(count, GFP_KERNEL);
109 if(kbuf == NULL)
110 return(-ENOMEM);
111
112 err = -EFAULT;
113 if(copy_from_user(kbuf, buffer, count))
114 goto out;
115
116 err = os_write_file(state->fd, kbuf, count);
117 if(err < 0)
118 goto out;
119 *ppos += err;
120
121 out:
122 kfree(kbuf);
123 return(err);
124}
125
126static unsigned int hostaudio_poll(struct file *file,
127 struct poll_table_struct *wait)
128{
129 unsigned int mask = 0;
130
131#ifdef DEBUG
132 printk("hostaudio: poll called (unimplemented)\n");
133#endif
134
135 return(mask);
136}
137
138static int hostaudio_ioctl(struct inode *inode, struct file *file,
139 unsigned int cmd, unsigned long arg)
140{
141 struct hostaudio_state *state = file->private_data;
142 unsigned long data = 0;
143 int err;
144
145#ifdef DEBUG
146 printk("hostaudio: ioctl called, cmd = %u\n", cmd);
147#endif
148 switch(cmd){
149 case SNDCTL_DSP_SPEED:
150 case SNDCTL_DSP_STEREO:
151 case SNDCTL_DSP_GETBLKSIZE:
152 case SNDCTL_DSP_CHANNELS:
153 case SNDCTL_DSP_SUBDIVIDE:
154 case SNDCTL_DSP_SETFRAGMENT:
155 if(get_user(data, (int *) arg))
156 return(-EFAULT);
157 break;
158 default:
159 break;
160 }
161
162 err = os_ioctl_generic(state->fd, cmd, (unsigned long) &data);
163
164 switch(cmd){
165 case SNDCTL_DSP_SPEED:
166 case SNDCTL_DSP_STEREO:
167 case SNDCTL_DSP_GETBLKSIZE:
168 case SNDCTL_DSP_CHANNELS:
169 case SNDCTL_DSP_SUBDIVIDE:
170 case SNDCTL_DSP_SETFRAGMENT:
171 if(put_user(data, (int *) arg))
172 return(-EFAULT);
173 break;
174 default:
175 break;
176 }
177
178 return(err);
179}
180
181static int hostaudio_open(struct inode *inode, struct file *file)
182{
183 struct hostaudio_state *state;
184 int r = 0, w = 0;
185 int ret;
186
187#ifdef DEBUG
188 printk("hostaudio: open called (host: %s)\n", dsp);
189#endif
190
191 state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
192 if(state == NULL)
193 return(-ENOMEM);
194
195 if(file->f_mode & FMODE_READ) r = 1;
196 if(file->f_mode & FMODE_WRITE) w = 1;
197
198 ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
199 if(ret < 0){
200 kfree(state);
201 return(ret);
202 }
203
204 state->fd = ret;
205 file->private_data = state;
206 return(0);
207}
208
209static int hostaudio_release(struct inode *inode, struct file *file)
210{
211 struct hostaudio_state *state = file->private_data;
212
213#ifdef DEBUG
214 printk("hostaudio: release called\n");
215#endif
216
217 os_close_file(state->fd);
218 kfree(state);
219
220 return(0);
221}
222
223/* /dev/mixer file operations */
224
225static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file,
226 unsigned int cmd, unsigned long arg)
227{
228 struct hostmixer_state *state = file->private_data;
229
230#ifdef DEBUG
231 printk("hostmixer: ioctl called\n");
232#endif
233
234 return(os_ioctl_generic(state->fd, cmd, arg));
235}
236
237static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
238{
239 struct hostmixer_state *state;
240 int r = 0, w = 0;
241 int ret;
242
243#ifdef DEBUG
244 printk("hostmixer: open called (host: %s)\n", mixer);
245#endif
246
247 state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL);
248 if(state == NULL) return(-ENOMEM);
249
250 if(file->f_mode & FMODE_READ) r = 1;
251 if(file->f_mode & FMODE_WRITE) w = 1;
252
253 ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
254
255 if(ret < 0){
256 printk("hostaudio_open_mixdev failed to open '%s', err = %d\n",
257 dsp, -ret);
258 kfree(state);
259 return(ret);
260 }
261
262 file->private_data = state;
263 return(0);
264}
265
266static int hostmixer_release(struct inode *inode, struct file *file)
267{
268 struct hostmixer_state *state = file->private_data;
269
270#ifdef DEBUG
271 printk("hostmixer: release called\n");
272#endif
273
274 os_close_file(state->fd);
275 kfree(state);
276
277 return(0);
278}
279
280
281/* kernel module operations */
282
283static struct file_operations hostaudio_fops = {
284 .owner = THIS_MODULE,
285 .llseek = no_llseek,
286 .read = hostaudio_read,
287 .write = hostaudio_write,
288 .poll = hostaudio_poll,
289 .ioctl = hostaudio_ioctl,
290 .mmap = NULL,
291 .open = hostaudio_open,
292 .release = hostaudio_release,
293};
294
295static struct file_operations hostmixer_fops = {
296 .owner = THIS_MODULE,
297 .llseek = no_llseek,
298 .ioctl = hostmixer_ioctl_mixdev,
299 .open = hostmixer_open_mixdev,
300 .release = hostmixer_release,
301};
302
303struct {
304 int dev_audio;
305 int dev_mixer;
306} module_data;
307
308MODULE_AUTHOR("Steve Schmidtke");
309MODULE_DESCRIPTION("UML Audio Relay");
310MODULE_LICENSE("GPL");
311
312static int __init hostaudio_init_module(void)
313{
314 printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
315 dsp, mixer);
316
317 module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
318 if(module_data.dev_audio < 0){
319 printk(KERN_ERR "hostaudio: couldn't register DSP device!\n");
320 return -ENODEV;
321 }
322
323 module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1);
324 if(module_data.dev_mixer < 0){
325 printk(KERN_ERR "hostmixer: couldn't register mixer "
326 "device!\n");
327 unregister_sound_dsp(module_data.dev_audio);
328 return -ENODEV;
329 }
330
331 return 0;
332}
333
334static void __exit hostaudio_cleanup_module (void)
335{
336 unregister_sound_mixer(module_data.dev_mixer);
337 unregister_sound_dsp(module_data.dev_audio);
338}
339
340module_init(hostaudio_init_module);
341module_exit(hostaudio_cleanup_module);
342
343/*
344 * Overrides for Emacs so that we follow Linus's tabbing style.
345 * Emacs will notice this stuff at the end of the file and automatically
346 * adjust the settings for this buffer only. This must remain at the end
347 * of the file.
348 * ---------------------------------------------------------------------------
349 * Local variables:
350 * c-file-style: "linux"
351 * End:
352 */
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
new file mode 100644
index 000000000000..6924f273ced9
--- /dev/null
+++ b/arch/um/drivers/line.c
@@ -0,0 +1,681 @@
1/*
2 * Copyright (C) 2001, 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/list.h"
9#include "linux/kd.h"
10#include "linux/interrupt.h"
11#include "linux/devfs_fs_kernel.h"
12#include "asm/uaccess.h"
13#include "chan_kern.h"
14#include "irq_user.h"
15#include "line.h"
16#include "kern.h"
17#include "user_util.h"
18#include "kern_util.h"
19#include "os.h"
20#include "irq_kern.h"
21
22#define LINE_BUFSIZE 4096
23
24static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused)
25{
26 struct tty_struct *tty = data;
27 struct line *line = tty->driver_data;
28
29 if (line)
30 chan_interrupt(&line->chan_list, &line->task, tty, irq);
31 return IRQ_HANDLED;
32}
33
34static void line_timer_cb(void *arg)
35{
36 struct tty_struct *tty = arg;
37 struct line *line = tty->driver_data;
38
39 line_interrupt(line->driver->read_irq, arg, NULL);
40}
41
42static int write_room(struct line *dev)
43{
44 int n;
45
46 if (dev->buffer == NULL)
47 return (LINE_BUFSIZE - 1);
48
49 n = dev->head - dev->tail;
50 if (n <= 0)
51 n = LINE_BUFSIZE + n;
52 return (n - 1);
53}
54
55static int buffer_data(struct line *line, const char *buf, int len)
56{
57 int end, room;
58
59 if(line->buffer == NULL){
60 line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
61 if (line->buffer == NULL) {
62 printk("buffer_data - atomic allocation failed\n");
63 return(0);
64 }
65 line->head = line->buffer;
66 line->tail = line->buffer;
67 }
68
69 room = write_room(line);
70 len = (len > room) ? room : len;
71
72 end = line->buffer + LINE_BUFSIZE - line->tail;
73 if(len < end){
74 memcpy(line->tail, buf, len);
75 line->tail += len;
76 }
77 else {
78 memcpy(line->tail, buf, end);
79 buf += end;
80 memcpy(line->buffer, buf, len - end);
81 line->tail = line->buffer + len - end;
82 }
83
84 return(len);
85}
86
87static int flush_buffer(struct line *line)
88{
89 int n, count;
90
91 if ((line->buffer == NULL) || (line->head == line->tail))
92 return(1);
93
94 if (line->tail < line->head) {
95 count = line->buffer + LINE_BUFSIZE - line->head;
96 n = write_chan(&line->chan_list, line->head, count,
97 line->driver->write_irq);
98 if (n < 0)
99 return(n);
100 if (n == count)
101 line->head = line->buffer;
102 else {
103 line->head += n;
104 return(0);
105 }
106 }
107
108 count = line->tail - line->head;
109 n = write_chan(&line->chan_list, line->head, count,
110 line->driver->write_irq);
111 if(n < 0) return(n);
112
113 line->head += n;
114 return(line->head == line->tail);
115}
116
117int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
118{
119 struct line *line = tty->driver_data;
120 unsigned long flags;
121 int n, err, ret = 0;
122
123 if(tty->stopped) return 0;
124
125 down(&line->sem);
126 if(line->head != line->tail){
127 local_irq_save(flags);
128 ret = buffer_data(line, buf, len);
129 err = flush_buffer(line);
130 local_irq_restore(flags);
131 if(err <= 0 && (err != -EAGAIN || !ret))
132 ret = err;
133 }
134 else {
135 n = write_chan(&line->chan_list, buf, len,
136 line->driver->write_irq);
137 if(n < 0){
138 ret = n;
139 goto out_up;
140 }
141
142 len -= n;
143 ret += n;
144 if(len > 0)
145 ret += buffer_data(line, buf + n, len);
146 }
147 out_up:
148 up(&line->sem);
149 return(ret);
150}
151
152void line_put_char(struct tty_struct *tty, unsigned char ch)
153{
154 line_write(tty, &ch, sizeof(ch));
155}
156
157void line_set_termios(struct tty_struct *tty, struct termios * old)
158{
159 /* nothing */
160}
161
162int line_chars_in_buffer(struct tty_struct *tty)
163{
164 return 0;
165}
166
167static struct {
168 int cmd;
169 char *level;
170 char *name;
171} tty_ioctls[] = {
172 /* don't print these, they flood the log ... */
173 { TCGETS, NULL, "TCGETS" },
174 { TCSETS, NULL, "TCSETS" },
175 { TCSETSW, NULL, "TCSETSW" },
176 { TCFLSH, NULL, "TCFLSH" },
177 { TCSBRK, NULL, "TCSBRK" },
178
179 /* general tty stuff */
180 { TCSETSF, KERN_DEBUG, "TCSETSF" },
181 { TCGETA, KERN_DEBUG, "TCGETA" },
182 { TIOCMGET, KERN_DEBUG, "TIOCMGET" },
183 { TCSBRKP, KERN_DEBUG, "TCSBRKP" },
184 { TIOCMSET, KERN_DEBUG, "TIOCMSET" },
185
186 /* linux-specific ones */
187 { TIOCLINUX, KERN_INFO, "TIOCLINUX" },
188 { KDGKBMODE, KERN_INFO, "KDGKBMODE" },
189 { KDGKBTYPE, KERN_INFO, "KDGKBTYPE" },
190 { KDSIGACCEPT, KERN_INFO, "KDSIGACCEPT" },
191};
192
193int line_ioctl(struct tty_struct *tty, struct file * file,
194 unsigned int cmd, unsigned long arg)
195{
196 int ret;
197 int i;
198
199 ret = 0;
200 switch(cmd) {
201#ifdef TIOCGETP
202 case TIOCGETP:
203 case TIOCSETP:
204 case TIOCSETN:
205#endif
206#ifdef TIOCGETC
207 case TIOCGETC:
208 case TIOCSETC:
209#endif
210#ifdef TIOCGLTC
211 case TIOCGLTC:
212 case TIOCSLTC:
213#endif
214 case TCGETS:
215 case TCSETSF:
216 case TCSETSW:
217 case TCSETS:
218 case TCGETA:
219 case TCSETAF:
220 case TCSETAW:
221 case TCSETA:
222 case TCXONC:
223 case TCFLSH:
224 case TIOCOUTQ:
225 case TIOCINQ:
226 case TIOCGLCKTRMIOS:
227 case TIOCSLCKTRMIOS:
228 case TIOCPKT:
229 case TIOCGSOFTCAR:
230 case TIOCSSOFTCAR:
231 return -ENOIOCTLCMD;
232#if 0
233 case TCwhatever:
234 /* do something */
235 break;
236#endif
237 default:
238 for (i = 0; i < ARRAY_SIZE(tty_ioctls); i++)
239 if (cmd == tty_ioctls[i].cmd)
240 break;
241 if (i < ARRAY_SIZE(tty_ioctls)) {
242 if (NULL != tty_ioctls[i].level)
243 printk("%s%s: %s: ioctl %s called\n",
244 tty_ioctls[i].level, __FUNCTION__,
245 tty->name, tty_ioctls[i].name);
246 } else {
247 printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n",
248 __FUNCTION__, tty->name, cmd);
249 }
250 ret = -ENOIOCTLCMD;
251 break;
252 }
253 return(ret);
254}
255
256static irqreturn_t line_write_interrupt(int irq, void *data,
257 struct pt_regs *unused)
258{
259 struct tty_struct *tty = data;
260 struct line *line = tty->driver_data;
261 int err;
262
263 err = flush_buffer(line);
264 if(err == 0)
265 return(IRQ_NONE);
266 else if(err < 0){
267 line->head = line->buffer;
268 line->tail = line->buffer;
269 }
270
271 if(tty == NULL)
272 return(IRQ_NONE);
273
274 if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
275 (tty->ldisc.write_wakeup != NULL))
276 (tty->ldisc.write_wakeup)(tty);
277
278 /* BLOCKING mode
279 * In blocking mode, everything sleeps on tty->write_wait.
280 * Sleeping in the console driver would break non-blocking
281 * writes.
282 */
283
284 if(waitqueue_active(&tty->write_wait))
285 wake_up_interruptible(&tty->write_wait);
286 return(IRQ_HANDLED);
287}
288
289int line_setup_irq(int fd, int input, int output, struct tty_struct *tty)
290{
291 struct line *line = tty->driver_data;
292 struct line_driver *driver = line->driver;
293 int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM;
294
295 if(input) err = um_request_irq(driver->read_irq, fd, IRQ_READ,
296 line_interrupt, flags,
297 driver->read_irq_name, tty);
298 if(err) return(err);
299 if(output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
300 line_write_interrupt, flags,
301 driver->write_irq_name, tty);
302 line->have_irq = 1;
303 return(err);
304}
305
306void line_disable(struct tty_struct *tty, int current_irq)
307{
308 struct line *line = tty->driver_data;
309
310 if(!line->have_irq)
311 return;
312
313 if(line->driver->read_irq == current_irq)
314 free_irq_later(line->driver->read_irq, tty);
315 else {
316 free_irq_by_irq_and_dev(line->driver->read_irq, tty);
317 free_irq(line->driver->read_irq, tty);
318 }
319
320 if(line->driver->write_irq == current_irq)
321 free_irq_later(line->driver->write_irq, tty);
322 else {
323 free_irq_by_irq_and_dev(line->driver->write_irq, tty);
324 free_irq(line->driver->write_irq, tty);
325 }
326
327 line->have_irq = 0;
328}
329
330int line_open(struct line *lines, struct tty_struct *tty,
331 struct chan_opts *opts)
332{
333 struct line *line;
334 int err = 0;
335
336 line = &lines[tty->index];
337 tty->driver_data = line;
338
339 down(&line->sem);
340 if (tty->count == 1) {
341 if (!line->valid) {
342 err = -ENODEV;
343 goto out;
344 }
345 if (list_empty(&line->chan_list)) {
346 err = parse_chan_pair(line->init_str, &line->chan_list,
347 line->init_pri, tty->index, opts);
348 if(err) goto out;
349 err = open_chan(&line->chan_list);
350 if(err) goto out;
351 }
352 enable_chan(&line->chan_list, tty);
353 INIT_WORK(&line->task, line_timer_cb, tty);
354 }
355
356 if(!line->sigio){
357 chan_enable_winch(&line->chan_list, tty);
358 line->sigio = 1;
359 }
360 chan_window_size(&line->chan_list, &tty->winsize.ws_row,
361 &tty->winsize.ws_col);
362 line->count++;
363
364out:
365 up(&line->sem);
366 return(err);
367}
368
369void line_close(struct tty_struct *tty, struct file * filp)
370{
371 struct line *line = tty->driver_data;
372
373 down(&line->sem);
374 line->count--;
375 if (tty->count == 1) {
376 line_disable(tty, -1);
377 tty->driver_data = NULL;
378 }
379 up(&line->sem);
380}
381
382void close_lines(struct line *lines, int nlines)
383{
384 int i;
385
386 for(i = 0; i < nlines; i++)
387 close_chan(&lines[i].chan_list);
388}
389
390int line_setup(struct line *lines, int num, char *init, int all_allowed)
391{
392 int i, n;
393 char *end;
394
395 if(*init == '=') n = -1;
396 else {
397 n = simple_strtoul(init, &end, 0);
398 if(*end != '='){
399 printk(KERN_ERR "line_setup failed to parse \"%s\"\n",
400 init);
401 return(0);
402 }
403 init = end;
404 }
405 init++;
406 if((n >= 0) && (n >= num)){
407 printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
408 n, num - 1);
409 return(0);
410 }
411 else if (n >= 0){
412 if (lines[n].count > 0) {
413 printk("line_setup - device %d is open\n", n);
414 return(0);
415 }
416 if (lines[n].init_pri <= INIT_ONE){
417 lines[n].init_pri = INIT_ONE;
418 if (!strcmp(init, "none"))
419 lines[n].valid = 0;
420 else {
421 lines[n].init_str = init;
422 lines[n].valid = 1;
423 }
424 }
425 }
426 else if(!all_allowed){
427 printk("line_setup - can't configure all devices from "
428 "mconsole\n");
429 return(0);
430 }
431 else {
432 for(i = 0; i < num; i++){
433 if(lines[i].init_pri <= INIT_ALL){
434 lines[i].init_pri = INIT_ALL;
435 if(!strcmp(init, "none")) lines[i].valid = 0;
436 else {
437 lines[i].init_str = init;
438 lines[i].valid = 1;
439 }
440 }
441 }
442 }
443 return(1);
444}
445
446int line_config(struct line *lines, int num, char *str)
447{
448 char *new = uml_strdup(str);
449
450 if(new == NULL){
451 printk("line_config - uml_strdup failed\n");
452 return(-ENOMEM);
453 }
454 return(!line_setup(lines, num, new, 0));
455}
456
457int line_get_config(char *name, struct line *lines, int num, char *str,
458 int size, char **error_out)
459{
460 struct line *line;
461 char *end;
462 int dev, n = 0;
463
464 dev = simple_strtoul(name, &end, 0);
465 if((*end != '\0') || (end == name)){
466 *error_out = "line_get_config failed to parse device number";
467 return(0);
468 }
469
470 if((dev < 0) || (dev >= num)){
471 *error_out = "device number of of range";
472 return(0);
473 }
474
475 line = &lines[dev];
476
477 down(&line->sem);
478 if(!line->valid)
479 CONFIG_CHUNK(str, size, n, "none", 1);
480 else if(line->count == 0)
481 CONFIG_CHUNK(str, size, n, line->init_str, 1);
482 else n = chan_config_string(&line->chan_list, str, size, error_out);
483 up(&line->sem);
484
485 return(n);
486}
487
488int line_remove(struct line *lines, int num, char *str)
489{
490 char config[sizeof("conxxxx=none\0")];
491
492 sprintf(config, "%s=none", str);
493 return(!line_setup(lines, num, config, 0));
494}
495
496int line_write_room(struct tty_struct *tty)
497{
498 struct line *dev = tty->driver_data;
499 int room;
500
501 if (tty->stopped)
502 return 0;
503 room = write_room(dev);
504 if (0 == room)
505 printk(KERN_DEBUG "%s: %s: no room left in buffer\n",
506 __FUNCTION__,tty->name);
507 return room;
508}
509
510struct tty_driver *line_register_devfs(struct lines *set,
511 struct line_driver *line_driver,
512 struct tty_operations *ops, struct line *lines,
513 int nlines)
514{
515 int i;
516 struct tty_driver *driver = alloc_tty_driver(nlines);
517
518 if (!driver)
519 return NULL;
520
521 driver->driver_name = line_driver->name;
522 driver->name = line_driver->device_name;
523 driver->devfs_name = line_driver->devfs_name;
524 driver->major = line_driver->major;
525 driver->minor_start = line_driver->minor_start;
526 driver->type = line_driver->type;
527 driver->subtype = line_driver->subtype;
528 driver->flags = TTY_DRIVER_REAL_RAW;
529 driver->init_termios = tty_std_termios;
530 tty_set_operations(driver, ops);
531
532 if (tty_register_driver(driver)) {
533 printk("%s: can't register %s driver\n",
534 __FUNCTION__,line_driver->name);
535 put_tty_driver(driver);
536 return NULL;
537 }
538
539 for(i = 0; i < nlines; i++){
540 if(!lines[i].valid)
541 tty_unregister_device(driver, i);
542 }
543
544 mconsole_register_dev(&line_driver->mc);
545 return driver;
546}
547
548void lines_init(struct line *lines, int nlines)
549{
550 struct line *line;
551 int i;
552
553 for(i = 0; i < nlines; i++){
554 line = &lines[i];
555 INIT_LIST_HEAD(&line->chan_list);
556 sema_init(&line->sem, 1);
557 if(line->init_str != NULL){
558 line->init_str = uml_strdup(line->init_str);
559 if(line->init_str == NULL)
560 printk("lines_init - uml_strdup returned "
561 "NULL\n");
562 }
563 }
564}
565
566struct winch {
567 struct list_head list;
568 int fd;
569 int tty_fd;
570 int pid;
571 struct tty_struct *tty;
572};
573
574irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
575{
576 struct winch *winch = data;
577 struct tty_struct *tty;
578 struct line *line;
579 int err;
580 char c;
581
582 if(winch->fd != -1){
583 err = generic_read(winch->fd, &c, NULL);
584 if(err < 0){
585 if(err != -EAGAIN){
586 printk("winch_interrupt : read failed, "
587 "errno = %d\n", -err);
588 printk("fd %d is losing SIGWINCH support\n",
589 winch->tty_fd);
590 return(IRQ_HANDLED);
591 }
592 goto out;
593 }
594 }
595 tty = winch->tty;
596 if (tty != NULL) {
597 line = tty->driver_data;
598 chan_window_size(&line->chan_list,
599 &tty->winsize.ws_row,
600 &tty->winsize.ws_col);
601 kill_pg(tty->pgrp, SIGWINCH, 1);
602 }
603 out:
604 if(winch->fd != -1)
605 reactivate_fd(winch->fd, WINCH_IRQ);
606 return(IRQ_HANDLED);
607}
608
609DECLARE_MUTEX(winch_handler_sem);
610LIST_HEAD(winch_handlers);
611
612void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
613{
614 struct winch *winch;
615
616 down(&winch_handler_sem);
617 winch = kmalloc(sizeof(*winch), GFP_KERNEL);
618 if (winch == NULL) {
619 printk("register_winch_irq - kmalloc failed\n");
620 goto out;
621 }
622 *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
623 .fd = fd,
624 .tty_fd = tty_fd,
625 .pid = pid,
626 .tty = tty });
627 list_add(&winch->list, &winch_handlers);
628 if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
629 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
630 "winch", winch) < 0)
631 printk("register_winch_irq - failed to register IRQ\n");
632 out:
633 up(&winch_handler_sem);
634}
635
636static void winch_cleanup(void)
637{
638 struct list_head *ele;
639 struct winch *winch;
640
641 list_for_each(ele, &winch_handlers){
642 winch = list_entry(ele, struct winch, list);
643 if(winch->fd != -1){
644 deactivate_fd(winch->fd, WINCH_IRQ);
645 os_close_file(winch->fd);
646 }
647 if(winch->pid != -1)
648 os_kill_process(winch->pid, 1);
649 }
650}
651__uml_exitcall(winch_cleanup);
652
653char *add_xterm_umid(char *base)
654{
655 char *umid, *title;
656 int len;
657
658 umid = get_umid(1);
659 if(umid == NULL) return(base);
660
661 len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
662 title = kmalloc(len, GFP_KERNEL);
663 if(title == NULL){
664 printk("Failed to allocate buffer for xterm title\n");
665 return(base);
666 }
667
668 snprintf(title, len, "%s (%s)", base, umid);
669 return(title);
670}
671
672/*
673 * Overrides for Emacs so that we follow Linus's tabbing style.
674 * Emacs will notice this stuff at the end of the file and automatically
675 * adjust the settings for this buffer only. This must remain at the end
676 * of the file.
677 * ---------------------------------------------------------------------------
678 * Local variables:
679 * c-file-style: "linux"
680 * End:
681 */
diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h
new file mode 100644
index 000000000000..a2c6db243458
--- /dev/null
+++ b/arch/um/drivers/mcast.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "net_user.h"
7
8struct mcast_data {
9 char *addr;
10 unsigned short port;
11 void *mcast_addr;
12 int ttl;
13 void *dev;
14};
15
16extern struct net_user_info mcast_user_info;
17
18extern int mcast_user_write(int fd, void *buf, int len,
19 struct mcast_data *pri);
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/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
new file mode 100644
index 000000000000..faf714e87b5b
--- /dev/null
+++ b/arch/um/drivers/mcast_kern.c
@@ -0,0 +1,143 @@
1/*
2 * user-mode-linux networking multicast transport
3 * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
4 *
5 * based on the existing uml-networking code, which is
6 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
7 * James Leu (jleu@mindspring.net).
8 * Copyright (C) 2001 by various other people who didn't put their name here.
9 *
10 * Licensed under the GPL.
11 */
12
13#include "linux/kernel.h"
14#include "linux/init.h"
15#include "linux/netdevice.h"
16#include "linux/etherdevice.h"
17#include "linux/in.h"
18#include "linux/inet.h"
19#include "net_kern.h"
20#include "net_user.h"
21#include "mcast.h"
22
23struct mcast_init {
24 char *addr;
25 int port;
26 int ttl;
27};
28
29void mcast_init(struct net_device *dev, void *data)
30{
31 struct uml_net_private *pri;
32 struct mcast_data *dpri;
33 struct mcast_init *init = data;
34
35 pri = dev->priv;
36 dpri = (struct mcast_data *) pri->user;
37 dpri->addr = init->addr;
38 dpri->port = init->port;
39 dpri->ttl = init->ttl;
40 dpri->dev = dev;
41
42 printk("mcast backend ");
43 printk("multicast adddress: %s:%u, TTL:%u ",
44 dpri->addr, dpri->port, dpri->ttl);
45
46 printk("\n");
47}
48
49static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
50{
51 *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
52 if(*skb == NULL) return(-ENOMEM);
53 return(net_recvfrom(fd, (*skb)->mac.raw,
54 (*skb)->dev->mtu + ETH_HEADER_OTHER));
55}
56
57static int mcast_write(int fd, struct sk_buff **skb,
58 struct uml_net_private *lp)
59{
60 return mcast_user_write(fd, (*skb)->data, (*skb)->len,
61 (struct mcast_data *) &lp->user);
62}
63
64static struct net_kern_info mcast_kern_info = {
65 .init = mcast_init,
66 .protocol = eth_protocol,
67 .read = mcast_read,
68 .write = mcast_write,
69};
70
71int mcast_setup(char *str, char **mac_out, void *data)
72{
73 struct mcast_init *init = data;
74 char *port_str = NULL, *ttl_str = NULL, *remain;
75 char *last;
76 int n;
77
78 *init = ((struct mcast_init)
79 { .addr = "239.192.168.1",
80 .port = 1102,
81 .ttl = 1 });
82
83 remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
84 NULL);
85 if(remain != NULL){
86 printk(KERN_ERR "mcast_setup - Extra garbage on "
87 "specification : '%s'\n", remain);
88 return(0);
89 }
90
91 if(port_str != NULL){
92 n = simple_strtoul(port_str, &last, 10);
93 if((*last != '\0') || (last == port_str)){
94 printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
95 port_str);
96 return(0);
97 }
98 init->port = htons(n);
99 }
100
101 if(ttl_str != NULL){
102 init->ttl = simple_strtoul(ttl_str, &last, 10);
103 if((*last != '\0') || (last == ttl_str)){
104 printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
105 ttl_str);
106 return(0);
107 }
108 }
109
110 printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
111 init->port, init->ttl);
112
113 return(1);
114}
115
116static struct transport mcast_transport = {
117 .list = LIST_HEAD_INIT(mcast_transport.list),
118 .name = "mcast",
119 .setup = mcast_setup,
120 .user = &mcast_user_info,
121 .kern = &mcast_kern_info,
122 .private_size = sizeof(struct mcast_data),
123 .setup_size = sizeof(struct mcast_init),
124};
125
126static int register_mcast(void)
127{
128 register_transport(&mcast_transport);
129 return(1);
130}
131
132__initcall(register_mcast);
133
134/*
135 * Overrides for Emacs so that we follow Linus's tabbing style.
136 * Emacs will notice this stuff at the end of the file and automatically
137 * adjust the settings for this buffer only. This must remain at the end
138 * of the file.
139 * ---------------------------------------------------------------------------
140 * Local variables:
141 * c-file-style: "linux"
142 * End:
143 */
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
new file mode 100644
index 000000000000..0fe1d9fa9139
--- /dev/null
+++ b/arch/um/drivers/mcast_user.c
@@ -0,0 +1,177 @@
1/*
2 * user-mode-linux networking multicast transport
3 * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
4 *
5 * based on the existing uml-networking code, which is
6 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
7 * James Leu (jleu@mindspring.net).
8 * Copyright (C) 2001 by various other people who didn't put their name here.
9 *
10 * Licensed under the GPL.
11 *
12 */
13
14#include <errno.h>
15#include <unistd.h>
16#include <linux/inet.h>
17#include <sys/socket.h>
18#include <sys/un.h>
19#include <sys/time.h>
20#include <netinet/in.h>
21#include "net_user.h"
22#include "mcast.h"
23#include "kern_util.h"
24#include "user_util.h"
25#include "user.h"
26#include "os.h"
27
28#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
29
30static struct sockaddr_in *new_addr(char *addr, unsigned short port)
31{
32 struct sockaddr_in *sin;
33
34 sin = um_kmalloc(sizeof(struct sockaddr_in));
35 if(sin == NULL){
36 printk("new_addr: allocation of sockaddr_in failed\n");
37 return(NULL);
38 }
39 sin->sin_family = AF_INET;
40 sin->sin_addr.s_addr = in_aton(addr);
41 sin->sin_port = port;
42 return(sin);
43}
44
45static void mcast_user_init(void *data, void *dev)
46{
47 struct mcast_data *pri = data;
48
49 pri->mcast_addr = new_addr(pri->addr, pri->port);
50 pri->dev = dev;
51}
52
53static int mcast_open(void *data)
54{
55 struct mcast_data *pri = data;
56 struct sockaddr_in *sin = pri->mcast_addr;
57 struct ip_mreq mreq;
58 int fd, yes = 1;
59
60
61 if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) {
62 fd = -EINVAL;
63 goto out;
64 }
65
66 fd = socket(AF_INET, SOCK_DGRAM, 0);
67 if (fd < 0){
68 printk("mcast_open : data socket failed, errno = %d\n",
69 errno);
70 fd = -ENOMEM;
71 goto out;
72 }
73
74 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
75 printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
76 errno);
77 os_close_file(fd);
78 fd = -EINVAL;
79 goto out;
80 }
81
82 /* set ttl according to config */
83 if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
84 sizeof(pri->ttl)) < 0) {
85 printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
86 errno);
87 os_close_file(fd);
88 fd = -EINVAL;
89 goto out;
90 }
91
92 /* set LOOP, so data does get fed back to local sockets */
93 if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
94 printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
95 errno);
96 os_close_file(fd);
97 fd = -EINVAL;
98 goto out;
99 }
100
101 /* bind socket to mcast address */
102 if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
103 printk("mcast_open : data bind failed, errno = %d\n", errno);
104 os_close_file(fd);
105 fd = -EINVAL;
106 goto out;
107 }
108
109 /* subscribe to the multicast group */
110 mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
111 mreq.imr_interface.s_addr = 0;
112 if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
113 &mreq, sizeof(mreq)) < 0) {
114 printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n",
115 errno);
116 printk("There appears not to be a multicast-capable network "
117 "interface on the host.\n");
118 printk("eth0 should be configured in order to use the "
119 "multicast transport.\n");
120 os_close_file(fd);
121 fd = -EINVAL;
122 }
123
124 out:
125 return(fd);
126}
127
128static void mcast_close(int fd, void *data)
129{
130 struct ip_mreq mreq;
131 struct mcast_data *pri = data;
132 struct sockaddr_in *sin = pri->mcast_addr;
133
134 mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
135 mreq.imr_interface.s_addr = 0;
136 if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
137 &mreq, sizeof(mreq)) < 0) {
138 printk("mcast_open: IP_DROP_MEMBERSHIP failed, error = %d\n",
139 errno);
140 }
141
142 os_close_file(fd);
143}
144
145int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
146{
147 struct sockaddr_in *data_addr = pri->mcast_addr;
148
149 return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
150}
151
152static int mcast_set_mtu(int mtu, void *data)
153{
154 return(mtu);
155}
156
157struct net_user_info mcast_user_info = {
158 .init = mcast_user_init,
159 .open = mcast_open,
160 .close = mcast_close,
161 .remove = NULL,
162 .set_mtu = mcast_set_mtu,
163 .add_address = NULL,
164 .delete_address = NULL,
165 .max_packet = MAX_PACKET - ETH_HEADER_OTHER
166};
167
168/*
169 * Overrides for Emacs so that we follow Linus's tabbing style.
170 * Emacs will notice this stuff at the end of the file and automatically
171 * adjust the settings for this buffer only. This must remain at the end
172 * of the file.
173 * ---------------------------------------------------------------------------
174 * Local variables:
175 * c-file-style: "linux"
176 * End:
177 */
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
new file mode 100644
index 000000000000..d7c7adcc0a67
--- /dev/null
+++ b/arch/um/drivers/mconsole_kern.c
@@ -0,0 +1,619 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
3 * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
4 * Licensed under the GPL
5 */
6
7#include "linux/kernel.h"
8#include "linux/slab.h"
9#include "linux/init.h"
10#include "linux/notifier.h"
11#include "linux/reboot.h"
12#include "linux/utsname.h"
13#include "linux/ctype.h"
14#include "linux/interrupt.h"
15#include "linux/sysrq.h"
16#include "linux/workqueue.h"
17#include "linux/module.h"
18#include "linux/file.h"
19#include "linux/fs.h"
20#include "linux/namei.h"
21#include "linux/proc_fs.h"
22#include "linux/syscalls.h"
23#include "asm/irq.h"
24#include "asm/uaccess.h"
25#include "user_util.h"
26#include "kern_util.h"
27#include "kern.h"
28#include "mconsole.h"
29#include "mconsole_kern.h"
30#include "irq_user.h"
31#include "init.h"
32#include "os.h"
33#include "umid.h"
34#include "irq_kern.h"
35
36static int do_unlink_socket(struct notifier_block *notifier,
37 unsigned long what, void *data)
38{
39 return(mconsole_unlink_socket());
40}
41
42
43static struct notifier_block reboot_notifier = {
44 .notifier_call = do_unlink_socket,
45 .priority = 0,
46};
47
48/* Safe without explicit locking for now. Tasklets provide their own
49 * locking, and the interrupt handler is safe because it can't interrupt
50 * itself and it can only happen on CPU 0.
51 */
52
53LIST_HEAD(mc_requests);
54
55static void mc_work_proc(void *unused)
56{
57 struct mconsole_entry *req;
58 unsigned long flags;
59
60 while(!list_empty(&mc_requests)){
61 local_save_flags(flags);
62 req = list_entry(mc_requests.next, struct mconsole_entry,
63 list);
64 list_del(&req->list);
65 local_irq_restore(flags);
66 req->request.cmd->handler(&req->request);
67 kfree(req);
68 }
69}
70
71DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
72
73static irqreturn_t mconsole_interrupt(int irq, void *dev_id,
74 struct pt_regs *regs)
75{
76 /* long to avoid size mismatch warnings from gcc */
77 long fd;
78 struct mconsole_entry *new;
79 struct mc_request req;
80
81 fd = (long) dev_id;
82 while (mconsole_get_request(fd, &req)){
83 if(req.cmd->context == MCONSOLE_INTR)
84 (*req.cmd->handler)(&req);
85 else {
86 new = kmalloc(sizeof(*new), GFP_ATOMIC);
87 if(new == NULL)
88 mconsole_reply(&req, "Out of memory", 1, 0);
89 else {
90 new->request = req;
91 list_add(&new->list, &mc_requests);
92 }
93 }
94 }
95 if(!list_empty(&mc_requests))
96 schedule_work(&mconsole_work);
97 reactivate_fd(fd, MCONSOLE_IRQ);
98 return(IRQ_HANDLED);
99}
100
101void mconsole_version(struct mc_request *req)
102{
103 char version[256];
104
105 sprintf(version, "%s %s %s %s %s", system_utsname.sysname,
106 system_utsname.nodename, system_utsname.release,
107 system_utsname.version, system_utsname.machine);
108 mconsole_reply(req, version, 0, 0);
109}
110
111void mconsole_log(struct mc_request *req)
112{
113 int len;
114 char *ptr = req->request.data;
115
116 ptr += strlen("log ");
117
118 len = req->len - (ptr - req->request.data);
119 printk("%.*s", len, ptr);
120 mconsole_reply(req, "", 0, 0);
121}
122
123/* This is a more convoluted version of mconsole_proc, which has some stability
124 * problems; however, we need it fixed, because it is expected that UML users
125 * mount HPPFS instead of procfs on /proc. And we want mconsole_proc to still
126 * show the real procfs content, not the ones from hppfs.*/
127#if 0
128void mconsole_proc(struct mc_request *req)
129{
130 struct nameidata nd;
131 struct file_system_type *proc;
132 struct super_block *super;
133 struct file *file;
134 int n, err;
135 char *ptr = req->request.data, *buf;
136
137 ptr += strlen("proc");
138 while(isspace(*ptr)) ptr++;
139
140 proc = get_fs_type("proc");
141 if(proc == NULL){
142 mconsole_reply(req, "procfs not registered", 1, 0);
143 goto out;
144 }
145
146 super = (*proc->get_sb)(proc, 0, NULL, NULL);
147 put_filesystem(proc);
148 if(super == NULL){
149 mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
150 goto out;
151 }
152 up_write(&super->s_umount);
153
154 nd.dentry = super->s_root;
155 nd.mnt = NULL;
156 nd.flags = O_RDONLY + 1;
157 nd.last_type = LAST_ROOT;
158
159 /* START: it was experienced that the stability problems are closed
160 * if commenting out these two calls + the below read cycle. To
161 * make UML crash again, it was enough to readd either one.*/
162 err = link_path_walk(ptr, &nd);
163 if(err){
164 mconsole_reply(req, "Failed to look up file", 1, 0);
165 goto out_kill;
166 }
167
168 file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
169 if(IS_ERR(file)){
170 mconsole_reply(req, "Failed to open file", 1, 0);
171 goto out_kill;
172 }
173 /*END*/
174
175 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
176 if(buf == NULL){
177 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
178 goto out_fput;
179 }
180
181 if((file->f_op != NULL) && (file->f_op->read != NULL)){
182 do {
183 n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
184 &file->f_pos);
185 if(n >= 0){
186 buf[n] = '\0';
187 mconsole_reply(req, buf, 0, (n > 0));
188 }
189 else {
190 mconsole_reply(req, "Read of file failed",
191 1, 0);
192 goto out_free;
193 }
194 } while(n > 0);
195 }
196 else mconsole_reply(req, "", 0, 0);
197
198 out_free:
199 kfree(buf);
200 out_fput:
201 fput(file);
202 out_kill:
203 deactivate_super(super);
204 out: ;
205}
206#endif
207
208void mconsole_proc(struct mc_request *req)
209{
210 char path[64];
211 char *buf;
212 int len;
213 int fd;
214 int first_chunk = 1;
215 char *ptr = req->request.data;
216
217 ptr += strlen("proc");
218 while(isspace(*ptr)) ptr++;
219 snprintf(path, sizeof(path), "/proc/%s", ptr);
220
221 fd = sys_open(path, 0, 0);
222 if (fd < 0) {
223 mconsole_reply(req, "Failed to open file", 1, 0);
224 printk("open %s: %d\n",path,fd);
225 goto out;
226 }
227
228 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
229 if(buf == NULL){
230 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
231 goto out_close;
232 }
233
234 for (;;) {
235 len = sys_read(fd, buf, PAGE_SIZE-1);
236 if (len < 0) {
237 mconsole_reply(req, "Read of file failed", 1, 0);
238 goto out_free;
239 }
240 /*Begin the file content on his own line.*/
241 if (first_chunk) {
242 mconsole_reply(req, "\n", 0, 1);
243 first_chunk = 0;
244 }
245 if (len == PAGE_SIZE-1) {
246 buf[len] = '\0';
247 mconsole_reply(req, buf, 0, 1);
248 } else {
249 buf[len] = '\0';
250 mconsole_reply(req, buf, 0, 0);
251 break;
252 }
253 }
254
255 out_free:
256 kfree(buf);
257 out_close:
258 sys_close(fd);
259 out:
260 /* nothing */;
261}
262
263#define UML_MCONSOLE_HELPTEXT \
264"Commands: \n\
265 version - Get kernel version \n\
266 help - Print this message \n\
267 halt - Halt UML \n\
268 reboot - Reboot UML \n\
269 config <dev>=<config> - Add a new device to UML; \n\
270 same syntax as command line \n\
271 config <dev> - Query the configuration of a device \n\
272 remove <dev> - Remove a device from UML \n\
273 sysrq <letter> - Performs the SysRq action controlled by the letter \n\
274 cad - invoke the Ctl-Alt-Del handler \n\
275 stop - pause the UML; it will do nothing until it receives a 'go' \n\
276 go - continue the UML after a 'stop' \n\
277 log <string> - make UML enter <string> into the kernel log\n\
278 proc <file> - returns the contents of the UML's /proc/<file>\n\
279"
280
281void mconsole_help(struct mc_request *req)
282{
283 mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
284}
285
286void mconsole_halt(struct mc_request *req)
287{
288 mconsole_reply(req, "", 0, 0);
289 machine_halt();
290}
291
292void mconsole_reboot(struct mc_request *req)
293{
294 mconsole_reply(req, "", 0, 0);
295 machine_restart(NULL);
296}
297
298extern void ctrl_alt_del(void);
299
300void mconsole_cad(struct mc_request *req)
301{
302 mconsole_reply(req, "", 0, 0);
303 ctrl_alt_del();
304}
305
306void mconsole_go(struct mc_request *req)
307{
308 mconsole_reply(req, "Not stopped", 1, 0);
309}
310
311void mconsole_stop(struct mc_request *req)
312{
313 deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
314 os_set_fd_block(req->originating_fd, 1);
315 mconsole_reply(req, "", 0, 0);
316 while(mconsole_get_request(req->originating_fd, req)){
317 if(req->cmd->handler == mconsole_go) break;
318 (*req->cmd->handler)(req);
319 }
320 os_set_fd_block(req->originating_fd, 0);
321 reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
322 mconsole_reply(req, "", 0, 0);
323}
324
325/* This list is populated by __initcall routines. */
326
327LIST_HEAD(mconsole_devices);
328
329void mconsole_register_dev(struct mc_device *new)
330{
331 list_add(&new->list, &mconsole_devices);
332}
333
334static struct mc_device *mconsole_find_dev(char *name)
335{
336 struct list_head *ele;
337 struct mc_device *dev;
338
339 list_for_each(ele, &mconsole_devices){
340 dev = list_entry(ele, struct mc_device, list);
341 if(!strncmp(name, dev->name, strlen(dev->name)))
342 return(dev);
343 }
344 return(NULL);
345}
346
347#define CONFIG_BUF_SIZE 64
348
349static void mconsole_get_config(int (*get_config)(char *, char *, int,
350 char **),
351 struct mc_request *req, char *name)
352{
353 char default_buf[CONFIG_BUF_SIZE], *error, *buf;
354 int n, size;
355
356 if(get_config == NULL){
357 mconsole_reply(req, "No get_config routine defined", 1, 0);
358 return;
359 }
360
361 error = NULL;
362 size = sizeof(default_buf)/sizeof(default_buf[0]);
363 buf = default_buf;
364
365 while(1){
366 n = (*get_config)(name, buf, size, &error);
367 if(error != NULL){
368 mconsole_reply(req, error, 1, 0);
369 goto out;
370 }
371
372 if(n <= size){
373 mconsole_reply(req, buf, 0, 0);
374 goto out;
375 }
376
377 if(buf != default_buf)
378 kfree(buf);
379
380 size = n;
381 buf = kmalloc(size, GFP_KERNEL);
382 if(buf == NULL){
383 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
384 return;
385 }
386 }
387 out:
388 if(buf != default_buf)
389 kfree(buf);
390
391}
392
393void mconsole_config(struct mc_request *req)
394{
395 struct mc_device *dev;
396 char *ptr = req->request.data, *name;
397 int err;
398
399 ptr += strlen("config");
400 while(isspace(*ptr)) ptr++;
401 dev = mconsole_find_dev(ptr);
402 if(dev == NULL){
403 mconsole_reply(req, "Bad configuration option", 1, 0);
404 return;
405 }
406
407 name = &ptr[strlen(dev->name)];
408 ptr = name;
409 while((*ptr != '=') && (*ptr != '\0'))
410 ptr++;
411
412 if(*ptr == '='){
413 err = (*dev->config)(name);
414 mconsole_reply(req, "", err, 0);
415 }
416 else mconsole_get_config(dev->get_config, req, name);
417}
418
419void mconsole_remove(struct mc_request *req)
420{
421 struct mc_device *dev;
422 char *ptr = req->request.data;
423 int err;
424
425 ptr += strlen("remove");
426 while(isspace(*ptr)) ptr++;
427 dev = mconsole_find_dev(ptr);
428 if(dev == NULL){
429 mconsole_reply(req, "Bad remove option", 1, 0);
430 return;
431 }
432 err = (*dev->remove)(&ptr[strlen(dev->name)]);
433 mconsole_reply(req, "", err, 0);
434}
435
436#ifdef CONFIG_MAGIC_SYSRQ
437void mconsole_sysrq(struct mc_request *req)
438{
439 char *ptr = req->request.data;
440
441 ptr += strlen("sysrq");
442 while(isspace(*ptr)) ptr++;
443
444 mconsole_reply(req, "", 0, 0);
445 handle_sysrq(*ptr, &current->thread.regs, NULL);
446}
447#else
448void mconsole_sysrq(struct mc_request *req)
449{
450 mconsole_reply(req, "Sysrq not compiled in", 1, 0);
451}
452#endif
453
454/* Changed by mconsole_setup, which is __setup, and called before SMP is
455 * active.
456 */
457static char *notify_socket = NULL;
458
459int mconsole_init(void)
460{
461 /* long to avoid size mismatch warnings from gcc */
462 long sock;
463 int err;
464 char file[256];
465
466 if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
467 snprintf(mconsole_socket_name, sizeof(file), "%s", file);
468
469 sock = os_create_unix_socket(file, sizeof(file), 1);
470 if (sock < 0){
471 printk("Failed to initialize management console\n");
472 return(1);
473 }
474
475 register_reboot_notifier(&reboot_notifier);
476
477 err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
478 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
479 "mconsole", (void *)sock);
480 if (err){
481 printk("Failed to get IRQ for management console\n");
482 return(1);
483 }
484
485 if(notify_socket != NULL){
486 notify_socket = uml_strdup(notify_socket);
487 if(notify_socket != NULL)
488 mconsole_notify(notify_socket, MCONSOLE_SOCKET,
489 mconsole_socket_name,
490 strlen(mconsole_socket_name) + 1);
491 else printk(KERN_ERR "mconsole_setup failed to strdup "
492 "string\n");
493 }
494
495 printk("mconsole (version %d) initialized on %s\n",
496 MCONSOLE_VERSION, mconsole_socket_name);
497 return(0);
498}
499
500__initcall(mconsole_init);
501
502static int write_proc_mconsole(struct file *file, const char __user *buffer,
503 unsigned long count, void *data)
504{
505 char *buf;
506
507 buf = kmalloc(count + 1, GFP_KERNEL);
508 if(buf == NULL)
509 return(-ENOMEM);
510
511 if(copy_from_user(buf, buffer, count)){
512 count = -EFAULT;
513 goto out;
514 }
515
516 buf[count] = '\0';
517
518 mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
519 out:
520 kfree(buf);
521 return(count);
522}
523
524static int create_proc_mconsole(void)
525{
526 struct proc_dir_entry *ent;
527
528 if(notify_socket == NULL) return(0);
529
530 ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
531 if(ent == NULL){
532 printk("create_proc_mconsole : create_proc_entry failed\n");
533 return(0);
534 }
535
536 ent->read_proc = NULL;
537 ent->write_proc = write_proc_mconsole;
538 return(0);
539}
540
541static DEFINE_SPINLOCK(notify_spinlock);
542
543void lock_notify(void)
544{
545 spin_lock(&notify_spinlock);
546}
547
548void unlock_notify(void)
549{
550 spin_unlock(&notify_spinlock);
551}
552
553__initcall(create_proc_mconsole);
554
555#define NOTIFY "=notify:"
556
557static int mconsole_setup(char *str)
558{
559 if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
560 str += strlen(NOTIFY);
561 notify_socket = str;
562 }
563 else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
564 return(1);
565}
566
567__setup("mconsole", mconsole_setup);
568
569__uml_help(mconsole_setup,
570"mconsole=notify:<socket>\n"
571" Requests that the mconsole driver send a message to the named Unix\n"
572" socket containing the name of the mconsole socket. This also serves\n"
573" to notify outside processes when UML has booted far enough to respond\n"
574" to mconsole requests.\n\n"
575);
576
577static int notify_panic(struct notifier_block *self, unsigned long unused1,
578 void *ptr)
579{
580 char *message = ptr;
581
582 if(notify_socket == NULL) return(0);
583
584 mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
585 strlen(message) + 1);
586 return(0);
587}
588
589static struct notifier_block panic_exit_notifier = {
590 .notifier_call = notify_panic,
591 .next = NULL,
592 .priority = 1
593};
594
595static int add_notifier(void)
596{
597 notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
598 return(0);
599}
600
601__initcall(add_notifier);
602
603char *mconsole_notify_socket(void)
604{
605 return(notify_socket);
606}
607
608EXPORT_SYMBOL(mconsole_notify_socket);
609
610/*
611 * Overrides for Emacs so that we follow Linus's tabbing style.
612 * Emacs will notice this stuff at the end of the file and automatically
613 * adjust the settings for this buffer only. This must remain at the end
614 * of the file.
615 * ---------------------------------------------------------------------------
616 * Local variables:
617 * c-file-style: "linux"
618 * End:
619 */
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
new file mode 100644
index 000000000000..fe5afb13252c
--- /dev/null
+++ b/arch/um/drivers/mconsole_user.c
@@ -0,0 +1,215 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
3 * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
4 * Licensed under the GPL
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <errno.h>
10#include <signal.h>
11#include <sys/socket.h>
12#include <sys/types.h>
13#include <sys/uio.h>
14#include <sys/un.h>
15#include <unistd.h>
16#include "user.h"
17#include "mconsole.h"
18#include "umid.h"
19
20static struct mconsole_command commands[] = {
21 { "version", mconsole_version, MCONSOLE_INTR },
22 { "halt", mconsole_halt, MCONSOLE_PROC },
23 { "reboot", mconsole_reboot, MCONSOLE_PROC },
24 { "config", mconsole_config, MCONSOLE_PROC },
25 { "remove", mconsole_remove, MCONSOLE_PROC },
26 { "sysrq", mconsole_sysrq, MCONSOLE_INTR },
27 { "help", mconsole_help, MCONSOLE_INTR },
28 { "cad", mconsole_cad, MCONSOLE_INTR },
29 { "stop", mconsole_stop, MCONSOLE_PROC },
30 { "go", mconsole_go, MCONSOLE_INTR },
31 { "log", mconsole_log, MCONSOLE_INTR },
32 { "proc", mconsole_proc, MCONSOLE_PROC },
33};
34
35/* Initialized in mconsole_init, which is an initcall */
36char mconsole_socket_name[256];
37
38int mconsole_reply_v0(struct mc_request *req, char *reply)
39{
40 struct iovec iov;
41 struct msghdr msg;
42
43 iov.iov_base = reply;
44 iov.iov_len = strlen(reply);
45
46 msg.msg_name = &(req->origin);
47 msg.msg_namelen = req->originlen;
48 msg.msg_iov = &iov;
49 msg.msg_iovlen = 1;
50 msg.msg_control = NULL;
51 msg.msg_controllen = 0;
52 msg.msg_flags = 0;
53
54 return sendmsg(req->originating_fd, &msg, 0);
55}
56
57static struct mconsole_command *mconsole_parse(struct mc_request *req)
58{
59 struct mconsole_command *cmd;
60 int i;
61
62 for(i=0;i<sizeof(commands)/sizeof(commands[0]);i++){
63 cmd = &commands[i];
64 if(!strncmp(req->request.data, cmd->command,
65 strlen(cmd->command))){
66 return(cmd);
67 }
68 }
69 return(NULL);
70}
71
72#define MIN(a,b) ((a)<(b) ? (a):(b))
73
74#define STRINGX(x) #x
75#define STRING(x) STRINGX(x)
76
77int mconsole_get_request(int fd, struct mc_request *req)
78{
79 int len;
80
81 req->originlen = sizeof(req->origin);
82 req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
83 (struct sockaddr *) req->origin, &req->originlen);
84 if (req->len < 0)
85 return 0;
86
87 req->originating_fd = fd;
88
89 if(req->request.magic != MCONSOLE_MAGIC){
90 /* Unversioned request */
91 len = MIN(sizeof(req->request.data) - 1,
92 strlen((char *) &req->request));
93 memmove(req->request.data, &req->request, len);
94 req->request.data[len] = '\0';
95
96 req->request.magic = MCONSOLE_MAGIC;
97 req->request.version = 0;
98 req->request.len = len;
99
100 mconsole_reply_v0(req, "ERR Version 0 mconsole clients are "
101 "not supported by this driver");
102 return(0);
103 }
104
105 if(req->request.len >= MCONSOLE_MAX_DATA){
106 mconsole_reply(req, "Request too large", 1, 0);
107 return(0);
108 }
109 if(req->request.version != MCONSOLE_VERSION){
110 mconsole_reply(req, "This driver only supports version "
111 STRING(MCONSOLE_VERSION) " clients", 1, 0);
112 }
113
114 req->request.data[req->request.len] = '\0';
115 req->cmd = mconsole_parse(req);
116 if(req->cmd == NULL){
117 mconsole_reply(req, "Unknown command", 1, 0);
118 return(0);
119 }
120
121 return(1);
122}
123
124int mconsole_reply(struct mc_request *req, char *str, int err, int more)
125{
126 struct mconsole_reply reply;
127 int total, len, n;
128
129 total = strlen(str);
130 do {
131 reply.err = err;
132
133 /* err can only be true on the first packet */
134 err = 0;
135
136 len = MIN(total, MCONSOLE_MAX_DATA - 1);
137
138 if(len == total) reply.more = more;
139 else reply.more = 1;
140
141 memcpy(reply.data, str, len);
142 reply.data[len] = '\0';
143 total -= len;
144 str += len;
145 reply.len = len + 1;
146
147 len = sizeof(reply) + reply.len - sizeof(reply.data);
148
149 n = sendto(req->originating_fd, &reply, len, 0,
150 (struct sockaddr *) req->origin, req->originlen);
151
152 if(n < 0) return(-errno);
153 } while(total > 0);
154 return(0);
155}
156
157int mconsole_unlink_socket(void)
158{
159 unlink(mconsole_socket_name);
160 return 0;
161}
162
163static int notify_sock = -1;
164
165int mconsole_notify(char *sock_name, int type, const void *data, int len)
166{
167 struct sockaddr_un target;
168 struct mconsole_notify packet;
169 int n, err = 0;
170
171 lock_notify();
172 if(notify_sock < 0){
173 notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0);
174 if(notify_sock < 0){
175 printk("mconsole_notify - socket failed, errno = %d\n",
176 errno);
177 err = -errno;
178 }
179 }
180 unlock_notify();
181
182 if(err)
183 return(err);
184
185 target.sun_family = AF_UNIX;
186 strcpy(target.sun_path, sock_name);
187
188 packet.magic = MCONSOLE_MAGIC;
189 packet.version = MCONSOLE_VERSION;
190 packet.type = type;
191 len = (len > sizeof(packet.data)) ? sizeof(packet.data) : len;
192 packet.len = len;
193 memcpy(packet.data, data, len);
194
195 err = 0;
196 len = sizeof(packet) + packet.len - sizeof(packet.data);
197 n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target,
198 sizeof(target));
199 if(n < 0){
200 printk("mconsole_notify - sendto failed, errno = %d\n", errno);
201 err = -errno;
202 }
203 return(err);
204}
205
206/*
207 * Overrides for Emacs so that we follow Linus's tabbing style.
208 * Emacs will notice this stuff at the end of the file and automatically
209 * adjust the settings for this buffer only. This must remain at the end
210 * of the file.
211 * ---------------------------------------------------------------------------
212 * Local variables:
213 * c-file-style: "linux"
214 * End:
215 */
diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
new file mode 100644
index 000000000000..a63231dffe05
--- /dev/null
+++ b/arch/um/drivers/mmapper_kern.c
@@ -0,0 +1,150 @@
1/*
2 * arch/um/drivers/mmapper_kern.c
3 *
4 * BRIEF MODULE DESCRIPTION
5 *
6 * Copyright (C) 2000 RidgeRun, Inc.
7 * Author: RidgeRun, Inc.
8 * Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
9 *
10 */
11
12#include <linux/types.h>
13#include <linux/kdev_t.h>
14#include <linux/time.h>
15#include <linux/devfs_fs_kernel.h>
16#include <linux/module.h>
17#include <linux/mm.h>
18#include <linux/slab.h>
19#include <linux/init.h>
20#include <linux/smp_lock.h>
21#include <asm/uaccess.h>
22#include <asm/irq.h>
23#include <asm/pgtable.h>
24#include "mem_user.h"
25#include "user_util.h"
26
27/* These are set in mmapper_init, which is called at boot time */
28static unsigned long mmapper_size;
29static unsigned long p_buf = 0;
30static char *v_buf = NULL;
31
32static ssize_t
33mmapper_read(struct file *file, char *buf, size_t count, loff_t *ppos)
34{
35 if(*ppos > mmapper_size)
36 return -EINVAL;
37
38 if(count + *ppos > mmapper_size)
39 count = count + *ppos - mmapper_size;
40
41 if(count < 0)
42 return -EINVAL;
43
44 copy_to_user(buf,&v_buf[*ppos],count);
45
46 return count;
47}
48
49static ssize_t
50mmapper_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
51{
52 if(*ppos > mmapper_size)
53 return -EINVAL;
54
55 if(count + *ppos > mmapper_size)
56 count = count + *ppos - mmapper_size;
57
58 if(count < 0)
59 return -EINVAL;
60
61 copy_from_user(&v_buf[*ppos],buf,count);
62
63 return count;
64}
65
66static int
67mmapper_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
68 unsigned long arg)
69{
70 return(-ENOIOCTLCMD);
71}
72
73static int
74mmapper_mmap(struct file *file, struct vm_area_struct * vma)
75{
76 int ret = -EINVAL;
77 int size;
78
79 lock_kernel();
80 if (vma->vm_pgoff != 0)
81 goto out;
82
83 size = vma->vm_end - vma->vm_start;
84 if(size > mmapper_size) return(-EFAULT);
85
86 /* XXX A comment above remap_pfn_range says it should only be
87 * called when the mm semaphore is held
88 */
89 if (remap_pfn_range(vma, vma->vm_start, p_buf >> PAGE_SHIFT, size,
90 vma->vm_page_prot))
91 goto out;
92 ret = 0;
93out:
94 unlock_kernel();
95 return ret;
96}
97
98static int
99mmapper_open(struct inode *inode, struct file *file)
100{
101 return 0;
102}
103
104static int
105mmapper_release(struct inode *inode, struct file *file)
106{
107 return 0;
108}
109
110static struct file_operations mmapper_fops = {
111 .owner = THIS_MODULE,
112 .read = mmapper_read,
113 .write = mmapper_write,
114 .ioctl = mmapper_ioctl,
115 .mmap = mmapper_mmap,
116 .open = mmapper_open,
117 .release = mmapper_release,
118};
119
120static int __init mmapper_init(void)
121{
122 printk(KERN_INFO "Mapper v0.1\n");
123
124 v_buf = (char *) find_iomem("mmapper", &mmapper_size);
125 if(mmapper_size == 0){
126 printk(KERN_ERR "mmapper_init - find_iomem failed\n");
127 return(0);
128 }
129
130 p_buf = __pa(v_buf);
131
132 devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUGO|S_IWUGO, "mmapper");
133 return(0);
134}
135
136static void mmapper_exit(void)
137{
138}
139
140module_init(mmapper_init);
141module_exit(mmapper_exit);
142
143MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>");
144MODULE_DESCRIPTION("DSPLinux simulator mmapper driver");
145/*
146 * ---------------------------------------------------------------------------
147 * Local variables:
148 * c-file-style: "linux"
149 * End:
150 */
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
new file mode 100644
index 000000000000..4eeaf88c1e97
--- /dev/null
+++ b/arch/um/drivers/net_kern.c
@@ -0,0 +1,896 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
3 * James Leu (jleu@mindspring.net).
4 * Copyright (C) 2001 by various other people who didn't put their name here.
5 * Licensed under the GPL.
6 */
7
8#include "linux/config.h"
9#include "linux/kernel.h"
10#include "linux/netdevice.h"
11#include "linux/rtnetlink.h"
12#include "linux/skbuff.h"
13#include "linux/socket.h"
14#include "linux/spinlock.h"
15#include "linux/module.h"
16#include "linux/init.h"
17#include "linux/etherdevice.h"
18#include "linux/list.h"
19#include "linux/inetdevice.h"
20#include "linux/ctype.h"
21#include "linux/bootmem.h"
22#include "linux/ethtool.h"
23#include "asm/uaccess.h"
24#include "user_util.h"
25#include "kern_util.h"
26#include "net_kern.h"
27#include "net_user.h"
28#include "mconsole_kern.h"
29#include "init.h"
30#include "irq_user.h"
31#include "irq_kern.h"
32
33#define DRIVER_NAME "uml-netdev"
34
35static DEFINE_SPINLOCK(opened_lock);
36LIST_HEAD(opened);
37
38static int uml_net_rx(struct net_device *dev)
39{
40 struct uml_net_private *lp = dev->priv;
41 int pkt_len;
42 struct sk_buff *skb;
43
44 /* If we can't allocate memory, try again next round. */
45 skb = dev_alloc_skb(dev->mtu);
46 if (skb == NULL) {
47 lp->stats.rx_dropped++;
48 return 0;
49 }
50
51 skb->dev = dev;
52 skb_put(skb, dev->mtu);
53 skb->mac.raw = skb->data;
54 pkt_len = (*lp->read)(lp->fd, &skb, lp);
55
56 if (pkt_len > 0) {
57 skb_trim(skb, pkt_len);
58 skb->protocol = (*lp->protocol)(skb);
59 netif_rx(skb);
60
61 lp->stats.rx_bytes += skb->len;
62 lp->stats.rx_packets++;
63 return pkt_len;
64 }
65
66 kfree_skb(skb);
67 return pkt_len;
68}
69
70irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
71{
72 struct net_device *dev = dev_id;
73 struct uml_net_private *lp = dev->priv;
74 int err;
75
76 if(!netif_running(dev))
77 return(IRQ_NONE);
78
79 spin_lock(&lp->lock);
80 while((err = uml_net_rx(dev)) > 0) ;
81 if(err < 0) {
82 printk(KERN_ERR
83 "Device '%s' read returned %d, shutting it down\n",
84 dev->name, err);
85 dev_close(dev);
86 goto out;
87 }
88 reactivate_fd(lp->fd, UM_ETH_IRQ);
89
90 out:
91 spin_unlock(&lp->lock);
92 return(IRQ_HANDLED);
93}
94
95static int uml_net_open(struct net_device *dev)
96{
97 struct uml_net_private *lp = dev->priv;
98 char addr[sizeof("255.255.255.255\0")];
99 int err;
100
101 spin_lock(&lp->lock);
102
103 if(lp->fd >= 0){
104 err = -ENXIO;
105 goto out;
106 }
107
108 if(!lp->have_mac){
109 dev_ip_addr(dev, addr, &lp->mac[2]);
110 set_ether_mac(dev, lp->mac);
111 }
112
113 lp->fd = (*lp->open)(&lp->user);
114 if(lp->fd < 0){
115 err = lp->fd;
116 goto out;
117 }
118
119 err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,
120 SA_INTERRUPT | SA_SHIRQ, dev->name, dev);
121 if(err != 0){
122 printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);
123 if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
124 lp->fd = -1;
125 err = -ENETUNREACH;
126 }
127
128 lp->tl.data = (unsigned long) &lp->user;
129 netif_start_queue(dev);
130
131 /* clear buffer - it can happen that the host side of the interface
132 * is full when we get here. In this case, new data is never queued,
133 * SIGIOs never arrive, and the net never works.
134 */
135 while((err = uml_net_rx(dev)) > 0) ;
136
137 out:
138 spin_unlock(&lp->lock);
139 return(err);
140}
141
142static int uml_net_close(struct net_device *dev)
143{
144 struct uml_net_private *lp = dev->priv;
145
146 netif_stop_queue(dev);
147 spin_lock(&lp->lock);
148
149 free_irq_by_irq_and_dev(dev->irq, dev);
150 free_irq(dev->irq, dev);
151 if(lp->close != NULL)
152 (*lp->close)(lp->fd, &lp->user);
153 lp->fd = -1;
154
155 spin_unlock(&lp->lock);
156 return 0;
157}
158
159static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
160{
161 struct uml_net_private *lp = dev->priv;
162 unsigned long flags;
163 int len;
164
165 netif_stop_queue(dev);
166
167 spin_lock_irqsave(&lp->lock, flags);
168
169 len = (*lp->write)(lp->fd, &skb, lp);
170
171 if(len == skb->len) {
172 lp->stats.tx_packets++;
173 lp->stats.tx_bytes += skb->len;
174 dev->trans_start = jiffies;
175 netif_start_queue(dev);
176
177 /* this is normally done in the interrupt when tx finishes */
178 netif_wake_queue(dev);
179 }
180 else if(len == 0){
181 netif_start_queue(dev);
182 lp->stats.tx_dropped++;
183 }
184 else {
185 netif_start_queue(dev);
186 printk(KERN_ERR "uml_net_start_xmit: failed(%d)\n", len);
187 }
188
189 spin_unlock_irqrestore(&lp->lock, flags);
190
191 dev_kfree_skb(skb);
192
193 return 0;
194}
195
196static struct net_device_stats *uml_net_get_stats(struct net_device *dev)
197{
198 struct uml_net_private *lp = dev->priv;
199 return &lp->stats;
200}
201
202static void uml_net_set_multicast_list(struct net_device *dev)
203{
204 if (dev->flags & IFF_PROMISC) return;
205 else if (dev->mc_count) dev->flags |= IFF_ALLMULTI;
206 else dev->flags &= ~IFF_ALLMULTI;
207}
208
209static void uml_net_tx_timeout(struct net_device *dev)
210{
211 dev->trans_start = jiffies;
212 netif_wake_queue(dev);
213}
214
215static int uml_net_set_mac(struct net_device *dev, void *addr)
216{
217 struct uml_net_private *lp = dev->priv;
218 struct sockaddr *hwaddr = addr;
219
220 spin_lock(&lp->lock);
221 memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
222 spin_unlock(&lp->lock);
223
224 return(0);
225}
226
227static int uml_net_change_mtu(struct net_device *dev, int new_mtu)
228{
229 struct uml_net_private *lp = dev->priv;
230 int err = 0;
231
232 spin_lock(&lp->lock);
233
234 new_mtu = (*lp->set_mtu)(new_mtu, &lp->user);
235 if(new_mtu < 0){
236 err = new_mtu;
237 goto out;
238 }
239
240 dev->mtu = new_mtu;
241
242 out:
243 spin_unlock(&lp->lock);
244 return err;
245}
246
247static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
248{
249 static const struct ethtool_drvinfo info = {
250 .cmd = ETHTOOL_GDRVINFO,
251 .driver = DRIVER_NAME,
252 .version = "42",
253 };
254 void *useraddr;
255 u32 ethcmd;
256
257 switch (cmd) {
258 case SIOCETHTOOL:
259 useraddr = ifr->ifr_data;
260 if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
261 return -EFAULT;
262 switch (ethcmd) {
263 case ETHTOOL_GDRVINFO:
264 if (copy_to_user(useraddr, &info, sizeof(info)))
265 return -EFAULT;
266 return 0;
267 default:
268 return -EOPNOTSUPP;
269 }
270 default:
271 return -EINVAL;
272 }
273}
274
275void uml_net_user_timer_expire(unsigned long _conn)
276{
277#ifdef undef
278 struct connection *conn = (struct connection *)_conn;
279
280 dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn);
281 do_connect(conn);
282#endif
283}
284
285static DEFINE_SPINLOCK(devices_lock);
286static struct list_head devices = LIST_HEAD_INIT(devices);
287
288static struct device_driver uml_net_driver = {
289 .name = DRIVER_NAME,
290 .bus = &platform_bus_type,
291};
292static int driver_registered;
293
294static int eth_configure(int n, void *init, char *mac,
295 struct transport *transport)
296{
297 struct uml_net *device;
298 struct net_device *dev;
299 struct uml_net_private *lp;
300 int save, err, size;
301
302 size = transport->private_size + sizeof(struct uml_net_private) +
303 sizeof(((struct uml_net_private *) 0)->user);
304
305 device = kmalloc(sizeof(*device), GFP_KERNEL);
306 if (device == NULL) {
307 printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
308 return(1);
309 }
310
311 memset(device, 0, sizeof(*device));
312 INIT_LIST_HEAD(&device->list);
313 device->index = n;
314
315 spin_lock(&devices_lock);
316 list_add(&device->list, &devices);
317 spin_unlock(&devices_lock);
318
319 if (setup_etheraddr(mac, device->mac))
320 device->have_mac = 1;
321
322 printk(KERN_INFO "Netdevice %d ", n);
323 if (device->have_mac)
324 printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
325 device->mac[0], device->mac[1],
326 device->mac[2], device->mac[3],
327 device->mac[4], device->mac[5]);
328 printk(": ");
329 dev = alloc_etherdev(size);
330 if (dev == NULL) {
331 printk(KERN_ERR "eth_configure: failed to allocate device\n");
332 return 1;
333 }
334
335 /* sysfs register */
336 if (!driver_registered) {
337 driver_register(&uml_net_driver);
338 driver_registered = 1;
339 }
340 device->pdev.id = n;
341 device->pdev.name = DRIVER_NAME;
342 platform_device_register(&device->pdev);
343 SET_NETDEV_DEV(dev,&device->pdev.dev);
344
345 /* If this name ends up conflicting with an existing registered
346 * netdevice, that is OK, register_netdev{,ice}() will notice this
347 * and fail.
348 */
349 snprintf(dev->name, sizeof(dev->name), "eth%d", n);
350 device->dev = dev;
351
352 (*transport->kern->init)(dev, init);
353
354 dev->mtu = transport->user->max_packet;
355 dev->open = uml_net_open;
356 dev->hard_start_xmit = uml_net_start_xmit;
357 dev->stop = uml_net_close;
358 dev->get_stats = uml_net_get_stats;
359 dev->set_multicast_list = uml_net_set_multicast_list;
360 dev->tx_timeout = uml_net_tx_timeout;
361 dev->set_mac_address = uml_net_set_mac;
362 dev->change_mtu = uml_net_change_mtu;
363 dev->do_ioctl = uml_net_ioctl;
364 dev->watchdog_timeo = (HZ >> 1);
365 dev->irq = UM_ETH_IRQ;
366
367 rtnl_lock();
368 err = register_netdevice(dev);
369 rtnl_unlock();
370 if (err) {
371 device->dev = NULL;
372 /* XXX: should we call ->remove() here? */
373 free_netdev(dev);
374 return 1;
375 }
376 lp = dev->priv;
377
378 /* lp.user is the first four bytes of the transport data, which
379 * has already been initialized. This structure assignment will
380 * overwrite that, so we make sure that .user gets overwritten with
381 * what it already has.
382 */
383 save = lp->user[0];
384 *lp = ((struct uml_net_private)
385 { .list = LIST_HEAD_INIT(lp->list),
386 .dev = dev,
387 .fd = -1,
388 .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
389 .have_mac = device->have_mac,
390 .protocol = transport->kern->protocol,
391 .open = transport->user->open,
392 .close = transport->user->close,
393 .remove = transport->user->remove,
394 .read = transport->kern->read,
395 .write = transport->kern->write,
396 .add_address = transport->user->add_address,
397 .delete_address = transport->user->delete_address,
398 .set_mtu = transport->user->set_mtu,
399 .user = { save } });
400
401 init_timer(&lp->tl);
402 spin_lock_init(&lp->lock);
403 lp->tl.function = uml_net_user_timer_expire;
404 if (lp->have_mac)
405 memcpy(lp->mac, device->mac, sizeof(lp->mac));
406
407 if (transport->user->init)
408 (*transport->user->init)(&lp->user, dev);
409
410 if (device->have_mac)
411 set_ether_mac(dev, device->mac);
412
413 spin_lock(&opened_lock);
414 list_add(&lp->list, &opened);
415 spin_unlock(&opened_lock);
416
417 return(0);
418}
419
420static struct uml_net *find_device(int n)
421{
422 struct uml_net *device;
423 struct list_head *ele;
424
425 spin_lock(&devices_lock);
426 list_for_each(ele, &devices){
427 device = list_entry(ele, struct uml_net, list);
428 if(device->index == n)
429 goto out;
430 }
431 device = NULL;
432 out:
433 spin_unlock(&devices_lock);
434 return(device);
435}
436
437static int eth_parse(char *str, int *index_out, char **str_out)
438{
439 char *end;
440 int n;
441
442 n = simple_strtoul(str, &end, 0);
443 if(end == str){
444 printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str);
445 return(1);
446 }
447 if(n < 0){
448 printk(KERN_ERR "eth_setup: device %d is negative\n", n);
449 return(1);
450 }
451 str = end;
452 if(*str != '='){
453 printk(KERN_ERR
454 "eth_setup: expected '=' after device number\n");
455 return(1);
456 }
457 str++;
458 if(find_device(n)){
459 printk(KERN_ERR "eth_setup: Device %d already configured\n",
460 n);
461 return(1);
462 }
463 if(index_out) *index_out = n;
464 *str_out = str;
465 return(0);
466}
467
468struct eth_init {
469 struct list_head list;
470 char *init;
471 int index;
472};
473
474/* Filled in at boot time. Will need locking if the transports become
475 * modular.
476 */
477struct list_head transports = LIST_HEAD_INIT(transports);
478
479/* Filled in during early boot */
480struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
481
482static int check_transport(struct transport *transport, char *eth, int n,
483 void **init_out, char **mac_out)
484{
485 int len;
486
487 len = strlen(transport->name);
488 if(strncmp(eth, transport->name, len))
489 return(0);
490
491 eth += len;
492 if(*eth == ',')
493 eth++;
494 else if(*eth != '\0')
495 return(0);
496
497 *init_out = kmalloc(transport->setup_size, GFP_KERNEL);
498 if(*init_out == NULL)
499 return(1);
500
501 if(!transport->setup(eth, mac_out, *init_out)){
502 kfree(*init_out);
503 *init_out = NULL;
504 }
505 return(1);
506}
507
508void register_transport(struct transport *new)
509{
510 struct list_head *ele, *next;
511 struct eth_init *eth;
512 void *init;
513 char *mac = NULL;
514 int match;
515
516 list_add(&new->list, &transports);
517
518 list_for_each_safe(ele, next, &eth_cmd_line){
519 eth = list_entry(ele, struct eth_init, list);
520 match = check_transport(new, eth->init, eth->index, &init,
521 &mac);
522 if(!match)
523 continue;
524 else if(init != NULL){
525 eth_configure(eth->index, init, mac, new);
526 kfree(init);
527 }
528 list_del(&eth->list);
529 }
530}
531
532static int eth_setup_common(char *str, int index)
533{
534 struct list_head *ele;
535 struct transport *transport;
536 void *init;
537 char *mac = NULL;
538
539 list_for_each(ele, &transports){
540 transport = list_entry(ele, struct transport, list);
541 if(!check_transport(transport, str, index, &init, &mac))
542 continue;
543 if(init != NULL){
544 eth_configure(index, init, mac, transport);
545 kfree(init);
546 }
547 return(1);
548 }
549 return(0);
550}
551
552static int eth_setup(char *str)
553{
554 struct eth_init *new;
555 int n, err;
556
557 err = eth_parse(str, &n, &str);
558 if(err) return(1);
559
560 new = alloc_bootmem(sizeof(new));
561 if (new == NULL){
562 printk("eth_init : alloc_bootmem failed\n");
563 return(1);
564 }
565
566 INIT_LIST_HEAD(&new->list);
567 new->index = n;
568 new->init = str;
569
570 list_add_tail(&new->list, &eth_cmd_line);
571 return(1);
572}
573
574__setup("eth", eth_setup);
575__uml_help(eth_setup,
576"eth[0-9]+=<transport>,<options>\n"
577" Configure a network device.\n\n"
578);
579
580#if 0
581static int eth_init(void)
582{
583 struct list_head *ele, *next;
584 struct eth_init *eth;
585
586 list_for_each_safe(ele, next, &eth_cmd_line){
587 eth = list_entry(ele, struct eth_init, list);
588
589 if(eth_setup_common(eth->init, eth->index))
590 list_del(&eth->list);
591 }
592
593 return(1);
594}
595__initcall(eth_init);
596#endif
597
598static int net_config(char *str)
599{
600 int n, err;
601
602 err = eth_parse(str, &n, &str);
603 if(err) return(err);
604
605 str = uml_strdup(str);
606 if(str == NULL){
607 printk(KERN_ERR "net_config failed to strdup string\n");
608 return(-1);
609 }
610 err = !eth_setup_common(str, n);
611 if(err)
612 kfree(str);
613 return(err);
614}
615
616static int net_remove(char *str)
617{
618 struct uml_net *device;
619 struct net_device *dev;
620 struct uml_net_private *lp;
621 char *end;
622 int n;
623
624 n = simple_strtoul(str, &end, 0);
625 if((*end != '\0') || (end == str))
626 return(-1);
627
628 device = find_device(n);
629 if(device == NULL)
630 return(0);
631
632 dev = device->dev;
633 lp = dev->priv;
634 if(lp->fd > 0) return(-1);
635 if(lp->remove != NULL) (*lp->remove)(&lp->user);
636 unregister_netdev(dev);
637 platform_device_unregister(&device->pdev);
638
639 list_del(&device->list);
640 kfree(device);
641 free_netdev(dev);
642 return(0);
643}
644
645static struct mc_device net_mc = {
646 .name = "eth",
647 .config = net_config,
648 .get_config = NULL,
649 .remove = net_remove,
650};
651
652static int uml_inetaddr_event(struct notifier_block *this, unsigned long event,
653 void *ptr)
654{
655 struct in_ifaddr *ifa = ptr;
656 u32 addr = ifa->ifa_address;
657 u32 netmask = ifa->ifa_mask;
658 struct net_device *dev = ifa->ifa_dev->dev;
659 struct uml_net_private *lp;
660 void (*proc)(unsigned char *, unsigned char *, void *);
661 unsigned char addr_buf[4], netmask_buf[4];
662
663 if(dev->open != uml_net_open) return(NOTIFY_DONE);
664
665 lp = dev->priv;
666
667 proc = NULL;
668 switch (event){
669 case NETDEV_UP:
670 proc = lp->add_address;
671 break;
672 case NETDEV_DOWN:
673 proc = lp->delete_address;
674 break;
675 }
676 if(proc != NULL){
677 addr_buf[0] = addr & 0xff;
678 addr_buf[1] = (addr >> 8) & 0xff;
679 addr_buf[2] = (addr >> 16) & 0xff;
680 addr_buf[3] = addr >> 24;
681 netmask_buf[0] = netmask & 0xff;
682 netmask_buf[1] = (netmask >> 8) & 0xff;
683 netmask_buf[2] = (netmask >> 16) & 0xff;
684 netmask_buf[3] = netmask >> 24;
685 (*proc)(addr_buf, netmask_buf, &lp->user);
686 }
687 return(NOTIFY_DONE);
688}
689
690struct notifier_block uml_inetaddr_notifier = {
691 .notifier_call = uml_inetaddr_event,
692};
693
694static int uml_net_init(void)
695{
696 struct list_head *ele;
697 struct uml_net_private *lp;
698 struct in_device *ip;
699 struct in_ifaddr *in;
700
701 mconsole_register_dev(&net_mc);
702 register_inetaddr_notifier(&uml_inetaddr_notifier);
703
704 /* Devices may have been opened already, so the uml_inetaddr_notifier
705 * didn't get a chance to run for them. This fakes it so that
706 * addresses which have already been set up get handled properly.
707 */
708 list_for_each(ele, &opened){
709 lp = list_entry(ele, struct uml_net_private, list);
710 ip = lp->dev->ip_ptr;
711 if(ip == NULL) continue;
712 in = ip->ifa_list;
713 while(in != NULL){
714 uml_inetaddr_event(NULL, NETDEV_UP, in);
715 in = in->ifa_next;
716 }
717 }
718
719 return(0);
720}
721
722__initcall(uml_net_init);
723
724static void close_devices(void)
725{
726 struct list_head *ele;
727 struct uml_net_private *lp;
728
729 list_for_each(ele, &opened){
730 lp = list_entry(ele, struct uml_net_private, list);
731 if((lp->close != NULL) && (lp->fd >= 0))
732 (*lp->close)(lp->fd, &lp->user);
733 if(lp->remove != NULL) (*lp->remove)(&lp->user);
734 }
735}
736
737__uml_exitcall(close_devices);
738
739int setup_etheraddr(char *str, unsigned char *addr)
740{
741 char *end;
742 int i;
743
744 if(str == NULL)
745 return(0);
746 for(i=0;i<6;i++){
747 addr[i] = simple_strtoul(str, &end, 16);
748 if((end == str) ||
749 ((*end != ':') && (*end != ',') && (*end != '\0'))){
750 printk(KERN_ERR
751 "setup_etheraddr: failed to parse '%s' "
752 "as an ethernet address\n", str);
753 return(0);
754 }
755 str = end + 1;
756 }
757 if(addr[0] & 1){
758 printk(KERN_ERR
759 "Attempt to assign a broadcast ethernet address to a "
760 "device disallowed\n");
761 return(0);
762 }
763 return(1);
764}
765
766void dev_ip_addr(void *d, char *buf, char *bin_buf)
767{
768 struct net_device *dev = d;
769 struct in_device *ip = dev->ip_ptr;
770 struct in_ifaddr *in;
771 u32 addr;
772
773 if((ip == NULL) || ((in = ip->ifa_list) == NULL)){
774 printk(KERN_WARNING "dev_ip_addr - device not assigned an "
775 "IP address\n");
776 return;
777 }
778 addr = in->ifa_address;
779 sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff,
780 (addr >> 16) & 0xff, addr >> 24);
781 if(bin_buf){
782 bin_buf[0] = addr & 0xff;
783 bin_buf[1] = (addr >> 8) & 0xff;
784 bin_buf[2] = (addr >> 16) & 0xff;
785 bin_buf[3] = addr >> 24;
786 }
787}
788
789void set_ether_mac(void *d, unsigned char *addr)
790{
791 struct net_device *dev = d;
792
793 memcpy(dev->dev_addr, addr, ETH_ALEN);
794}
795
796struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
797{
798 if((skb != NULL) && (skb_tailroom(skb) < extra)){
799 struct sk_buff *skb2;
800
801 skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
802 dev_kfree_skb(skb);
803 skb = skb2;
804 }
805 if(skb != NULL) skb_put(skb, extra);
806 return(skb);
807}
808
809void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *,
810 void *),
811 void *arg)
812{
813 struct net_device *dev = d;
814 struct in_device *ip = dev->ip_ptr;
815 struct in_ifaddr *in;
816 unsigned char address[4], netmask[4];
817
818 if(ip == NULL) return;
819 in = ip->ifa_list;
820 while(in != NULL){
821 address[0] = in->ifa_address & 0xff;
822 address[1] = (in->ifa_address >> 8) & 0xff;
823 address[2] = (in->ifa_address >> 16) & 0xff;
824 address[3] = in->ifa_address >> 24;
825 netmask[0] = in->ifa_mask & 0xff;
826 netmask[1] = (in->ifa_mask >> 8) & 0xff;
827 netmask[2] = (in->ifa_mask >> 16) & 0xff;
828 netmask[3] = in->ifa_mask >> 24;
829 (*cb)(address, netmask, arg);
830 in = in->ifa_next;
831 }
832}
833
834int dev_netmask(void *d, void *m)
835{
836 struct net_device *dev = d;
837 struct in_device *ip = dev->ip_ptr;
838 struct in_ifaddr *in;
839 __u32 *mask_out = m;
840
841 if(ip == NULL)
842 return(1);
843
844 in = ip->ifa_list;
845 if(in == NULL)
846 return(1);
847
848 *mask_out = in->ifa_mask;
849 return(0);
850}
851
852void *get_output_buffer(int *len_out)
853{
854 void *ret;
855
856 ret = (void *) __get_free_pages(GFP_KERNEL, 0);
857 if(ret) *len_out = PAGE_SIZE;
858 else *len_out = 0;
859 return(ret);
860}
861
862void free_output_buffer(void *buffer)
863{
864 free_pages((unsigned long) buffer, 0);
865}
866
867int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out,
868 char **gate_addr)
869{
870 char *remain;
871
872 remain = split_if_spec(str, dev_name, mac_out, gate_addr, NULL);
873 if(remain != NULL){
874 printk("tap_setup_common - Extra garbage on specification : "
875 "'%s'\n", remain);
876 return(1);
877 }
878
879 return(0);
880}
881
882unsigned short eth_protocol(struct sk_buff *skb)
883{
884 return(eth_type_trans(skb, skb->dev));
885}
886
887/*
888 * Overrides for Emacs so that we follow Linus's tabbing style.
889 * Emacs will notice this stuff at the end of the file and automatically
890 * adjust the settings for this buffer only. This must remain at the end
891 * of the file.
892 * ---------------------------------------------------------------------------
893 * Local variables:
894 * c-file-style: "linux"
895 * End:
896 */
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
new file mode 100644
index 000000000000..47229fe4a813
--- /dev/null
+++ b/arch/um/drivers/net_user.c
@@ -0,0 +1,255 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stddef.h>
7#include <stdarg.h>
8#include <unistd.h>
9#include <stdio.h>
10#include <errno.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/socket.h>
14#include <sys/wait.h>
15#include "user.h"
16#include "user_util.h"
17#include "kern_util.h"
18#include "net_user.h"
19#include "helper.h"
20#include "os.h"
21
22int tap_open_common(void *dev, char *gate_addr)
23{
24 int tap_addr[4];
25
26 if(gate_addr == NULL) return(0);
27 if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0],
28 &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){
29 printk("Invalid tap IP address - '%s'\n", gate_addr);
30 return(-EINVAL);
31 }
32 return(0);
33}
34
35void tap_check_ips(char *gate_addr, char *eth_addr)
36{
37 int tap_addr[4];
38
39 if((gate_addr != NULL) &&
40 (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0],
41 &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) &&
42 (eth_addr[0] == tap_addr[0]) &&
43 (eth_addr[1] == tap_addr[1]) &&
44 (eth_addr[2] == tap_addr[2]) &&
45 (eth_addr[3] == tap_addr[3])){
46 printk("The tap IP address and the UML eth IP address"
47 " must be different\n");
48 }
49}
50
51void read_output(int fd, char *output, int len)
52{
53 int remain, n, actual;
54 char c;
55
56 if(output == NULL){
57 output = &c;
58 len = sizeof(c);
59 }
60
61 *output = '\0';
62 n = os_read_file(fd, &remain, sizeof(remain));
63 if(n != sizeof(remain)){
64 printk("read_output - read of length failed, err = %d\n", -n);
65 return;
66 }
67
68 while(remain != 0){
69 n = (remain < len) ? remain : len;
70 actual = os_read_file(fd, output, n);
71 if(actual != n){
72 printk("read_output - read of data failed, "
73 "err = %d\n", -actual);
74 return;
75 }
76 remain -= actual;
77 }
78 return;
79}
80
81int net_read(int fd, void *buf, int len)
82{
83 int n;
84
85 n = os_read_file(fd, buf, len);
86
87 if(n == -EAGAIN)
88 return(0);
89 else if(n == 0)
90 return(-ENOTCONN);
91 return(n);
92}
93
94int net_recvfrom(int fd, void *buf, int len)
95{
96 int n;
97
98 while(((n = recvfrom(fd, buf, len, 0, NULL, NULL)) < 0) &&
99 (errno == EINTR)) ;
100
101 if(n < 0){
102 if(errno == EAGAIN) return(0);
103 return(-errno);
104 }
105 else if(n == 0) return(-ENOTCONN);
106 return(n);
107}
108
109int net_write(int fd, void *buf, int len)
110{
111 int n;
112
113 n = os_write_file(fd, buf, len);
114
115 if(n == -EAGAIN)
116 return(0);
117 else if(n == 0)
118 return(-ENOTCONN);
119 return(n);
120}
121
122int net_send(int fd, void *buf, int len)
123{
124 int n;
125
126 while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ;
127 if(n < 0){
128 if(errno == EAGAIN) return(0);
129 return(-errno);
130 }
131 else if(n == 0) return(-ENOTCONN);
132 return(n);
133}
134
135int net_sendto(int fd, void *buf, int len, void *to, int sock_len)
136{
137 int n;
138
139 while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to,
140 sock_len)) < 0) && (errno == EINTR)) ;
141 if(n < 0){
142 if(errno == EAGAIN) return(0);
143 return(-errno);
144 }
145 else if(n == 0) return(-ENOTCONN);
146 return(n);
147}
148
149struct change_pre_exec_data {
150 int close_me;
151 int stdout;
152};
153
154static void change_pre_exec(void *arg)
155{
156 struct change_pre_exec_data *data = arg;
157
158 os_close_file(data->close_me);
159 dup2(data->stdout, 1);
160}
161
162static int change_tramp(char **argv, char *output, int output_len)
163{
164 int pid, fds[2], err;
165 struct change_pre_exec_data pe_data;
166
167 err = os_pipe(fds, 1, 0);
168 if(err < 0){
169 printk("change_tramp - pipe failed, err = %d\n", -err);
170 return(err);
171 }
172 pe_data.close_me = fds[0];
173 pe_data.stdout = fds[1];
174 pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
175
176 read_output(fds[0], output, output_len);
177 os_close_file(fds[0]);
178 os_close_file(fds[1]);
179
180 if (pid > 0)
181 CATCH_EINTR(err = waitpid(pid, NULL, 0));
182 return(pid);
183}
184
185static void change(char *dev, char *what, unsigned char *addr,
186 unsigned char *netmask)
187{
188 char addr_buf[sizeof("255.255.255.255\0")];
189 char netmask_buf[sizeof("255.255.255.255\0")];
190 char version[sizeof("nnnnn\0")];
191 char *argv[] = { "uml_net", version, what, dev, addr_buf,
192 netmask_buf, NULL };
193 char *output;
194 int output_len, pid;
195
196 sprintf(version, "%d", UML_NET_VERSION);
197 sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
198 sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1],
199 netmask[2], netmask[3]);
200
201 output_len = page_size();
202 output = um_kmalloc(output_len);
203 if(output == NULL)
204 printk("change : failed to allocate output buffer\n");
205
206 pid = change_tramp(argv, output, output_len);
207 if(pid < 0) return;
208
209 if(output != NULL){
210 printk("%s", output);
211 kfree(output);
212 }
213}
214
215void open_addr(unsigned char *addr, unsigned char *netmask, void *arg)
216{
217 change(arg, "add", addr, netmask);
218}
219
220void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
221{
222 change(arg, "del", addr, netmask);
223}
224
225char *split_if_spec(char *str, ...)
226{
227 char **arg, *end;
228 va_list ap;
229
230 va_start(ap, str);
231 while((arg = va_arg(ap, char **)) != NULL){
232 if(*str == '\0')
233 return(NULL);
234 end = strchr(str, ',');
235 if(end != str)
236 *arg = str;
237 if(end == NULL)
238 return(NULL);
239 *end++ = '\0';
240 str = end;
241 }
242 va_end(ap);
243 return(str);
244}
245
246/*
247 * Overrides for Emacs so that we follow Linus's tabbing style.
248 * Emacs will notice this stuff at the end of the file and automatically
249 * adjust the settings for this buffer only. This must remain at the end
250 * of the file.
251 * ---------------------------------------------------------------------------
252 * Local variables:
253 * c-file-style: "linux"
254 * End:
255 */
diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c
new file mode 100644
index 000000000000..14cc5f78398a
--- /dev/null
+++ b/arch/um/drivers/null.c
@@ -0,0 +1,56 @@
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 "chan_user.h"
9#include "os.h"
10
11static int null_chan;
12
13static void *null_init(char *str, int device, struct chan_opts *opts)
14{
15 return(&null_chan);
16}
17
18static int null_open(int input, int output, int primary, void *d,
19 char **dev_out)
20{
21 *dev_out = NULL;
22 return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0));
23}
24
25static int null_read(int fd, char *c_out, void *unused)
26{
27 return(-ENODEV);
28}
29
30static void null_free(void *data)
31{
32}
33
34struct chan_ops null_ops = {
35 .type = "null",
36 .init = null_init,
37 .open = null_open,
38 .close = generic_close,
39 .read = null_read,
40 .write = generic_write,
41 .console_write = generic_console_write,
42 .window_size = generic_window_size,
43 .free = null_free,
44 .winch = 0,
45};
46
47/*
48 * Overrides for Emacs so that we follow Linus's tabbing style.
49 * Emacs will notice this stuff at the end of the file and automatically
50 * adjust the settings for this buffer only. This must remain at the end
51 * of the file.
52 * ---------------------------------------------------------------------------
53 * Local variables:
54 * c-file-style: "linux"
55 * End:
56 */
diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c
new file mode 100644
index 000000000000..07c80f2156ef
--- /dev/null
+++ b/arch/um/drivers/pcap_kern.c
@@ -0,0 +1,123 @@
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/netdevice.h"
8#include "linux/etherdevice.h"
9#include "net_kern.h"
10#include "net_user.h"
11#include "pcap_user.h"
12
13struct pcap_init {
14 char *host_if;
15 int promisc;
16 int optimize;
17 char *filter;
18};
19
20void pcap_init(struct net_device *dev, void *data)
21{
22 struct uml_net_private *pri;
23 struct pcap_data *ppri;
24 struct pcap_init *init = data;
25
26 pri = dev->priv;
27 ppri = (struct pcap_data *) pri->user;
28 ppri->host_if = init->host_if;
29 ppri->promisc = init->promisc;
30 ppri->optimize = init->optimize;
31 ppri->filter = init->filter;
32}
33
34static int pcap_read(int fd, struct sk_buff **skb,
35 struct uml_net_private *lp)
36{
37 *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
38 if(*skb == NULL) return(-ENOMEM);
39 return(pcap_user_read(fd, (*skb)->mac.raw,
40 (*skb)->dev->mtu + ETH_HEADER_OTHER,
41 (struct pcap_data *) &lp->user));
42}
43
44static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
45{
46 return(-EPERM);
47}
48
49static struct net_kern_info pcap_kern_info = {
50 .init = pcap_init,
51 .protocol = eth_protocol,
52 .read = pcap_read,
53 .write = pcap_write,
54};
55
56int pcap_setup(char *str, char **mac_out, void *data)
57{
58 struct pcap_init *init = data;
59 char *remain, *host_if = NULL, *options[2] = { NULL, NULL };
60 int i;
61
62 *init = ((struct pcap_init)
63 { .host_if = "eth0",
64 .promisc = 1,
65 .optimize = 0,
66 .filter = NULL });
67
68 remain = split_if_spec(str, &host_if, &init->filter,
69 &options[0], &options[1], NULL);
70 if(remain != NULL){
71 printk(KERN_ERR "pcap_setup - Extra garbage on "
72 "specification : '%s'\n", remain);
73 return(0);
74 }
75
76 if(host_if != NULL)
77 init->host_if = host_if;
78
79 for(i = 0; i < sizeof(options)/sizeof(options[0]); i++){
80 if(options[i] == NULL)
81 continue;
82 if(!strcmp(options[i], "promisc"))
83 init->promisc = 1;
84 else if(!strcmp(options[i], "nopromisc"))
85 init->promisc = 0;
86 else if(!strcmp(options[i], "optimize"))
87 init->optimize = 1;
88 else if(!strcmp(options[i], "nooptimize"))
89 init->optimize = 0;
90 else printk("pcap_setup : bad option - '%s'\n", options[i]);
91 }
92
93 return(1);
94}
95
96static struct transport pcap_transport = {
97 .list = LIST_HEAD_INIT(pcap_transport.list),
98 .name = "pcap",
99 .setup = pcap_setup,
100 .user = &pcap_user_info,
101 .kern = &pcap_kern_info,
102 .private_size = sizeof(struct pcap_data),
103 .setup_size = sizeof(struct pcap_init),
104};
105
106static int register_pcap(void)
107{
108 register_transport(&pcap_transport);
109 return(1);
110}
111
112__initcall(register_pcap);
113
114/*
115 * Overrides for Emacs so that we follow Linus's tabbing style.
116 * Emacs will notice this stuff at the end of the file and automatically
117 * adjust the settings for this buffer only. This must remain at the end
118 * of the file.
119 * ---------------------------------------------------------------------------
120 * Local variables:
121 * c-file-style: "linux"
122 * End:
123 */
diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c
new file mode 100644
index 000000000000..edfcb29273e1
--- /dev/null
+++ b/arch/um/drivers/pcap_user.c
@@ -0,0 +1,143 @@
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 <string.h>
9#include <errno.h>
10#include <pcap.h>
11#include <asm/types.h>
12#include "net_user.h"
13#include "pcap_user.h"
14#include "user.h"
15
16#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
17
18#define PCAP_FD(p) (*(int *)(p))
19
20static void pcap_user_init(void *data, void *dev)
21{
22 struct pcap_data *pri = data;
23 pcap_t *p;
24 char errors[PCAP_ERRBUF_SIZE];
25
26 p = pcap_open_live(pri->host_if, MAX_PACKET, pri->promisc, 0, errors);
27 if(p == NULL){
28 printk("pcap_user_init : pcap_open_live failed - '%s'\n",
29 errors);
30 return;
31 }
32
33 pri->dev = dev;
34 pri->pcap = p;
35}
36
37static int pcap_open(void *data)
38{
39 struct pcap_data *pri = data;
40 __u32 netmask;
41 int err;
42
43 if(pri->pcap == NULL)
44 return(-ENODEV);
45
46 if(pri->filter != NULL){
47 err = dev_netmask(pri->dev, &netmask);
48 if(err < 0){
49 printk("pcap_open : dev_netmask failed\n");
50 return(-EIO);
51 }
52
53 pri->compiled = um_kmalloc(sizeof(struct bpf_program));
54 if(pri->compiled == NULL){
55 printk("pcap_open : kmalloc failed\n");
56 return(-ENOMEM);
57 }
58
59 err = pcap_compile(pri->pcap,
60 (struct bpf_program *) pri->compiled,
61 pri->filter, pri->optimize, netmask);
62 if(err < 0){
63 printk("pcap_open : pcap_compile failed - '%s'\n",
64 pcap_geterr(pri->pcap));
65 return(-EIO);
66 }
67
68 err = pcap_setfilter(pri->pcap, pri->compiled);
69 if(err < 0){
70 printk("pcap_open : pcap_setfilter failed - '%s'\n",
71 pcap_geterr(pri->pcap));
72 return(-EIO);
73 }
74 }
75
76 return(PCAP_FD(pri->pcap));
77}
78
79static void pcap_remove(void *data)
80{
81 struct pcap_data *pri = data;
82
83 if(pri->compiled != NULL)
84 pcap_freecode(pri->compiled);
85
86 pcap_close(pri->pcap);
87}
88
89struct pcap_handler_data {
90 char *buffer;
91 int len;
92};
93
94static void handler(u_char *data, const struct pcap_pkthdr *header,
95 const u_char *packet)
96{
97 int len;
98
99 struct pcap_handler_data *hdata = (struct pcap_handler_data *) data;
100
101 len = hdata->len < header->caplen ? hdata->len : header->caplen;
102 memcpy(hdata->buffer, packet, len);
103 hdata->len = len;
104}
105
106int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri)
107{
108 struct pcap_handler_data hdata = ((struct pcap_handler_data)
109 { .buffer = buffer,
110 .len = len });
111 int n;
112
113 n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata);
114 if(n < 0){
115 printk("pcap_dispatch failed - %s\n", pcap_geterr(pri->pcap));
116 return(-EIO);
117 }
118 else if(n == 0)
119 return(0);
120 return(hdata.len);
121}
122
123struct net_user_info pcap_user_info = {
124 .init = pcap_user_init,
125 .open = pcap_open,
126 .close = NULL,
127 .remove = pcap_remove,
128 .set_mtu = NULL,
129 .add_address = NULL,
130 .delete_address = NULL,
131 .max_packet = MAX_PACKET - ETH_HEADER_OTHER
132};
133
134/*
135 * Overrides for Emacs so that we follow Linus's tabbing style.
136 * Emacs will notice this stuff at the end of the file and automatically
137 * adjust the settings for this buffer only. This must remain at the end
138 * of the file.
139 * ---------------------------------------------------------------------------
140 * Local variables:
141 * c-file-style: "linux"
142 * End:
143 */
diff --git a/arch/um/drivers/pcap_user.h b/arch/um/drivers/pcap_user.h
new file mode 100644
index 000000000000..58f9f6a1420f
--- /dev/null
+++ b/arch/um/drivers/pcap_user.h
@@ -0,0 +1,31 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "net_user.h"
7
8struct pcap_data {
9 char *host_if;
10 int promisc;
11 int optimize;
12 char *filter;
13 void *compiled;
14 void *pcap;
15 void *dev;
16};
17
18extern struct net_user_info pcap_user_info;
19
20extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri);
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/drivers/port.h b/arch/um/drivers/port.h
new file mode 100644
index 000000000000..9117609a575d
--- /dev/null
+++ b/arch/um/drivers/port.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __PORT_H__
7#define __PORT_H__
8
9extern void *port_data(int port);
10extern int port_wait(void *data);
11extern void port_kern_close(void *d);
12extern int port_connection(int fd, int *socket_out, int *pid_out);
13extern int port_listen_fd(int port);
14extern void port_read(int fd, void *data);
15extern void port_kern_free(void *d);
16extern int port_rcv_fd(int fd);
17extern void port_remove_dev(void *d);
18
19#endif
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/drivers/port_kern.c b/arch/um/drivers/port_kern.c
new file mode 100644
index 000000000000..b5ee07472f79
--- /dev/null
+++ b/arch/um/drivers/port_kern.c
@@ -0,0 +1,309 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/list.h"
7#include "linux/sched.h"
8#include "linux/slab.h"
9#include "linux/interrupt.h"
10#include "linux/irq.h"
11#include "linux/spinlock.h"
12#include "linux/errno.h"
13#include "asm/atomic.h"
14#include "asm/semaphore.h"
15#include "asm/errno.h"
16#include "kern_util.h"
17#include "kern.h"
18#include "irq_user.h"
19#include "irq_kern.h"
20#include "port.h"
21#include "init.h"
22#include "os.h"
23
24struct port_list {
25 struct list_head list;
26 atomic_t wait_count;
27 int has_connection;
28 struct completion done;
29 int port;
30 int fd;
31 spinlock_t lock;
32 struct list_head pending;
33 struct list_head connections;
34};
35
36struct port_dev {
37 struct port_list *port;
38 int helper_pid;
39 int telnetd_pid;
40};
41
42struct connection {
43 struct list_head list;
44 int fd;
45 int helper_pid;
46 int socket[2];
47 int telnetd_pid;
48 struct port_list *port;
49};
50
51static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs)
52{
53 struct connection *conn = data;
54 int fd;
55
56 fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
57 if(fd < 0){
58 if(fd == -EAGAIN)
59 return(IRQ_NONE);
60
61 printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n",
62 -fd);
63 os_close_file(conn->fd);
64 }
65
66 list_del(&conn->list);
67
68 conn->fd = fd;
69 list_add(&conn->list, &conn->port->connections);
70
71 complete(&conn->port->done);
72 return(IRQ_HANDLED);
73}
74
75#define NO_WAITER_MSG \
76 "****\n" \
77 "There are currently no UML consoles waiting for port connections.\n" \
78 "Either disconnect from one to make it available or activate some more\n" \
79 "by enabling more consoles in the UML /etc/inittab.\n" \
80 "****\n"
81
82static int port_accept(struct port_list *port)
83{
84 struct connection *conn;
85 int fd, socket[2], pid, ret = 0;
86
87 fd = port_connection(port->fd, socket, &pid);
88 if(fd < 0){
89 if(fd != -EAGAIN)
90 printk(KERN_ERR "port_accept : port_connection "
91 "returned %d\n", -fd);
92 goto out;
93 }
94
95 conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
96 if(conn == NULL){
97 printk(KERN_ERR "port_accept : failed to allocate "
98 "connection\n");
99 goto out_close;
100 }
101 *conn = ((struct connection)
102 { .list = LIST_HEAD_INIT(conn->list),
103 .fd = fd,
104 .socket = { socket[0], socket[1] },
105 .telnetd_pid = pid,
106 .port = port });
107
108 if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt,
109 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
110 "telnetd", conn)){
111 printk(KERN_ERR "port_accept : failed to get IRQ for "
112 "telnetd\n");
113 goto out_free;
114 }
115
116 if(atomic_read(&port->wait_count) == 0){
117 os_write_file(fd, NO_WAITER_MSG, sizeof(NO_WAITER_MSG));
118 printk("No one waiting for port\n");
119 }
120 list_add(&conn->list, &port->pending);
121 return(1);
122
123 out_free:
124 kfree(conn);
125 out_close:
126 os_close_file(fd);
127 if(pid != -1)
128 os_kill_process(pid, 1);
129 out:
130 return(ret);
131}
132
133DECLARE_MUTEX(ports_sem);
134struct list_head ports = LIST_HEAD_INIT(ports);
135
136void port_work_proc(void *unused)
137{
138 struct port_list *port;
139 struct list_head *ele;
140 unsigned long flags;
141
142 local_irq_save(flags);
143 list_for_each(ele, &ports){
144 port = list_entry(ele, struct port_list, list);
145 if(!port->has_connection)
146 continue;
147 reactivate_fd(port->fd, ACCEPT_IRQ);
148 while(port_accept(port)) ;
149 port->has_connection = 0;
150 }
151 local_irq_restore(flags);
152}
153
154DECLARE_WORK(port_work, port_work_proc, NULL);
155
156static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs)
157{
158 struct port_list *port = data;
159
160 port->has_connection = 1;
161 schedule_work(&port_work);
162 return(IRQ_HANDLED);
163}
164
165void *port_data(int port_num)
166{
167 struct list_head *ele;
168 struct port_list *port;
169 struct port_dev *dev = NULL;
170 int fd;
171
172 down(&ports_sem);
173 list_for_each(ele, &ports){
174 port = list_entry(ele, struct port_list, list);
175 if(port->port == port_num) goto found;
176 }
177 port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
178 if(port == NULL){
179 printk(KERN_ERR "Allocation of port list failed\n");
180 goto out;
181 }
182
183 fd = port_listen_fd(port_num);
184 if(fd < 0){
185 printk(KERN_ERR "binding to port %d failed, errno = %d\n",
186 port_num, -fd);
187 goto out_free;
188 }
189 if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt,
190 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port",
191 port)){
192 printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
193 goto out_close;
194 }
195
196 *port = ((struct port_list)
197 { .list = LIST_HEAD_INIT(port->list),
198 .wait_count = ATOMIC_INIT(0),
199 .has_connection = 0,
200 .port = port_num,
201 .fd = fd,
202 .pending = LIST_HEAD_INIT(port->pending),
203 .connections = LIST_HEAD_INIT(port->connections) });
204 spin_lock_init(&port->lock);
205 init_completion(&port->done);
206 list_add(&port->list, &ports);
207
208 found:
209 dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
210 if(dev == NULL){
211 printk(KERN_ERR "Allocation of port device entry failed\n");
212 goto out;
213 }
214
215 *dev = ((struct port_dev) { .port = port,
216 .helper_pid = -1,
217 .telnetd_pid = -1 });
218 goto out;
219
220 out_free:
221 kfree(port);
222 out_close:
223 os_close_file(fd);
224 out:
225 up(&ports_sem);
226 return(dev);
227}
228
229int port_wait(void *data)
230{
231 struct port_dev *dev = data;
232 struct connection *conn;
233 struct port_list *port = dev->port;
234 int fd;
235
236 atomic_inc(&port->wait_count);
237 while(1){
238 fd = -ERESTARTSYS;
239 if(wait_for_completion_interruptible(&port->done))
240 goto out;
241
242 spin_lock(&port->lock);
243
244 conn = list_entry(port->connections.next, struct connection,
245 list);
246 list_del(&conn->list);
247 spin_unlock(&port->lock);
248
249 os_shutdown_socket(conn->socket[0], 1, 1);
250 os_close_file(conn->socket[0]);
251 os_shutdown_socket(conn->socket[1], 1, 1);
252 os_close_file(conn->socket[1]);
253
254 /* This is done here because freeing an IRQ can't be done
255 * within the IRQ handler. So, pipe_interrupt always ups
256 * the semaphore regardless of whether it got a successful
257 * connection. Then we loop here throwing out failed
258 * connections until a good one is found.
259 */
260 free_irq_by_irq_and_dev(TELNETD_IRQ, conn);
261 free_irq(TELNETD_IRQ, conn);
262
263 if(conn->fd >= 0) break;
264 os_close_file(conn->fd);
265 kfree(conn);
266 }
267
268 fd = conn->fd;
269 dev->helper_pid = conn->helper_pid;
270 dev->telnetd_pid = conn->telnetd_pid;
271 kfree(conn);
272 out:
273 atomic_dec(&port->wait_count);
274 return fd;
275}
276
277void port_remove_dev(void *d)
278{
279 struct port_dev *dev = d;
280
281 if(dev->helper_pid != -1)
282 os_kill_process(dev->helper_pid, 0);
283 if(dev->telnetd_pid != -1)
284 os_kill_process(dev->telnetd_pid, 1);
285 dev->helper_pid = -1;
286 dev->telnetd_pid = -1;
287}
288
289void port_kern_free(void *d)
290{
291 struct port_dev *dev = d;
292
293 port_remove_dev(dev);
294 kfree(dev);
295}
296
297static void free_port(void)
298{
299 struct list_head *ele;
300 struct port_list *port;
301
302 list_for_each(ele, &ports){
303 port = list_entry(ele, struct port_list, list);
304 free_irq_by_fd(port->fd);
305 os_close_file(port->fd);
306 }
307}
308
309__uml_exitcall(free_port);
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
new file mode 100644
index 000000000000..14dd2002d2da
--- /dev/null
+++ b/arch/um/drivers/port_user.c
@@ -0,0 +1,225 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stddef.h>
8#include <stdlib.h>
9#include <string.h>
10#include <errno.h>
11#include <unistd.h>
12#include <termios.h>
13#include <sys/socket.h>
14#include <sys/un.h>
15#include <netinet/in.h>
16#include "user_util.h"
17#include "kern_util.h"
18#include "user.h"
19#include "chan_user.h"
20#include "port.h"
21#include "helper.h"
22#include "os.h"
23
24struct port_chan {
25 int raw;
26 struct termios tt;
27 void *kernel_data;
28 char dev[sizeof("32768\0")];
29};
30
31static void *port_init(char *str, int device, struct chan_opts *opts)
32{
33 struct port_chan *data;
34 void *kern_data;
35 char *end;
36 int port;
37
38 if(*str != ':'){
39 printk("port_init : channel type 'port' must specify a "
40 "port number\n");
41 return(NULL);
42 }
43 str++;
44 port = strtoul(str, &end, 0);
45 if((*end != '\0') || (end == str)){
46 printk("port_init : couldn't parse port '%s'\n", str);
47 return(NULL);
48 }
49
50 kern_data = port_data(port);
51 if(kern_data == NULL)
52 return(NULL);
53
54 data = um_kmalloc(sizeof(*data));
55 if(data == NULL)
56 goto err;
57
58 *data = ((struct port_chan) { .raw = opts->raw,
59 .kernel_data = kern_data });
60 sprintf(data->dev, "%d", port);
61
62 return(data);
63 err:
64 port_kern_free(kern_data);
65 return(NULL);
66}
67
68static void port_free(void *d)
69{
70 struct port_chan *data = d;
71
72 port_kern_free(data->kernel_data);
73 kfree(data);
74}
75
76static int port_open(int input, int output, int primary, void *d,
77 char **dev_out)
78{
79 struct port_chan *data = d;
80 int fd, err;
81
82 fd = port_wait(data->kernel_data);
83 if((fd >= 0) && data->raw){
84 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
85 if(err)
86 return(err);
87
88 err = raw(fd);
89 if(err)
90 return(err);
91 }
92 *dev_out = data->dev;
93 return(fd);
94}
95
96static void port_close(int fd, void *d)
97{
98 struct port_chan *data = d;
99
100 port_remove_dev(data->kernel_data);
101 os_close_file(fd);
102}
103
104static int port_console_write(int fd, const char *buf, int n, void *d)
105{
106 struct port_chan *data = d;
107
108 return(generic_console_write(fd, buf, n, &data->tt));
109}
110
111struct chan_ops port_ops = {
112 .type = "port",
113 .init = port_init,
114 .open = port_open,
115 .close = port_close,
116 .read = generic_read,
117 .write = generic_write,
118 .console_write = port_console_write,
119 .window_size = generic_window_size,
120 .free = port_free,
121 .winch = 1,
122};
123
124int port_listen_fd(int port)
125{
126 struct sockaddr_in addr;
127 int fd, err, arg;
128
129 fd = socket(PF_INET, SOCK_STREAM, 0);
130 if(fd == -1)
131 return(-errno);
132
133 arg = 1;
134 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){
135 err = -errno;
136 goto out;
137 }
138
139 addr.sin_family = AF_INET;
140 addr.sin_port = htons(port);
141 addr.sin_addr.s_addr = htonl(INADDR_ANY);
142 if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0){
143 err = -errno;
144 goto out;
145 }
146
147 if(listen(fd, 1) < 0){
148 err = -errno;
149 goto out;
150 }
151
152 err = os_set_fd_block(fd, 0);
153 if(err < 0)
154 goto out;
155
156 return(fd);
157 out:
158 os_close_file(fd);
159 return(err);
160}
161
162struct port_pre_exec_data {
163 int sock_fd;
164 int pipe_fd;
165};
166
167void port_pre_exec(void *arg)
168{
169 struct port_pre_exec_data *data = arg;
170
171 dup2(data->sock_fd, 0);
172 dup2(data->sock_fd, 1);
173 dup2(data->sock_fd, 2);
174 os_close_file(data->sock_fd);
175 dup2(data->pipe_fd, 3);
176 os_shutdown_socket(3, 1, 0);
177 os_close_file(data->pipe_fd);
178}
179
180int port_connection(int fd, int *socket, int *pid_out)
181{
182 int new, err;
183 char *argv[] = { "/usr/sbin/in.telnetd", "-L",
184 "/usr/lib/uml/port-helper", NULL };
185 struct port_pre_exec_data data;
186
187 new = os_accept_connection(fd);
188 if(new < 0)
189 return(new);
190
191 err = os_pipe(socket, 0, 0);
192 if(err < 0)
193 goto out_close;
194
195 data = ((struct port_pre_exec_data)
196 { .sock_fd = new,
197 .pipe_fd = socket[1] });
198
199 err = run_helper(port_pre_exec, &data, argv, NULL);
200 if(err < 0)
201 goto out_shutdown;
202
203 *pid_out = err;
204 return(new);
205
206 out_shutdown:
207 os_shutdown_socket(socket[0], 1, 1);
208 os_close_file(socket[0]);
209 os_shutdown_socket(socket[1], 1, 1);
210 os_close_file(socket[1]);
211 out_close:
212 os_close_file(new);
213 return(err);
214}
215
216/*
217 * Overrides for Emacs so that we follow Linus's tabbing style.
218 * Emacs will notice this stuff at the end of the file and automatically
219 * adjust the settings for this buffer only. This must remain at the end
220 * of the file.
221 * ---------------------------------------------------------------------------
222 * Local variables:
223 * c-file-style: "linux"
224 * End:
225 */
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
new file mode 100644
index 000000000000..ed84d01df6cc
--- /dev/null
+++ b/arch/um/drivers/pty.c
@@ -0,0 +1,162 @@
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 <string.h>
9#include <errno.h>
10#include <termios.h>
11#include "chan_user.h"
12#include "user.h"
13#include "user_util.h"
14#include "kern_util.h"
15#include "os.h"
16
17struct pty_chan {
18 void (*announce)(char *dev_name, int dev);
19 int dev;
20 int raw;
21 struct termios tt;
22 char dev_name[sizeof("/dev/pts/0123456\0")];
23};
24
25static void *pty_chan_init(char *str, int device, struct chan_opts *opts)
26{
27 struct pty_chan *data;
28
29 data = um_kmalloc(sizeof(*data));
30 if(data == NULL) return(NULL);
31 *data = ((struct pty_chan) { .announce = opts->announce,
32 .dev = device,
33 .raw = opts->raw });
34 return(data);
35}
36
37static int pts_open(int input, int output, int primary, void *d,
38 char **dev_out)
39{
40 struct pty_chan *data = d;
41 char *dev;
42 int fd, err;
43
44 fd = get_pty();
45 if(fd < 0){
46 printk("open_pts : Failed to open pts\n");
47 return(-errno);
48 }
49 if(data->raw){
50 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
51 if(err)
52 return(err);
53
54 err = raw(fd);
55 if(err)
56 return(err);
57 }
58
59 dev = ptsname(fd);
60 sprintf(data->dev_name, "%s", dev);
61 *dev_out = data->dev_name;
62 if (data->announce)
63 (*data->announce)(dev, data->dev);
64 return(fd);
65}
66
67static int getmaster(char *line)
68{
69 char *pty, *bank, *cp;
70 int master, err;
71
72 pty = &line[strlen("/dev/ptyp")];
73 for (bank = "pqrs"; *bank; bank++) {
74 line[strlen("/dev/pty")] = *bank;
75 *pty = '0';
76 if (os_stat_file(line, NULL) < 0)
77 break;
78 for (cp = "0123456789abcdef"; *cp; cp++) {
79 *pty = *cp;
80 master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
81 if (master >= 0) {
82 char *tp = &line[strlen("/dev/")];
83
84 /* verify slave side is usable */
85 *tp = 't';
86 err = os_access(line, OS_ACC_RW_OK);
87 *tp = 'p';
88 if(err == 0) return(master);
89 (void) os_close_file(master);
90 }
91 }
92 }
93 return(-1);
94}
95
96static int pty_open(int input, int output, int primary, void *d,
97 char **dev_out)
98{
99 struct pty_chan *data = d;
100 int fd, err;
101 char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
102
103 fd = getmaster(dev);
104 if(fd < 0)
105 return(-errno);
106
107 if(data->raw){
108 err = raw(fd);
109 if(err)
110 return(err);
111 }
112
113 if(data->announce) (*data->announce)(dev, data->dev);
114
115 sprintf(data->dev_name, "%s", dev);
116 *dev_out = data->dev_name;
117 return(fd);
118}
119
120static int pty_console_write(int fd, const char *buf, int n, void *d)
121{
122 struct pty_chan *data = d;
123
124 return(generic_console_write(fd, buf, n, &data->tt));
125}
126
127struct chan_ops pty_ops = {
128 .type = "pty",
129 .init = pty_chan_init,
130 .open = pty_open,
131 .close = generic_close,
132 .read = generic_read,
133 .write = generic_write,
134 .console_write = pty_console_write,
135 .window_size = generic_window_size,
136 .free = generic_free,
137 .winch = 0,
138};
139
140struct chan_ops pts_ops = {
141 .type = "pts",
142 .init = pty_chan_init,
143 .open = pts_open,
144 .close = generic_close,
145 .read = generic_read,
146 .write = generic_write,
147 .console_write = pty_console_write,
148 .window_size = generic_window_size,
149 .free = generic_free,
150 .winch = 0,
151};
152
153/*
154 * Overrides for Emacs so that we follow Linus's tabbing style.
155 * Emacs will notice this stuff at the end of the file and automatically
156 * adjust the settings for this buffer only. This must remain at the end
157 * of the file.
158 * ---------------------------------------------------------------------------
159 * Local variables:
160 * c-file-style: "linux"
161 * End:
162 */
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
new file mode 100644
index 000000000000..d43e9fab05a7
--- /dev/null
+++ b/arch/um/drivers/random.c
@@ -0,0 +1,122 @@
1/* Much of this ripped from hw_random.c */
2
3#include <linux/module.h>
4#include <linux/fs.h>
5#include <linux/miscdevice.h>
6#include <linux/delay.h>
7#include <asm/uaccess.h>
8#include "os.h"
9
10/*
11 * core module and version information
12 */
13#define RNG_VERSION "1.0.0"
14#define RNG_MODULE_NAME "random"
15#define RNG_DRIVER_NAME RNG_MODULE_NAME " virtual driver " RNG_VERSION
16#define PFX RNG_MODULE_NAME ": "
17
18#define RNG_MISCDEV_MINOR 183 /* official */
19
20static int random_fd = -1;
21
22static int rng_dev_open (struct inode *inode, struct file *filp)
23{
24 /* enforce read-only access to this chrdev */
25 if ((filp->f_mode & FMODE_READ) == 0)
26 return -EINVAL;
27 if (filp->f_mode & FMODE_WRITE)
28 return -EINVAL;
29
30 return 0;
31}
32
33static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
34 loff_t * offp)
35{
36 u32 data;
37 int n, ret = 0, have_data;
38
39 while(size){
40 n = os_read_file(random_fd, &data, sizeof(data));
41 if(n > 0){
42 have_data = n;
43 while (have_data && size) {
44 if (put_user((u8)data, buf++)) {
45 ret = ret ? : -EFAULT;
46 break;
47 }
48 size--;
49 ret++;
50 have_data--;
51 data>>=8;
52 }
53 }
54 else if(n == -EAGAIN){
55 if (filp->f_flags & O_NONBLOCK)
56 return ret ? : -EAGAIN;
57
58 if(need_resched()){
59 current->state = TASK_INTERRUPTIBLE;
60 schedule_timeout(1);
61 }
62 }
63 else return n;
64 if (signal_pending (current))
65 return ret ? : -ERESTARTSYS;
66 }
67 return ret;
68}
69
70static struct file_operations rng_chrdev_ops = {
71 .owner = THIS_MODULE,
72 .open = rng_dev_open,
73 .read = rng_dev_read,
74};
75
76static struct miscdevice rng_miscdev = {
77 RNG_MISCDEV_MINOR,
78 RNG_MODULE_NAME,
79 &rng_chrdev_ops,
80};
81
82/*
83 * rng_init - initialize RNG module
84 */
85static int __init rng_init (void)
86{
87 int err;
88
89 err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
90 if(err < 0)
91 goto out;
92
93 random_fd = err;
94
95 err = os_set_fd_block(random_fd, 0);
96 if(err)
97 goto err_out_cleanup_hw;
98
99 err = misc_register (&rng_miscdev);
100 if (err) {
101 printk (KERN_ERR PFX "misc device register failed\n");
102 goto err_out_cleanup_hw;
103 }
104
105 out:
106 return err;
107
108 err_out_cleanup_hw:
109 random_fd = -1;
110 goto out;
111}
112
113/*
114 * rng_cleanup - shutdown RNG module
115 */
116static void __exit rng_cleanup (void)
117{
118 misc_deregister (&rng_miscdev);
119}
120
121module_init (rng_init);
122module_exit (rng_cleanup);
diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h
new file mode 100644
index 000000000000..495f2f1b1420
--- /dev/null
+++ b/arch/um/drivers/slip.h
@@ -0,0 +1,39 @@
1#ifndef __UM_SLIP_H
2#define __UM_SLIP_H
3
4#define BUF_SIZE 1500
5 /* two bytes each for a (pathological) max packet of escaped chars + *
6 * terminating END char + initial END char */
7#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
8
9struct slip_data {
10 void *dev;
11 char name[sizeof("slnnnnn\0")];
12 char *addr;
13 char *gate_addr;
14 int slave;
15 char ibuf[ENC_BUF_SIZE];
16 char obuf[ENC_BUF_SIZE];
17 int more; /* more data: do not read fd until ibuf has been drained */
18 int pos;
19 int esc;
20};
21
22extern struct net_user_info slip_user_info;
23
24extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
25extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri);
26extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri);
27
28#endif
29
30/*
31 * Overrides for Emacs so that we follow Linus's tabbing style.
32 * Emacs will notice this stuff at the end of the file and automatically
33 * adjust the settings for this buffer only. This must remain at the end
34 * of the file.
35 * ---------------------------------------------------------------------------
36 * Local variables:
37 * c-file-style: "linux"
38 * End:
39 */
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
new file mode 100644
index 000000000000..0886eedba213
--- /dev/null
+++ b/arch/um/drivers/slip_kern.c
@@ -0,0 +1,109 @@
1#include "linux/config.h"
2#include "linux/kernel.h"
3#include "linux/stddef.h"
4#include "linux/init.h"
5#include "linux/netdevice.h"
6#include "linux/if_arp.h"
7#include "net_kern.h"
8#include "net_user.h"
9#include "kern.h"
10#include "slip.h"
11
12struct slip_init {
13 char *gate_addr;
14};
15
16void slip_init(struct net_device *dev, void *data)
17{
18 struct uml_net_private *private;
19 struct slip_data *spri;
20 struct slip_init *init = data;
21
22 private = dev->priv;
23 spri = (struct slip_data *) private->user;
24 *spri = ((struct slip_data)
25 { .name = { '\0' },
26 .addr = NULL,
27 .gate_addr = init->gate_addr,
28 .slave = -1,
29 .ibuf = { '\0' },
30 .obuf = { '\0' },
31 .pos = 0,
32 .esc = 0,
33 .dev = dev });
34
35 dev->init = NULL;
36 dev->hard_header_len = 0;
37 dev->addr_len = 4;
38 dev->type = ARPHRD_ETHER;
39 dev->tx_queue_len = 256;
40 dev->flags = IFF_NOARP;
41 printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
42}
43
44static unsigned short slip_protocol(struct sk_buff *skbuff)
45{
46 return(htons(ETH_P_IP));
47}
48
49static int slip_read(int fd, struct sk_buff **skb,
50 struct uml_net_private *lp)
51{
52 return(slip_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu,
53 (struct slip_data *) &lp->user));
54}
55
56static int slip_write(int fd, struct sk_buff **skb,
57 struct uml_net_private *lp)
58{
59 return(slip_user_write(fd, (*skb)->data, (*skb)->len,
60 (struct slip_data *) &lp->user));
61}
62
63struct net_kern_info slip_kern_info = {
64 .init = slip_init,
65 .protocol = slip_protocol,
66 .read = slip_read,
67 .write = slip_write,
68};
69
70static int slip_setup(char *str, char **mac_out, void *data)
71{
72 struct slip_init *init = data;
73
74 *init = ((struct slip_init)
75 { .gate_addr = NULL });
76
77 if(str[0] != '\0')
78 init->gate_addr = str;
79 return(1);
80}
81
82static struct transport slip_transport = {
83 .list = LIST_HEAD_INIT(slip_transport.list),
84 .name = "slip",
85 .setup = slip_setup,
86 .user = &slip_user_info,
87 .kern = &slip_kern_info,
88 .private_size = sizeof(struct slip_data),
89 .setup_size = sizeof(struct slip_init),
90};
91
92static int register_slip(void)
93{
94 register_transport(&slip_transport);
95 return(1);
96}
97
98__initcall(register_slip);
99
100/*
101 * Overrides for Emacs so that we follow Linus's tabbing style.
102 * Emacs will notice this stuff at the end of the file and automatically
103 * adjust the settings for this buffer only. This must remain at the end
104 * of the file.
105 * ---------------------------------------------------------------------------
106 * Local variables:
107 * c-file-style: "linux"
108 * End:
109 */
diff --git a/arch/um/drivers/slip_proto.h b/arch/um/drivers/slip_proto.h
new file mode 100644
index 000000000000..7206361ace45
--- /dev/null
+++ b/arch/um/drivers/slip_proto.h
@@ -0,0 +1,93 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __UM_SLIP_PROTO_H__
7#define __UM_SLIP_PROTO_H__
8
9/* SLIP protocol characters. */
10#define SLIP_END 0300 /* indicates end of frame */
11#define SLIP_ESC 0333 /* indicates byte stuffing */
12#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */
13#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
14
15static inline int slip_unesc(unsigned char c,char *buf,int *pos, int *esc)
16{
17 int ret;
18
19 switch(c){
20 case SLIP_END:
21 *esc = 0;
22 ret=*pos;
23 *pos=0;
24 return(ret);
25 case SLIP_ESC:
26 *esc = 1;
27 return(0);
28 case SLIP_ESC_ESC:
29 if(*esc){
30 *esc = 0;
31 c = SLIP_ESC;
32 }
33 break;
34 case SLIP_ESC_END:
35 if(*esc){
36 *esc = 0;
37 c = SLIP_END;
38 }
39 break;
40 }
41 buf[(*pos)++] = c;
42 return(0);
43}
44
45static inline int slip_esc(unsigned char *s, unsigned char *d, int len)
46{
47 unsigned char *ptr = d;
48 unsigned char c;
49
50 /*
51 * Send an initial END character to flush out any
52 * data that may have accumulated in the receiver
53 * due to line noise.
54 */
55
56 *ptr++ = SLIP_END;
57
58 /*
59 * For each byte in the packet, send the appropriate
60 * character sequence, according to the SLIP protocol.
61 */
62
63 while (len-- > 0) {
64 switch(c = *s++) {
65 case SLIP_END:
66 *ptr++ = SLIP_ESC;
67 *ptr++ = SLIP_ESC_END;
68 break;
69 case SLIP_ESC:
70 *ptr++ = SLIP_ESC;
71 *ptr++ = SLIP_ESC_ESC;
72 break;
73 default:
74 *ptr++ = c;
75 break;
76 }
77 }
78 *ptr++ = SLIP_END;
79 return (ptr - d);
80}
81
82#endif
83
84/*
85 * Overrides for Emacs so that we follow Linus's tabbing style.
86 * Emacs will notice this stuff at the end of the file and automatically
87 * adjust the settings for this buffer only. This must remain at the end
88 * of the file.
89 * ---------------------------------------------------------------------------
90 * Local variables:
91 * c-file-style: "linux"
92 * End:
93 */
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
new file mode 100644
index 000000000000..d94846b1b4cf
--- /dev/null
+++ b/arch/um/drivers/slip_user.c
@@ -0,0 +1,280 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <stddef.h>
5#include <sched.h>
6#include <string.h>
7#include <errno.h>
8#include <sys/termios.h>
9#include <sys/wait.h>
10#include <sys/signal.h>
11#include "user_util.h"
12#include "kern_util.h"
13#include "user.h"
14#include "net_user.h"
15#include "slip.h"
16#include "slip_proto.h"
17#include "helper.h"
18#include "os.h"
19
20void slip_user_init(void *data, void *dev)
21{
22 struct slip_data *pri = data;
23
24 pri->dev = dev;
25}
26
27static int set_up_tty(int fd)
28{
29 int i;
30 struct termios tios;
31
32 if (tcgetattr(fd, &tios) < 0) {
33 printk("could not get initial terminal attributes\n");
34 return(-1);
35 }
36
37 tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
38 tios.c_iflag = IGNBRK | IGNPAR;
39 tios.c_oflag = 0;
40 tios.c_lflag = 0;
41 for (i = 0; i < NCCS; i++)
42 tios.c_cc[i] = 0;
43 tios.c_cc[VMIN] = 1;
44 tios.c_cc[VTIME] = 0;
45
46 cfsetospeed(&tios, B38400);
47 cfsetispeed(&tios, B38400);
48
49 if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
50 printk("failed to set terminal attributes\n");
51 return(-1);
52 }
53 return(0);
54}
55
56struct slip_pre_exec_data {
57 int stdin;
58 int stdout;
59 int close_me;
60};
61
62static void slip_pre_exec(void *arg)
63{
64 struct slip_pre_exec_data *data = arg;
65
66 if(data->stdin >= 0) dup2(data->stdin, 0);
67 dup2(data->stdout, 1);
68 if(data->close_me >= 0) os_close_file(data->close_me);
69}
70
71static int slip_tramp(char **argv, int fd)
72{
73 struct slip_pre_exec_data pe_data;
74 char *output;
75 int status, pid, fds[2], err, output_len;
76
77 err = os_pipe(fds, 1, 0);
78 if(err < 0){
79 printk("slip_tramp : pipe failed, err = %d\n", -err);
80 return(err);
81 }
82
83 err = 0;
84 pe_data.stdin = fd;
85 pe_data.stdout = fds[1];
86 pe_data.close_me = fds[0];
87 pid = run_helper(slip_pre_exec, &pe_data, argv, NULL);
88
89 if(pid < 0) err = pid;
90 else {
91 output_len = page_size();
92 output = um_kmalloc(output_len);
93 if(output == NULL)
94 printk("slip_tramp : failed to allocate output "
95 "buffer\n");
96
97 os_close_file(fds[1]);
98 read_output(fds[0], output, output_len);
99 if(output != NULL){
100 printk("%s", output);
101 kfree(output);
102 }
103 CATCH_EINTR(err = waitpid(pid, &status, 0));
104 if(err < 0)
105 err = errno;
106 else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
107 printk("'%s' didn't exit with status 0\n", argv[0]);
108 err = -EINVAL;
109 }
110 }
111
112 os_close_file(fds[0]);
113
114 return(err);
115}
116
117static int slip_open(void *data)
118{
119 struct slip_data *pri = data;
120 char version_buf[sizeof("nnnnn\0")];
121 char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
122 char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf,
123 NULL };
124 int sfd, mfd, err;
125
126 mfd = get_pty();
127 if(mfd < 0){
128 printk("umn : Failed to open pty, err = %d\n", -mfd);
129 return(mfd);
130 }
131 sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0);
132 if(sfd < 0){
133 printk("Couldn't open tty for slip line, err = %d\n", -sfd);
134 os_close_file(mfd);
135 return(sfd);
136 }
137 if(set_up_tty(sfd)) return(-1);
138 pri->slave = sfd;
139 pri->pos = 0;
140 pri->esc = 0;
141 if(pri->gate_addr != NULL){
142 sprintf(version_buf, "%d", UML_NET_VERSION);
143 strcpy(gate_buf, pri->gate_addr);
144
145 err = slip_tramp(argv, sfd);
146
147 if(err < 0){
148 printk("slip_tramp failed - err = %d\n", -err);
149 return(err);
150 }
151 err = os_get_ifname(pri->slave, pri->name);
152 if(err < 0){
153 printk("get_ifname failed, err = %d\n", -err);
154 return(err);
155 }
156 iter_addresses(pri->dev, open_addr, pri->name);
157 }
158 else {
159 err = os_set_slip(sfd);
160 if(err < 0){
161 printk("Failed to set slip discipline encapsulation - "
162 "err = %d\n", -err);
163 return(err);
164 }
165 }
166 return(mfd);
167}
168
169static void slip_close(int fd, void *data)
170{
171 struct slip_data *pri = data;
172 char version_buf[sizeof("nnnnn\0")];
173 char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name,
174 NULL };
175 int err;
176
177 if(pri->gate_addr != NULL)
178 iter_addresses(pri->dev, close_addr, pri->name);
179
180 sprintf(version_buf, "%d", UML_NET_VERSION);
181
182 err = slip_tramp(argv, pri->slave);
183
184 if(err != 0)
185 printk("slip_tramp failed - errno = %d\n", -err);
186 os_close_file(fd);
187 os_close_file(pri->slave);
188 pri->slave = -1;
189}
190
191int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
192{
193 int i, n, size, start;
194
195 if(pri->more>0) {
196 i = 0;
197 while(i < pri->more) {
198 size = slip_unesc(pri->ibuf[i++],
199 pri->ibuf, &pri->pos, &pri->esc);
200 if(size){
201 memcpy(buf, pri->ibuf, size);
202 memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
203 pri->more=pri->more-i;
204 return(size);
205 }
206 }
207 pri->more=0;
208 }
209
210 n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
211 if(n <= 0) return(n);
212
213 start = pri->pos;
214 for(i = 0; i < n; i++){
215 size = slip_unesc(pri->ibuf[start + i],
216 pri->ibuf, &pri->pos, &pri->esc);
217 if(size){
218 memcpy(buf, pri->ibuf, size);
219 memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
220 pri->more=n-(i+1);
221 return(size);
222 }
223 }
224 return(0);
225}
226
227int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
228{
229 int actual, n;
230
231 actual = slip_esc(buf, pri->obuf, len);
232 n = net_write(fd, pri->obuf, actual);
233 if(n < 0) return(n);
234 else return(len);
235}
236
237static int slip_set_mtu(int mtu, void *data)
238{
239 return(mtu);
240}
241
242static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
243 void *data)
244{
245 struct slip_data *pri = data;
246
247 if(pri->slave < 0) return;
248 open_addr(addr, netmask, pri->name);
249}
250
251static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
252 void *data)
253{
254 struct slip_data *pri = data;
255
256 if(pri->slave < 0) return;
257 close_addr(addr, netmask, pri->name);
258}
259
260struct net_user_info slip_user_info = {
261 .init = slip_user_init,
262 .open = slip_open,
263 .close = slip_close,
264 .remove = NULL,
265 .set_mtu = slip_set_mtu,
266 .add_address = slip_add_addr,
267 .delete_address = slip_del_addr,
268 .max_packet = BUF_SIZE
269};
270
271/*
272 * Overrides for Emacs so that we follow Linus's tabbing style.
273 * Emacs will notice this stuff at the end of the file and automatically
274 * adjust the settings for this buffer only. This must remain at the end
275 * of the file.
276 * ---------------------------------------------------------------------------
277 * Local variables:
278 * c-file-style: "linux"
279 * End:
280 */
diff --git a/arch/um/drivers/slirp.h b/arch/um/drivers/slirp.h
new file mode 100644
index 000000000000..04e407d1e44a
--- /dev/null
+++ b/arch/um/drivers/slirp.h
@@ -0,0 +1,51 @@
1#ifndef __UM_SLIRP_H
2#define __UM_SLIRP_H
3
4#define BUF_SIZE 1500
5 /* two bytes each for a (pathological) max packet of escaped chars + *
6 * terminating END char + initial END char */
7#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
8
9#define SLIRP_MAX_ARGS 100
10/*
11 * XXX this next definition is here because I don't understand why this
12 * initializer doesn't work in slirp_kern.c:
13 *
14 * argv : { init->argv[ 0 ... SLIRP_MAX_ARGS-1 ] },
15 *
16 * or why I can't typecast like this:
17 *
18 * argv : (char* [SLIRP_MAX_ARGS])(init->argv),
19 */
20struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; };
21
22struct slirp_data {
23 void *dev;
24 struct arg_list_dummy_wrapper argw;
25 int pid;
26 int slave;
27 char ibuf[ENC_BUF_SIZE];
28 char obuf[ENC_BUF_SIZE];
29 int more; /* more data: do not read fd until ibuf has been drained */
30 int pos;
31 int esc;
32};
33
34extern struct net_user_info slirp_user_info;
35
36extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
37extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri);
38extern int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri);
39
40#endif
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/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
new file mode 100644
index 000000000000..c9d6b52a831d
--- /dev/null
+++ b/arch/um/drivers/slirp_kern.c
@@ -0,0 +1,135 @@
1#include "linux/kernel.h"
2#include "linux/stddef.h"
3#include "linux/init.h"
4#include "linux/netdevice.h"
5#include "linux/if_arp.h"
6#include "net_kern.h"
7#include "net_user.h"
8#include "kern.h"
9#include "slirp.h"
10
11struct slirp_init {
12 struct arg_list_dummy_wrapper argw; /* XXX should be simpler... */
13};
14
15void slirp_init(struct net_device *dev, void *data)
16{
17 struct uml_net_private *private;
18 struct slirp_data *spri;
19 struct slirp_init *init = data;
20 int i;
21
22 private = dev->priv;
23 spri = (struct slirp_data *) private->user;
24 *spri = ((struct slirp_data)
25 { .argw = init->argw,
26 .pid = -1,
27 .slave = -1,
28 .ibuf = { '\0' },
29 .obuf = { '\0' },
30 .pos = 0,
31 .esc = 0,
32 .dev = dev });
33
34 dev->init = NULL;
35 dev->hard_header_len = 0;
36 dev->header_cache_update = NULL;
37 dev->hard_header_cache = NULL;
38 dev->hard_header = NULL;
39 dev->addr_len = 0;
40 dev->type = ARPHRD_SLIP;
41 dev->tx_queue_len = 256;
42 dev->flags = IFF_NOARP;
43 printk("SLIRP backend - command line:");
44 for(i=0;spri->argw.argv[i]!=NULL;i++) {
45 printk(" '%s'",spri->argw.argv[i]);
46 }
47 printk("\n");
48}
49
50static unsigned short slirp_protocol(struct sk_buff *skbuff)
51{
52 return(htons(ETH_P_IP));
53}
54
55static int slirp_read(int fd, struct sk_buff **skb,
56 struct uml_net_private *lp)
57{
58 return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu,
59 (struct slirp_data *) &lp->user));
60}
61
62static int slirp_write(int fd, struct sk_buff **skb,
63 struct uml_net_private *lp)
64{
65 return(slirp_user_write(fd, (*skb)->data, (*skb)->len,
66 (struct slirp_data *) &lp->user));
67}
68
69struct net_kern_info slirp_kern_info = {
70 .init = slirp_init,
71 .protocol = slirp_protocol,
72 .read = slirp_read,
73 .write = slirp_write,
74};
75
76static int slirp_setup(char *str, char **mac_out, void *data)
77{
78 struct slirp_init *init = data;
79 int i=0;
80
81 *init = ((struct slirp_init)
82 { argw : { { "slirp", NULL } } });
83
84 str = split_if_spec(str, mac_out, NULL);
85
86 if(str == NULL) { /* no command line given after MAC addr */
87 return(1);
88 }
89
90 do {
91 if(i>=SLIRP_MAX_ARGS-1) {
92 printk("slirp_setup: truncating slirp arguments\n");
93 break;
94 }
95 init->argw.argv[i++] = str;
96 while(*str && *str!=',') {
97 if(*str=='_') *str=' ';
98 str++;
99 }
100 if(*str!=',')
101 break;
102 *str++='\0';
103 } while(1);
104 init->argw.argv[i]=NULL;
105 return(1);
106}
107
108static struct transport slirp_transport = {
109 .list = LIST_HEAD_INIT(slirp_transport.list),
110 .name = "slirp",
111 .setup = slirp_setup,
112 .user = &slirp_user_info,
113 .kern = &slirp_kern_info,
114 .private_size = sizeof(struct slirp_data),
115 .setup_size = sizeof(struct slirp_init),
116};
117
118static int register_slirp(void)
119{
120 register_transport(&slirp_transport);
121 return(1);
122}
123
124__initcall(register_slirp);
125
126/*
127 * Overrides for Emacs so that we follow Linus's tabbing style.
128 * Emacs will notice this stuff at the end of the file and automatically
129 * adjust the settings for this buffer only. This must remain at the end
130 * of the file.
131 * ---------------------------------------------------------------------------
132 * Local variables:
133 * c-file-style: "linux"
134 * End:
135 */
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
new file mode 100644
index 000000000000..c322515c71cc
--- /dev/null
+++ b/arch/um/drivers/slirp_user.c
@@ -0,0 +1,201 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <stddef.h>
5#include <sched.h>
6#include <string.h>
7#include <errno.h>
8#include <sys/wait.h>
9#include <sys/signal.h>
10#include "user_util.h"
11#include "kern_util.h"
12#include "user.h"
13#include "net_user.h"
14#include "slirp.h"
15#include "slip_proto.h"
16#include "helper.h"
17#include "os.h"
18
19void slirp_user_init(void *data, void *dev)
20{
21 struct slirp_data *pri = data;
22
23 pri->dev = dev;
24}
25
26struct slirp_pre_exec_data {
27 int stdin;
28 int stdout;
29};
30
31static void slirp_pre_exec(void *arg)
32{
33 struct slirp_pre_exec_data *data = arg;
34
35 if(data->stdin != -1) dup2(data->stdin, 0);
36 if(data->stdout != -1) dup2(data->stdout, 1);
37}
38
39static int slirp_tramp(char **argv, int fd)
40{
41 struct slirp_pre_exec_data pe_data;
42 int pid;
43
44 pe_data.stdin = fd;
45 pe_data.stdout = fd;
46 pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL);
47
48 return(pid);
49}
50
51/* XXX This is just a trivial wrapper around os_pipe */
52static int slirp_datachan(int *mfd, int *sfd)
53{
54 int fds[2], err;
55
56 err = os_pipe(fds, 1, 1);
57 if(err < 0){
58 printk("slirp_datachan: Failed to open pipe, err = %d\n", -err);
59 return(err);
60 }
61
62 *mfd = fds[0];
63 *sfd = fds[1];
64 return(0);
65}
66
67static int slirp_open(void *data)
68{
69 struct slirp_data *pri = data;
70 int sfd, mfd, pid, err;
71
72 err = slirp_datachan(&mfd, &sfd);
73 if(err)
74 return(err);
75
76 pid = slirp_tramp(pri->argw.argv, sfd);
77
78 if(pid < 0){
79 printk("slirp_tramp failed - errno = %d\n", -pid);
80 os_close_file(sfd);
81 os_close_file(mfd);
82 return(pid);
83 }
84
85 pri->slave = sfd;
86 pri->pos = 0;
87 pri->esc = 0;
88
89 pri->pid = pid;
90
91 return(mfd);
92}
93
94static void slirp_close(int fd, void *data)
95{
96 struct slirp_data *pri = data;
97 int status,err;
98
99 os_close_file(fd);
100 os_close_file(pri->slave);
101
102 pri->slave = -1;
103
104 if(pri->pid<1) {
105 printk("slirp_close: no child process to shut down\n");
106 return;
107 }
108
109#if 0
110 if(kill(pri->pid, SIGHUP)<0) {
111 printk("slirp_close: sending hangup to %d failed (%d)\n",
112 pri->pid, errno);
113 }
114#endif
115
116 CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG));
117 if(err < 0) {
118 printk("slirp_close: waitpid returned %d\n", errno);
119 return;
120 }
121
122 if(err == 0) {
123 printk("slirp_close: process %d has not exited\n");
124 return;
125 }
126
127 pri->pid = -1;
128}
129
130int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
131{
132 int i, n, size, start;
133
134 if(pri->more>0) {
135 i = 0;
136 while(i < pri->more) {
137 size = slip_unesc(pri->ibuf[i++],
138 pri->ibuf,&pri->pos,&pri->esc);
139 if(size){
140 memcpy(buf, pri->ibuf, size);
141 memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
142 pri->more=pri->more-i;
143 return(size);
144 }
145 }
146 pri->more=0;
147 }
148
149 n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
150 if(n <= 0) return(n);
151
152 start = pri->pos;
153 for(i = 0; i < n; i++){
154 size = slip_unesc(pri->ibuf[start + i],
155 pri->ibuf,&pri->pos,&pri->esc);
156 if(size){
157 memcpy(buf, pri->ibuf, size);
158 memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
159 pri->more=n-(i+1);
160 return(size);
161 }
162 }
163 return(0);
164}
165
166int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri)
167{
168 int actual, n;
169
170 actual = slip_esc(buf, pri->obuf, len);
171 n = net_write(fd, pri->obuf, actual);
172 if(n < 0) return(n);
173 else return(len);
174}
175
176static int slirp_set_mtu(int mtu, void *data)
177{
178 return(mtu);
179}
180
181struct net_user_info slirp_user_info = {
182 .init = slirp_user_init,
183 .open = slirp_open,
184 .close = slirp_close,
185 .remove = NULL,
186 .set_mtu = slirp_set_mtu,
187 .add_address = NULL,
188 .delete_address = NULL,
189 .max_packet = BUF_SIZE
190};
191
192/*
193 * Overrides for Emacs so that we follow Linus's tabbing style.
194 * Emacs will notice this stuff at the end of the file and automatically
195 * adjust the settings for this buffer only. This must remain at the end
196 * of the file.
197 * ---------------------------------------------------------------------------
198 * Local variables:
199 * c-file-style: "linux"
200 * End:
201 */
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
new file mode 100644
index 000000000000..c5839c3141f8
--- /dev/null
+++ b/arch/um/drivers/ssl.c
@@ -0,0 +1,251 @@
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/fs.h"
8#include "linux/tty.h"
9#include "linux/tty_driver.h"
10#include "linux/major.h"
11#include "linux/mm.h"
12#include "linux/init.h"
13#include "linux/console.h"
14#include "asm/termbits.h"
15#include "asm/irq.h"
16#include "line.h"
17#include "ssl.h"
18#include "chan_kern.h"
19#include "user_util.h"
20#include "kern_util.h"
21#include "kern.h"
22#include "init.h"
23#include "irq_user.h"
24#include "mconsole_kern.h"
25#include "2_5compat.h"
26
27static int ssl_version = 1;
28
29/* Referenced only by tty_driver below - presumably it's locked correctly
30 * by the tty driver.
31 */
32
33static struct tty_driver *ssl_driver;
34
35#define NR_PORTS 64
36
37void ssl_announce(char *dev_name, int dev)
38{
39 printk(KERN_INFO "Serial line %d assigned device '%s'\n", dev,
40 dev_name);
41}
42
43static struct chan_opts opts = {
44 .announce = ssl_announce,
45 .xterm_title = "Serial Line #%d",
46 .raw = 1,
47 .tramp_stack = 0,
48 .in_kernel = 1,
49};
50
51static int ssl_config(char *str);
52static int ssl_get_config(char *dev, char *str, int size, char **error_out);
53static int ssl_remove(char *str);
54
55static struct line_driver driver = {
56 .name = "UML serial line",
57 .device_name = "ttyS",
58 .devfs_name = "tts/",
59 .major = TTY_MAJOR,
60 .minor_start = 64,
61 .type = TTY_DRIVER_TYPE_SERIAL,
62 .subtype = 0,
63 .read_irq = SSL_IRQ,
64 .read_irq_name = "ssl",
65 .write_irq = SSL_WRITE_IRQ,
66 .write_irq_name = "ssl-write",
67 .symlink_from = "serial",
68 .symlink_to = "tts",
69 .mc = {
70 .name = "ssl",
71 .config = ssl_config,
72 .get_config = ssl_get_config,
73 .remove = ssl_remove,
74 },
75};
76
77/* The array is initialized by line_init, which is an initcall. The
78 * individual elements are protected by individual semaphores.
79 */
80static struct line serial_lines[NR_PORTS] =
81 { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) };
82
83static struct lines lines = LINES_INIT(NR_PORTS);
84
85static int ssl_config(char *str)
86{
87 return(line_config(serial_lines,
88 sizeof(serial_lines)/sizeof(serial_lines[0]), str));
89}
90
91static int ssl_get_config(char *dev, char *str, int size, char **error_out)
92{
93 return(line_get_config(dev, serial_lines,
94 sizeof(serial_lines)/sizeof(serial_lines[0]),
95 str, size, error_out));
96}
97
98static int ssl_remove(char *str)
99{
100 return(line_remove(serial_lines,
101 sizeof(serial_lines)/sizeof(serial_lines[0]), str));
102}
103
104int ssl_open(struct tty_struct *tty, struct file *filp)
105{
106 return line_open(serial_lines, tty, &opts);
107}
108
109#if 0
110static int ssl_chars_in_buffer(struct tty_struct *tty)
111{
112 return(0);
113}
114
115static void ssl_flush_buffer(struct tty_struct *tty)
116{
117 return;
118}
119
120static void ssl_throttle(struct tty_struct * tty)
121{
122 printk(KERN_ERR "Someone should implement ssl_throttle\n");
123}
124
125static void ssl_unthrottle(struct tty_struct * tty)
126{
127 printk(KERN_ERR "Someone should implement ssl_unthrottle\n");
128}
129
130static void ssl_stop(struct tty_struct *tty)
131{
132 printk(KERN_ERR "Someone should implement ssl_stop\n");
133}
134
135static void ssl_start(struct tty_struct *tty)
136{
137 printk(KERN_ERR "Someone should implement ssl_start\n");
138}
139
140void ssl_hangup(struct tty_struct *tty)
141{
142}
143#endif
144
145static struct tty_operations ssl_ops = {
146 .open = ssl_open,
147 .close = line_close,
148 .write = line_write,
149 .put_char = line_put_char,
150 .write_room = line_write_room,
151 .chars_in_buffer = line_chars_in_buffer,
152 .set_termios = line_set_termios,
153 .ioctl = line_ioctl,
154#if 0
155 .flush_chars = ssl_flush_chars,
156 .flush_buffer = ssl_flush_buffer,
157 .throttle = ssl_throttle,
158 .unthrottle = ssl_unthrottle,
159 .stop = ssl_stop,
160 .start = ssl_start,
161 .hangup = ssl_hangup,
162#endif
163};
164
165/* Changed by ssl_init and referenced by ssl_exit, which are both serialized
166 * by being an initcall and exitcall, respectively.
167 */
168static int ssl_init_done = 0;
169
170static void ssl_console_write(struct console *c, const char *string,
171 unsigned len)
172{
173 struct line *line = &serial_lines[c->index];
174
175 down(&line->sem);
176 console_write_chan(&line->chan_list, string, len);
177 up(&line->sem);
178}
179
180static struct tty_driver *ssl_console_device(struct console *c, int *index)
181{
182 *index = c->index;
183 return ssl_driver;
184}
185
186static int ssl_console_setup(struct console *co, char *options)
187{
188 struct line *line = &serial_lines[co->index];
189
190 return console_open_chan(line,co,&opts);
191}
192
193static struct console ssl_cons = {
194 .name = "ttyS",
195 .write = ssl_console_write,
196 .device = ssl_console_device,
197 .setup = ssl_console_setup,
198 .flags = CON_PRINTBUFFER,
199 .index = -1,
200};
201
202int ssl_init(void)
203{
204 char *new_title;
205
206 printk(KERN_INFO "Initializing software serial port version %d\n",
207 ssl_version);
208 ssl_driver = line_register_devfs(&lines, &driver, &ssl_ops,
209 serial_lines, ARRAY_SIZE(serial_lines));
210
211 lines_init(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]));
212
213 new_title = add_xterm_umid(opts.xterm_title);
214 if (new_title != NULL)
215 opts.xterm_title = new_title;
216
217 ssl_init_done = 1;
218 register_console(&ssl_cons);
219 return(0);
220}
221late_initcall(ssl_init);
222
223static void ssl_exit(void)
224{
225 if (!ssl_init_done)
226 return;
227 close_lines(serial_lines,
228 sizeof(serial_lines)/sizeof(serial_lines[0]));
229}
230__uml_exitcall(ssl_exit);
231
232static int ssl_chan_setup(char *str)
233{
234 return(line_setup(serial_lines,
235 sizeof(serial_lines)/sizeof(serial_lines[0]),
236 str, 1));
237}
238
239__setup("ssl", ssl_chan_setup);
240__channel_help(ssl_chan_setup, "ssl");
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/drivers/ssl.h b/arch/um/drivers/ssl.h
new file mode 100644
index 000000000000..98412aa66607
--- /dev/null
+++ b/arch/um/drivers/ssl.h
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SSL_H__
7#define __SSL_H__
8
9extern int ssl_read(int fd, int line);
10extern void ssl_receive_char(int line, char ch);
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/drivers/stderr_console.c b/arch/um/drivers/stderr_console.c
new file mode 100644
index 000000000000..98565b53d170
--- /dev/null
+++ b/arch/um/drivers/stderr_console.c
@@ -0,0 +1,45 @@
1#include <linux/init.h>
2#include <linux/console.h>
3
4#include "chan_user.h"
5
6/* ----------------------------------------------------------------------------- */
7/* trivial console driver -- simply dump everything to stderr */
8
9/*
10 * Don't register by default -- as this registeres very early in the
11 * boot process it becomes the default console. And as this isn't a
12 * real tty driver init isn't able to open /dev/console then.
13 *
14 * In most cases this isn't what you want ...
15 */
16static int use_stderr_console = 0;
17
18static void stderr_console_write(struct console *console, const char *string,
19 unsigned len)
20{
21 generic_write(2 /* stderr */, string, len, NULL);
22}
23
24static struct console stderr_console = {
25 .name "stderr",
26 .write stderr_console_write,
27 .flags CON_PRINTBUFFER,
28};
29
30static int __init stderr_console_init(void)
31{
32 if (use_stderr_console)
33 register_console(&stderr_console);
34 return 0;
35}
36console_initcall(stderr_console_init);
37
38static int stderr_setup(char *str)
39{
40 if (!str)
41 return 0;
42 use_stderr_console = simple_strtoul(str,&str,0);
43 return 1;
44}
45__setup("stderr=", stderr_setup);
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
new file mode 100644
index 000000000000..e604d7c87695
--- /dev/null
+++ b/arch/um/drivers/stdio_console.c
@@ -0,0 +1,205 @@
1/*
2 * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/posix_types.h"
8#include "linux/tty.h"
9#include "linux/tty_flip.h"
10#include "linux/types.h"
11#include "linux/major.h"
12#include "linux/kdev_t.h"
13#include "linux/console.h"
14#include "linux/string.h"
15#include "linux/sched.h"
16#include "linux/list.h"
17#include "linux/init.h"
18#include "linux/interrupt.h"
19#include "linux/slab.h"
20#include "linux/hardirq.h"
21#include "asm/current.h"
22#include "asm/irq.h"
23#include "stdio_console.h"
24#include "line.h"
25#include "chan_kern.h"
26#include "user_util.h"
27#include "kern_util.h"
28#include "irq_user.h"
29#include "mconsole_kern.h"
30#include "init.h"
31#include "2_5compat.h"
32
33#define MAX_TTYS (16)
34
35/* ----------------------------------------------------------------------------- */
36
37/* Referenced only by tty_driver below - presumably it's locked correctly
38 * by the tty driver.
39 */
40
41static struct tty_driver *console_driver;
42
43void stdio_announce(char *dev_name, int dev)
44{
45 printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
46 dev_name);
47}
48
49static struct chan_opts opts = {
50 .announce = stdio_announce,
51 .xterm_title = "Virtual Console #%d",
52 .raw = 1,
53 .tramp_stack = 0,
54 .in_kernel = 1,
55};
56
57static int con_config(char *str);
58static int con_get_config(char *dev, char *str, int size, char **error_out);
59static int con_remove(char *str);
60
61static struct line_driver driver = {
62 .name = "UML console",
63 .device_name = "tty",
64 .devfs_name = "vc/",
65 .major = TTY_MAJOR,
66 .minor_start = 0,
67 .type = TTY_DRIVER_TYPE_CONSOLE,
68 .subtype = SYSTEM_TYPE_CONSOLE,
69 .read_irq = CONSOLE_IRQ,
70 .read_irq_name = "console",
71 .write_irq = CONSOLE_WRITE_IRQ,
72 .write_irq_name = "console-write",
73 .symlink_from = "ttys",
74 .symlink_to = "vc",
75 .mc = {
76 .name = "con",
77 .config = con_config,
78 .get_config = con_get_config,
79 .remove = con_remove,
80 },
81};
82
83static struct lines console_lines = LINES_INIT(MAX_TTYS);
84
85/* The array is initialized by line_init, which is an initcall. The
86 * individual elements are protected by individual semaphores.
87 */
88struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
89 [ 1 ... MAX_TTYS - 1 ] =
90 LINE_INIT(CONFIG_CON_CHAN, &driver) };
91
92static int con_config(char *str)
93{
94 return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str));
95}
96
97static int con_get_config(char *dev, char *str, int size, char **error_out)
98{
99 return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str,
100 size, error_out));
101}
102
103static int con_remove(char *str)
104{
105 return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str));
106}
107
108static int con_open(struct tty_struct *tty, struct file *filp)
109{
110 return line_open(vts, tty, &opts);
111}
112
113static int con_init_done = 0;
114
115static struct tty_operations console_ops = {
116 .open = con_open,
117 .close = line_close,
118 .write = line_write,
119 .write_room = line_write_room,
120 .chars_in_buffer = line_chars_in_buffer,
121 .set_termios = line_set_termios,
122 .ioctl = line_ioctl,
123};
124
125static void uml_console_write(struct console *console, const char *string,
126 unsigned len)
127{
128 struct line *line = &vts[console->index];
129
130 down(&line->sem);
131 console_write_chan(&line->chan_list, string, len);
132 up(&line->sem);
133}
134
135static struct tty_driver *uml_console_device(struct console *c, int *index)
136{
137 *index = c->index;
138 return console_driver;
139}
140
141static int uml_console_setup(struct console *co, char *options)
142{
143 struct line *line = &vts[co->index];
144
145 return console_open_chan(line,co,&opts);
146}
147
148static struct console stdiocons = {
149 .name = "tty",
150 .write = uml_console_write,
151 .device = uml_console_device,
152 .setup = uml_console_setup,
153 .flags = CON_PRINTBUFFER,
154 .index = -1,
155 .data = &vts,
156};
157
158int stdio_init(void)
159{
160 char *new_title;
161
162 console_driver = line_register_devfs(&console_lines, &driver,
163 &console_ops, vts,
164 ARRAY_SIZE(vts));
165 if (NULL == console_driver)
166 return -1;
167 printk(KERN_INFO "Initialized stdio console driver\n");
168
169 lines_init(vts, sizeof(vts)/sizeof(vts[0]));
170
171 new_title = add_xterm_umid(opts.xterm_title);
172 if(new_title != NULL)
173 opts.xterm_title = new_title;
174
175 con_init_done = 1;
176 register_console(&stdiocons);
177 return(0);
178}
179late_initcall(stdio_init);
180
181static void console_exit(void)
182{
183 if (!con_init_done)
184 return;
185 close_lines(vts, sizeof(vts)/sizeof(vts[0]));
186}
187__uml_exitcall(console_exit);
188
189static int console_chan_setup(char *str)
190{
191 return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1));
192}
193__setup("con", console_chan_setup);
194__channel_help(console_chan_setup, "con");
195
196/*
197 * Overrides for Emacs so that we follow Linus's tabbing style.
198 * Emacs will notice this stuff at the end of the file and automatically
199 * adjust the settings for this buffer only. This must remain at the end
200 * of the file.
201 * ---------------------------------------------------------------------------
202 * Local variables:
203 * c-file-style: "linux"
204 * End:
205 */
diff --git a/arch/um/drivers/stdio_console.h b/arch/um/drivers/stdio_console.h
new file mode 100644
index 000000000000..505a3d5bea5e
--- /dev/null
+++ b/arch/um/drivers/stdio_console.h
@@ -0,0 +1,21 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __STDIO_CONSOLE_H
7#define __STDIO_CONSOLE_H
8
9extern void save_console_flags(void);
10#endif
11
12/*
13 * Overrides for Emacs so that we follow Linus's tabbing style.
14 * Emacs will notice this stuff at the end of the file and automatically
15 * adjust the settings for this buffer only. This must remain at the end
16 * of the file.
17 * ---------------------------------------------------------------------------
18 * Local variables:
19 * c-file-style: "linux"
20 * End:
21 */
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
new file mode 100644
index 000000000000..6fbb670ee274
--- /dev/null
+++ b/arch/um/drivers/tty.c
@@ -0,0 +1,92 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <termios.h>
8#include <errno.h>
9#include <unistd.h>
10#include "chan_user.h"
11#include "user_util.h"
12#include "user.h"
13#include "os.h"
14
15struct tty_chan {
16 char *dev;
17 int raw;
18 struct termios tt;
19};
20
21static void *tty_chan_init(char *str, int device, struct chan_opts *opts)
22{
23 struct tty_chan *data;
24
25 if(*str != ':'){
26 printk("tty_init : channel type 'tty' must specify "
27 "a device\n");
28 return(NULL);
29 }
30 str++;
31
32 data = um_kmalloc(sizeof(*data));
33 if(data == NULL)
34 return(NULL);
35 *data = ((struct tty_chan) { .dev = str,
36 .raw = opts->raw });
37
38 return(data);
39}
40
41static int tty_open(int input, int output, int primary, void *d,
42 char **dev_out)
43{
44 struct tty_chan *data = d;
45 int fd, err;
46
47 fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0);
48 if(fd < 0) return(fd);
49 if(data->raw){
50 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
51 if(err)
52 return(err);
53
54 err = raw(fd);
55 if(err)
56 return(err);
57 }
58
59 *dev_out = data->dev;
60 return(fd);
61}
62
63static int tty_console_write(int fd, const char *buf, int n, void *d)
64{
65 struct tty_chan *data = d;
66
67 return(generic_console_write(fd, buf, n, &data->tt));
68}
69
70struct chan_ops tty_ops = {
71 .type = "tty",
72 .init = tty_chan_init,
73 .open = tty_open,
74 .close = generic_close,
75 .read = generic_read,
76 .write = generic_write,
77 .console_write = tty_console_write,
78 .window_size = generic_window_size,
79 .free = generic_free,
80 .winch = 0,
81};
82
83/*
84 * Overrides for Emacs so that we follow Linus's tabbing style.
85 * Emacs will notice this stuff at the end of the file and automatically
86 * adjust the settings for this buffer only. This must remain at the end
87 * of the file.
88 * ---------------------------------------------------------------------------
89 * Local variables:
90 * c-file-style: "linux"
91 * End:
92 */
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
new file mode 100644
index 000000000000..4d8b165bfa48
--- /dev/null
+++ b/arch/um/drivers/ubd_kern.c
@@ -0,0 +1,1669 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6/* 2001-09-28...2002-04-17
7 * Partition stuff by James_McMechan@hotmail.com
8 * old style ubd by setting UBD_SHIFT to 0
9 * 2002-09-27...2002-10-18 massive tinkering for 2.5
10 * partitions have changed in 2.5
11 * 2003-01-29 more tinkering for 2.5.59-1
12 * This should now address the sysfs problems and has
13 * the symlink for devfs to allow for booting with
14 * the common /dev/ubd/discX/... names rather than
15 * only /dev/ubdN/discN this version also has lots of
16 * clean ups preparing for ubd-many.
17 * James McMechan
18 */
19
20#define MAJOR_NR UBD_MAJOR
21#define UBD_SHIFT 4
22
23#include "linux/config.h"
24#include "linux/module.h"
25#include "linux/blkdev.h"
26#include "linux/hdreg.h"
27#include "linux/init.h"
28#include "linux/devfs_fs_kernel.h"
29#include "linux/cdrom.h"
30#include "linux/proc_fs.h"
31#include "linux/ctype.h"
32#include "linux/capability.h"
33#include "linux/mm.h"
34#include "linux/vmalloc.h"
35#include "linux/blkpg.h"
36#include "linux/genhd.h"
37#include "linux/spinlock.h"
38#include "asm/segment.h"
39#include "asm/uaccess.h"
40#include "asm/irq.h"
41#include "asm/types.h"
42#include "asm/tlbflush.h"
43#include "user_util.h"
44#include "mem_user.h"
45#include "kern_util.h"
46#include "kern.h"
47#include "mconsole_kern.h"
48#include "init.h"
49#include "irq_user.h"
50#include "irq_kern.h"
51#include "ubd_user.h"
52#include "2_5compat.h"
53#include "os.h"
54#include "mem.h"
55#include "mem_kern.h"
56#include "cow.h"
57
58enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP };
59
60struct io_thread_req {
61 enum ubd_req op;
62 int fds[2];
63 unsigned long offsets[2];
64 unsigned long long offset;
65 unsigned long length;
66 char *buffer;
67 int sectorsize;
68 unsigned long sector_mask;
69 unsigned long long cow_offset;
70 unsigned long bitmap_words[2];
71 int map_fd;
72 unsigned long long map_offset;
73 int error;
74};
75
76extern int open_ubd_file(char *file, struct openflags *openflags,
77 char **backing_file_out, int *bitmap_offset_out,
78 unsigned long *bitmap_len_out, int *data_offset_out,
79 int *create_cow_out);
80extern int create_cow_file(char *cow_file, char *backing_file,
81 struct openflags flags, int sectorsize,
82 int alignment, int *bitmap_offset_out,
83 unsigned long *bitmap_len_out,
84 int *data_offset_out);
85extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
86extern void do_io(struct io_thread_req *req);
87
88static inline int ubd_test_bit(__u64 bit, unsigned char *data)
89{
90 __u64 n;
91 int bits, off;
92
93 bits = sizeof(data[0]) * 8;
94 n = bit / bits;
95 off = bit % bits;
96 return((data[n] & (1 << off)) != 0);
97}
98
99static inline void ubd_set_bit(__u64 bit, unsigned char *data)
100{
101 __u64 n;
102 int bits, off;
103
104 bits = sizeof(data[0]) * 8;
105 n = bit / bits;
106 off = bit % bits;
107 data[n] |= (1 << off);
108}
109/*End stuff from ubd_user.h*/
110
111#define DRIVER_NAME "uml-blkdev"
112
113static DEFINE_SPINLOCK(ubd_io_lock);
114static DEFINE_SPINLOCK(ubd_lock);
115
116static void (*do_ubd)(void);
117
118static int ubd_open(struct inode * inode, struct file * filp);
119static int ubd_release(struct inode * inode, struct file * file);
120static int ubd_ioctl(struct inode * inode, struct file * file,
121 unsigned int cmd, unsigned long arg);
122
123#define MAX_DEV (8)
124
125/* Changed in early boot */
126static int ubd_do_mmap = 0;
127#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE
128
129static struct block_device_operations ubd_blops = {
130 .owner = THIS_MODULE,
131 .open = ubd_open,
132 .release = ubd_release,
133 .ioctl = ubd_ioctl,
134};
135
136/* Protected by the queue_lock */
137static request_queue_t *ubd_queue;
138
139/* Protected by ubd_lock */
140static int fake_major = MAJOR_NR;
141
142static struct gendisk *ubd_gendisk[MAX_DEV];
143static struct gendisk *fake_gendisk[MAX_DEV];
144
145#ifdef CONFIG_BLK_DEV_UBD_SYNC
146#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
147 .cl = 1 })
148#else
149#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
150 .cl = 1 })
151#endif
152
153/* Not protected - changed only in ubd_setup_common and then only to
154 * to enable O_SYNC.
155 */
156static struct openflags global_openflags = OPEN_FLAGS;
157
158struct cow {
159 char *file;
160 int fd;
161 unsigned long *bitmap;
162 unsigned long bitmap_len;
163 int bitmap_offset;
164 int data_offset;
165};
166
167struct ubd {
168 char *file;
169 int count;
170 int fd;
171 __u64 size;
172 struct openflags boot_openflags;
173 struct openflags openflags;
174 int no_cow;
175 struct cow cow;
176 struct platform_device pdev;
177
178 int map_writes;
179 int map_reads;
180 int nomap_writes;
181 int nomap_reads;
182 int write_maps;
183};
184
185#define DEFAULT_COW { \
186 .file = NULL, \
187 .fd = -1, \
188 .bitmap = NULL, \
189 .bitmap_offset = 0, \
190 .data_offset = 0, \
191}
192
193#define DEFAULT_UBD { \
194 .file = NULL, \
195 .count = 0, \
196 .fd = -1, \
197 .size = -1, \
198 .boot_openflags = OPEN_FLAGS, \
199 .openflags = OPEN_FLAGS, \
200 .no_cow = 0, \
201 .cow = DEFAULT_COW, \
202 .map_writes = 0, \
203 .map_reads = 0, \
204 .nomap_writes = 0, \
205 .nomap_reads = 0, \
206 .write_maps = 0, \
207}
208
209struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
210
211static int ubd0_init(void)
212{
213 struct ubd *dev = &ubd_dev[0];
214
215 if(dev->file == NULL)
216 dev->file = "root_fs";
217 return(0);
218}
219
220__initcall(ubd0_init);
221
222/* Only changed by fake_ide_setup which is a setup */
223static int fake_ide = 0;
224static struct proc_dir_entry *proc_ide_root = NULL;
225static struct proc_dir_entry *proc_ide = NULL;
226
227static void make_proc_ide(void)
228{
229 proc_ide_root = proc_mkdir("ide", NULL);
230 proc_ide = proc_mkdir("ide0", proc_ide_root);
231}
232
233static int proc_ide_read_media(char *page, char **start, off_t off, int count,
234 int *eof, void *data)
235{
236 int len;
237
238 strcpy(page, "disk\n");
239 len = strlen("disk\n");
240 len -= off;
241 if (len < count){
242 *eof = 1;
243 if (len <= 0) return 0;
244 }
245 else len = count;
246 *start = page + off;
247 return len;
248}
249
250static void make_ide_entries(char *dev_name)
251{
252 struct proc_dir_entry *dir, *ent;
253 char name[64];
254
255 if(proc_ide_root == NULL) make_proc_ide();
256
257 dir = proc_mkdir(dev_name, proc_ide);
258 if(!dir) return;
259
260 ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
261 if(!ent) return;
262 ent->nlink = 1;
263 ent->data = NULL;
264 ent->read_proc = proc_ide_read_media;
265 ent->write_proc = NULL;
266 sprintf(name,"ide0/%s", dev_name);
267 proc_symlink(dev_name, proc_ide_root, name);
268}
269
270static int fake_ide_setup(char *str)
271{
272 fake_ide = 1;
273 return(1);
274}
275
276__setup("fake_ide", fake_ide_setup);
277
278__uml_help(fake_ide_setup,
279"fake_ide\n"
280" Create ide0 entries that map onto ubd devices.\n\n"
281);
282
283static int parse_unit(char **ptr)
284{
285 char *str = *ptr, *end;
286 int n = -1;
287
288 if(isdigit(*str)) {
289 n = simple_strtoul(str, &end, 0);
290 if(end == str)
291 return(-1);
292 *ptr = end;
293 }
294 else if (('a' <= *str) && (*str <= 'h')) {
295 n = *str - 'a';
296 str++;
297 *ptr = str;
298 }
299 return(n);
300}
301
302static int ubd_setup_common(char *str, int *index_out)
303{
304 struct ubd *dev;
305 struct openflags flags = global_openflags;
306 char *backing_file;
307 int n, err, i;
308
309 if(index_out) *index_out = -1;
310 n = *str;
311 if(n == '='){
312 char *end;
313 int major;
314
315 str++;
316 if(!strcmp(str, "mmap")){
317 CHOOSE_MODE(printk("mmap not supported by the ubd "
318 "driver in tt mode\n"),
319 ubd_do_mmap = 1);
320 return(0);
321 }
322
323 if(!strcmp(str, "sync")){
324 global_openflags = of_sync(global_openflags);
325 return(0);
326 }
327 major = simple_strtoul(str, &end, 0);
328 if((*end != '\0') || (end == str)){
329 printk(KERN_ERR
330 "ubd_setup : didn't parse major number\n");
331 return(1);
332 }
333
334 err = 1;
335 spin_lock(&ubd_lock);
336 if(fake_major != MAJOR_NR){
337 printk(KERN_ERR "Can't assign a fake major twice\n");
338 goto out1;
339 }
340
341 fake_major = major;
342
343 printk(KERN_INFO "Setting extra ubd major number to %d\n",
344 major);
345 err = 0;
346 out1:
347 spin_unlock(&ubd_lock);
348 return(err);
349 }
350
351 n = parse_unit(&str);
352 if(n < 0){
353 printk(KERN_ERR "ubd_setup : couldn't parse unit number "
354 "'%s'\n", str);
355 return(1);
356 }
357 if(n >= MAX_DEV){
358 printk(KERN_ERR "ubd_setup : index %d out of range "
359 "(%d devices, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1);
360 return(1);
361 }
362
363 err = 1;
364 spin_lock(&ubd_lock);
365
366 dev = &ubd_dev[n];
367 if(dev->file != NULL){
368 printk(KERN_ERR "ubd_setup : device already configured\n");
369 goto out;
370 }
371
372 if (index_out)
373 *index_out = n;
374
375 for (i = 0; i < 4; i++) {
376 switch (*str) {
377 case 'r':
378 flags.w = 0;
379 break;
380 case 's':
381 flags.s = 1;
382 break;
383 case 'd':
384 dev->no_cow = 1;
385 break;
386 case '=':
387 str++;
388 goto break_loop;
389 default:
390 printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r,s or d)\n");
391 goto out;
392 }
393 str++;
394 }
395
396 if (*str == '=')
397 printk(KERN_ERR "ubd_setup : Too many flags specified\n");
398 else
399 printk(KERN_ERR "ubd_setup : Expected '='\n");
400 goto out;
401
402break_loop:
403 err = 0;
404 backing_file = strchr(str, ',');
405
406 if (!backing_file) {
407 backing_file = strchr(str, ':');
408 }
409
410 if(backing_file){
411 if(dev->no_cow)
412 printk(KERN_ERR "Can't specify both 'd' and a "
413 "cow file\n");
414 else {
415 *backing_file = '\0';
416 backing_file++;
417 }
418 }
419 dev->file = str;
420 dev->cow.file = backing_file;
421 dev->boot_openflags = flags;
422out:
423 spin_unlock(&ubd_lock);
424 return(err);
425}
426
427static int ubd_setup(char *str)
428{
429 ubd_setup_common(str, NULL);
430 return(1);
431}
432
433__setup("ubd", ubd_setup);
434__uml_help(ubd_setup,
435"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
436" This is used to associate a device with a file in the underlying\n"
437" filesystem. When specifying two filenames, the first one is the\n"
438" COW name and the second is the backing file name. As separator you can\n"
439" use either a ':' or a ',': the first one allows writing things like;\n"
440" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
441" while with a ',' the shell would not expand the 2nd '~'.\n"
442" When using only one filename, UML will detect whether to thread it like\n"
443" a COW file or a backing file. To override this detection, add the 'd'\n"
444" flag:\n"
445" ubd0d=BackingFile\n"
446" Usually, there is a filesystem in the file, but \n"
447" that's not required. Swap devices containing swap files can be\n"
448" specified like this. Also, a file which doesn't contain a\n"
449" filesystem can have its contents read in the virtual \n"
450" machine by running 'dd' on the device. <n> must be in the range\n"
451" 0 to 7. Appending an 'r' to the number will cause that device\n"
452" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
453" an 's' will cause data to be written to disk on the host immediately.\n\n"
454);
455
456static int udb_setup(char *str)
457{
458 printk("udb%s specified on command line is almost certainly a ubd -> "
459 "udb TYPO\n", str);
460 return(1);
461}
462
463__setup("udb", udb_setup);
464__uml_help(udb_setup,
465"udb\n"
466" This option is here solely to catch ubd -> udb typos, which can be\n\n"
467" to impossible to catch visually unless you specifically look for\n\n"
468" them. The only result of any option starting with 'udb' is an error\n\n"
469" in the boot output.\n\n"
470);
471
472static int fakehd_set = 0;
473static int fakehd(char *str)
474{
475 printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
476 fakehd_set = 1;
477 return 1;
478}
479
480__setup("fakehd", fakehd);
481__uml_help(fakehd,
482"fakehd\n"
483" Change the ubd device name to \"hd\".\n\n"
484);
485
486static void do_ubd_request(request_queue_t * q);
487
488/* Only changed by ubd_init, which is an initcall. */
489int thread_fd = -1;
490
491/* Changed by ubd_handler, which is serialized because interrupts only
492 * happen on CPU 0.
493 */
494int intr_count = 0;
495
496/* call ubd_finish if you need to serialize */
497static void __ubd_finish(struct request *req, int error)
498{
499 int nsect;
500
501 if(error){
502 end_request(req, 0);
503 return;
504 }
505 nsect = req->current_nr_sectors;
506 req->sector += nsect;
507 req->buffer += nsect << 9;
508 req->errors = 0;
509 req->nr_sectors -= nsect;
510 req->current_nr_sectors = 0;
511 end_request(req, 1);
512}
513
514static inline void ubd_finish(struct request *req, int error)
515{
516 spin_lock(&ubd_io_lock);
517 __ubd_finish(req, error);
518 spin_unlock(&ubd_io_lock);
519}
520
521/* Called without ubd_io_lock held */
522static void ubd_handler(void)
523{
524 struct io_thread_req req;
525 struct request *rq = elv_next_request(ubd_queue);
526 int n, err;
527
528 do_ubd = NULL;
529 intr_count++;
530 n = os_read_file(thread_fd, &req, sizeof(req));
531 if(n != sizeof(req)){
532 printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
533 "err = %d\n", os_getpid(), -n);
534 spin_lock(&ubd_io_lock);
535 end_request(rq, 0);
536 spin_unlock(&ubd_io_lock);
537 return;
538 }
539
540 if((req.op != UBD_MMAP) &&
541 ((req.offset != ((__u64) (rq->sector)) << 9) ||
542 (req.length != (rq->current_nr_sectors) << 9)))
543 panic("I/O op mismatch");
544
545 if(req.map_fd != -1){
546 err = physmem_subst_mapping(req.buffer, req.map_fd,
547 req.map_offset, 1);
548 if(err)
549 printk("ubd_handler - physmem_subst_mapping failed, "
550 "err = %d\n", -err);
551 }
552
553 ubd_finish(rq, req.error);
554 reactivate_fd(thread_fd, UBD_IRQ);
555 do_ubd_request(ubd_queue);
556}
557
558static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
559{
560 ubd_handler();
561 return(IRQ_HANDLED);
562}
563
564/* Only changed by ubd_init, which is an initcall. */
565static int io_pid = -1;
566
567void kill_io_thread(void)
568{
569 if(io_pid != -1)
570 os_kill_process(io_pid, 1);
571}
572
573__uml_exitcall(kill_io_thread);
574
575static int ubd_file_size(struct ubd *dev, __u64 *size_out)
576{
577 char *file;
578
579 file = dev->cow.file ? dev->cow.file : dev->file;
580 return(os_file_size(file, size_out));
581}
582
583static void ubd_close(struct ubd *dev)
584{
585 if(ubd_do_mmap)
586 physmem_forget_descriptor(dev->fd);
587 os_close_file(dev->fd);
588 if(dev->cow.file == NULL)
589 return;
590
591 if(ubd_do_mmap)
592 physmem_forget_descriptor(dev->cow.fd);
593 os_close_file(dev->cow.fd);
594 vfree(dev->cow.bitmap);
595 dev->cow.bitmap = NULL;
596}
597
598static int ubd_open_dev(struct ubd *dev)
599{
600 struct openflags flags;
601 char **back_ptr;
602 int err, create_cow, *create_ptr;
603
604 dev->openflags = dev->boot_openflags;
605 create_cow = 0;
606 create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
607 back_ptr = dev->no_cow ? NULL : &dev->cow.file;
608 dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr,
609 &dev->cow.bitmap_offset, &dev->cow.bitmap_len,
610 &dev->cow.data_offset, create_ptr);
611
612 if((dev->fd == -ENOENT) && create_cow){
613 dev->fd = create_cow_file(dev->file, dev->cow.file,
614 dev->openflags, 1 << 9, PAGE_SIZE,
615 &dev->cow.bitmap_offset,
616 &dev->cow.bitmap_len,
617 &dev->cow.data_offset);
618 if(dev->fd >= 0){
619 printk(KERN_INFO "Creating \"%s\" as COW file for "
620 "\"%s\"\n", dev->file, dev->cow.file);
621 }
622 }
623
624 if(dev->fd < 0){
625 printk("Failed to open '%s', errno = %d\n", dev->file,
626 -dev->fd);
627 return(dev->fd);
628 }
629
630 if(dev->cow.file != NULL){
631 err = -ENOMEM;
632 dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
633 if(dev->cow.bitmap == NULL){
634 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
635 goto error;
636 }
637 flush_tlb_kernel_vm();
638
639 err = read_cow_bitmap(dev->fd, dev->cow.bitmap,
640 dev->cow.bitmap_offset,
641 dev->cow.bitmap_len);
642 if(err < 0)
643 goto error;
644
645 flags = dev->openflags;
646 flags.w = 0;
647 err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL,
648 NULL, NULL);
649 if(err < 0) goto error;
650 dev->cow.fd = err;
651 }
652 return(0);
653 error:
654 os_close_file(dev->fd);
655 return(err);
656}
657
658static int ubd_new_disk(int major, u64 size, int unit,
659 struct gendisk **disk_out)
660
661{
662 struct gendisk *disk;
663 char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")];
664 int err;
665
666 disk = alloc_disk(1 << UBD_SHIFT);
667 if(disk == NULL)
668 return(-ENOMEM);
669
670 disk->major = major;
671 disk->first_minor = unit << UBD_SHIFT;
672 disk->fops = &ubd_blops;
673 set_capacity(disk, size / 512);
674 if(major == MAJOR_NR){
675 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
676 sprintf(disk->devfs_name, "ubd/disc%d", unit);
677 sprintf(from, "ubd/%d", unit);
678 sprintf(to, "disc%d/disc", unit);
679 err = devfs_mk_symlink(from, to);
680 if(err)
681 printk("ubd_new_disk failed to make link from %s to "
682 "%s, error = %d\n", from, to, err);
683 }
684 else {
685 sprintf(disk->disk_name, "ubd_fake%d", unit);
686 sprintf(disk->devfs_name, "ubd_fake/disc%d", unit);
687 }
688
689 /* sysfs register (not for ide fake devices) */
690 if (major == MAJOR_NR) {
691 ubd_dev[unit].pdev.id = unit;
692 ubd_dev[unit].pdev.name = DRIVER_NAME;
693 platform_device_register(&ubd_dev[unit].pdev);
694 disk->driverfs_dev = &ubd_dev[unit].pdev.dev;
695 }
696
697 disk->private_data = &ubd_dev[unit];
698 disk->queue = ubd_queue;
699 add_disk(disk);
700
701 *disk_out = disk;
702 return 0;
703}
704
705#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
706
707static int ubd_add(int n)
708{
709 struct ubd *dev = &ubd_dev[n];
710 int err;
711
712 if(dev->file == NULL)
713 return(-ENODEV);
714
715 if (ubd_open_dev(dev))
716 return(-ENODEV);
717
718 err = ubd_file_size(dev, &dev->size);
719 if(err < 0)
720 return(err);
721
722 dev->size = ROUND_BLOCK(dev->size);
723
724 err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
725 if(err)
726 return(err);
727
728 if(fake_major != MAJOR_NR)
729 ubd_new_disk(fake_major, dev->size, n,
730 &fake_gendisk[n]);
731
732 /* perhaps this should also be under the "if (fake_major)" above */
733 /* using the fake_disk->disk_name and also the fakehd_set name */
734 if (fake_ide)
735 make_ide_entries(ubd_gendisk[n]->disk_name);
736
737 ubd_close(dev);
738 return 0;
739}
740
741static int ubd_config(char *str)
742{
743 int n, err;
744
745 str = uml_strdup(str);
746 if(str == NULL){
747 printk(KERN_ERR "ubd_config failed to strdup string\n");
748 return(1);
749 }
750 err = ubd_setup_common(str, &n);
751 if(err){
752 kfree(str);
753 return(-1);
754 }
755 if(n == -1) return(0);
756
757 spin_lock(&ubd_lock);
758 err = ubd_add(n);
759 if(err)
760 ubd_dev[n].file = NULL;
761 spin_unlock(&ubd_lock);
762
763 return(err);
764}
765
766static int ubd_get_config(char *name, char *str, int size, char **error_out)
767{
768 struct ubd *dev;
769 int n, len = 0;
770
771 n = parse_unit(&name);
772 if((n >= MAX_DEV) || (n < 0)){
773 *error_out = "ubd_get_config : device number out of range";
774 return(-1);
775 }
776
777 dev = &ubd_dev[n];
778 spin_lock(&ubd_lock);
779
780 if(dev->file == NULL){
781 CONFIG_CHUNK(str, size, len, "", 1);
782 goto out;
783 }
784
785 CONFIG_CHUNK(str, size, len, dev->file, 0);
786
787 if(dev->cow.file != NULL){
788 CONFIG_CHUNK(str, size, len, ",", 0);
789 CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
790 }
791 else CONFIG_CHUNK(str, size, len, "", 1);
792
793 out:
794 spin_unlock(&ubd_lock);
795 return(len);
796}
797
798static int ubd_remove(char *str)
799{
800 struct ubd *dev;
801 int n, err = -ENODEV;
802
803 n = parse_unit(&str);
804
805 if((n < 0) || (n >= MAX_DEV))
806 return(err);
807
808 dev = &ubd_dev[n];
809 if(dev->count > 0)
810 return(-EBUSY); /* you cannot remove a open disk */
811
812 err = 0;
813 spin_lock(&ubd_lock);
814
815 if(ubd_gendisk[n] == NULL)
816 goto out;
817
818 del_gendisk(ubd_gendisk[n]);
819 put_disk(ubd_gendisk[n]);
820 ubd_gendisk[n] = NULL;
821
822 if(fake_gendisk[n] != NULL){
823 del_gendisk(fake_gendisk[n]);
824 put_disk(fake_gendisk[n]);
825 fake_gendisk[n] = NULL;
826 }
827
828 platform_device_unregister(&dev->pdev);
829 *dev = ((struct ubd) DEFAULT_UBD);
830 err = 0;
831 out:
832 spin_unlock(&ubd_lock);
833 return(err);
834}
835
836static struct mc_device ubd_mc = {
837 .name = "ubd",
838 .config = ubd_config,
839 .get_config = ubd_get_config,
840 .remove = ubd_remove,
841};
842
843static int ubd_mc_init(void)
844{
845 mconsole_register_dev(&ubd_mc);
846 return 0;
847}
848
849__initcall(ubd_mc_init);
850
851static struct device_driver ubd_driver = {
852 .name = DRIVER_NAME,
853 .bus = &platform_bus_type,
854};
855
856int ubd_init(void)
857{
858 int i;
859
860 devfs_mk_dir("ubd");
861 if (register_blkdev(MAJOR_NR, "ubd"))
862 return -1;
863
864 ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock);
865 if (!ubd_queue) {
866 unregister_blkdev(MAJOR_NR, "ubd");
867 return -1;
868 }
869
870 if (fake_major != MAJOR_NR) {
871 char name[sizeof("ubd_nnn\0")];
872
873 snprintf(name, sizeof(name), "ubd_%d", fake_major);
874 devfs_mk_dir(name);
875 if (register_blkdev(fake_major, "ubd"))
876 return -1;
877 }
878 driver_register(&ubd_driver);
879 for (i = 0; i < MAX_DEV; i++)
880 ubd_add(i);
881 return 0;
882}
883
884late_initcall(ubd_init);
885
886int ubd_driver_init(void){
887 unsigned long stack;
888 int err;
889
890 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
891 if(global_openflags.s){
892 printk(KERN_INFO "ubd: Synchronous mode\n");
893 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
894 * enough. So use anyway the io thread. */
895 }
896 stack = alloc_stack(0, 0);
897 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
898 &thread_fd);
899 if(io_pid < 0){
900 printk(KERN_ERR
901 "ubd : Failed to start I/O thread (errno = %d) - "
902 "falling back to synchronous I/O\n", -io_pid);
903 io_pid = -1;
904 return(0);
905 }
906 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
907 SA_INTERRUPT, "ubd", ubd_dev);
908 if(err != 0)
909 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
910 return(err);
911}
912
913device_initcall(ubd_driver_init);
914
915static int ubd_open(struct inode *inode, struct file *filp)
916{
917 struct gendisk *disk = inode->i_bdev->bd_disk;
918 struct ubd *dev = disk->private_data;
919 int err = 0;
920
921 if(dev->count == 0){
922 err = ubd_open_dev(dev);
923 if(err){
924 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
925 disk->disk_name, dev->file, -err);
926 goto out;
927 }
928 }
929 dev->count++;
930 if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
931 if(--dev->count == 0) ubd_close(dev);
932 err = -EROFS;
933 }
934 out:
935 return(err);
936}
937
938static int ubd_release(struct inode * inode, struct file * file)
939{
940 struct gendisk *disk = inode->i_bdev->bd_disk;
941 struct ubd *dev = disk->private_data;
942
943 if(--dev->count == 0)
944 ubd_close(dev);
945 return(0);
946}
947
948static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
949 __u64 *cow_offset, unsigned long *bitmap,
950 __u64 bitmap_offset, unsigned long *bitmap_words,
951 __u64 bitmap_len)
952{
953 __u64 sector = io_offset >> 9;
954 int i, update_bitmap = 0;
955
956 for(i = 0; i < length >> 9; i++){
957 if(cow_mask != NULL)
958 ubd_set_bit(i, (unsigned char *) cow_mask);
959 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
960 continue;
961
962 update_bitmap = 1;
963 ubd_set_bit(sector + i, (unsigned char *) bitmap);
964 }
965
966 if(!update_bitmap)
967 return;
968
969 *cow_offset = sector / (sizeof(unsigned long) * 8);
970
971 /* This takes care of the case where we're exactly at the end of the
972 * device, and *cow_offset + 1 is off the end. So, just back it up
973 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
974 * for the original diagnosis.
975 */
976 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
977 sizeof(unsigned long) - 1))
978 (*cow_offset)--;
979
980 bitmap_words[0] = bitmap[*cow_offset];
981 bitmap_words[1] = bitmap[*cow_offset + 1];
982
983 *cow_offset *= sizeof(unsigned long);
984 *cow_offset += bitmap_offset;
985}
986
987static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
988 __u64 bitmap_offset, __u64 bitmap_len)
989{
990 __u64 sector = req->offset >> 9;
991 int i;
992
993 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
994 panic("Operation too long");
995
996 if(req->op == UBD_READ) {
997 for(i = 0; i < req->length >> 9; i++){
998 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
999 ubd_set_bit(i, (unsigned char *)
1000 &req->sector_mask);
1001 }
1002 }
1003 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1004 &req->cow_offset, bitmap, bitmap_offset,
1005 req->bitmap_words, bitmap_len);
1006}
1007
1008static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset)
1009{
1010 __u64 sector;
1011 unsigned char *bitmap;
1012 int bit, i;
1013
1014 /* mmap must have been requested on the command line */
1015 if(!ubd_do_mmap)
1016 return(-1);
1017
1018 /* The buffer must be page aligned */
1019 if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0)
1020 return(-1);
1021
1022 /* The request must be a page long */
1023 if((req->current_nr_sectors << 9) != PAGE_SIZE)
1024 return(-1);
1025
1026 if(dev->cow.file == NULL)
1027 return(dev->fd);
1028
1029 sector = offset >> 9;
1030 bitmap = (unsigned char *) dev->cow.bitmap;
1031 bit = ubd_test_bit(sector, bitmap);
1032
1033 for(i = 1; i < req->current_nr_sectors; i++){
1034 if(ubd_test_bit(sector + i, bitmap) != bit)
1035 return(-1);
1036 }
1037
1038 if(bit || (rq_data_dir(req) == WRITE))
1039 offset += dev->cow.data_offset;
1040
1041 /* The data on disk must be page aligned */
1042 if((offset % UBD_MMAP_BLOCK_SIZE) != 0)
1043 return(-1);
1044
1045 return(bit ? dev->fd : dev->cow.fd);
1046}
1047
1048static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset,
1049 struct request *req,
1050 struct io_thread_req *io_req)
1051{
1052 int err;
1053
1054 if(rq_data_dir(req) == WRITE){
1055 /* Writes are almost no-ops since the new data is already in the
1056 * host page cache
1057 */
1058 dev->map_writes++;
1059 if(dev->cow.file != NULL)
1060 cowify_bitmap(io_req->offset, io_req->length,
1061 &io_req->sector_mask, &io_req->cow_offset,
1062 dev->cow.bitmap, dev->cow.bitmap_offset,
1063 io_req->bitmap_words,
1064 dev->cow.bitmap_len);
1065 }
1066 else {
1067 int w;
1068
1069 if((dev->cow.file != NULL) && (fd == dev->cow.fd))
1070 w = 0;
1071 else w = dev->openflags.w;
1072
1073 if((dev->cow.file != NULL) && (fd == dev->fd))
1074 offset += dev->cow.data_offset;
1075
1076 err = physmem_subst_mapping(req->buffer, fd, offset, w);
1077 if(err){
1078 printk("physmem_subst_mapping failed, err = %d\n",
1079 -err);
1080 return(1);
1081 }
1082 dev->map_reads++;
1083 }
1084 io_req->op = UBD_MMAP;
1085 io_req->buffer = req->buffer;
1086 return(0);
1087}
1088
1089/* Called with ubd_io_lock held */
1090static int prepare_request(struct request *req, struct io_thread_req *io_req)
1091{
1092 struct gendisk *disk = req->rq_disk;
1093 struct ubd *dev = disk->private_data;
1094 __u64 offset;
1095 int len, fd;
1096
1097 if(req->rq_status == RQ_INACTIVE) return(1);
1098
1099 if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
1100 printk("Write attempted on readonly ubd device %s\n",
1101 disk->disk_name);
1102 end_request(req, 0);
1103 return(1);
1104 }
1105
1106 offset = ((__u64) req->sector) << 9;
1107 len = req->current_nr_sectors << 9;
1108
1109 io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
1110 io_req->fds[1] = dev->fd;
1111 io_req->map_fd = -1;
1112 io_req->cow_offset = -1;
1113 io_req->offset = offset;
1114 io_req->length = len;
1115 io_req->error = 0;
1116 io_req->sector_mask = 0;
1117
1118 fd = mmap_fd(req, dev, io_req->offset);
1119 if(fd > 0){
1120 /* If mmapping is otherwise OK, but the first access to the
1121 * page is a write, then it's not mapped in yet. So we have
1122 * to write the data to disk first, then we can map the disk
1123 * page in and continue normally from there.
1124 */
1125 if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){
1126 io_req->map_fd = dev->fd;
1127 io_req->map_offset = io_req->offset +
1128 dev->cow.data_offset;
1129 dev->write_maps++;
1130 }
1131 else return(prepare_mmap_request(dev, fd, io_req->offset, req,
1132 io_req));
1133 }
1134
1135 if(rq_data_dir(req) == READ)
1136 dev->nomap_reads++;
1137 else dev->nomap_writes++;
1138
1139 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
1140 io_req->offsets[0] = 0;
1141 io_req->offsets[1] = dev->cow.data_offset;
1142 io_req->buffer = req->buffer;
1143 io_req->sectorsize = 1 << 9;
1144
1145 if(dev->cow.file != NULL)
1146 cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
1147 dev->cow.bitmap_len);
1148
1149 return(0);
1150}
1151
1152/* Called with ubd_io_lock held */
1153static void do_ubd_request(request_queue_t *q)
1154{
1155 struct io_thread_req io_req;
1156 struct request *req;
1157 int err, n;
1158
1159 if(thread_fd == -1){
1160 while((req = elv_next_request(q)) != NULL){
1161 err = prepare_request(req, &io_req);
1162 if(!err){
1163 do_io(&io_req);
1164 __ubd_finish(req, io_req.error);
1165 }
1166 }
1167 }
1168 else {
1169 if(do_ubd || (req = elv_next_request(q)) == NULL)
1170 return;
1171 err = prepare_request(req, &io_req);
1172 if(!err){
1173 do_ubd = ubd_handler;
1174 n = os_write_file(thread_fd, (char *) &io_req,
1175 sizeof(io_req));
1176 if(n != sizeof(io_req))
1177 printk("write to io thread failed, "
1178 "errno = %d\n", -n);
1179 }
1180 }
1181}
1182
1183static int ubd_ioctl(struct inode * inode, struct file * file,
1184 unsigned int cmd, unsigned long arg)
1185{
1186 struct hd_geometry __user *loc = (struct hd_geometry __user *) arg;
1187 struct ubd *dev = inode->i_bdev->bd_disk->private_data;
1188 struct hd_driveid ubd_id = {
1189 .cyls = 0,
1190 .heads = 128,
1191 .sectors = 32,
1192 };
1193
1194 switch (cmd) {
1195 struct hd_geometry g;
1196 struct cdrom_volctrl volume;
1197 case HDIO_GETGEO:
1198 if(!loc) return(-EINVAL);
1199 g.heads = 128;
1200 g.sectors = 32;
1201 g.cylinders = dev->size / (128 * 32 * 512);
1202 g.start = get_start_sect(inode->i_bdev);
1203 return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);
1204
1205 case HDIO_GET_IDENTITY:
1206 ubd_id.cyls = dev->size / (128 * 32 * 512);
1207 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1208 sizeof(ubd_id)))
1209 return(-EFAULT);
1210 return(0);
1211
1212 case CDROMVOLREAD:
1213 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1214 return(-EFAULT);
1215 volume.channel0 = 255;
1216 volume.channel1 = 255;
1217 volume.channel2 = 255;
1218 volume.channel3 = 255;
1219 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1220 return(-EFAULT);
1221 return(0);
1222 }
1223 return(-EINVAL);
1224}
1225
1226static int ubd_check_remapped(int fd, unsigned long address, int is_write,
1227 __u64 offset)
1228{
1229 __u64 bitmap_offset;
1230 unsigned long new_bitmap[2];
1231 int i, err, n;
1232
1233 /* If it's not a write access, we can't do anything about it */
1234 if(!is_write)
1235 return(0);
1236
1237 /* We have a write */
1238 for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){
1239 struct ubd *dev = &ubd_dev[i];
1240
1241 if((dev->fd != fd) && (dev->cow.fd != fd))
1242 continue;
1243
1244 /* It's a write to a ubd device */
1245
1246 if(!dev->openflags.w){
1247 /* It's a write access on a read-only device - probably
1248 * shouldn't happen. If the kernel is trying to change
1249 * something with no intention of writing it back out,
1250 * then this message will clue us in that this needs
1251 * fixing
1252 */
1253 printk("Write access to mapped page from readonly ubd "
1254 "device %d\n", i);
1255 return(0);
1256 }
1257
1258 /* It's a write to a writeable ubd device - it must be COWed
1259 * because, otherwise, the page would have been mapped in
1260 * writeable
1261 */
1262
1263 if(!dev->cow.file)
1264 panic("Write fault on writeable non-COW ubd device %d",
1265 i);
1266
1267 /* It should also be an access to the backing file since the
1268 * COW pages should be mapped in read-write
1269 */
1270
1271 if(fd == dev->fd)
1272 panic("Write fault on a backing page of ubd "
1273 "device %d\n", i);
1274
1275 /* So, we do the write, copying the backing data to the COW
1276 * file...
1277 */
1278
1279 err = os_seek_file(dev->fd, offset + dev->cow.data_offset);
1280 if(err < 0)
1281 panic("Couldn't seek to %lld in COW file of ubd "
1282 "device %d, err = %d",
1283 offset + dev->cow.data_offset, i, -err);
1284
1285 n = os_write_file(dev->fd, (void *) address, PAGE_SIZE);
1286 if(n != PAGE_SIZE)
1287 panic("Couldn't copy data to COW file of ubd "
1288 "device %d, err = %d", i, -n);
1289
1290 /* ... updating the COW bitmap... */
1291
1292 cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset,
1293 dev->cow.bitmap, dev->cow.bitmap_offset,
1294 new_bitmap, dev->cow.bitmap_len);
1295
1296 err = os_seek_file(dev->fd, bitmap_offset);
1297 if(err < 0)
1298 panic("Couldn't seek to %lld in COW file of ubd "
1299 "device %d, err = %d", bitmap_offset, i, -err);
1300
1301 n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap));
1302 if(n != sizeof(new_bitmap))
1303 panic("Couldn't update bitmap of ubd device %d, "
1304 "err = %d", i, -n);
1305
1306 /* Maybe we can map the COW page in, and maybe we can't. If
1307 * it is a pre-V3 COW file, we can't, since the alignment will
1308 * be wrong. If it is a V3 or later COW file which has been
1309 * moved to a system with a larger page size, then maybe we
1310 * can't, depending on the exact location of the page.
1311 */
1312
1313 offset += dev->cow.data_offset;
1314
1315 /* Remove the remapping, putting the original anonymous page
1316 * back. If the COW file can be mapped in, that is done.
1317 * Otherwise, the COW page is read in.
1318 */
1319
1320 if(!physmem_remove_mapping((void *) address))
1321 panic("Address 0x%lx not remapped by ubd device %d",
1322 address, i);
1323 if((offset % UBD_MMAP_BLOCK_SIZE) == 0)
1324 physmem_subst_mapping((void *) address, dev->fd,
1325 offset, 1);
1326 else {
1327 err = os_seek_file(dev->fd, offset);
1328 if(err < 0)
1329 panic("Couldn't seek to %lld in COW file of "
1330 "ubd device %d, err = %d", offset, i,
1331 -err);
1332
1333 n = os_read_file(dev->fd, (void *) address, PAGE_SIZE);
1334 if(n != PAGE_SIZE)
1335 panic("Failed to read page from offset %llx of "
1336 "COW file of ubd device %d, err = %d",
1337 offset, i, -n);
1338 }
1339
1340 return(1);
1341 }
1342
1343 /* It's not a write on a ubd device */
1344 return(0);
1345}
1346
1347static struct remapper ubd_remapper = {
1348 .list = LIST_HEAD_INIT(ubd_remapper.list),
1349 .proc = ubd_check_remapped,
1350};
1351
1352static int ubd_remapper_setup(void)
1353{
1354 if(ubd_do_mmap)
1355 register_remapper(&ubd_remapper);
1356
1357 return(0);
1358}
1359
1360__initcall(ubd_remapper_setup);
1361
1362static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
1363{
1364 struct uml_stat buf1, buf2;
1365 int err;
1366
1367 if(from_cmdline == NULL) return(1);
1368 if(!strcmp(from_cmdline, from_cow)) return(1);
1369
1370 err = os_stat_file(from_cmdline, &buf1);
1371 if(err < 0){
1372 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
1373 return(1);
1374 }
1375 err = os_stat_file(from_cow, &buf2);
1376 if(err < 0){
1377 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
1378 return(1);
1379 }
1380 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
1381 return(1);
1382
1383 printk("Backing file mismatch - \"%s\" requested,\n"
1384 "\"%s\" specified in COW header of \"%s\"\n",
1385 from_cmdline, from_cow, cow);
1386 return(0);
1387}
1388
1389static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1390{
1391 unsigned long modtime;
1392 long long actual;
1393 int err;
1394
1395 err = os_file_modtime(file, &modtime);
1396 if(err < 0){
1397 printk("Failed to get modification time of backing file "
1398 "\"%s\", err = %d\n", file, -err);
1399 return(err);
1400 }
1401
1402 err = os_file_size(file, &actual);
1403 if(err < 0){
1404 printk("Failed to get size of backing file \"%s\", "
1405 "err = %d\n", file, -err);
1406 return(err);
1407 }
1408
1409 if(actual != size){
1410 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1411 * the typecast.*/
1412 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1413 "file\n", (unsigned long long) size, actual);
1414 return(-EINVAL);
1415 }
1416 if(modtime != mtime){
1417 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1418 "file\n", mtime, modtime);
1419 return(-EINVAL);
1420 }
1421 return(0);
1422}
1423
1424int read_cow_bitmap(int fd, void *buf, int offset, int len)
1425{
1426 int err;
1427
1428 err = os_seek_file(fd, offset);
1429 if(err < 0)
1430 return(err);
1431
1432 err = os_read_file(fd, buf, len);
1433 if(err < 0)
1434 return(err);
1435
1436 return(0);
1437}
1438
1439int open_ubd_file(char *file, struct openflags *openflags,
1440 char **backing_file_out, int *bitmap_offset_out,
1441 unsigned long *bitmap_len_out, int *data_offset_out,
1442 int *create_cow_out)
1443{
1444 time_t mtime;
1445 unsigned long long size;
1446 __u32 version, align;
1447 char *backing_file;
1448 int fd, err, sectorsize, same, mode = 0644;
1449
1450 fd = os_open_file(file, *openflags, mode);
1451 if(fd < 0){
1452 if((fd == -ENOENT) && (create_cow_out != NULL))
1453 *create_cow_out = 1;
1454 if(!openflags->w ||
1455 ((fd != -EROFS) && (fd != -EACCES))) return(fd);
1456 openflags->w = 0;
1457 fd = os_open_file(file, *openflags, mode);
1458 if(fd < 0)
1459 return(fd);
1460 }
1461
1462 err = os_lock_file(fd, openflags->w);
1463 if(err < 0){
1464 printk("Failed to lock '%s', err = %d\n", file, -err);
1465 goto out_close;
1466 }
1467
1468 if(backing_file_out == NULL) return(fd);
1469
1470 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1471 &size, &sectorsize, &align, bitmap_offset_out);
1472 if(err && (*backing_file_out != NULL)){
1473 printk("Failed to read COW header from COW file \"%s\", "
1474 "errno = %d\n", file, -err);
1475 goto out_close;
1476 }
1477 if(err) return(fd);
1478
1479 if(backing_file_out == NULL) return(fd);
1480
1481 same = same_backing_files(*backing_file_out, backing_file, file);
1482
1483 if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
1484 printk("Switching backing file to '%s'\n", *backing_file_out);
1485 err = write_cow_header(file, fd, *backing_file_out,
1486 sectorsize, align, &size);
1487 if(err){
1488 printk("Switch failed, errno = %d\n", -err);
1489 return(err);
1490 }
1491 }
1492 else {
1493 *backing_file_out = backing_file;
1494 err = backing_file_mismatch(*backing_file_out, size, mtime);
1495 if(err) goto out_close;
1496 }
1497
1498 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1499 bitmap_len_out, data_offset_out);
1500
1501 return(fd);
1502 out_close:
1503 os_close_file(fd);
1504 return(err);
1505}
1506
1507int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1508 int sectorsize, int alignment, int *bitmap_offset_out,
1509 unsigned long *bitmap_len_out, int *data_offset_out)
1510{
1511 int err, fd;
1512
1513 flags.c = 1;
1514 fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
1515 if(fd < 0){
1516 err = fd;
1517 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1518 -err);
1519 goto out;
1520 }
1521
1522 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1523 bitmap_offset_out, bitmap_len_out,
1524 data_offset_out);
1525 if(!err)
1526 return(fd);
1527 os_close_file(fd);
1528 out:
1529 return(err);
1530}
1531
1532static int update_bitmap(struct io_thread_req *req)
1533{
1534 int n;
1535
1536 if(req->cow_offset == -1)
1537 return(0);
1538
1539 n = os_seek_file(req->fds[1], req->cow_offset);
1540 if(n < 0){
1541 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1542 return(1);
1543 }
1544
1545 n = os_write_file(req->fds[1], &req->bitmap_words,
1546 sizeof(req->bitmap_words));
1547 if(n != sizeof(req->bitmap_words)){
1548 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1549 req->fds[1]);
1550 return(1);
1551 }
1552
1553 return(0);
1554}
1555
1556void do_io(struct io_thread_req *req)
1557{
1558 char *buf;
1559 unsigned long len;
1560 int n, nsectors, start, end, bit;
1561 int err;
1562 __u64 off;
1563
1564 if(req->op == UBD_MMAP){
1565 /* Touch the page to force the host to do any necessary IO to
1566 * get it into memory
1567 */
1568 n = *((volatile int *) req->buffer);
1569 req->error = update_bitmap(req);
1570 return;
1571 }
1572
1573 nsectors = req->length / req->sectorsize;
1574 start = 0;
1575 do {
1576 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1577 end = start;
1578 while((end < nsectors) &&
1579 (ubd_test_bit(end, (unsigned char *)
1580 &req->sector_mask) == bit))
1581 end++;
1582
1583 off = req->offset + req->offsets[bit] +
1584 start * req->sectorsize;
1585 len = (end - start) * req->sectorsize;
1586 buf = &req->buffer[start * req->sectorsize];
1587
1588 err = os_seek_file(req->fds[bit], off);
1589 if(err < 0){
1590 printk("do_io - lseek failed : err = %d\n", -err);
1591 req->error = 1;
1592 return;
1593 }
1594 if(req->op == UBD_READ){
1595 n = 0;
1596 do {
1597 buf = &buf[n];
1598 len -= n;
1599 n = os_read_file(req->fds[bit], buf, len);
1600 if (n < 0) {
1601 printk("do_io - read failed, err = %d "
1602 "fd = %d\n", -n, req->fds[bit]);
1603 req->error = 1;
1604 return;
1605 }
1606 } while((n < len) && (n != 0));
1607 if (n < len) memset(&buf[n], 0, len - n);
1608 }
1609 else {
1610 n = os_write_file(req->fds[bit], buf, len);
1611 if(n != len){
1612 printk("do_io - write failed err = %d "
1613 "fd = %d\n", -n, req->fds[bit]);
1614 req->error = 1;
1615 return;
1616 }
1617 }
1618
1619 start = end;
1620 } while(start < nsectors);
1621
1622 req->error = update_bitmap(req);
1623}
1624
1625/* Changed in start_io_thread, which is serialized by being called only
1626 * from ubd_init, which is an initcall.
1627 */
1628int kernel_fd = -1;
1629
1630/* Only changed by the io thread */
1631int io_count = 0;
1632
1633int io_thread(void *arg)
1634{
1635 struct io_thread_req req;
1636 int n;
1637
1638 ignore_sigwinch_sig();
1639 while(1){
1640 n = os_read_file(kernel_fd, &req, sizeof(req));
1641 if(n != sizeof(req)){
1642 if(n < 0)
1643 printk("io_thread - read failed, fd = %d, "
1644 "err = %d\n", kernel_fd, -n);
1645 else {
1646 printk("io_thread - short read, fd = %d, "
1647 "length = %d\n", kernel_fd, n);
1648 }
1649 continue;
1650 }
1651 io_count++;
1652 do_io(&req);
1653 n = os_write_file(kernel_fd, &req, sizeof(req));
1654 if(n != sizeof(req))
1655 printk("io_thread - write failed, fd = %d, err = %d\n",
1656 kernel_fd, -n);
1657 }
1658}
1659
1660/*
1661 * Overrides for Emacs so that we follow Linus's tabbing style.
1662 * Emacs will notice this stuff at the end of the file and automatically
1663 * adjust the settings for this buffer only. This must remain at the end
1664 * of the file.
1665 * ---------------------------------------------------------------------------
1666 * Local variables:
1667 * c-file-style: "linux"
1668 * End:
1669 */
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
new file mode 100644
index 000000000000..b94d2bc4fe06
--- /dev/null
+++ b/arch/um/drivers/ubd_user.c
@@ -0,0 +1,75 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com)
4 * Licensed under the GPL
5 */
6
7#include <stddef.h>
8#include <unistd.h>
9#include <errno.h>
10#include <sched.h>
11#include <signal.h>
12#include <string.h>
13#include <netinet/in.h>
14#include <sys/time.h>
15#include <sys/socket.h>
16#include <sys/mman.h>
17#include <sys/param.h>
18#include "asm/types.h"
19#include "user_util.h"
20#include "kern_util.h"
21#include "user.h"
22#include "ubd_user.h"
23#include "os.h"
24#include "cow.h"
25
26#include <endian.h>
27#include <byteswap.h>
28
29void ignore_sigwinch_sig(void)
30{
31 signal(SIGWINCH, SIG_IGN);
32}
33
34int start_io_thread(unsigned long sp, int *fd_out)
35{
36 int pid, fds[2], err;
37
38 err = os_pipe(fds, 1, 1);
39 if(err < 0){
40 printk("start_io_thread - os_pipe failed, err = %d\n", -err);
41 goto out;
42 }
43
44 kernel_fd = fds[0];
45 *fd_out = fds[1];
46
47 pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
48 NULL);
49 if(pid < 0){
50 printk("start_io_thread - clone failed : errno = %d\n", errno);
51 err = -errno;
52 goto out_close;
53 }
54
55 return(pid);
56
57 out_close:
58 os_close_file(fds[0]);
59 os_close_file(fds[1]);
60 kernel_fd = -1;
61 *fd_out = -1;
62 out:
63 return(err);
64}
65
66/*
67 * Overrides for Emacs so that we follow Linus's tabbing style.
68 * Emacs will notice this stuff at the end of the file and automatically
69 * adjust the settings for this buffer only. This must remain at the end
70 * of the file.
71 * ---------------------------------------------------------------------------
72 * Local variables:
73 * c-file-style: "linux"
74 * End:
75 */
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
new file mode 100644
index 000000000000..93dc1911363f
--- /dev/null
+++ b/arch/um/drivers/xterm.c
@@ -0,0 +1,225 @@
1/*
2 * Copyright (C) 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 <string.h>
10#include <errno.h>
11#include <termios.h>
12#include <signal.h>
13#include <sched.h>
14#include <sys/socket.h>
15#include "kern_util.h"
16#include "chan_user.h"
17#include "helper.h"
18#include "user_util.h"
19#include "user.h"
20#include "os.h"
21#include "xterm.h"
22
23struct xterm_chan {
24 int pid;
25 int helper_pid;
26 char *title;
27 int device;
28 int raw;
29 struct termios tt;
30 unsigned long stack;
31 int direct_rcv;
32};
33
34/* Not static because it's called directly by the tt mode gdb code */
35void *xterm_init(char *str, int device, struct chan_opts *opts)
36{
37 struct xterm_chan *data;
38
39 data = malloc(sizeof(*data));
40 if(data == NULL) return(NULL);
41 *data = ((struct xterm_chan) { .pid = -1,
42 .helper_pid = -1,
43 .device = device,
44 .title = opts->xterm_title,
45 .raw = opts->raw,
46 .stack = opts->tramp_stack,
47 .direct_rcv = !opts->in_kernel } );
48 return(data);
49}
50
51/* Only changed by xterm_setup, which is a setup */
52static char *terminal_emulator = "xterm";
53static char *title_switch = "-T";
54static char *exec_switch = "-e";
55
56static int __init xterm_setup(char *line, int *add)
57{
58 *add = 0;
59 terminal_emulator = line;
60
61 line = strchr(line, ',');
62 if(line == NULL) return(0);
63 *line++ = '\0';
64 if(*line) title_switch = line;
65
66 line = strchr(line, ',');
67 if(line == NULL) return(0);
68 *line++ = '\0';
69 if(*line) exec_switch = line;
70
71 return(0);
72}
73
74__uml_setup("xterm=", xterm_setup,
75"xterm=<terminal emulator>,<title switch>,<exec switch>\n"
76" Specifies an alternate terminal emulator to use for the debugger,\n"
77" consoles, and serial lines when they are attached to the xterm channel.\n"
78" The values are the terminal emulator binary, the switch it uses to set\n"
79" its title, and the switch it uses to execute a subprocess,\n"
80" respectively. The title switch must have the form '<switch> title',\n"
81" not '<switch>=title'. Similarly, the exec switch must have the form\n"
82" '<switch> command arg1 arg2 ...'.\n"
83" The default values are 'xterm=xterm,-T,-e'. Values for gnome-terminal\n"
84" are 'xterm=gnome-terminal,-t,-x'.\n\n"
85);
86
87/* XXX This badly needs some cleaning up in the error paths
88 * Not static because it's called directly by the tt mode gdb code
89 */
90int xterm_open(int input, int output, int primary, void *d,
91 char **dev_out)
92{
93 struct xterm_chan *data = d;
94 unsigned long stack;
95 int pid, fd, new, err;
96 char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
97 char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
98 "/usr/lib/uml/port-helper", "-uml-socket",
99 file, NULL };
100
101 if(os_access(argv[4], OS_ACC_X_OK) < 0)
102 argv[4] = "port-helper";
103
104 /* Check that DISPLAY is set, this doesn't guarantee the xterm
105 * will work but w/o it we can be pretty sure it won't. */
106 if (!getenv("DISPLAY")) {
107 printk("xterm_open: $DISPLAY not set.\n");
108 return -ENODEV;
109 }
110
111 fd = mkstemp(file);
112 if(fd < 0){
113 printk("xterm_open : mkstemp failed, errno = %d\n", errno);
114 return(-errno);
115 }
116
117 if(unlink(file)){
118 printk("xterm_open : unlink failed, errno = %d\n", errno);
119 return(-errno);
120 }
121 os_close_file(fd);
122
123 fd = os_create_unix_socket(file, sizeof(file), 1);
124 if(fd < 0){
125 printk("xterm_open : create_unix_socket failed, errno = %d\n",
126 -fd);
127 return(fd);
128 }
129
130 sprintf(title, data->title, data->device);
131 stack = data->stack;
132 pid = run_helper(NULL, NULL, argv, &stack);
133 if(pid < 0){
134 printk("xterm_open : run_helper failed, errno = %d\n", -pid);
135 return(pid);
136 }
137
138 if(data->stack == 0) free_stack(stack, 0);
139
140 if (data->direct_rcv) {
141 new = os_rcv_fd(fd, &data->helper_pid);
142 } else {
143 err = os_set_fd_block(fd, 0);
144 if(err < 0){
145 printk("xterm_open : failed to set descriptor "
146 "non-blocking, err = %d\n", -err);
147 return(err);
148 }
149 new = xterm_fd(fd, &data->helper_pid);
150 }
151 if(new < 0){
152 printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
153 goto out;
154 }
155
156 CATCH_EINTR(err = tcgetattr(new, &data->tt));
157 if(err){
158 new = err;
159 goto out;
160 }
161
162 if(data->raw){
163 err = raw(new);
164 if(err){
165 new = err;
166 goto out;
167 }
168 }
169
170 data->pid = pid;
171 *dev_out = NULL;
172 out:
173 unlink(file);
174 return(new);
175}
176
177/* Not static because it's called directly by the tt mode gdb code */
178void xterm_close(int fd, void *d)
179{
180 struct xterm_chan *data = d;
181
182 if(data->pid != -1)
183 os_kill_process(data->pid, 1);
184 data->pid = -1;
185 if(data->helper_pid != -1)
186 os_kill_process(data->helper_pid, 0);
187 data->helper_pid = -1;
188 os_close_file(fd);
189}
190
191static void xterm_free(void *d)
192{
193 free(d);
194}
195
196static int xterm_console_write(int fd, const char *buf, int n, void *d)
197{
198 struct xterm_chan *data = d;
199
200 return(generic_console_write(fd, buf, n, &data->tt));
201}
202
203struct chan_ops xterm_ops = {
204 .type = "xterm",
205 .init = xterm_init,
206 .open = xterm_open,
207 .close = xterm_close,
208 .read = generic_read,
209 .write = generic_write,
210 .console_write = xterm_console_write,
211 .window_size = generic_window_size,
212 .free = xterm_free,
213 .winch = 1,
214};
215
216/*
217 * Overrides for Emacs so that we follow Linus's tabbing style.
218 * Emacs will notice this stuff at the end of the file and automatically
219 * adjust the settings for this buffer only. This must remain at the end
220 * of the file.
221 * ---------------------------------------------------------------------------
222 * Local variables:
223 * c-file-style: "linux"
224 * End:
225 */
diff --git a/arch/um/drivers/xterm.h b/arch/um/drivers/xterm.h
new file mode 100644
index 000000000000..f33a6e77b186
--- /dev/null
+++ b/arch/um/drivers/xterm.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __XTERM_H__
7#define __XTERM_H__
8
9extern int xterm_fd(int socket, int *pid_out);
10
11#endif
12
13/*
14 * Overrides for Emacs so that we follow Linus's tabbing style.
15 * Emacs will notice this stuff at the end of the file and automatically
16 * adjust the settings for this buffer only. This must remain at the end
17 * of the file.
18 * ---------------------------------------------------------------------------
19 * Local variables:
20 * c-file-style: "linux"
21 * End:
22 */
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
new file mode 100644
index 000000000000..7917b9d1cec8
--- /dev/null
+++ b/arch/um/drivers/xterm_kern.c
@@ -0,0 +1,93 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/errno.h"
7#include "linux/slab.h"
8#include "linux/signal.h"
9#include "linux/interrupt.h"
10#include "asm/semaphore.h"
11#include "asm/irq.h"
12#include "irq_user.h"
13#include "irq_kern.h"
14#include "kern_util.h"
15#include "os.h"
16#include "xterm.h"
17
18struct xterm_wait {
19 struct completion ready;
20 int fd;
21 int pid;
22 int new_fd;
23};
24
25static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs)
26{
27 struct xterm_wait *xterm = data;
28 int fd;
29
30 fd = os_rcv_fd(xterm->fd, &xterm->pid);
31 if(fd == -EAGAIN)
32 return(IRQ_NONE);
33
34 xterm->new_fd = fd;
35 complete(&xterm->ready);
36 return(IRQ_HANDLED);
37}
38
39int xterm_fd(int socket, int *pid_out)
40{
41 struct xterm_wait *data;
42 int err, ret;
43
44 data = kmalloc(sizeof(*data), GFP_KERNEL);
45 if(data == NULL){
46 printk(KERN_ERR "xterm_fd : failed to allocate xterm_wait\n");
47 return(-ENOMEM);
48 }
49
50 /* This is a locked semaphore... */
51 *data = ((struct xterm_wait)
52 { .fd = socket,
53 .pid = -1,
54 .new_fd = -1 });
55 init_completion(&data->ready);
56
57 err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt,
58 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
59 "xterm", data);
60 if (err){
61 printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
62 "err = %d\n", err);
63 ret = err;
64 goto out;
65 }
66
67 /* ... so here we wait for an xterm interrupt.
68 *
69 * XXX Note, if the xterm doesn't work for some reason (eg. DISPLAY
70 * isn't set) this will hang... */
71 wait_for_completion(&data->ready);
72
73 free_irq_by_irq_and_dev(XTERM_IRQ, data);
74 free_irq(XTERM_IRQ, data);
75
76 ret = data->new_fd;
77 *pid_out = data->pid;
78 out:
79 kfree(data);
80
81 return(ret);
82}
83
84/*
85 * Overrides for Emacs so that we follow Linus's tabbing style.
86 * Emacs will notice this stuff at the end of the file and automatically
87 * adjust the settings for this buffer only. This must remain at the end
88 * of the file.
89 * ---------------------------------------------------------------------------
90 * Local variables:
91 * c-file-style: "linux"
92 * End:
93 */
diff --git a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h
new file mode 100644
index 000000000000..abdb015a4d71
--- /dev/null
+++ b/arch/um/include/2_5compat.h
@@ -0,0 +1,24 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __2_5_COMPAT_H__
7#define __2_5_COMPAT_H__
8
9#define INIT_HARDSECT(arr, maj, sizes)
10
11#define SET_PRI(task) do ; while(0)
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/include/chan_kern.h b/arch/um/include/chan_kern.h
new file mode 100644
index 000000000000..da9a6717e7a4
--- /dev/null
+++ b/arch/um/include/chan_kern.h
@@ -0,0 +1,60 @@
1/*
2 * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __CHAN_KERN_H__
7#define __CHAN_KERN_H__
8
9#include "linux/tty.h"
10#include "linux/list.h"
11#include "linux/console.h"
12#include "chan_user.h"
13#include "line.h"
14
15struct chan {
16 struct list_head list;
17 char *dev;
18 unsigned int primary:1;
19 unsigned int input:1;
20 unsigned int output:1;
21 unsigned int opened:1;
22 int fd;
23 enum chan_init_pri pri;
24 struct chan_ops *ops;
25 void *data;
26};
27
28extern void chan_interrupt(struct list_head *chans, struct work_struct *task,
29 struct tty_struct *tty, int irq);
30extern int parse_chan_pair(char *str, struct list_head *chans, int pri,
31 int device, struct chan_opts *opts);
32extern int open_chan(struct list_head *chans);
33extern int write_chan(struct list_head *chans, const char *buf, int len,
34 int write_irq);
35extern int console_write_chan(struct list_head *chans, const char *buf,
36 int len);
37extern int console_open_chan(struct line *line, struct console *co,
38 struct chan_opts *opts);
39extern void close_chan(struct list_head *chans);
40extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty);
41extern void enable_chan(struct list_head *chans, struct tty_struct *tty);
42extern int chan_window_size(struct list_head *chans,
43 unsigned short *rows_out,
44 unsigned short *cols_out);
45extern int chan_out_fd(struct list_head *chans);
46extern int chan_config_string(struct list_head *chans, char *str, int size,
47 char **error_out);
48
49#endif
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/include/chan_user.h b/arch/um/include/chan_user.h
new file mode 100644
index 000000000000..f77d9aa4c164
--- /dev/null
+++ b/arch/um/include/chan_user.h
@@ -0,0 +1,67 @@
1/*
2 * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __CHAN_USER_H__
7#define __CHAN_USER_H__
8
9#include "init.h"
10
11struct chan_opts {
12 void (*announce)(char *dev_name, int dev);
13 char *xterm_title;
14 int raw;
15 unsigned long tramp_stack;
16 int in_kernel;
17};
18
19enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
20
21struct chan_ops {
22 char *type;
23 void *(*init)(char *, int, struct chan_opts *);
24 int (*open)(int, int, int, void *, char **);
25 void (*close)(int, void *);
26 int (*read)(int, char *, void *);
27 int (*write)(int, const char *, int, void *);
28 int (*console_write)(int, const char *, int, void *);
29 int (*window_size)(int, void *, unsigned short *, unsigned short *);
30 void (*free)(void *);
31 int winch;
32};
33
34extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops,
35 xterm_ops;
36
37extern void generic_close(int fd, void *unused);
38extern int generic_read(int fd, char *c_out, void *unused);
39extern int generic_write(int fd, const char *buf, int n, void *unused);
40extern int generic_console_write(int fd, const char *buf, int n, void *state);
41extern int generic_window_size(int fd, void *unused, unsigned short *rows_out,
42 unsigned short *cols_out);
43extern void generic_free(void *data);
44
45struct tty_struct;
46extern void register_winch(int fd, struct tty_struct *tty);
47extern void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty);
48
49#define __channel_help(fn, prefix) \
50__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
51" Attach a console or serial line to a host channel. See\n" \
52" http://user-mode-linux.sourceforge.net/input.html for a complete\n" \
53" description of this switch.\n\n" \
54);
55
56#endif
57
58/*
59 * Overrides for Emacs so that we follow Linus's tabbing style.
60 * Emacs will notice this stuff at the end of the file and automatically
61 * adjust the settings for this buffer only. This must remain at the end
62 * of the file.
63 * ---------------------------------------------------------------------------
64 * Local variables:
65 * c-file-style: "linux"
66 * End:
67 */
diff --git a/arch/um/include/choose-mode.h b/arch/um/include/choose-mode.h
new file mode 100644
index 000000000000..8e6b62f5e9ac
--- /dev/null
+++ b/arch/um/include/choose-mode.h
@@ -0,0 +1,42 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __CHOOSE_MODE_H__
7#define __CHOOSE_MODE_H__
8
9#include "uml-config.h"
10
11#if defined(UML_CONFIG_MODE_TT) && defined(UML_CONFIG_MODE_SKAS)
12#define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas))
13
14#elif defined(UML_CONFIG_MODE_SKAS)
15#define CHOOSE_MODE(tt, skas) (skas)
16
17#elif defined(UML_CONFIG_MODE_TT)
18#define CHOOSE_MODE(tt, skas) (tt)
19#endif
20
21#define CHOOSE_MODE_PROC(tt, skas, args...) \
22 CHOOSE_MODE(tt(args), skas(args))
23
24extern int mode_tt;
25static inline void *__choose_mode(void *tt, void *skas) {
26 return mode_tt ? tt : skas;
27}
28
29#define __CHOOSE_MODE(tt, skas) (*( (typeof(tt) *) __choose_mode(&(tt), &(skas))))
30
31#endif
32
33/*
34 * Overrides for Emacs so that we follow Linus's tabbing style.
35 * Emacs will notice this stuff at the end of the file and automatically
36 * adjust the settings for this buffer only. This must remain at the end
37 * of the file.
38 * ---------------------------------------------------------------------------
39 * Local variables:
40 * c-file-style: "linux"
41 * End:
42 */
diff --git a/arch/um/include/elf_user.h b/arch/um/include/elf_user.h
new file mode 100644
index 000000000000..53516b637272
--- /dev/null
+++ b/arch/um/include/elf_user.h
@@ -0,0 +1,19 @@
1/*
2 * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
3 * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
4 * Licensed under the GPL
5 */
6
7#ifndef __ELF_USER_H__
8#define __ELF_USER_H__
9
10/* For compilation on a host that doesn't support AT_SYSINFO (Linux 2.4) */
11
12#ifndef AT_SYSINFO
13#define AT_SYSINFO 32
14#endif
15#ifndef AT_SYSINFO_EHDR
16#define AT_SYSINFO_EHDR 33
17#endif
18
19#endif
diff --git a/arch/um/include/frame_kern.h b/arch/um/include/frame_kern.h
new file mode 100644
index 000000000000..ce9514f57211
--- /dev/null
+++ b/arch/um/include/frame_kern.h
@@ -0,0 +1,32 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __FRAME_KERN_H_
7#define __FRAME_KERN_H_
8
9#define _S(nr) (1<<((nr)-1))
10#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
11
12extern int setup_signal_stack_sc(unsigned long stack_top, int sig,
13 struct k_sigaction *ka,
14 struct pt_regs *regs,
15 sigset_t *mask);
16extern int setup_signal_stack_si(unsigned long stack_top, int sig,
17 struct k_sigaction *ka,
18 struct pt_regs *regs, siginfo_t *info,
19 sigset_t *mask);
20
21#endif
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/include/helper.h b/arch/um/include/helper.h
new file mode 100644
index 000000000000..162ac31192fd
--- /dev/null
+++ b/arch/um/include/helper.h
@@ -0,0 +1,27 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __HELPER_H__
7#define __HELPER_H__
8
9extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
10 unsigned long *stack_out);
11extern int run_helper_thread(int (*proc)(void *), void *arg,
12 unsigned int flags, unsigned long *stack_out,
13 int stack_order);
14extern int helper_wait(int pid);
15
16#endif
17
18/*
19 * Overrides for Emacs so that we follow Linus's tabbing style.
20 * Emacs will notice this stuff at the end of the file and automatically
21 * adjust the settings for this buffer only. This must remain at the end
22 * of the file.
23 * ---------------------------------------------------------------------------
24 * Local variables:
25 * c-file-style: "linux"
26 * End:
27 */
diff --git a/arch/um/include/init.h b/arch/um/include/init.h
new file mode 100644
index 000000000000..55c2693f8778
--- /dev/null
+++ b/arch/um/include/init.h
@@ -0,0 +1,132 @@
1#ifndef _LINUX_UML_INIT_H
2#define _LINUX_UML_INIT_H
3
4/* These macros are used to mark some functions or
5 * initialized data (doesn't apply to uninitialized data)
6 * as `initialization' functions. The kernel can take this
7 * as hint that the function is used only during the initialization
8 * phase and free up used memory resources after
9 *
10 * Usage:
11 * For functions:
12 *
13 * You should add __init immediately before the function name, like:
14 *
15 * static void __init initme(int x, int y)
16 * {
17 * extern int z; z = x * y;
18 * }
19 *
20 * If the function has a prototype somewhere, you can also add
21 * __init between closing brace of the prototype and semicolon:
22 *
23 * extern int initialize_foobar_device(int, int, int) __init;
24 *
25 * For initialized data:
26 * You should insert __initdata between the variable name and equal
27 * sign followed by value, e.g.:
28 *
29 * static int init_variable __initdata = 0;
30 * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
31 *
32 * Don't forget to initialize data not at file scope, i.e. within a function,
33 * as gcc otherwise puts the data into the bss section and not into the init
34 * section.
35 *
36 * Also note, that this data cannot be "const".
37 */
38
39#ifndef _LINUX_INIT_H
40typedef int (*initcall_t)(void);
41typedef void (*exitcall_t)(void);
42
43/* These are for everybody (although not all archs will actually
44 discard it in modules) */
45#define __init __attribute__ ((__section__ (".init.text")))
46#define __initdata __attribute__ ((__section__ (".init.data")))
47#define __exitdata __attribute__ ((__section__(".exit.data")))
48#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
49
50#ifdef MODULE
51#define __exit __attribute__ ((__section__(".exit.text")))
52#else
53#define __exit __attribute_used__ __attribute__ ((__section__(".exit.text")))
54#endif
55
56#endif
57
58#ifndef MODULE
59struct uml_param {
60 const char *str;
61 int (*setup_func)(char *, int *);
62};
63
64extern initcall_t __uml_initcall_start, __uml_initcall_end;
65extern initcall_t __uml_postsetup_start, __uml_postsetup_end;
66extern const char *__uml_help_start, *__uml_help_end;
67#endif
68
69#define __uml_initcall(fn) \
70 static initcall_t __uml_initcall_##fn __uml_init_call = fn
71
72#define __uml_exitcall(fn) \
73 static exitcall_t __uml_exitcall_##fn __uml_exit_call = fn
74
75extern struct uml_param __uml_setup_start, __uml_setup_end;
76
77#define __uml_postsetup(fn) \
78 static initcall_t __uml_postsetup_##fn __uml_postsetup_call = fn
79
80#define __non_empty_string(dummyname,string) \
81 struct __uml_non_empty_string_struct_##dummyname \
82 { \
83 char _string[sizeof(string)-2]; \
84 }
85
86#ifndef MODULE
87#define __uml_setup(str, fn, help...) \
88 __non_empty_string(fn ##_setup, str); \
89 __uml_help(fn, help); \
90 static char __uml_setup_str_##fn[] __initdata = str; \
91 static struct uml_param __uml_setup_##fn __uml_init_setup = { __uml_setup_str_##fn, fn }
92#else
93#define __uml_setup(str, fn, help...) \
94
95#endif
96
97#define __uml_help(fn, help...) \
98 __non_empty_string(fn ##__help, help); \
99 static char __uml_help_str_##fn[] __initdata = help; \
100 static const char *__uml_help_##fn __uml_setup_help = __uml_help_str_##fn
101
102/*
103 * Mark functions and data as being only used at initialization
104 * or exit time.
105 */
106#define __uml_init_setup __attribute_used__ __attribute__ ((__section__ (".uml.setup.init")))
107#define __uml_setup_help __attribute_used__ __attribute__ ((__section__ (".uml.help.init")))
108#define __uml_init_call __attribute_used__ __attribute__ ((__section__ (".uml.initcall.init")))
109#define __uml_postsetup_call __attribute_used__ __attribute__ ((__section__ (".uml.postsetup.init")))
110#define __uml_exit_call __attribute_used__ __attribute__ ((__section__ (".uml.exitcall.exit")))
111
112#ifndef __KERNEL__
113
114#define __initcall(fn) static initcall_t __initcall_##fn __init_call = fn
115#define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn
116
117#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
118
119#endif
120
121#endif /* _LINUX_UML_INIT_H */
122
123/*
124 * Overrides for Emacs so that we follow Linus's tabbing style.
125 * Emacs will notice this stuff at the end of the file and automatically
126 * adjust the settings for this buffer only. This must remain at the end
127 * of the file.
128 * ---------------------------------------------------------------------------
129 * Local variables:
130 * c-file-style: "linux"
131 * End:
132 */
diff --git a/arch/um/include/initrd.h b/arch/um/include/initrd.h
new file mode 100644
index 000000000000..439b9a814985
--- /dev/null
+++ b/arch/um/include/initrd.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __INITRD_USER_H__
7#define __INITRD_USER_H__
8
9extern int load_initrd(char *filename, void *buf, int size);
10
11#endif
12
13/*
14 * Overrides for Emacs so that we follow Linus's tabbing style.
15 * Emacs will notice this stuff at the end of the file and automatically
16 * adjust the settings for this buffer only. This must remain at the end
17 * of the file.
18 * ---------------------------------------------------------------------------
19 * Local variables:
20 * c-file-style: "linux"
21 * End:
22 */
diff --git a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h
new file mode 100644
index 000000000000..3af52a634c4c
--- /dev/null
+++ b/arch/um/include/irq_kern.h
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __IRQ_KERN_H__
7#define __IRQ_KERN_H__
8
9#include "linux/interrupt.h"
10
11extern int um_request_irq(unsigned int irq, int fd, int type,
12 irqreturn_t (*handler)(int, void *,
13 struct pt_regs *),
14 unsigned long irqflags, const char * devname,
15 void *dev_id);
16
17#endif
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/include/irq_user.h b/arch/um/include/irq_user.h
new file mode 100644
index 000000000000..f724b717213f
--- /dev/null
+++ b/arch/um/include/irq_user.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __IRQ_USER_H__
7#define __IRQ_USER_H__
8
9enum { IRQ_READ, IRQ_WRITE };
10
11extern void sigio_handler(int sig, union uml_pt_regs *regs);
12extern int activate_fd(int irq, int fd, int type, void *dev_id);
13extern void free_irq_by_irq_and_dev(unsigned int irq, void *dev_id);
14extern void free_irq_by_fd(int fd);
15extern void reactivate_fd(int fd, int irqnum);
16extern void deactivate_fd(int fd, int irqnum);
17extern int deactivate_all_fds(void);
18extern void forward_interrupts(int pid);
19extern void init_irq_signals(int on_sigstack);
20extern void forward_ipi(int fd, int pid);
21extern void free_irq_later(int irq, void *dev_id);
22extern int activate_ipi(int fd, int pid);
23extern unsigned long irq_lock(void);
24extern void irq_unlock(unsigned long flags);
25#endif
26
27/*
28 * Overrides for Emacs so that we follow Linus's tabbing style.
29 * Emacs will notice this stuff at the end of the file and automatically
30 * adjust the settings for this buffer only. This must remain at the end
31 * of the file.
32 * ---------------------------------------------------------------------------
33 * Local variables:
34 * c-file-style: "linux"
35 * End:
36 */
diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h
new file mode 100644
index 000000000000..1e3170768b5c
--- /dev/null
+++ b/arch/um/include/kern.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __KERN_H__
7#define __KERN_H__
8
9/* These are all user-mode things which are convenient to call directly
10 * from kernel code and for which writing a wrapper is too much of a pain.
11 * The regular include files can't be included because this file is included
12 * only into kernel code, and user-space includes conflict with kernel
13 * includes.
14 */
15
16extern int errno;
17
18extern int clone(int (*proc)(void *), void *sp, int flags, void *data);
19extern int sleep(int);
20extern int printf(char *fmt, ...);
21extern char *strerror(int errnum);
22extern char *ptsname(int __fd);
23extern int munmap(void *, int);
24extern void *sbrk(int increment);
25extern void *malloc(int size);
26extern void perror(char *err);
27extern int kill(int pid, int sig);
28extern int getuid(void);
29extern int getgid(void);
30extern int pause(void);
31extern int write(int, const void *, int);
32extern int exit(int);
33extern int close(int);
34extern int read(unsigned int, char *, int);
35extern int pipe(int *);
36extern int sched_yield(void);
37extern int ptrace(int op, int pid, long addr, long data);
38#endif
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/include/kern_util.h b/arch/um/include/kern_util.h
new file mode 100644
index 000000000000..15389c886b41
--- /dev/null
+++ b/arch/um/include/kern_util.h
@@ -0,0 +1,125 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __KERN_UTIL_H__
7#define __KERN_UTIL_H__
8
9#include "linux/threads.h"
10#include "sysdep/ptrace.h"
11
12extern int ncpus;
13extern char *linux_prog;
14extern char *gdb_init;
15extern int kmalloc_ok;
16extern int timer_irq_inited;
17extern int jail;
18extern int nsyscalls;
19
20extern struct task_struct *idle_threads[NR_CPUS];
21
22#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
23#define UML_ROUND_UP(addr) \
24 UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
25
26extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
27extern unsigned long stack_sp(unsigned long page);
28extern int kernel_thread_proc(void *data);
29extern void syscall_segv(int sig);
30extern int current_pid(void);
31extern unsigned long alloc_stack(int order, int atomic);
32extern int do_signal(void);
33extern int is_stack_fault(unsigned long sp);
34extern unsigned long segv(unsigned long address, unsigned long ip,
35 int is_write, int is_user, void *sc);
36extern int handle_page_fault(unsigned long address, unsigned long ip,
37 int is_write, int is_user, int *code_out);
38extern void syscall_ready(void);
39extern void set_tracing(void *t, int tracing);
40extern int is_tracing(void *task);
41extern int segv_syscall(void);
42extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
43extern int page_size(void);
44extern unsigned long page_mask(void);
45extern int need_finish_fork(void);
46extern void free_stack(unsigned long stack, int order);
47extern void add_input_request(int op, void (*proc)(int), void *arg);
48extern char *current_cmd(void);
49extern void timer_handler(int sig, union uml_pt_regs *regs);
50extern int set_signals(int enable);
51extern void force_sigbus(void);
52extern int pid_to_processor_id(int pid);
53extern void block_signals(void);
54extern void unblock_signals(void);
55extern void deliver_signals(void *t);
56extern int next_syscall_index(int max);
57extern int next_trap_index(int max);
58extern void default_idle(void);
59extern void finish_fork(void);
60extern void paging_init(void);
61extern void init_flush_vm(void);
62extern void *syscall_sp(void *t);
63extern void syscall_trace(union uml_pt_regs *regs, int entryexit);
64extern int hz(void);
65extern void uml_idle_timer(void);
66extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs);
67extern int external_pid(void *t);
68extern void boot_timer_handler(int sig);
69extern void interrupt_end(void);
70extern void initial_thread_cb(void (*proc)(void *), void *arg);
71extern int debugger_signal(int status, int pid);
72extern void debugger_parent_signal(int status, int pid);
73extern void child_signal(int pid, int status);
74extern int init_ptrace_proxy(int idle_pid, int startup, int stop);
75extern int init_parent_proxy(int pid);
76extern int singlestepping(void *t);
77extern void check_stack_overflow(void *ptr);
78extern void relay_signal(int sig, union uml_pt_regs *regs);
79extern void not_implemented(void);
80extern int user_context(unsigned long sp);
81extern void timer_irq(union uml_pt_regs *regs);
82extern void unprotect_stack(unsigned long stack);
83extern void do_uml_exitcalls(void);
84extern int attach_debugger(int idle_pid, int pid, int stop);
85extern void bad_segv(unsigned long address, unsigned long ip, int is_write);
86extern int config_gdb(char *str);
87extern int remove_gdb(void);
88extern char *uml_strdup(char *string);
89extern void unprotect_kernel_mem(void);
90extern void protect_kernel_mem(void);
91extern void uml_cleanup(void);
92extern void set_current(void *t);
93extern void lock_signalled_task(void *t);
94extern void IPI_handler(int cpu);
95extern int jail_setup(char *line, int *add);
96extern void *get_init_task(void);
97extern int clear_user_proc(void *buf, int size);
98extern int copy_to_user_proc(void *to, void *from, int size);
99extern int copy_from_user_proc(void *to, void *from, int size);
100extern int strlen_user_proc(char *str);
101extern void bus_handler(int sig, union uml_pt_regs *regs);
102extern void winch(int sig, union uml_pt_regs *regs);
103extern long execute_syscall(void *r);
104extern int smp_sigio_handler(void);
105extern void *get_current(void);
106extern struct task_struct *get_task(int pid, int require);
107extern void machine_halt(void);
108extern int is_syscall(unsigned long addr);
109extern void arch_switch(void);
110extern void free_irq(unsigned int, void *);
111extern int um_in_interrupt(void);
112extern int cpu(void);
113
114#endif
115
116/*
117 * Overrides for Emacs so that we follow Linus's tabbing style.
118 * Emacs will notice this stuff at the end of the file and automatically
119 * adjust the settings for this buffer only. This must remain at the end
120 * of the file.
121 * ---------------------------------------------------------------------------
122 * Local variables:
123 * c-file-style: "linux"
124 * End:
125 */
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
new file mode 100644
index 000000000000..6d81ecc17be5
--- /dev/null
+++ b/arch/um/include/line.h
@@ -0,0 +1,108 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __LINE_H__
7#define __LINE_H__
8
9#include "linux/list.h"
10#include "linux/workqueue.h"
11#include "linux/tty.h"
12#include "linux/interrupt.h"
13#include "asm/semaphore.h"
14#include "chan_user.h"
15#include "mconsole_kern.h"
16
17struct line_driver {
18 char *name;
19 char *device_name;
20 char *devfs_name;
21 short major;
22 short minor_start;
23 short type;
24 short subtype;
25 int read_irq;
26 char *read_irq_name;
27 int write_irq;
28 char *write_irq_name;
29 char *symlink_from;
30 char *symlink_to;
31 struct mc_device mc;
32};
33
34struct line {
35 char *init_str;
36 int init_pri;
37 struct list_head chan_list;
38 int valid;
39 int count;
40 struct semaphore sem;
41 char *buffer;
42 char *head;
43 char *tail;
44 int sigio;
45 struct work_struct task;
46 struct line_driver *driver;
47 int have_irq;
48};
49
50#define LINE_INIT(str, d) \
51 { init_str : str, \
52 init_pri : INIT_STATIC, \
53 chan_list : { }, \
54 valid : 1, \
55 sem : { }, \
56 buffer : NULL, \
57 head : NULL, \
58 tail : NULL, \
59 sigio : 0, \
60 driver : d, \
61 have_irq : 0 }
62
63struct lines {
64 int num;
65};
66
67#define LINES_INIT(n) { num : n }
68
69extern void line_close(struct tty_struct *tty, struct file * filp);
70extern int line_open(struct line *lines, struct tty_struct *tty,
71 struct chan_opts *opts);
72extern int line_setup(struct line *lines, int num, char *init,
73 int all_allowed);
74extern int line_write(struct tty_struct *tty, const unsigned char *buf, int len);
75extern void line_put_char(struct tty_struct *tty, unsigned char ch);
76extern void line_set_termios(struct tty_struct *tty, struct termios * old);
77extern int line_chars_in_buffer(struct tty_struct *tty);
78extern int line_write_room(struct tty_struct *tty);
79extern int line_ioctl(struct tty_struct *tty, struct file * file,
80 unsigned int cmd, unsigned long arg);
81extern char *add_xterm_umid(char *base);
82extern int line_setup_irq(int fd, int input, int output, struct tty_struct *tty);
83extern void line_close_chan(struct line *line);
84extern void line_disable(struct tty_struct *tty, int current_irq);
85extern struct tty_driver * line_register_devfs(struct lines *set,
86 struct line_driver *line_driver,
87 struct tty_operations *driver,
88 struct line *lines,
89 int nlines);
90extern void lines_init(struct line *lines, int nlines);
91extern void close_lines(struct line *lines, int nlines);
92extern int line_config(struct line *lines, int num, char *str);
93extern int line_remove(struct line *lines, int num, char *str);
94extern int line_get_config(char *dev, struct line *lines, int num, char *str,
95 int size, char **error_out);
96
97#endif
98
99/*
100 * Overrides for Emacs so that we follow Linus's tabbing style.
101 * Emacs will notice this stuff at the end of the file and automatically
102 * adjust the settings for this buffer only. This must remain at the end
103 * of the file.
104 * ---------------------------------------------------------------------------
105 * Local variables:
106 * c-file-style: "linux"
107 * End:
108 */
diff --git a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h
new file mode 100644
index 000000000000..9fbe3083fdd8
--- /dev/null
+++ b/arch/um/include/mconsole.h
@@ -0,0 +1,103 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
3 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
4 * Licensed under the GPL
5 */
6
7#ifndef __MCONSOLE_H__
8#define __MCONSOLE_H__
9
10#ifndef __KERNEL__
11#include <stdint.h>
12#define u32 uint32_t
13#endif
14
15#define MCONSOLE_MAGIC (0xcafebabe)
16#define MCONSOLE_MAX_DATA (512)
17#define MCONSOLE_VERSION 2
18
19struct mconsole_request {
20 u32 magic;
21 u32 version;
22 u32 len;
23 char data[MCONSOLE_MAX_DATA];
24};
25
26struct mconsole_reply {
27 u32 err;
28 u32 more;
29 u32 len;
30 char data[MCONSOLE_MAX_DATA];
31};
32
33struct mconsole_notify {
34 u32 magic;
35 u32 version;
36 enum { MCONSOLE_SOCKET, MCONSOLE_PANIC, MCONSOLE_HANG,
37 MCONSOLE_USER_NOTIFY } type;
38 u32 len;
39 char data[MCONSOLE_MAX_DATA];
40};
41
42struct mc_request;
43
44enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC };
45
46struct mconsole_command
47{
48 char *command;
49 void (*handler)(struct mc_request *req);
50 enum mc_context context;
51};
52
53struct mc_request
54{
55 int len;
56 int as_interrupt;
57
58 int originating_fd;
59 int originlen;
60 unsigned char origin[128]; /* sockaddr_un */
61
62 struct mconsole_request request;
63 struct mconsole_command *cmd;
64};
65
66extern char mconsole_socket_name[];
67
68extern int mconsole_unlink_socket(void);
69extern int mconsole_reply(struct mc_request *req, char *reply, int err,
70 int more);
71
72extern void mconsole_version(struct mc_request *req);
73extern void mconsole_help(struct mc_request *req);
74extern void mconsole_halt(struct mc_request *req);
75extern void mconsole_reboot(struct mc_request *req);
76extern void mconsole_config(struct mc_request *req);
77extern void mconsole_remove(struct mc_request *req);
78extern void mconsole_sysrq(struct mc_request *req);
79extern void mconsole_cad(struct mc_request *req);
80extern void mconsole_stop(struct mc_request *req);
81extern void mconsole_go(struct mc_request *req);
82extern void mconsole_log(struct mc_request *req);
83extern void mconsole_proc(struct mc_request *req);
84
85extern int mconsole_get_request(int fd, struct mc_request *req);
86extern int mconsole_notify(char *sock_name, int type, const void *data,
87 int len);
88extern char *mconsole_notify_socket(void);
89extern void lock_notify(void);
90extern void unlock_notify(void);
91
92#endif
93
94/*
95 * Overrides for Emacs so that we follow Linus's tabbing style.
96 * Emacs will notice this stuff at the end of the file and automatically
97 * adjust the settings for this buffer only. This must remain at the end
98 * of the file.
99 * ---------------------------------------------------------------------------
100 * Local variables:
101 * c-file-style: "linux"
102 * End:
103 */
diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h
new file mode 100644
index 000000000000..61c274fcee5d
--- /dev/null
+++ b/arch/um/include/mconsole_kern.h
@@ -0,0 +1,62 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MCONSOLE_KERN_H__
7#define __MCONSOLE_KERN_H__
8
9#include "linux/config.h"
10#include "linux/list.h"
11#include "mconsole.h"
12
13struct mconsole_entry {
14 struct list_head list;
15 struct mc_request request;
16};
17
18struct mc_device {
19 struct list_head list;
20 char *name;
21 int (*config)(char *);
22 int (*get_config)(char *, char *, int, char **);
23 int (*remove)(char *);
24};
25
26#define CONFIG_CHUNK(str, size, current, chunk, end) \
27do { \
28 current += strlen(chunk); \
29 if(current >= size) \
30 str = NULL; \
31 if(str != NULL){ \
32 strcpy(str, chunk); \
33 str += strlen(chunk); \
34 } \
35 if(end) \
36 current++; \
37} while(0)
38
39#ifdef CONFIG_MCONSOLE
40
41extern void mconsole_register_dev(struct mc_device *new);
42
43#else
44
45static inline void mconsole_register_dev(struct mc_device *new)
46{
47}
48
49#endif
50
51#endif
52
53/*
54 * Overrides for Emacs so that we follow Linus's tabbing style.
55 * Emacs will notice this stuff at the end of the file and automatically
56 * adjust the settings for this buffer only. This must remain at the end
57 * of the file.
58 * ---------------------------------------------------------------------------
59 * Local variables:
60 * c-file-style: "linux"
61 * End:
62 */
diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h
new file mode 100644
index 000000000000..10c46c38949a
--- /dev/null
+++ b/arch/um/include/mem.h
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2002, 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MEM_H__
7#define __MEM_H__
8
9#include "linux/types.h"
10
11extern int phys_mapping(unsigned long phys, __u64 *offset_out);
12extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w);
13extern int is_remapped(void *virt);
14extern int physmem_remove_mapping(void *virt);
15extern void physmem_forget_descriptor(int fd);
16
17#endif
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/include/mem_kern.h b/arch/um/include/mem_kern.h
new file mode 100644
index 000000000000..cb7e196d366b
--- /dev/null
+++ b/arch/um/include/mem_kern.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MEM_KERN_H__
7#define __MEM_KERN_H__
8
9#include "linux/list.h"
10#include "linux/types.h"
11
12struct remapper {
13 struct list_head list;
14 int (*proc)(int, unsigned long, int, __u64);
15};
16
17extern void register_remapper(struct remapper *info);
18
19#endif
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/include/mem_user.h b/arch/um/include/mem_user.h
new file mode 100644
index 000000000000..d6404bb64662
--- /dev/null
+++ b/arch/um/include/mem_user.h
@@ -0,0 +1,83 @@
1/*
2 * arch/um/include/mem_user.h
3 *
4 * BRIEF MODULE DESCRIPTION
5 * user side memory interface for support 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#ifndef _MEM_USER_H
33#define _MEM_USER_H
34
35struct iomem_region {
36 struct iomem_region *next;
37 char *driver;
38 int fd;
39 int size;
40 unsigned long phys;
41 unsigned long virt;
42};
43
44extern struct iomem_region *iomem_regions;
45extern int iomem_size;
46
47#define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1))
48
49extern unsigned long host_task_size;
50extern unsigned long task_size;
51
52extern void check_devanon(void);
53extern int init_mem_user(void);
54extern int create_mem_file(unsigned long len);
55extern void setup_memory(void *entry);
56extern unsigned long find_iomem(char *driver, unsigned long *len_out);
57extern int init_maps(unsigned long physmem, unsigned long iomem,
58 unsigned long highmem);
59extern unsigned long get_vm(unsigned long len);
60extern void setup_physmem(unsigned long start, unsigned long usable,
61 unsigned long len, unsigned long highmem);
62extern void add_iomem(char *name, int fd, unsigned long size);
63extern unsigned long phys_offset(unsigned long phys);
64extern void unmap_physmem(void);
65extern void map_memory(unsigned long virt, unsigned long phys,
66 unsigned long len, int r, int w, int x);
67extern int protect_memory(unsigned long addr, unsigned long len,
68 int r, int w, int x, int must_succeed);
69extern unsigned long get_kmem_end(void);
70extern void check_tmpexec(void);
71
72#endif
73
74/*
75 * Overrides for Emacs so that we follow Linus's tabbing style.
76 * Emacs will notice this stuff at the end of the file and automatically
77 * adjust the settings for this buffer only. This must remain at the end
78 * of the file.
79 * ---------------------------------------------------------------------------
80 * Local variables:
81 * c-file-style: "linux"
82 * End:
83 */
diff --git a/arch/um/include/mode.h b/arch/um/include/mode.h
new file mode 100644
index 000000000000..786cf563eb05
--- /dev/null
+++ b/arch/um/include/mode.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MODE_H__
7#define __MODE_H__
8
9#include "uml-config.h"
10
11#ifdef UML_CONFIG_MODE_TT
12#include "mode-tt.h"
13#endif
14
15#ifdef UML_CONFIG_MODE_SKAS
16#include "mode-skas.h"
17#endif
18
19#endif
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/include/mode_kern.h b/arch/um/include/mode_kern.h
new file mode 100644
index 000000000000..2d88afd0cf16
--- /dev/null
+++ b/arch/um/include/mode_kern.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MODE_KERN_H__
7#define __MODE_KERN_H__
8
9#include "linux/config.h"
10
11#ifdef CONFIG_MODE_TT
12#include "mode_kern-tt.h"
13#endif
14
15#ifdef CONFIG_MODE_SKAS
16#include "mode_kern-skas.h"
17#endif
18
19#endif
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/include/net_kern.h b/arch/um/include/net_kern.h
new file mode 100644
index 000000000000..1c07949a13d6
--- /dev/null
+++ b/arch/um/include/net_kern.h
@@ -0,0 +1,82 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __UM_NET_KERN_H
7#define __UM_NET_KERN_H
8
9#include "linux/netdevice.h"
10#include "linux/skbuff.h"
11#include "linux/socket.h"
12#include "linux/list.h"
13
14struct uml_net {
15 struct list_head list;
16 struct net_device *dev;
17 struct platform_device pdev;
18 int index;
19 unsigned char mac[ETH_ALEN];
20 int have_mac;
21};
22
23struct uml_net_private {
24 struct list_head list;
25 spinlock_t lock;
26 struct net_device *dev;
27 struct timer_list tl;
28 struct net_device_stats stats;
29 int fd;
30 unsigned char mac[ETH_ALEN];
31 int have_mac;
32 unsigned short (*protocol)(struct sk_buff *);
33 int (*open)(void *);
34 void (*close)(int, void *);
35 void (*remove)(void *);
36 int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
37 int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
38
39 void (*add_address)(unsigned char *, unsigned char *, void *);
40 void (*delete_address)(unsigned char *, unsigned char *, void *);
41 int (*set_mtu)(int mtu, void *);
42 int user[1];
43};
44
45struct net_kern_info {
46 void (*init)(struct net_device *, void *);
47 unsigned short (*protocol)(struct sk_buff *);
48 int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
49 int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
50};
51
52struct transport {
53 struct list_head list;
54 char *name;
55 int (*setup)(char *, char **, void *);
56 struct net_user_info *user;
57 struct net_kern_info *kern;
58 int private_size;
59 int setup_size;
60};
61
62extern struct net_device *ether_init(int);
63extern unsigned short ether_protocol(struct sk_buff *);
64extern int setup_etheraddr(char *str, unsigned char *addr);
65extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra);
66extern int tap_setup_common(char *str, char *type, char **dev_name,
67 char **mac_out, char **gate_addr);
68extern void register_transport(struct transport *new);
69extern unsigned short eth_protocol(struct sk_buff *skb);
70
71#endif
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/include/net_user.h b/arch/um/include/net_user.h
new file mode 100644
index 000000000000..36807b796e9f
--- /dev/null
+++ b/arch/um/include/net_user.h
@@ -0,0 +1,66 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __UM_NET_USER_H__
7#define __UM_NET_USER_H__
8
9#define ETH_ADDR_LEN (6)
10#define ETH_HEADER_ETHERTAP (16)
11#define ETH_HEADER_OTHER (14)
12#define ETH_MAX_PACKET (1500)
13
14#define UML_NET_VERSION (4)
15
16struct net_user_info {
17 void (*init)(void *, void *);
18 int (*open)(void *);
19 void (*close)(int, void *);
20 void (*remove)(void *);
21 int (*set_mtu)(int mtu, void *);
22 void (*add_address)(unsigned char *, unsigned char *, void *);
23 void (*delete_address)(unsigned char *, unsigned char *, void *);
24 int max_packet;
25};
26
27extern void ether_user_init(void *data, void *dev);
28extern void dev_ip_addr(void *d, char *buf, char *bin_buf);
29extern void set_ether_mac(void *d, unsigned char *addr);
30extern void iter_addresses(void *d, void (*cb)(unsigned char *,
31 unsigned char *, void *),
32 void *arg);
33
34extern void *get_output_buffer(int *len_out);
35extern void free_output_buffer(void *buffer);
36
37extern int tap_open_common(void *dev, char *gate_addr);
38extern void tap_check_ips(char *gate_addr, char *eth_addr);
39
40extern void read_output(int fd, char *output_out, int len);
41
42extern int net_read(int fd, void *buf, int len);
43extern int net_recvfrom(int fd, void *buf, int len);
44extern int net_write(int fd, void *buf, int len);
45extern int net_send(int fd, void *buf, int len);
46extern int net_sendto(int fd, void *buf, int len, void *to, int sock_len);
47
48extern void open_addr(unsigned char *addr, unsigned char *netmask, void *arg);
49extern void close_addr(unsigned char *addr, unsigned char *netmask, void *arg);
50
51extern char *split_if_spec(char *str, ...);
52
53extern int dev_netmask(void *d, void *m);
54
55#endif
56
57/*
58 * Overrides for Emacs so that we follow Linus's tabbing style.
59 * Emacs will notice this stuff at the end of the file and automatically
60 * adjust the settings for this buffer only. This must remain at the end
61 * of the file.
62 * ---------------------------------------------------------------------------
63 * Local variables:
64 * c-file-style: "linux"
65 * End:
66 */
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
new file mode 100644
index 000000000000..07340c8cf203
--- /dev/null
+++ b/arch/um/include/os.h
@@ -0,0 +1,183 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __OS_H__
7#define __OS_H__
8
9#include "asm/types.h"
10#include "../os/include/file.h"
11
12#define OS_TYPE_FILE 1
13#define OS_TYPE_DIR 2
14#define OS_TYPE_SYMLINK 3
15#define OS_TYPE_CHARDEV 4
16#define OS_TYPE_BLOCKDEV 5
17#define OS_TYPE_FIFO 6
18#define OS_TYPE_SOCK 7
19
20/* os_access() flags */
21#define OS_ACC_F_OK 0 /* Test for existence. */
22#define OS_ACC_X_OK 1 /* Test for execute permission. */
23#define OS_ACC_W_OK 2 /* Test for write permission. */
24#define OS_ACC_R_OK 4 /* Test for read permission. */
25#define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */
26
27/*
28 * types taken from stat_file() in hostfs_user.c
29 * (if they are wrong here, they are wrong there...).
30 */
31struct uml_stat {
32 int ust_dev; /* device */
33 unsigned long long ust_ino; /* inode */
34 int ust_mode; /* protection */
35 int ust_nlink; /* number of hard links */
36 int ust_uid; /* user ID of owner */
37 int ust_gid; /* group ID of owner */
38 unsigned long long ust_size; /* total size, in bytes */
39 int ust_blksize; /* blocksize for filesystem I/O */
40 unsigned long long ust_blocks; /* number of blocks allocated */
41 unsigned long ust_atime; /* time of last access */
42 unsigned long ust_mtime; /* time of last modification */
43 unsigned long ust_ctime; /* time of last change */
44};
45
46struct openflags {
47 unsigned int r : 1;
48 unsigned int w : 1;
49 unsigned int s : 1; /* O_SYNC */
50 unsigned int c : 1; /* O_CREAT */
51 unsigned int t : 1; /* O_TRUNC */
52 unsigned int a : 1; /* O_APPEND */
53 unsigned int e : 1; /* O_EXCL */
54 unsigned int cl : 1; /* FD_CLOEXEC */
55};
56
57#define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \
58 .t = 0, .a = 0, .e = 0, .cl = 0 })
59
60static inline struct openflags of_read(struct openflags flags)
61{
62 flags.r = 1;
63 return(flags);
64}
65
66static inline struct openflags of_write(struct openflags flags)
67{
68 flags.w = 1;
69 return(flags);
70}
71
72static inline struct openflags of_rdwr(struct openflags flags)
73{
74 return(of_read(of_write(flags)));
75}
76
77static inline struct openflags of_set_rw(struct openflags flags, int r, int w)
78{
79 flags.r = r;
80 flags.w = w;
81 return(flags);
82}
83
84static inline struct openflags of_sync(struct openflags flags)
85{
86 flags.s = 1;
87 return(flags);
88}
89
90static inline struct openflags of_create(struct openflags flags)
91{
92 flags.c = 1;
93 return(flags);
94}
95
96static inline struct openflags of_trunc(struct openflags flags)
97{
98 flags.t = 1;
99 return(flags);
100}
101
102static inline struct openflags of_append(struct openflags flags)
103{
104 flags.a = 1;
105 return(flags);
106}
107
108static inline struct openflags of_excl(struct openflags flags)
109{
110 flags.e = 1;
111 return(flags);
112}
113
114static inline struct openflags of_cloexec(struct openflags flags)
115{
116 flags.cl = 1;
117 return(flags);
118}
119
120extern int os_stat_file(const char *file_name, struct uml_stat *buf);
121extern int os_stat_fd(const int fd, struct uml_stat *buf);
122extern int os_access(const char *file, int mode);
123extern void os_print_error(int error, const char* str);
124extern int os_get_exec_close(int fd, int *close_on_exec);
125extern int os_set_exec_close(int fd, int close_on_exec);
126extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg);
127extern int os_window_size(int fd, int *rows, int *cols);
128extern int os_new_tty_pgrp(int fd, int pid);
129extern int os_get_ifname(int fd, char *namebuf);
130extern int os_set_slip(int fd);
131extern int os_set_owner(int fd, int pid);
132extern int os_sigio_async(int master, int slave);
133extern int os_mode_fd(int fd, int mode);
134
135extern int os_seek_file(int fd, __u64 offset);
136extern int os_open_file(char *file, struct openflags flags, int mode);
137extern int os_read_file(int fd, void *buf, int len);
138extern int os_write_file(int fd, const void *buf, int count);
139extern int os_file_size(char *file, long long *size_out);
140extern int os_file_modtime(char *file, unsigned long *modtime);
141extern int os_pipe(int *fd, int stream, int close_on_exec);
142extern int os_set_fd_async(int fd, int owner);
143extern int os_clear_fd_async(int fd);
144extern int os_set_fd_block(int fd, int blocking);
145extern int os_accept_connection(int fd);
146extern int os_create_unix_socket(char *file, int len, int close_on_exec);
147extern int os_shutdown_socket(int fd, int r, int w);
148extern void os_close_file(int fd);
149extern int os_rcv_fd(int fd, int *helper_pid_out);
150extern int create_unix_socket(char *file, int len, int close_on_exec);
151extern int os_connect_socket(char *name);
152extern int os_file_type(char *file);
153extern int os_file_mode(char *file, struct openflags *mode_out);
154extern int os_lock_file(int fd, int excl);
155
156extern unsigned long os_process_pc(int pid);
157extern int os_process_parent(int pid);
158extern void os_stop_process(int pid);
159extern void os_kill_process(int pid, int reap_child);
160extern void os_kill_ptraced_process(int pid, int reap_child);
161extern void os_usr1_process(int pid);
162extern int os_getpid(void);
163
164extern int os_map_memory(void *virt, int fd, unsigned long long off,
165 unsigned long len, int r, int w, int x);
166extern int os_protect_memory(void *addr, unsigned long len,
167 int r, int w, int x);
168extern int os_unmap_memory(void *addr, int len);
169extern void os_flush_stdout(void);
170extern unsigned long long os_usecs(void);
171
172#endif
173
174/*
175 * Overrides for Emacs so that we follow Linus's tabbing style.
176 * Emacs will notice this stuff at the end of the file and automatically
177 * adjust the settings for this buffer only. This must remain at the end
178 * of the file.
179 * ---------------------------------------------------------------------------
180 * Local variables:
181 * c-file-style: "linux"
182 * End:
183 */
diff --git a/arch/um/include/process.h b/arch/um/include/process.h
new file mode 100644
index 000000000000..5af9157ff54f
--- /dev/null
+++ b/arch/um/include/process.h
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __PROCESS_H__
7#define __PROCESS_H__
8
9#include <signal.h>
10
11extern void sig_handler(int sig, struct sigcontext sc);
12extern void alarm_handler(int sig, struct sigcontext sc);
13
14#endif
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/include/ptrace_user.h b/arch/um/include/ptrace_user.h
new file mode 100644
index 000000000000..f3450e6bc18d
--- /dev/null
+++ b/arch/um/include/ptrace_user.h
@@ -0,0 +1,60 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __PTRACE_USER_H__
7#define __PTRACE_USER_H__
8
9#include "sysdep/ptrace_user.h"
10
11extern int ptrace_getregs(long pid, unsigned long *regs_out);
12extern int ptrace_setregs(long pid, unsigned long *regs_in);
13extern int ptrace_getfpregs(long pid, unsigned long *regs_out);
14extern int ptrace_setfpregs(long pid, unsigned long *regs);
15extern void arch_enter_kernel(void *task, int pid);
16extern void arch_leave_kernel(void *task, int pid);
17extern void ptrace_pokeuser(unsigned long addr, unsigned long data);
18
19
20/* syscall emulation path in ptrace */
21
22#ifndef PTRACE_SYSEMU
23#define PTRACE_SYSEMU 31
24#endif
25#ifndef PTRACE_SYSEMU_SINGLESTEP
26#define PTRACE_SYSEMU_SINGLESTEP 32
27#endif
28
29/* On architectures, that started to support PTRACE_O_TRACESYSGOOD
30 * in linux 2.4, there are two different definitions of
31 * PTRACE_SETOPTIONS: linux 2.4 uses 21 while linux 2.6 uses 0x4200.
32 * For binary compatibility, 2.6 also supports the old "21", named
33 * PTRACE_OLDSETOPTION. On these architectures, UML always must use
34 * "21", to ensure the kernel runs on 2.4 and 2.6 host without
35 * recompilation. So, we use PTRACE_OLDSETOPTIONS in UML.
36 * We also want to be able to build the kernel on 2.4, which doesn't
37 * have PTRACE_OLDSETOPTIONS. So, if it is missing, we declare
38 * PTRACE_OLDSETOPTIONS to to be the same as PTRACE_SETOPTIONS.
39 *
40 * On architectures, that start to support PTRACE_O_TRACESYSGOOD on
41 * linux 2.6, PTRACE_OLDSETOPTIONS never is defined, and also isn't
42 * supported by the host kernel. In that case, our trick lets us use
43 * the new 0x4200 with the name PTRACE_OLDSETOPTIONS.
44 */
45#ifndef PTRACE_OLDSETOPTIONS
46#define PTRACE_OLDSETOPTIONS PTRACE_SETOPTIONS
47#endif
48
49void set_using_sysemu(int value);
50int get_using_sysemu(void);
51extern int sysemu_supported;
52
53#define SELECT_PTRACE_OPERATION(sysemu_mode, singlestep_mode) \
54 (((int[3][3] ) { \
55 { PTRACE_SYSCALL, PTRACE_SYSCALL, PTRACE_SINGLESTEP }, \
56 { PTRACE_SYSEMU, PTRACE_SYSEMU, PTRACE_SINGLESTEP }, \
57 { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, PTRACE_SYSEMU_SINGLESTEP }}) \
58 [sysemu_mode][singlestep_mode])
59
60#endif
diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h
new file mode 100644
index 000000000000..8744abb5224f
--- /dev/null
+++ b/arch/um/include/registers.h
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2004 PathScale, Inc
3 * Licensed under the GPL
4 */
5
6#ifndef __REGISTERS_H
7#define __REGISTERS_H
8
9#include "sysdep/ptrace.h"
10
11extern void init_thread_registers(union uml_pt_regs *to);
12extern int save_fp_registers(int pid, unsigned long *fp_regs);
13extern int restore_fp_registers(int pid, unsigned long *fp_regs);
14extern void save_registers(int pid, union uml_pt_regs *regs);
15extern void restore_registers(int pid, union uml_pt_regs *regs);
16extern void init_registers(int pid);
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/include/sigcontext.h b/arch/um/include/sigcontext.h
new file mode 100644
index 000000000000..59816ca7a8df
--- /dev/null
+++ b/arch/um/include/sigcontext.h
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __UML_SIGCONTEXT_H__
7#define __UML_SIGCONTEXT_H__
8
9#include "sysdep/sigcontext.h"
10
11extern int sc_size(void *data);
12extern void sc_to_sc(void *to_ptr, void *from_ptr);
13
14#endif
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/include/sigio.h b/arch/um/include/sigio.h
new file mode 100644
index 000000000000..37d76e29a147
--- /dev/null
+++ b/arch/um/include/sigio.h
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SIGIO_H__
7#define __SIGIO_H__
8
9extern int write_sigio_irq(int fd);
10extern int register_sigio_fd(int fd);
11extern int read_sigio_fd(int fd);
12extern int add_sigio_fd(int fd, int read);
13extern int ignore_sigio_fd(int fd);
14extern void sigio_lock(void);
15extern void sigio_unlock(void);
16
17#endif
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/include/signal_kern.h b/arch/um/include/signal_kern.h
new file mode 100644
index 000000000000..aeb5d5ab1dfd
--- /dev/null
+++ b/arch/um/include/signal_kern.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SIGNAL_KERN_H__
7#define __SIGNAL_KERN_H__
8
9extern int have_signals(void *t);
10
11#endif
12
13/*
14 * Overrides for Emacs so that we follow Linus's tabbing style.
15 * Emacs will notice this stuff at the end of the file and automatically
16 * adjust the settings for this buffer only. This must remain at the end
17 * of the file.
18 * ---------------------------------------------------------------------------
19 * Local variables:
20 * c-file-style: "linux"
21 * End:
22 */
diff --git a/arch/um/include/signal_user.h b/arch/um/include/signal_user.h
new file mode 100644
index 000000000000..b075e543d864
--- /dev/null
+++ b/arch/um/include/signal_user.h
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SIGNAL_USER_H__
7#define __SIGNAL_USER_H__
8
9extern int signal_stack_size;
10
11extern int change_sig(int signal, int on);
12extern void set_sigstack(void *stack, int size);
13extern void set_handler(int sig, void (*handler)(int), int flags, ...);
14extern int set_signals(int enable);
15extern int get_signals(void);
16
17#endif
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/include/skas_ptrace.h b/arch/um/include/skas_ptrace.h
new file mode 100644
index 000000000000..cfb5fb4f5b91
--- /dev/null
+++ b/arch/um/include/skas_ptrace.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_PTRACE_H
7#define __SKAS_PTRACE_H
8
9struct ptrace_faultinfo {
10 int is_write;
11 unsigned long addr;
12};
13
14struct ptrace_ldt {
15 int func;
16 void *ptr;
17 unsigned long bytecount;
18};
19
20#define PTRACE_FAULTINFO 52
21#define PTRACE_SIGPENDING 53
22#define PTRACE_LDT 54
23#define PTRACE_SWITCH_MM 55
24
25#endif
26
27/*
28 * Overrides for Emacs so that we follow Linus's tabbing style.
29 * Emacs will notice this stuff at the end of the file and automatically
30 * adjust the settings for this buffer only. This must remain at the end
31 * of the file.
32 * ---------------------------------------------------------------------------
33 * Local variables:
34 * c-file-style: "linux"
35 * End:
36 */
diff --git a/arch/um/include/syscall_user.h b/arch/um/include/syscall_user.h
new file mode 100644
index 000000000000..811d0ec2445e
--- /dev/null
+++ b/arch/um/include/syscall_user.h
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SYSCALL_USER_H
7#define __SYSCALL_USER_H
8
9extern int record_syscall_start(int syscall);
10extern void record_syscall_end(int index, long result);
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/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h
new file mode 100644
index 000000000000..3a2a45811aa3
--- /dev/null
+++ b/arch/um/include/sysdep-i386/checksum.h
@@ -0,0 +1,219 @@
1/*
2 * Licensed under the GPL
3 */
4
5#ifndef __UM_SYSDEP_CHECKSUM_H
6#define __UM_SYSDEP_CHECKSUM_H
7
8#include "linux/in6.h"
9#include "linux/string.h"
10
11/*
12 * computes the checksum of a memory block at buff, length len,
13 * and adds in "sum" (32-bit)
14 *
15 * returns a 32-bit number suitable for feeding into itself
16 * or csum_tcpudp_magic
17 *
18 * this function must be called with even lengths, except
19 * for the last fragment, which may be odd
20 *
21 * it's best to have buff aligned on a 32-bit boundary
22 */
23unsigned int csum_partial(const unsigned char * buff, int len,
24 unsigned int sum);
25
26/*
27 * the same as csum_partial, but copies from src while it
28 * checksums, and handles user-space pointer exceptions correctly, when needed.
29 *
30 * here even more important to align src and dst on a 32-bit (or even
31 * better 64-bit) boundary
32 */
33
34unsigned int csum_partial_copy_to(const unsigned char *src, unsigned char *dst,
35 int len, int sum, int *err_ptr);
36unsigned int csum_partial_copy_from(const unsigned char *src, unsigned char *dst,
37 int len, int sum, int *err_ptr);
38
39/*
40 * Note: when you get a NULL pointer exception here this means someone
41 * passed in an incorrect kernel address to one of these functions.
42 *
43 * If you use these functions directly please don't forget the
44 * access_ok().
45 */
46
47static __inline__
48unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst,
49 int len, int sum)
50{
51 memcpy(dst, src, len);
52 return(csum_partial(dst, len, sum));
53}
54
55static __inline__
56unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
57 int len, int sum, int *err_ptr)
58{
59 return csum_partial_copy_from(src, dst, len, sum, err_ptr);
60}
61
62/*
63 * These are the old (and unsafe) way of doing checksums, a warning message
64 * will be printed if they are used and an exception occurs.
65 *
66 * these functions should go away after some time.
67 */
68
69#define csum_partial_copy_fromuser csum_partial_copy_from_user
70unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst, int len, int sum);
71
72/*
73 * This is a version of ip_compute_csum() optimized for IP headers,
74 * which always checksum on 4 octet boundaries.
75 *
76 * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
77 * Arnt Gulbrandsen.
78 */
79static inline unsigned short ip_fast_csum(unsigned char * iph,
80 unsigned int ihl)
81{
82 unsigned int sum;
83
84 __asm__ __volatile__(
85 "movl (%1), %0 ;\n"
86 "subl $4, %2 ;\n"
87 "jbe 2f ;\n"
88 "addl 4(%1), %0 ;\n"
89 "adcl 8(%1), %0 ;\n"
90 "adcl 12(%1), %0 ;\n"
91"1: adcl 16(%1), %0 ;\n"
92 "lea 4(%1), %1 ;\n"
93 "decl %2 ;\n"
94 "jne 1b ;\n"
95 "adcl $0, %0 ;\n"
96 "movl %0, %2 ;\n"
97 "shrl $16, %0 ;\n"
98 "addw %w2, %w0 ;\n"
99 "adcl $0, %0 ;\n"
100 "notl %0 ;\n"
101"2: ;\n"
102 /* Since the input registers which are loaded with iph and ipl
103 are modified, we must also specify them as outputs, or gcc
104 will assume they contain their original values. */
105 : "=r" (sum), "=r" (iph), "=r" (ihl)
106 : "1" (iph), "2" (ihl)
107 : "memory");
108 return(sum);
109}
110
111/*
112 * Fold a partial checksum
113 */
114
115static inline unsigned int csum_fold(unsigned int sum)
116{
117 __asm__(
118 "addl %1, %0 ;\n"
119 "adcl $0xffff, %0 ;\n"
120 : "=r" (sum)
121 : "r" (sum << 16), "0" (sum & 0xffff0000)
122 );
123 return (~sum) >> 16;
124}
125
126static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
127 unsigned long daddr,
128 unsigned short len,
129 unsigned short proto,
130 unsigned int sum)
131{
132 __asm__(
133 "addl %1, %0 ;\n"
134 "adcl %2, %0 ;\n"
135 "adcl %3, %0 ;\n"
136 "adcl $0, %0 ;\n"
137 : "=r" (sum)
138 : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
139 return sum;
140}
141
142/*
143 * computes the checksum of the TCP/UDP pseudo-header
144 * returns a 16-bit checksum, already complemented
145 */
146static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
147 unsigned long daddr,
148 unsigned short len,
149 unsigned short proto,
150 unsigned int sum)
151{
152 return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
153}
154
155/*
156 * this routine is used for miscellaneous IP-like checksums, mainly
157 * in icmp.c
158 */
159
160static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
161{
162 return csum_fold (csum_partial(buff, len, 0));
163}
164
165#define _HAVE_ARCH_IPV6_CSUM
166static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
167 struct in6_addr *daddr,
168 __u32 len,
169 unsigned short proto,
170 unsigned int sum)
171{
172 __asm__(
173 "addl 0(%1), %0 ;\n"
174 "adcl 4(%1), %0 ;\n"
175 "adcl 8(%1), %0 ;\n"
176 "adcl 12(%1), %0 ;\n"
177 "adcl 0(%2), %0 ;\n"
178 "adcl 4(%2), %0 ;\n"
179 "adcl 8(%2), %0 ;\n"
180 "adcl 12(%2), %0 ;\n"
181 "adcl %3, %0 ;\n"
182 "adcl %4, %0 ;\n"
183 "adcl $0, %0 ;\n"
184 : "=&r" (sum)
185 : "r" (saddr), "r" (daddr),
186 "r"(htonl(len)), "r"(htonl(proto)), "0"(sum));
187
188 return csum_fold(sum);
189}
190
191/*
192 * Copy and checksum to user
193 */
194#define HAVE_CSUM_COPY_USER
195static __inline__ unsigned int csum_and_copy_to_user(const unsigned char *src,
196 unsigned char *dst,
197 int len, int sum, int *err_ptr)
198{
199 if (access_ok(VERIFY_WRITE, dst, len))
200 return(csum_partial_copy_to(src, dst, len, sum, err_ptr));
201
202 if (len)
203 *err_ptr = -EFAULT;
204
205 return -1; /* invalid checksum */
206}
207
208#endif
209
210/*
211 * Overrides for Emacs so that we follow Linus's tabbing style.
212 * Emacs will notice this stuff at the end of the file and automatically
213 * adjust the settings for this buffer only. This must remain at the end
214 * of the file.
215 * ---------------------------------------------------------------------------
216 * Local variables:
217 * c-file-style: "linux"
218 * End:
219 */
diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h
new file mode 100644
index 000000000000..661d495e2044
--- /dev/null
+++ b/arch/um/include/sysdep-i386/ptrace.h
@@ -0,0 +1,241 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SYSDEP_I386_PTRACE_H
7#define __SYSDEP_I386_PTRACE_H
8
9#include "uml-config.h"
10#include "user_constants.h"
11
12#define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long))
13#define MAX_REG_OFFSET (UM_FRAME_SIZE)
14
15extern void update_debugregs(int seq);
16
17/* syscall emulation path in ptrace */
18
19#ifndef PTRACE_SYSEMU
20#define PTRACE_SYSEMU 31
21#endif
22
23void set_using_sysemu(int value);
24int get_using_sysemu(void);
25extern int sysemu_supported;
26
27#ifdef UML_CONFIG_MODE_TT
28#include "sysdep/sc.h"
29#endif
30
31#ifdef UML_CONFIG_MODE_SKAS
32
33#include "skas_ptregs.h"
34
35#define REGS_IP(r) ((r)[HOST_IP])
36#define REGS_SP(r) ((r)[HOST_SP])
37#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
38#define REGS_EAX(r) ((r)[HOST_EAX])
39#define REGS_EBX(r) ((r)[HOST_EBX])
40#define REGS_ECX(r) ((r)[HOST_ECX])
41#define REGS_EDX(r) ((r)[HOST_EDX])
42#define REGS_ESI(r) ((r)[HOST_ESI])
43#define REGS_EDI(r) ((r)[HOST_EDI])
44#define REGS_EBP(r) ((r)[HOST_EBP])
45#define REGS_CS(r) ((r)[HOST_CS])
46#define REGS_SS(r) ((r)[HOST_SS])
47#define REGS_DS(r) ((r)[HOST_DS])
48#define REGS_ES(r) ((r)[HOST_ES])
49#define REGS_FS(r) ((r)[HOST_FS])
50#define REGS_GS(r) ((r)[HOST_GS])
51
52#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res)
53
54#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
55
56#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type)
57
58#define REGS_FAULT_ADDR(r) ((r)->fault_addr)
59
60#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type)
61
62#endif
63#ifndef PTRACE_SYSEMU_SINGLESTEP
64#define PTRACE_SYSEMU_SINGLESTEP 32
65#endif
66
67#include "choose-mode.h"
68
69union uml_pt_regs {
70#ifdef UML_CONFIG_MODE_TT
71 struct tt_regs {
72 long syscall;
73 void *sc;
74 } tt;
75#endif
76#ifdef UML_CONFIG_MODE_SKAS
77 struct skas_regs {
78 unsigned long regs[HOST_FRAME_SIZE];
79 unsigned long fp[HOST_FP_SIZE];
80 unsigned long xfp[HOST_XFP_SIZE];
81 unsigned long fault_addr;
82 unsigned long fault_type;
83 unsigned long trap_type;
84 long syscall;
85 int is_user;
86 } skas;
87#endif
88};
89
90#define EMPTY_UML_PT_REGS { }
91
92extern int mode_tt;
93
94#define UPT_SC(r) ((r)->tt.sc)
95#define UPT_IP(r) \
96 __CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
97#define UPT_SP(r) \
98 __CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
99#define UPT_EFLAGS(r) \
100 __CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
101#define UPT_EAX(r) \
102 __CHOOSE_MODE(SC_EAX(UPT_SC(r)), REGS_EAX((r)->skas.regs))
103#define UPT_EBX(r) \
104 __CHOOSE_MODE(SC_EBX(UPT_SC(r)), REGS_EBX((r)->skas.regs))
105#define UPT_ECX(r) \
106 __CHOOSE_MODE(SC_ECX(UPT_SC(r)), REGS_ECX((r)->skas.regs))
107#define UPT_EDX(r) \
108 __CHOOSE_MODE(SC_EDX(UPT_SC(r)), REGS_EDX((r)->skas.regs))
109#define UPT_ESI(r) \
110 __CHOOSE_MODE(SC_ESI(UPT_SC(r)), REGS_ESI((r)->skas.regs))
111#define UPT_EDI(r) \
112 __CHOOSE_MODE(SC_EDI(UPT_SC(r)), REGS_EDI((r)->skas.regs))
113#define UPT_EBP(r) \
114 __CHOOSE_MODE(SC_EBP(UPT_SC(r)), REGS_EBP((r)->skas.regs))
115#define UPT_ORIG_EAX(r) \
116 __CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
117#define UPT_CS(r) \
118 __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
119#define UPT_SS(r) \
120 __CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs))
121#define UPT_DS(r) \
122 __CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
123#define UPT_ES(r) \
124 __CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
125#define UPT_FS(r) \
126 __CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
127#define UPT_GS(r) \
128 __CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
129
130#define UPT_SYSCALL_ARG1(r) UPT_EBX(r)
131#define UPT_SYSCALL_ARG2(r) UPT_ECX(r)
132#define UPT_SYSCALL_ARG3(r) UPT_EDX(r)
133#define UPT_SYSCALL_ARG4(r) UPT_ESI(r)
134#define UPT_SYSCALL_ARG5(r) UPT_EDI(r)
135#define UPT_SYSCALL_ARG6(r) UPT_EBP(r)
136
137extern int user_context(unsigned long sp);
138
139#define UPT_IS_USER(r) \
140 CHOOSE_MODE(user_context(UPT_SP(r)), (r)->skas.is_user)
141
142struct syscall_args {
143 unsigned long args[6];
144};
145
146#define SYSCALL_ARGS(r) ((struct syscall_args) \
147 { .args = { UPT_SYSCALL_ARG1(r), \
148 UPT_SYSCALL_ARG2(r), \
149 UPT_SYSCALL_ARG3(r), \
150 UPT_SYSCALL_ARG4(r), \
151 UPT_SYSCALL_ARG5(r), \
152 UPT_SYSCALL_ARG6(r) } } )
153
154#define UPT_REG(regs, reg) \
155 ({ unsigned long val; \
156 switch(reg){ \
157 case EIP: val = UPT_IP(regs); break; \
158 case UESP: val = UPT_SP(regs); break; \
159 case EAX: val = UPT_EAX(regs); break; \
160 case EBX: val = UPT_EBX(regs); break; \
161 case ECX: val = UPT_ECX(regs); break; \
162 case EDX: val = UPT_EDX(regs); break; \
163 case ESI: val = UPT_ESI(regs); break; \
164 case EDI: val = UPT_EDI(regs); break; \
165 case EBP: val = UPT_EBP(regs); break; \
166 case ORIG_EAX: val = UPT_ORIG_EAX(regs); break; \
167 case CS: val = UPT_CS(regs); break; \
168 case SS: val = UPT_SS(regs); break; \
169 case DS: val = UPT_DS(regs); break; \
170 case ES: val = UPT_ES(regs); break; \
171 case FS: val = UPT_FS(regs); break; \
172 case GS: val = UPT_GS(regs); break; \
173 case EFL: val = UPT_EFLAGS(regs); break; \
174 default : \
175 panic("Bad register in UPT_REG : %d\n", reg); \
176 val = -1; \
177 } \
178 val; \
179 })
180
181
182#define UPT_SET(regs, reg, val) \
183 do { \
184 switch(reg){ \
185 case EIP: UPT_IP(regs) = val; break; \
186 case UESP: UPT_SP(regs) = val; break; \
187 case EAX: UPT_EAX(regs) = val; break; \
188 case EBX: UPT_EBX(regs) = val; break; \
189 case ECX: UPT_ECX(regs) = val; break; \
190 case EDX: UPT_EDX(regs) = val; break; \
191 case ESI: UPT_ESI(regs) = val; break; \
192 case EDI: UPT_EDI(regs) = val; break; \
193 case EBP: UPT_EBP(regs) = val; break; \
194 case ORIG_EAX: UPT_ORIG_EAX(regs) = val; break; \
195 case CS: UPT_CS(regs) = val; break; \
196 case SS: UPT_SS(regs) = val; break; \
197 case DS: UPT_DS(regs) = val; break; \
198 case ES: UPT_ES(regs) = val; break; \
199 case FS: UPT_FS(regs) = val; break; \
200 case GS: UPT_GS(regs) = val; break; \
201 case EFL: UPT_EFLAGS(regs) = val; break; \
202 default : \
203 panic("Bad register in UPT_SET : %d\n", reg); \
204 break; \
205 } \
206 } while (0)
207
208#define UPT_SET_SYSCALL_RETURN(r, res) \
209 CHOOSE_MODE(SC_SET_SYSCALL_RETURN(UPT_SC(r), (res)), \
210 REGS_SET_SYSCALL_RETURN((r)->skas.regs, (res)))
211
212#define UPT_RESTART_SYSCALL(r) \
213 CHOOSE_MODE(SC_RESTART_SYSCALL(UPT_SC(r)), \
214 REGS_RESTART_SYSCALL((r)->skas.regs))
215
216#define UPT_ORIG_SYSCALL(r) UPT_EAX(r)
217#define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r)
218#define UPT_SYSCALL_RET(r) UPT_EAX(r)
219
220#define UPT_SEGV_IS_FIXABLE(r) \
221 CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \
222 REGS_SEGV_IS_FIXABLE(&r->skas))
223
224#define UPT_FAULT_ADDR(r) \
225 __CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas))
226
227#define UPT_FAULT_WRITE(r) \
228 CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas))
229
230#endif
231
232/*
233 * Overrides for Emacs so that we follow Linus's tabbing style.
234 * Emacs will notice this stuff at the end of the file and automatically
235 * adjust the settings for this buffer only. This must remain at the end
236 * of the file.
237 * ---------------------------------------------------------------------------
238 * Local variables:
239 * c-file-style: "linux"
240 * End:
241 */
diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h
new file mode 100644
index 000000000000..eca8066e7a43
--- /dev/null
+++ b/arch/um/include/sysdep-i386/ptrace_user.h
@@ -0,0 +1,62 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SYSDEP_I386_PTRACE_USER_H__
7#define __SYSDEP_I386_PTRACE_USER_H__
8
9#include <sys/ptrace.h>
10#include <linux/ptrace.h>
11#include <asm/ptrace.h>
12
13#define PT_OFFSET(r) ((r) * sizeof(long))
14
15#define PT_SYSCALL_NR(regs) ((regs)[ORIG_EAX])
16#define PT_SYSCALL_NR_OFFSET PT_OFFSET(ORIG_EAX)
17
18#define PT_SYSCALL_ARG1_OFFSET PT_OFFSET(EBX)
19#define PT_SYSCALL_ARG2_OFFSET PT_OFFSET(ECX)
20#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
21#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
22#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
23
24#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
25
26#define PT_IP_OFFSET PT_OFFSET(EIP)
27#define PT_IP(regs) ((regs)[EIP])
28#define PT_SP(regs) ((regs)[UESP])
29
30#ifndef FRAME_SIZE
31#define FRAME_SIZE (17)
32#endif
33#define FRAME_SIZE_OFFSET (FRAME_SIZE * sizeof(unsigned long))
34
35#define FP_FRAME_SIZE (27)
36#define FPX_FRAME_SIZE (128)
37
38#ifdef PTRACE_GETREGS
39#define UM_HAVE_GETREGS
40#endif
41
42#ifdef PTRACE_SETREGS
43#define UM_HAVE_SETREGS
44#endif
45
46#ifdef PTRACE_GETFPREGS
47#define UM_HAVE_GETFPREGS
48#endif
49
50#ifdef PTRACE_SETFPREGS
51#define UM_HAVE_SETFPREGS
52#endif
53
54#ifdef PTRACE_GETFPXREGS
55#define UM_HAVE_GETFPXREGS
56#endif
57
58#ifdef PTRACE_SETFPXREGS
59#define UM_HAVE_SETFPXREGS
60#endif
61
62#endif
diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h
new file mode 100644
index 000000000000..dfee589de360
--- /dev/null
+++ b/arch/um/include/sysdep-i386/sigcontext.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SYS_SIGCONTEXT_I386_H
7#define __SYS_SIGCONTEXT_I386_H
8
9#include <sysdep/sc.h>
10
11#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
12
13#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc))
14#define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result)
15
16#define SC_FAULT_ADDR(sc) SC_CR2(sc)
17#define SC_FAULT_TYPE(sc) SC_ERR(sc)
18
19#define FAULT_WRITE(err) (err & 2)
20#define TO_SC_ERR(is_write) ((is_write) ? 2 : 0)
21
22#define SC_FAULT_WRITE(sc) (FAULT_WRITE(SC_ERR(sc)))
23
24#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc)
25
26/* ptrace expects that, at the start of a system call, %eax contains
27 * -ENOSYS, so this makes it so.
28 */
29#define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
30
31/* This is Page Fault */
32#define SEGV_IS_FIXABLE(trap) (trap == 14)
33
34#define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc)))
35
36extern unsigned long *sc_sigmask(void *sc_ptr);
37extern int sc_get_fpregs(unsigned long buf, void *sc_ptr);
38
39#endif
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/include/sysdep-i386/signal.h b/arch/um/include/sysdep-i386/signal.h
new file mode 100644
index 000000000000..b1e1f7a77499
--- /dev/null
+++ b/arch/um/include/sysdep-i386/signal.h
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2004 PathScale, Inc
3 * Licensed under the GPL
4 */
5
6#ifndef __I386_SIGNAL_H_
7#define __I386_SIGNAL_H_
8
9#include <signal.h>
10
11#define ARCH_GET_SIGCONTEXT(sc, sig) \
12 do sc = (struct sigcontext *) (&sig + 1); while(0)
13
14#endif
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/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h
new file mode 100644
index 000000000000..5db81ec9087d
--- /dev/null
+++ b/arch/um/include/sysdep-i386/syscalls.h
@@ -0,0 +1,123 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "asm/unistd.h"
7#include "sysdep/ptrace.h"
8
9typedef long syscall_handler_t(struct pt_regs);
10
11/* Not declared on x86, incompatible declarations on x86_64, so these have
12 * to go here rather than in sys_call_table.c
13 */
14extern syscall_handler_t sys_ptrace;
15extern syscall_handler_t sys_rt_sigaction;
16
17extern syscall_handler_t old_mmap_i386;
18
19#define EXECUTE_SYSCALL(syscall, regs) \
20 ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
21
22extern long sys_mmap2(unsigned long addr, unsigned long len,
23 unsigned long prot, unsigned long flags,
24 unsigned long fd, unsigned long pgoff);
25
26/* On i386 they choose a meaningless naming.*/
27#define __NR_kexec_load __NR_sys_kexec_load
28
29#define ARCH_SYSCALLS \
30 [ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid, \
31 [ __NR_break ] = (syscall_handler_t *) sys_ni_syscall, \
32 [ __NR_oldstat ] = (syscall_handler_t *) sys_stat, \
33 [ __NR_umount ] = (syscall_handler_t *) sys_oldumount, \
34 [ __NR_stime ] = um_stime, \
35 [ __NR_oldfstat ] = (syscall_handler_t *) sys_fstat, \
36 [ __NR_stty ] = (syscall_handler_t *) sys_ni_syscall, \
37 [ __NR_gtty ] = (syscall_handler_t *) sys_ni_syscall, \
38 [ __NR_nice ] = (syscall_handler_t *) sys_nice, \
39 [ __NR_ftime ] = (syscall_handler_t *) sys_ni_syscall, \
40 [ __NR_prof ] = (syscall_handler_t *) sys_ni_syscall, \
41 [ __NR_signal ] = (syscall_handler_t *) sys_signal, \
42 [ __NR_lock ] = (syscall_handler_t *) sys_ni_syscall, \
43 [ __NR_mpx ] = (syscall_handler_t *) sys_ni_syscall, \
44 [ __NR_ulimit ] = (syscall_handler_t *) sys_ni_syscall, \
45 [ __NR_oldolduname ] = (syscall_handler_t *) sys_olduname, \
46 [ __NR_sigaction ] = (syscall_handler_t *) sys_sigaction, \
47 [ __NR_sgetmask ] = (syscall_handler_t *) sys_sgetmask, \
48 [ __NR_ssetmask ] = (syscall_handler_t *) sys_ssetmask, \
49 [ __NR_sigsuspend ] = (syscall_handler_t *) sys_sigsuspend, \
50 [ __NR_sigpending ] = (syscall_handler_t *) sys_sigpending, \
51 [ __NR_oldlstat ] = (syscall_handler_t *) sys_lstat, \
52 [ __NR_readdir ] = old_readdir, \
53 [ __NR_profil ] = (syscall_handler_t *) sys_ni_syscall, \
54 [ __NR_socketcall ] = (syscall_handler_t *) sys_socketcall, \
55 [ __NR_olduname ] = (syscall_handler_t *) sys_uname, \
56 [ __NR_iopl ] = (syscall_handler_t *) sys_ni_syscall, \
57 [ __NR_idle ] = (syscall_handler_t *) sys_ni_syscall, \
58 [ __NR_ipc ] = (syscall_handler_t *) sys_ipc, \
59 [ __NR_sigreturn ] = (syscall_handler_t *) sys_sigreturn, \
60 [ __NR_sigprocmask ] = (syscall_handler_t *) sys_sigprocmask, \
61 [ __NR_bdflush ] = (syscall_handler_t *) sys_bdflush, \
62 [ __NR__llseek ] = (syscall_handler_t *) sys_llseek, \
63 [ __NR__newselect ] = (syscall_handler_t *) sys_select, \
64 [ __NR_vm86 ] = (syscall_handler_t *) sys_ni_syscall, \
65 [ __NR_mmap ] = (syscall_handler_t *) old_mmap_i386, \
66 [ __NR_ugetrlimit ] = (syscall_handler_t *) sys_getrlimit, \
67 [ __NR_mmap2 ] = (syscall_handler_t *) sys_mmap2, \
68 [ __NR_truncate64 ] = (syscall_handler_t *) sys_truncate64, \
69 [ __NR_ftruncate64 ] = (syscall_handler_t *) sys_ftruncate64, \
70 [ __NR_stat64 ] = (syscall_handler_t *) sys_stat64, \
71 [ __NR_lstat64 ] = (syscall_handler_t *) sys_lstat64, \
72 [ __NR_fstat64 ] = (syscall_handler_t *) sys_fstat64, \
73 [ __NR_fcntl64 ] = (syscall_handler_t *) sys_fcntl64, \
74 [ __NR_sendfile64 ] = (syscall_handler_t *) sys_sendfile64, \
75 [ __NR_statfs64 ] = (syscall_handler_t *) sys_statfs64, \
76 [ __NR_fstatfs64 ] = (syscall_handler_t *) sys_fstatfs64, \
77 [ __NR_fadvise64_64 ] = (syscall_handler_t *) sys_fadvise64_64, \
78 [ __NR_select ] = (syscall_handler_t *) old_select, \
79 [ __NR_vm86old ] = (syscall_handler_t *) sys_ni_syscall, \
80 [ __NR_modify_ldt ] = (syscall_handler_t *) sys_modify_ldt, \
81 [ __NR_lchown32 ] = (syscall_handler_t *) sys_lchown, \
82 [ __NR_getuid32 ] = (syscall_handler_t *) sys_getuid, \
83 [ __NR_getgid32 ] = (syscall_handler_t *) sys_getgid, \
84 [ __NR_geteuid32 ] = (syscall_handler_t *) sys_geteuid, \
85 [ __NR_getegid32 ] = (syscall_handler_t *) sys_getegid, \
86 [ __NR_setreuid32 ] = (syscall_handler_t *) sys_setreuid, \
87 [ __NR_setregid32 ] = (syscall_handler_t *) sys_setregid, \
88 [ __NR_getgroups32 ] = (syscall_handler_t *) sys_getgroups, \
89 [ __NR_setgroups32 ] = (syscall_handler_t *) sys_setgroups, \
90 [ __NR_fchown32 ] = (syscall_handler_t *) sys_fchown, \
91 [ __NR_setresuid32 ] = (syscall_handler_t *) sys_setresuid, \
92 [ __NR_getresuid32 ] = (syscall_handler_t *) sys_getresuid, \
93 [ __NR_setresgid32 ] = (syscall_handler_t *) sys_setresgid, \
94 [ __NR_getresgid32 ] = (syscall_handler_t *) sys_getresgid, \
95 [ __NR_chown32 ] = (syscall_handler_t *) sys_chown, \
96 [ __NR_setuid32 ] = (syscall_handler_t *) sys_setuid, \
97 [ __NR_setgid32 ] = (syscall_handler_t *) sys_setgid, \
98 [ __NR_setfsuid32 ] = (syscall_handler_t *) sys_setfsuid, \
99 [ __NR_setfsgid32 ] = (syscall_handler_t *) sys_setfsgid, \
100 [ __NR_pivot_root ] = (syscall_handler_t *) sys_pivot_root, \
101 [ __NR_mincore ] = (syscall_handler_t *) sys_mincore, \
102 [ __NR_madvise ] = (syscall_handler_t *) sys_madvise, \
103 [ 222 ] = (syscall_handler_t *) sys_ni_syscall, \
104 [ 223 ] = (syscall_handler_t *) sys_ni_syscall, \
105 [ __NR_set_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \
106 [ __NR_get_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \
107 [ 251 ] = (syscall_handler_t *) sys_ni_syscall, \
108 [ 285 ] = (syscall_handler_t *) sys_ni_syscall,
109
110/* 222 doesn't yet have a name in include/asm-i386/unistd.h */
111
112#define LAST_ARCH_SYSCALL 285
113
114/*
115 * Overrides for Emacs so that we follow Linus's tabbing style.
116 * Emacs will notice this stuff at the end of the file and automatically
117 * adjust the settings for this buffer only. This must remain at the end
118 * of the file.
119 * ---------------------------------------------------------------------------
120 * Local variables:
121 * c-file-style: "linux"
122 * End:
123 */
diff --git a/arch/um/include/sysdep-ia64/ptrace.h b/arch/um/include/sysdep-ia64/ptrace.h
new file mode 100644
index 000000000000..42dd8fb6f2f9
--- /dev/null
+++ b/arch/um/include/sysdep-ia64/ptrace.h
@@ -0,0 +1,26 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SYSDEP_IA64_PTRACE_H
7#define __SYSDEP_IA64_PTRACE_H
8
9struct sys_pt_regs {
10 int foo;
11};
12
13#define EMPTY_REGS { 0 }
14
15#endif
16
17/*
18 * Overrides for Emacs so that we follow Linus's tabbing style.
19 * Emacs will notice this stuff at the end of the file and automatically
20 * adjust the settings for this buffer only. This must remain at the end
21 * of the file.
22 * ---------------------------------------------------------------------------
23 * Local variables:
24 * c-file-style: "linux"
25 * End:
26 */
diff --git a/arch/um/include/sysdep-ia64/sigcontext.h b/arch/um/include/sysdep-ia64/sigcontext.h
new file mode 100644
index 000000000000..f15fb25260ba
--- /dev/null
+++ b/arch/um/include/sysdep-ia64/sigcontext.h
@@ -0,0 +1,20 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SYSDEP_IA64_SIGCONTEXT_H
7#define __SYSDEP_IA64_SIGCONTEXT_H
8
9#endif
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/include/sysdep-ia64/syscalls.h b/arch/um/include/sysdep-ia64/syscalls.h
new file mode 100644
index 000000000000..4a1f46ef1ebc
--- /dev/null
+++ b/arch/um/include/sysdep-ia64/syscalls.h
@@ -0,0 +1,20 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SYSDEP_IA64_SYSCALLS_H
7#define __SYSDEP_IA64_SYSCALLS_H
8
9#endif
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/include/sysdep-ppc/ptrace.h b/arch/um/include/sysdep-ppc/ptrace.h
new file mode 100644
index 000000000000..8a27353733a9
--- /dev/null
+++ b/arch/um/include/sysdep-ppc/ptrace.h
@@ -0,0 +1,104 @@
1/*
2 * Licensed under the GPL
3 */
4
5#ifndef __SYS_PTRACE_PPC_H
6#define __SYS_PTRACE_PPC_H
7
8#include "linux/config.h"
9#include "linux/types.h"
10
11/* the following taken from <asm-ppc/ptrace.h> */
12
13#ifdef CONFIG_PPC64
14#define PPC_REG unsigned long /*long*/
15#else
16#define PPC_REG unsigned long
17#endif
18struct sys_pt_regs_s {
19 PPC_REG gpr[32];
20 PPC_REG nip;
21 PPC_REG msr;
22 PPC_REG orig_gpr3; /* Used for restarting system calls */
23 PPC_REG ctr;
24 PPC_REG link;
25 PPC_REG xer;
26 PPC_REG ccr;
27 PPC_REG mq; /* 601 only (not used at present) */
28 /* Used on APUS to hold IPL value. */
29 PPC_REG trap; /* Reason for being here */
30 PPC_REG dar; /* Fault registers */
31 PPC_REG dsisr;
32 PPC_REG result; /* Result of a system call */
33};
34
35#define NUM_REGS (sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG))
36
37struct sys_pt_regs {
38 PPC_REG regs[sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG)];
39};
40
41#define UM_MAX_REG (PT_FPR0)
42#define UM_MAX_REG_OFFSET (UM_MAX_REG * sizeof(PPC_REG))
43
44#define EMPTY_REGS { { [ 0 ... NUM_REGS - 1] = 0 } }
45
46#define UM_REG(r, n) ((r)->regs[n])
47
48#define UM_SYSCALL_RET(r) UM_REG(r, PT_R3)
49#define UM_SP(r) UM_REG(r, PT_R1)
50#define UM_IP(r) UM_REG(r, PT_NIP)
51#define UM_ELF_ZERO(r) UM_REG(r, PT_FPSCR)
52#define UM_SYSCALL_NR(r) UM_REG(r, PT_R0)
53#define UM_SYSCALL_ARG1(r) UM_REG(r, PT_ORIG_R3)
54#define UM_SYSCALL_ARG2(r) UM_REG(r, PT_R4)
55#define UM_SYSCALL_ARG3(r) UM_REG(r, PT_R5)
56#define UM_SYSCALL_ARG4(r) UM_REG(r, PT_R6)
57#define UM_SYSCALL_ARG5(r) UM_REG(r, PT_R7)
58#define UM_SYSCALL_ARG6(r) UM_REG(r, PT_R8)
59
60#define UM_SYSCALL_NR_OFFSET (PT_R0 * sizeof(PPC_REG))
61#define UM_SYSCALL_RET_OFFSET (PT_R3 * sizeof(PPC_REG))
62#define UM_SYSCALL_ARG1_OFFSET (PT_R3 * sizeof(PPC_REG))
63#define UM_SYSCALL_ARG2_OFFSET (PT_R4 * sizeof(PPC_REG))
64#define UM_SYSCALL_ARG3_OFFSET (PT_R5 * sizeof(PPC_REG))
65#define UM_SYSCALL_ARG4_OFFSET (PT_R6 * sizeof(PPC_REG))
66#define UM_SYSCALL_ARG5_OFFSET (PT_R7 * sizeof(PPC_REG))
67#define UM_SYSCALL_ARG6_OFFSET (PT_R8 * sizeof(PPC_REG))
68#define UM_SP_OFFSET (PT_R1 * sizeof(PPC_REG))
69#define UM_IP_OFFSET (PT_NIP * sizeof(PPC_REG))
70#define UM_ELF_ZERO_OFFSET (PT_R3 * sizeof(PPC_REG))
71
72#define UM_SET_SYSCALL_RETURN(_regs, result) \
73do { \
74 if (result < 0) { \
75 (_regs)->regs[PT_CCR] |= 0x10000000; \
76 UM_SYSCALL_RET((_regs)) = -result; \
77 } else { \
78 UM_SYSCALL_RET((_regs)) = result; \
79 } \
80} while(0)
81
82extern void shove_aux_table(unsigned long sp);
83#define UM_FIX_EXEC_STACK(sp) shove_aux_table(sp);
84
85/* These aren't actually defined. The undefs are just to make sure
86 * everyone's clear on the concept.
87 */
88#undef UML_HAVE_GETREGS
89#undef UML_HAVE_GETFPREGS
90#undef UML_HAVE_SETREGS
91#undef UML_HAVE_SETFPREGS
92
93#endif
94
95/*
96 * Overrides for Emacs so that we follow Linus's tabbing style.
97 * Emacs will notice this stuff at the end of the file and automatically
98 * adjust the settings for this buffer only. This must remain at the end
99 * of the file.
100 * ---------------------------------------------------------------------------
101 * Local variables:
102 * c-file-style: "linux"
103 * End:
104 */
diff --git a/arch/um/include/sysdep-ppc/sigcontext.h b/arch/um/include/sysdep-ppc/sigcontext.h
new file mode 100644
index 000000000000..f20d965de9c7
--- /dev/null
+++ b/arch/um/include/sysdep-ppc/sigcontext.h
@@ -0,0 +1,62 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SYS_SIGCONTEXT_PPC_H
7#define __SYS_SIGCONTEXT_PPC_H
8
9#define DSISR_WRITE 0x02000000
10
11#define SC_FAULT_ADDR(sc) ({ \
12 struct sigcontext *_sc = (sc); \
13 long retval = -1; \
14 switch (_sc->regs->trap) { \
15 case 0x300: \
16 /* data exception */ \
17 retval = _sc->regs->dar; \
18 break; \
19 case 0x400: \
20 /* instruction exception */ \
21 retval = _sc->regs->nip; \
22 break; \
23 default: \
24 panic("SC_FAULT_ADDR: unhandled trap type\n"); \
25 } \
26 retval; \
27 })
28
29#define SC_FAULT_WRITE(sc) ({ \
30 struct sigcontext *_sc = (sc); \
31 long retval = -1; \
32 switch (_sc->regs->trap) { \
33 case 0x300: \
34 /* data exception */ \
35 retval = !!(_sc->regs->dsisr & DSISR_WRITE); \
36 break; \
37 case 0x400: \
38 /* instruction exception: not a write */ \
39 retval = 0; \
40 break; \
41 default: \
42 panic("SC_FAULT_ADDR: unhandled trap type\n"); \
43 } \
44 retval; \
45 })
46
47#define SC_IP(sc) ((sc)->regs->nip)
48#define SC_SP(sc) ((sc)->regs->gpr[1])
49#define SEGV_IS_FIXABLE(sc) (1)
50
51#endif
52
53/*
54 * Overrides for Emacs so that we follow Linus's tabbing style.
55 * Emacs will notice this stuff at the end of the file and automatically
56 * adjust the settings for this buffer only. This must remain at the end
57 * of the file.
58 * ---------------------------------------------------------------------------
59 * Local variables:
60 * c-file-style: "linux"
61 * End:
62 */
diff --git a/arch/um/include/sysdep-ppc/syscalls.h b/arch/um/include/sysdep-ppc/syscalls.h
new file mode 100644
index 000000000000..679df351e19b
--- /dev/null
+++ b/arch/um/include/sysdep-ppc/syscalls.h
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6typedef long syscall_handler_t(unsigned long arg1, unsigned long arg2,
7 unsigned long arg3, unsigned long arg4,
8 unsigned long arg5, unsigned long arg6);
9
10#define EXECUTE_SYSCALL(syscall, regs) \
11 (*sys_call_table[syscall])(UM_SYSCALL_ARG1(&regs), \
12 UM_SYSCALL_ARG2(&regs), \
13 UM_SYSCALL_ARG3(&regs), \
14 UM_SYSCALL_ARG4(&regs), \
15 UM_SYSCALL_ARG5(&regs), \
16 UM_SYSCALL_ARG6(&regs))
17
18extern syscall_handler_t sys_mincore;
19extern syscall_handler_t sys_madvise;
20
21/* old_mmap needs the correct prototype since syscall_kern.c includes
22 * this file.
23 */
24int old_mmap(unsigned long addr, unsigned long len,
25 unsigned long prot, unsigned long flags,
26 unsigned long fd, unsigned long offset);
27
28#define ARCH_SYSCALLS \
29 [ __NR_modify_ldt ] = sys_ni_syscall, \
30 [ __NR_pciconfig_read ] = sys_ni_syscall, \
31 [ __NR_pciconfig_write ] = sys_ni_syscall, \
32 [ __NR_pciconfig_iobase ] = sys_ni_syscall, \
33 [ __NR_pivot_root ] = sys_ni_syscall, \
34 [ __NR_multiplexer ] = sys_ni_syscall, \
35 [ __NR_mmap ] = old_mmap, \
36 [ __NR_madvise ] = sys_madvise, \
37 [ __NR_mincore ] = sys_mincore, \
38 [ __NR_iopl ] = (syscall_handler_t *) sys_ni_syscall, \
39 [ __NR_utimes ] = (syscall_handler_t *) sys_utimes, \
40 [ __NR_fadvise64 ] = (syscall_handler_t *) sys_fadvise64,
41
42#define LAST_ARCH_SYSCALL __NR_fadvise64
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/include/sysdep-x86_64/checksum.h b/arch/um/include/sysdep-x86_64/checksum.h
new file mode 100644
index 000000000000..572c6c19be33
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/checksum.h
@@ -0,0 +1,151 @@
1/*
2 * Licensed under the GPL
3 */
4
5#ifndef __UM_SYSDEP_CHECKSUM_H
6#define __UM_SYSDEP_CHECKSUM_H
7
8#include "linux/string.h"
9#include "linux/in6.h"
10#include "asm/uaccess.h"
11
12extern unsigned int csum_partial_copy_from(const unsigned char *src, unsigned char *dst, int len,
13 int sum, int *err_ptr);
14extern unsigned csum_partial(const unsigned char *buff, unsigned len,
15 unsigned sum);
16
17/*
18 * Note: when you get a NULL pointer exception here this means someone
19 * passed in an incorrect kernel address to one of these functions.
20 *
21 * If you use these functions directly please don't forget the
22 * access_ok().
23 */
24
25static __inline__
26unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst,
27 int len, int sum)
28{
29 memcpy(dst, src, len);
30 return(csum_partial(dst, len, sum));
31}
32
33static __inline__
34unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
35 int len, int sum, int *err_ptr)
36{
37 return csum_partial_copy_from(src, dst, len, sum, err_ptr);
38}
39
40/**
41 * csum_fold - Fold and invert a 32bit checksum.
42 * sum: 32bit unfolded sum
43 *
44 * Fold a 32bit running checksum to 16bit and invert it. This is usually
45 * the last step before putting a checksum into a packet.
46 * Make sure not to mix with 64bit checksums.
47 */
48static inline unsigned int csum_fold(unsigned int sum)
49{
50 __asm__(
51 " addl %1,%0\n"
52 " adcl $0xffff,%0"
53 : "=r" (sum)
54 : "r" (sum << 16), "0" (sum & 0xffff0000)
55 );
56 return (~sum) >> 16;
57}
58
59/**
60 * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.
61 * @saddr: source address
62 * @daddr: destination address
63 * @len: length of packet
64 * @proto: ip protocol of packet
65 * @sum: initial sum to be added in (32bit unfolded)
66 *
67 * Returns the pseudo header checksum the input data. Result is
68 * 32bit unfolded.
69 */
70static inline unsigned long
71csum_tcpudp_nofold(unsigned saddr, unsigned daddr, unsigned short len,
72 unsigned short proto, unsigned int sum)
73{
74 asm(" addl %1, %0\n"
75 " adcl %2, %0\n"
76 " adcl %3, %0\n"
77 " adcl $0, %0\n"
78 : "=r" (sum)
79 : "g" (daddr), "g" (saddr), "g" ((ntohs(len)<<16)+proto*256), "0" (sum));
80 return sum;
81}
82
83/*
84 * computes the checksum of the TCP/UDP pseudo-header
85 * returns a 16-bit checksum, already complemented
86 */
87static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
88 unsigned long daddr,
89 unsigned short len,
90 unsigned short proto,
91 unsigned int sum)
92{
93 return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
94}
95
96/**
97 * ip_fast_csum - Compute the IPv4 header checksum efficiently.
98 * iph: ipv4 header
99 * ihl: length of header / 4
100 */
101static inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl)
102{
103 unsigned int sum;
104
105 asm( " movl (%1), %0\n"
106 " subl $4, %2\n"
107 " jbe 2f\n"
108 " addl 4(%1), %0\n"
109 " adcl 8(%1), %0\n"
110 " adcl 12(%1), %0\n"
111 "1: adcl 16(%1), %0\n"
112 " lea 4(%1), %1\n"
113 " decl %2\n"
114 " jne 1b\n"
115 " adcl $0, %0\n"
116 " movl %0, %2\n"
117 " shrl $16, %0\n"
118 " addw %w2, %w0\n"
119 " adcl $0, %0\n"
120 " notl %0\n"
121 "2:"
122 /* Since the input registers which are loaded with iph and ipl
123 are modified, we must also specify them as outputs, or gcc
124 will assume they contain their original values. */
125 : "=r" (sum), "=r" (iph), "=r" (ihl)
126 : "1" (iph), "2" (ihl)
127 : "memory");
128 return(sum);
129}
130
131static inline unsigned add32_with_carry(unsigned a, unsigned b)
132{
133 asm("addl %2,%0\n\t"
134 "adcl $0,%0"
135 : "=r" (a)
136 : "0" (a), "r" (b));
137 return a;
138}
139
140#endif
141
142/*
143 * Overrides for Emacs so that we follow Linus's tabbing style.
144 * Emacs will notice this stuff at the end of the file and automatically
145 * adjust the settings for this buffer only. This must remain at the end
146 * of the file.
147 * ---------------------------------------------------------------------------
148 * Local variables:
149 * c-file-style: "linux"
150 * End:
151 */
diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h
new file mode 100644
index 000000000000..915c82daffbd
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/ptrace.h
@@ -0,0 +1,264 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#ifndef __SYSDEP_X86_64_PTRACE_H
8#define __SYSDEP_X86_64_PTRACE_H
9
10#include "uml-config.h"
11#include "user_constants.h"
12
13#define MAX_REG_OFFSET (UM_FRAME_SIZE)
14#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
15
16#ifdef UML_CONFIG_MODE_TT
17#include "sysdep/sc.h"
18#endif
19
20#ifdef UML_CONFIG_MODE_SKAS
21#include "skas_ptregs.h"
22
23#define REGS_IP(r) ((r)[HOST_IP])
24#define REGS_SP(r) ((r)[HOST_SP])
25
26#define REGS_RBX(r) ((r)[HOST_RBX])
27#define REGS_RCX(r) ((r)[HOST_RCX])
28#define REGS_RDX(r) ((r)[HOST_RDX])
29#define REGS_RSI(r) ((r)[HOST_RSI])
30#define REGS_RDI(r) ((r)[HOST_RDI])
31#define REGS_RBP(r) ((r)[HOST_RBP])
32#define REGS_RAX(r) ((r)[HOST_RAX])
33#define REGS_R8(r) ((r)[HOST_R8])
34#define REGS_R9(r) ((r)[HOST_R9])
35#define REGS_R10(r) ((r)[HOST_R10])
36#define REGS_R11(r) ((r)[HOST_R11])
37#define REGS_R12(r) ((r)[HOST_R12])
38#define REGS_R13(r) ((r)[HOST_R13])
39#define REGS_R14(r) ((r)[HOST_R14])
40#define REGS_R15(r) ((r)[HOST_R15])
41#define REGS_CS(r) ((r)[HOST_CS])
42#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
43#define REGS_SS(r) ((r)[HOST_SS])
44
45#define HOST_FS_BASE 21
46#define HOST_GS_BASE 22
47#define HOST_DS 23
48#define HOST_ES 24
49#define HOST_FS 25
50#define HOST_GS 26
51
52#define REGS_FS_BASE(r) ((r)[HOST_FS_BASE])
53#define REGS_GS_BASE(r) ((r)[HOST_GS_BASE])
54#define REGS_DS(r) ((r)[HOST_DS])
55#define REGS_ES(r) ((r)[HOST_ES])
56#define REGS_FS(r) ((r)[HOST_FS])
57#define REGS_GS(r) ((r)[HOST_GS])
58
59#define REGS_ORIG_RAX(r) ((r)[HOST_ORIG_RAX])
60
61#define REGS_SET_SYSCALL_RETURN(r, res) REGS_RAX(r) = (res)
62
63#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
64
65#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type)
66
67#define REGS_FAULT_ADDR(r) ((r)->fault_addr)
68
69#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type)
70
71#define REGS_TRAP(r) ((r)->trap_type)
72
73#define REGS_ERR(r) ((r)->fault_type)
74
75#endif
76
77#include "choose-mode.h"
78
79/* XXX */
80union uml_pt_regs {
81#ifdef UML_CONFIG_MODE_TT
82 struct tt_regs {
83 long syscall;
84 unsigned long orig_rax;
85 void *sc;
86 } tt;
87#endif
88#ifdef UML_CONFIG_MODE_SKAS
89 struct skas_regs {
90 /* XXX */
91 unsigned long regs[27];
92 unsigned long fp[65];
93 unsigned long fault_addr;
94 unsigned long fault_type;
95 unsigned long trap_type;
96 long syscall;
97 int is_user;
98 } skas;
99#endif
100};
101
102#define EMPTY_UML_PT_REGS { }
103
104/* XXX */
105extern int mode_tt;
106
107#define UPT_RBX(r) __CHOOSE_MODE(SC_RBX(UPT_SC(r)), REGS_RBX((r)->skas.regs))
108#define UPT_RCX(r) __CHOOSE_MODE(SC_RCX(UPT_SC(r)), REGS_RCX((r)->skas.regs))
109#define UPT_RDX(r) __CHOOSE_MODE(SC_RDX(UPT_SC(r)), REGS_RDX((r)->skas.regs))
110#define UPT_RSI(r) __CHOOSE_MODE(SC_RSI(UPT_SC(r)), REGS_RSI((r)->skas.regs))
111#define UPT_RDI(r) __CHOOSE_MODE(SC_RDI(UPT_SC(r)), REGS_RDI((r)->skas.regs))
112#define UPT_RBP(r) __CHOOSE_MODE(SC_RBP(UPT_SC(r)), REGS_RBP((r)->skas.regs))
113#define UPT_RAX(r) __CHOOSE_MODE(SC_RAX(UPT_SC(r)), REGS_RAX((r)->skas.regs))
114#define UPT_R8(r) __CHOOSE_MODE(SC_R8(UPT_SC(r)), REGS_R8((r)->skas.regs))
115#define UPT_R9(r) __CHOOSE_MODE(SC_R9(UPT_SC(r)), REGS_R9((r)->skas.regs))
116#define UPT_R10(r) __CHOOSE_MODE(SC_R10(UPT_SC(r)), REGS_R10((r)->skas.regs))
117#define UPT_R11(r) __CHOOSE_MODE(SC_R11(UPT_SC(r)), REGS_R11((r)->skas.regs))
118#define UPT_R12(r) __CHOOSE_MODE(SC_R12(UPT_SC(r)), REGS_R12((r)->skas.regs))
119#define UPT_R13(r) __CHOOSE_MODE(SC_R13(UPT_SC(r)), REGS_R13((r)->skas.regs))
120#define UPT_R14(r) __CHOOSE_MODE(SC_R14(UPT_SC(r)), REGS_R14((r)->skas.regs))
121#define UPT_R15(r) __CHOOSE_MODE(SC_R15(UPT_SC(r)), REGS_R15((r)->skas.regs))
122#define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
123#define UPT_FS(r) __CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
124#define UPT_GS(r) __CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
125#define UPT_DS(r) __CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
126#define UPT_ES(r) __CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
127#define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
128#define UPT_ORIG_RAX(r) \
129 __CHOOSE_MODE((r)->tt.orig_rax, REGS_ORIG_RAX((r)->skas.regs))
130
131#define UPT_IP(r) __CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
132#define UPT_SP(r) __CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs))
133
134#define UPT_EFLAGS(r) \
135 __CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs))
136#define UPT_SC(r) ((r)->tt.sc)
137#define UPT_SYSCALL_NR(r) __CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
138
139extern int user_context(unsigned long sp);
140
141#define UPT_IS_USER(r) \
142 CHOOSE_MODE(user_context(UPT_SP(r)), (r)->skas.is_user)
143
144#define UPT_SYSCALL_ARG1(r) UPT_RDI(r)
145#define UPT_SYSCALL_ARG2(r) UPT_RSI(r)
146#define UPT_SYSCALL_ARG3(r) UPT_RDX(r)
147#define UPT_SYSCALL_ARG4(r) UPT_R10(r)
148#define UPT_SYSCALL_ARG5(r) UPT_R8(r)
149#define UPT_SYSCALL_ARG6(r) UPT_R9(r)
150
151struct syscall_args {
152 unsigned long args[6];
153};
154
155#define SYSCALL_ARGS(r) ((struct syscall_args) \
156 { .args = { UPT_SYSCALL_ARG1(r), \
157 UPT_SYSCALL_ARG2(r), \
158 UPT_SYSCALL_ARG3(r), \
159 UPT_SYSCALL_ARG4(r), \
160 UPT_SYSCALL_ARG5(r), \
161 UPT_SYSCALL_ARG6(r) } } )
162
163#define UPT_REG(regs, reg) \
164 ({ unsigned long val; \
165 switch(reg){ \
166 case R8: val = UPT_R8(regs); break; \
167 case R9: val = UPT_R9(regs); break; \
168 case R10: val = UPT_R10(regs); break; \
169 case R11: val = UPT_R11(regs); break; \
170 case R12: val = UPT_R12(regs); break; \
171 case R13: val = UPT_R13(regs); break; \
172 case R14: val = UPT_R14(regs); break; \
173 case R15: val = UPT_R15(regs); break; \
174 case RIP: val = UPT_IP(regs); break; \
175 case RSP: val = UPT_SP(regs); break; \
176 case RAX: val = UPT_RAX(regs); break; \
177 case RBX: val = UPT_RBX(regs); break; \
178 case RCX: val = UPT_RCX(regs); break; \
179 case RDX: val = UPT_RDX(regs); break; \
180 case RSI: val = UPT_RSI(regs); break; \
181 case RDI: val = UPT_RDI(regs); break; \
182 case RBP: val = UPT_RBP(regs); break; \
183 case ORIG_RAX: val = UPT_ORIG_RAX(regs); break; \
184 case CS: val = UPT_CS(regs); break; \
185 case DS: val = UPT_DS(regs); break; \
186 case ES: val = UPT_ES(regs); break; \
187 case FS: val = UPT_FS(regs); break; \
188 case GS: val = UPT_GS(regs); break; \
189 case EFLAGS: val = UPT_EFLAGS(regs); break; \
190 default : \
191 panic("Bad register in UPT_REG : %d\n", reg); \
192 val = -1; \
193 } \
194 val; \
195 })
196
197
198#define UPT_SET(regs, reg, val) \
199 ({ unsigned long val; \
200 switch(reg){ \
201 case R8: UPT_R8(regs) = val; break; \
202 case R9: UPT_R9(regs) = val; break; \
203 case R10: UPT_R10(regs) = val; break; \
204 case R11: UPT_R11(regs) = val; break; \
205 case R12: UPT_R12(regs) = val; break; \
206 case R13: UPT_R13(regs) = val; break; \
207 case R14: UPT_R14(regs) = val; break; \
208 case R15: UPT_R15(regs) = val; break; \
209 case RIP: UPT_IP(regs) = val; break; \
210 case RSP: UPT_SP(regs) = val; break; \
211 case RAX: UPT_RAX(regs) = val; break; \
212 case RBX: UPT_RBX(regs) = val; break; \
213 case RCX: UPT_RCX(regs) = val; break; \
214 case RDX: UPT_RDX(regs) = val; break; \
215 case RSI: UPT_RSI(regs) = val; break; \
216 case RDI: UPT_RDI(regs) = val; break; \
217 case RBP: UPT_RBP(regs) = val; break; \
218 case ORIG_RAX: UPT_ORIG_RAX(regs) = val; break; \
219 case CS: UPT_CS(regs) = val; break; \
220 case DS: UPT_DS(regs) = val; break; \
221 case ES: UPT_ES(regs) = val; break; \
222 case FS: UPT_FS(regs) = val; break; \
223 case GS: UPT_GS(regs) = val; break; \
224 case EFLAGS: UPT_EFLAGS(regs) = val; break; \
225 default : \
226 panic("Bad register in UPT_SET : %d\n", reg); \
227 break; \
228 } \
229 val; \
230 })
231
232#define UPT_SET_SYSCALL_RETURN(r, res) \
233 CHOOSE_MODE(SC_SET_SYSCALL_RETURN(UPT_SC(r), (res)), \
234 REGS_SET_SYSCALL_RETURN((r)->skas.regs, (res)))
235
236#define UPT_RESTART_SYSCALL(r) \
237 CHOOSE_MODE(SC_RESTART_SYSCALL(UPT_SC(r)), \
238 REGS_RESTART_SYSCALL((r)->skas.regs))
239
240#define UPT_SEGV_IS_FIXABLE(r) \
241 CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \
242 REGS_SEGV_IS_FIXABLE(&r->skas))
243
244#define UPT_FAULT_ADDR(r) \
245 __CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas))
246
247#define UPT_FAULT_WRITE(r) \
248 CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas))
249
250#define UPT_TRAP(r) __CHOOSE_MODE(SC_TRAP_TYPE(UPT_SC(r)), REGS_TRAP(&r->skas))
251#define UPT_ERR(r) __CHOOSE_MODE(SC_FAULT_TYPE(UPT_SC(r)), REGS_ERR(&r->skas))
252
253#endif
254
255/*
256 * Overrides for Emacs so that we follow Linus's tabbing style.
257 * Emacs will notice this stuff at the end of the file and automatically
258 * adjust the settings for this buffer only. This must remain at the end
259 * of the file.
260 * ---------------------------------------------------------------------------
261 * Local variables:
262 * c-file-style: "linux"
263 * End:
264 */
diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h
new file mode 100644
index 000000000000..31729973fb14
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/ptrace_user.h
@@ -0,0 +1,69 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#ifndef __SYSDEP_X86_64_PTRACE_USER_H__
8#define __SYSDEP_X86_64_PTRACE_USER_H__
9
10#define __FRAME_OFFSETS
11#include <sys/ptrace.h>
12#include <linux/ptrace.h>
13#include <asm/ptrace.h>
14#undef __FRAME_OFFSETS
15
16#define PT_INDEX(off) ((off) / sizeof(unsigned long))
17
18#define PT_SYSCALL_NR(regs) ((regs)[PT_INDEX(ORIG_RAX)])
19#define PT_SYSCALL_NR_OFFSET (ORIG_RAX)
20
21#define PT_SYSCALL_ARG1(regs) (((unsigned long *) (regs))[PT_INDEX(RDI)])
22#define PT_SYSCALL_ARG1_OFFSET (RDI)
23
24#define PT_SYSCALL_ARG2(regs) (((unsigned long *) (regs))[PT_INDEX(RSI)])
25#define PT_SYSCALL_ARG2_OFFSET (RSI)
26
27#define PT_SYSCALL_ARG3(regs) (((unsigned long *) (regs))[PT_INDEX(RDX)])
28#define PT_SYSCALL_ARG3_OFFSET (RDX)
29
30#define PT_SYSCALL_ARG4(regs) (((unsigned long *) (regs))[PT_INDEX(RCX)])
31#define PT_SYSCALL_ARG4_OFFSET (RCX)
32
33#define PT_SYSCALL_ARG5(regs) (((unsigned long *) (regs))[PT_INDEX(R8)])
34#define PT_SYSCALL_ARG5_OFFSET (R8)
35
36#define PT_SYSCALL_ARG6(regs) (((unsigned long *) (regs))[PT_INDEX(R9)])
37#define PT_SYSCALL_ARG6_OFFSET (R9)
38
39#define PT_SYSCALL_RET_OFFSET (RAX)
40
41#define PT_IP_OFFSET (RIP)
42#define PT_IP(regs) ((regs)[PT_INDEX(RIP)])
43
44#define PT_SP_OFFSET (RSP)
45#define PT_SP(regs) ((regs)[PT_INDEX(RSP)])
46
47#define PT_ORIG_RAX_OFFSET (ORIG_RAX)
48#define PT_ORIG_RAX(regs) ((regs)[PT_INDEX(ORIG_RAX)])
49
50/* x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though
51 * it's defined in the kernel's include/linux/ptrace.h. Additionally, use the
52 * 2.4 name and value for 2.4 host compatibility.
53 */
54#ifndef PTRACE_OLDSETOPTIONS
55#define PTRACE_OLDSETOPTIONS 21
56#endif
57
58#endif
59
60/*
61 * Overrides for Emacs so that we follow Linus's tabbing style.
62 * Emacs will notice this stuff at the end of the file and automatically
63 * adjust the settings for this buffer only. This must remain at the end
64 * of the file.
65 * ---------------------------------------------------------------------------
66 * Local variables:
67 * c-file-style: "linux"
68 * End:
69 */
diff --git a/arch/um/include/sysdep-x86_64/sigcontext.h b/arch/um/include/sysdep-x86_64/sigcontext.h
new file mode 100644
index 000000000000..1e38a54ff4cf
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/sigcontext.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#ifndef __SYSDEP_X86_64_SIGCONTEXT_H
8#define __SYSDEP_X86_64_SIGCONTEXT_H
9
10#include <sysdep/sc.h>
11
12#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
13
14#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc))
15#define SC_SET_SYSCALL_RETURN(sc, result) SC_RAX(sc) = (result)
16
17#define SC_FAULT_ADDR(sc) SC_CR2(sc)
18#define SC_FAULT_TYPE(sc) SC_ERR(sc)
19
20#define FAULT_WRITE(err) ((err) & 2)
21
22#define SC_FAULT_WRITE(sc) FAULT_WRITE(SC_FAULT_TYPE(sc))
23
24#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc)
25
26/* ptrace expects that, at the start of a system call, %eax contains
27 * -ENOSYS, so this makes it so.
28 */
29
30#define SC_START_SYSCALL(sc) do SC_RAX(sc) = -ENOSYS; while(0)
31
32#define SEGV_IS_FIXABLE(trap) ((trap) == 14)
33#define SC_SEGV_IS_FIXABLE(sc) SEGV_IS_FIXABLE(SC_TRAP_TYPE(sc))
34
35extern unsigned long *sc_sigmask(void *sc_ptr);
36
37#endif
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 */
49
diff --git a/arch/um/include/sysdep-x86_64/signal.h b/arch/um/include/sysdep-x86_64/signal.h
new file mode 100644
index 000000000000..e5e52756fab4
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/signal.h
@@ -0,0 +1,27 @@
1/*
2 * Copyright (C) 2004 PathScale, Inc
3 * Licensed under the GPL
4 */
5
6#ifndef __X86_64_SIGNAL_H_
7#define __X86_64_SIGNAL_H_
8
9#define ARCH_GET_SIGCONTEXT(sc, sig_addr) \
10 do { \
11 struct ucontext *__uc; \
12 asm("movq %%rdx, %0" : "=r" (__uc)); \
13 sc = (struct sigcontext *) &__uc->uc_mcontext; \
14 } while(0)
15
16#endif
17
18/*
19 * Overrides for Emacs so that we follow Linus's tabbing style.
20 * Emacs will notice this stuff at the end of the file and automatically
21 * adjust the settings for this buffer only. This must remain at the end
22 * of the file.
23 * ---------------------------------------------------------------------------
24 * Local variables:
25 * c-file-style: "linux"
26 * End:
27 */
diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h
new file mode 100644
index 000000000000..b187a4157ff3
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/syscalls.h
@@ -0,0 +1,91 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#ifndef __SYSDEP_X86_64_SYSCALLS_H__
8#define __SYSDEP_X86_64_SYSCALLS_H__
9
10#include <linux/msg.h>
11#include <linux/shm.h>
12
13typedef long syscall_handler_t(void);
14
15extern syscall_handler_t *ia32_sys_call_table[];
16
17#define EXECUTE_SYSCALL(syscall, regs) \
18 (((long (*)(long, long, long, long, long, long)) \
19 (*sys_call_table[syscall]))(UPT_SYSCALL_ARG1(&regs->regs), \
20 UPT_SYSCALL_ARG2(&regs->regs), \
21 UPT_SYSCALL_ARG3(&regs->regs), \
22 UPT_SYSCALL_ARG4(&regs->regs), \
23 UPT_SYSCALL_ARG5(&regs->regs), \
24 UPT_SYSCALL_ARG6(&regs->regs)))
25
26extern long old_mmap(unsigned long addr, unsigned long len,
27 unsigned long prot, unsigned long flags,
28 unsigned long fd, unsigned long pgoff);
29extern syscall_handler_t wrap_sys_shmat;
30extern syscall_handler_t sys_modify_ldt;
31extern syscall_handler_t sys_arch_prctl;
32
33#define ARCH_SYSCALLS \
34 [ __NR_mmap ] = (syscall_handler_t *) old_mmap, \
35 [ __NR_select ] = (syscall_handler_t *) sys_select, \
36 [ __NR_mincore ] = (syscall_handler_t *) sys_mincore, \
37 [ __NR_madvise ] = (syscall_handler_t *) sys_madvise, \
38 [ __NR_shmget ] = (syscall_handler_t *) sys_shmget, \
39 [ __NR_shmat ] = (syscall_handler_t *) wrap_sys_shmat, \
40 [ __NR_shmctl ] = (syscall_handler_t *) sys_shmctl, \
41 [ __NR_semop ] = (syscall_handler_t *) sys_semop, \
42 [ __NR_semget ] = (syscall_handler_t *) sys_semget, \
43 [ __NR_semctl ] = (syscall_handler_t *) sys_semctl, \
44 [ __NR_shmdt ] = (syscall_handler_t *) sys_shmdt, \
45 [ __NR_msgget ] = (syscall_handler_t *) sys_msgget, \
46 [ __NR_msgsnd ] = (syscall_handler_t *) sys_msgsnd, \
47 [ __NR_msgrcv ] = (syscall_handler_t *) sys_msgrcv, \
48 [ __NR_msgctl ] = (syscall_handler_t *) sys_msgctl, \
49 [ __NR_pivot_root ] = (syscall_handler_t *) sys_pivot_root, \
50 [ __NR_tuxcall ] = (syscall_handler_t *) sys_ni_syscall, \
51 [ __NR_security ] = (syscall_handler_t *) sys_ni_syscall, \
52 [ __NR_epoll_ctl_old ] = (syscall_handler_t *) sys_ni_syscall, \
53 [ __NR_epoll_wait_old ] = (syscall_handler_t *) sys_ni_syscall, \
54 [ __NR_modify_ldt ] = (syscall_handler_t *) sys_modify_ldt, \
55 [ __NR_arch_prctl ] = (syscall_handler_t *) sys_arch_prctl, \
56 [ __NR_socket ] = (syscall_handler_t *) sys_socket, \
57 [ __NR_connect ] = (syscall_handler_t *) sys_connect, \
58 [ __NR_accept ] = (syscall_handler_t *) sys_accept, \
59 [ __NR_recvfrom ] = (syscall_handler_t *) sys_recvfrom, \
60 [ __NR_recvmsg ] = (syscall_handler_t *) sys_recvmsg, \
61 [ __NR_sendmsg ] = (syscall_handler_t *) sys_sendmsg, \
62 [ __NR_bind ] = (syscall_handler_t *) sys_bind, \
63 [ __NR_listen ] = (syscall_handler_t *) sys_listen, \
64 [ __NR_getsockname ] = (syscall_handler_t *) sys_getsockname, \
65 [ __NR_getpeername ] = (syscall_handler_t *) sys_getpeername, \
66 [ __NR_socketpair ] = (syscall_handler_t *) sys_socketpair, \
67 [ __NR_sendto ] = (syscall_handler_t *) sys_sendto, \
68 [ __NR_shutdown ] = (syscall_handler_t *) sys_shutdown, \
69 [ __NR_setsockopt ] = (syscall_handler_t *) sys_setsockopt, \
70 [ __NR_getsockopt ] = (syscall_handler_t *) sys_getsockopt, \
71 [ __NR_iopl ] = (syscall_handler_t *) sys_ni_syscall, \
72 [ __NR_set_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \
73 [ __NR_get_thread_area ] = (syscall_handler_t *) sys_ni_syscall, \
74 [ __NR_semtimedop ] = (syscall_handler_t *) sys_semtimedop, \
75 [ 251 ] = (syscall_handler_t *) sys_ni_syscall,
76
77#define LAST_ARCH_SYSCALL 251
78#define NR_syscalls 1024
79
80#endif
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/include/sysrq.h b/arch/um/include/sysrq.h
new file mode 100644
index 000000000000..2ce9423460b3
--- /dev/null
+++ b/arch/um/include/sysrq.h
@@ -0,0 +1,6 @@
1#ifndef __UM_SYSRQ_H
2#define __UM_SYSRQ_H
3
4extern void show_trace(unsigned long *stack);
5
6#endif
diff --git a/arch/um/include/tempfile.h b/arch/um/include/tempfile.h
new file mode 100644
index 000000000000..e36d9e0f5105
--- /dev/null
+++ b/arch/um/include/tempfile.h
@@ -0,0 +1,21 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TEMPFILE_H__
7#define __TEMPFILE_H__
8
9extern int make_tempfile(const char *template, char **tempname, int do_unlink);
10
11#endif
12/*
13 * Overrides for Emacs so that we follow Linus's tabbing style.
14 * Emacs will notice this stuff at the end of the file and automatically
15 * adjust the settings for this buffer only. This must remain at the end
16 * of the file.
17 * ---------------------------------------------------------------------------
18 * Local variables:
19 * c-file-style: "linux"
20 * End:
21 */
diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h
new file mode 100644
index 000000000000..6793a2fcd0ae
--- /dev/null
+++ b/arch/um/include/time_user.h
@@ -0,0 +1,18 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TIME_USER_H__
7#define __TIME_USER_H__
8
9extern void timer(void);
10extern void switch_timers(int to_real);
11extern void set_interval(int timer_type);
12extern void idle_sleep(int secs);
13extern void enable_timer(void);
14extern void disable_timer(void);
15extern unsigned long time_lock(void);
16extern void time_unlock(unsigned long);
17
18#endif
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h
new file mode 100644
index 000000000000..da1097285b8c
--- /dev/null
+++ b/arch/um/include/tlb.h
@@ -0,0 +1,67 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __TLB_H__
7#define __TLB_H__
8
9#include "um_mmu.h"
10
11struct host_vm_op {
12 enum { MMAP, MUNMAP, MPROTECT } type;
13 union {
14 struct {
15 unsigned long addr;
16 unsigned long len;
17 unsigned int r:1;
18 unsigned int w:1;
19 unsigned int x:1;
20 int fd;
21 __u64 offset;
22 } mmap;
23 struct {
24 unsigned long addr;
25 unsigned long len;
26 } munmap;
27 struct {
28 unsigned long addr;
29 unsigned long len;
30 unsigned int r:1;
31 unsigned int w:1;
32 unsigned int x:1;
33 } mprotect;
34 } u;
35};
36
37extern void mprotect_kernel_vm(int w);
38extern void force_flush_all(void);
39extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
40 unsigned long end_addr, int force, int data,
41 void (*do_ops)(int, struct host_vm_op *, int));
42extern int flush_tlb_kernel_range_common(unsigned long start,
43 unsigned long end);
44
45extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
46 int r, int w, int x, struct host_vm_op *ops, int index,
47 int last_filled, int data,
48 void (*do_ops)(int, struct host_vm_op *, int));
49extern int add_munmap(unsigned long addr, unsigned long len,
50 struct host_vm_op *ops, int index, int last_filled,
51 int data, void (*do_ops)(int, struct host_vm_op *, int));
52extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
53 int x, struct host_vm_op *ops, int index,
54 int last_filled, int data,
55 void (*do_ops)(int, struct host_vm_op *, int));
56#endif
57
58/*
59 * Overrides for Emacs so that we follow Linus's tabbing style.
60 * Emacs will notice this stuff at the end of the file and automatically
61 * adjust the settings for this buffer only. This must remain at the end
62 * of the file.
63 * ---------------------------------------------------------------------------
64 * Local variables:
65 * c-file-style: "linux"
66 * End:
67 */
diff --git a/arch/um/include/ubd_user.h b/arch/um/include/ubd_user.h
new file mode 100644
index 000000000000..bb66517f0739
--- /dev/null
+++ b/arch/um/include/ubd_user.h
@@ -0,0 +1,26 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com)
4 * Licensed under the GPL
5 */
6
7#ifndef __UM_UBD_USER_H
8#define __UM_UBD_USER_H
9
10extern void ignore_sigwinch_sig(void);
11extern int start_io_thread(unsigned long sp, int *fds_out);
12extern int io_thread(void *arg);
13extern int kernel_fd;
14
15#endif
16
17/*
18 * Overrides for Emacs so that we follow Linus's tabbing style.
19 * Emacs will notice this stuff at the end of the file and automatically
20 * adjust the settings for this buffer only. This must remain at the end
21 * of the file.
22 * ---------------------------------------------------------------------------
23 * Local variables:
24 * c-file-style: "linux"
25 * End:
26 */
diff --git a/arch/um/include/um_mmu.h b/arch/um/include/um_mmu.h
new file mode 100644
index 000000000000..0fa643238300
--- /dev/null
+++ b/arch/um/include/um_mmu.h
@@ -0,0 +1,40 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __ARCH_UM_MMU_H
7#define __ARCH_UM_MMU_H
8
9#include "uml-config.h"
10#include "choose-mode.h"
11
12#ifdef UML_CONFIG_MODE_TT
13#include "mmu-tt.h"
14#endif
15
16#ifdef UML_CONFIG_MODE_SKAS
17#include "mmu-skas.h"
18#endif
19
20typedef union mm_context {
21#ifdef UML_CONFIG_MODE_TT
22 struct mmu_context_tt tt;
23#endif
24#ifdef UML_CONFIG_MODE_SKAS
25 struct mmu_context_skas skas;
26#endif
27} mm_context_t;
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/include/um_uaccess.h b/arch/um/include/um_uaccess.h
new file mode 100644
index 000000000000..6e348cb6de24
--- /dev/null
+++ b/arch/um/include/um_uaccess.h
@@ -0,0 +1,125 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __ARCH_UM_UACCESS_H
7#define __ARCH_UM_UACCESS_H
8
9#include "linux/config.h"
10#include "choose-mode.h"
11
12#ifdef CONFIG_MODE_TT
13#include "uaccess-tt.h"
14#endif
15
16#ifdef CONFIG_MODE_SKAS
17#include "uaccess-skas.h"
18#endif
19
20#define access_ok(type, addr, size) \
21 CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
22
23/* this function will go away soon - use access_ok() instead */
24static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size)
25{
26 return (CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr,
27 size));
28}
29
30static inline int copy_from_user(void *to, const void __user *from, int n)
31{
32 return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to,
33 from, n));
34}
35
36static inline int copy_to_user(void __user *to, const void *from, int n)
37{
38 return(CHOOSE_MODE_PROC(copy_to_user_tt, copy_to_user_skas, to,
39 from, n));
40}
41
42/*
43 * strncpy_from_user: - Copy a NUL terminated string from userspace.
44 * @dst: Destination address, in kernel space. This buffer must be at
45 * least @count bytes long.
46 * @src: Source address, in user space.
47 * @count: Maximum number of bytes to copy, including the trailing NUL.
48 *
49 * Copies a NUL-terminated string from userspace to kernel space.
50 *
51 * On success, returns the length of the string (not including the trailing
52 * NUL).
53 *
54 * If access to userspace fails, returns -EFAULT (some data may have been
55 * copied).
56 *
57 * If @count is smaller than the length of the string, copies @count bytes
58 * and returns @count.
59 */
60
61static inline int strncpy_from_user(char *dst, const char __user *src, int count)
62{
63 return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas,
64 dst, src, count));
65}
66
67/*
68 * __clear_user: - Zero a block of memory in user space, with less checking.
69 * @to: Destination address, in user space.
70 * @n: Number of bytes to zero.
71 *
72 * Zero a block of memory in user space. Caller must check
73 * the specified block with access_ok() before calling this function.
74 *
75 * Returns number of bytes that could not be cleared.
76 * On success, this will be zero.
77 */
78static inline int __clear_user(void *mem, int len)
79{
80 return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len));
81}
82
83/*
84 * clear_user: - Zero a block of memory in user space.
85 * @to: Destination address, in user space.
86 * @n: Number of bytes to zero.
87 *
88 * Zero a block of memory in user space.
89 *
90 * Returns number of bytes that could not be cleared.
91 * On success, this will be zero.
92 */
93static inline int clear_user(void __user *mem, int len)
94{
95 return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len));
96}
97
98/*
99 * strlen_user: - Get the size of a string in user space.
100 * @str: The string to measure.
101 * @n: The maximum valid length
102 *
103 * Get the size of a NUL-terminated string in user space.
104 *
105 * Returns the size of the string INCLUDING the terminating NUL.
106 * On exception, returns 0.
107 * If the string is too long, returns a value greater than @n.
108 */
109static inline int strnlen_user(const void __user *str, long len)
110{
111 return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len));
112}
113
114#endif
115
116/*
117 * Overrides for Emacs so that we follow Linus's tabbing style.
118 * Emacs will notice this stuff at the end of the file and automatically
119 * adjust the settings for this buffer only. This must remain at the end
120 * of the file.
121 * ---------------------------------------------------------------------------
122 * Local variables:
123 * c-file-style: "linux"
124 * End:
125 */
diff --git a/arch/um/include/umid.h b/arch/um/include/umid.h
new file mode 100644
index 000000000000..11373c851f15
--- /dev/null
+++ b/arch/um/include/umid.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __UMID_H__
7#define __UMID_H__
8
9extern int umid_file_name(char *name, char *buf, int len);
10
11#endif
12
13/*
14 * Overrides for Emacs so that we follow Linus's tabbing style.
15 * Emacs will notice this stuff at the end of the file and automatically
16 * adjust the settings for this buffer only. This must remain at the end
17 * of the file.
18 * ---------------------------------------------------------------------------
19 * Local variables:
20 * c-file-style: "linux"
21 * End:
22 */
diff --git a/arch/um/include/uml_uaccess.h b/arch/um/include/uml_uaccess.h
new file mode 100644
index 000000000000..f77eb6428453
--- /dev/null
+++ b/arch/um/include/uml_uaccess.h
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __UML_UACCESS_H__
7#define __UML_UACCESS_H__
8
9extern int __do_copy_to_user(void *to, const void *from, int n,
10 void **fault_addr, void **fault_catcher);
11extern unsigned long __do_user_copy(void *to, const void *from, int n,
12 void **fault_addr, void **fault_catcher,
13 void (*op)(void *to, const void *from,
14 int n), int *faulted_out);
15void __do_copy(void *to, const void *from, int n);
16
17#endif
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/include/user.h b/arch/um/include/user.h
new file mode 100644
index 000000000000..57ee9e261228
--- /dev/null
+++ b/arch/um/include/user.h
@@ -0,0 +1,32 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __USER_H__
7#define __USER_H__
8
9extern void panic(const char *fmt, ...);
10extern int printk(const char *fmt, ...);
11extern void schedule(void);
12extern void *um_kmalloc(int size);
13extern void *um_kmalloc_atomic(int size);
14extern void kfree(void *ptr);
15extern int in_aton(char *str);
16extern int open_gdb_chan(void);
17extern int strlcpy(char *, const char *, int);
18extern void *um_vmalloc(int size);
19extern void vfree(void *ptr);
20
21#endif
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/include/user_util.h b/arch/um/include/user_util.h
new file mode 100644
index 000000000000..103cd320386c
--- /dev/null
+++ b/arch/um/include/user_util.h
@@ -0,0 +1,106 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __USER_UTIL_H__
7#define __USER_UTIL_H__
8
9#include "sysdep/ptrace.h"
10
11#define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
12
13extern int mode_tt;
14
15extern int grantpt(int __fd);
16extern int unlockpt(int __fd);
17extern char *ptsname(int __fd);
18
19struct cpu_task {
20 int pid;
21 void *task;
22};
23
24extern struct cpu_task cpu_tasks[];
25
26struct signal_info {
27 void (*handler)(int, union uml_pt_regs *);
28 int is_irq;
29};
30
31extern struct signal_info sig_info[];
32
33extern unsigned long low_physmem;
34extern unsigned long high_physmem;
35extern unsigned long uml_physmem;
36extern unsigned long uml_reserved;
37extern unsigned long end_vm;
38extern unsigned long start_vm;
39extern unsigned long highmem;
40
41extern char host_info[];
42
43extern char saved_command_line[];
44extern char command_line[];
45
46extern char *tempdir;
47
48extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
49extern unsigned long _unprotected_end;
50extern unsigned long brk_start;
51
52extern int pty_output_sigio;
53extern int pty_close_sigio;
54
55extern void stop(void);
56extern void stack_protections(unsigned long address);
57extern void task_protections(unsigned long address);
58extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
59extern void *add_signal_handler(int sig, void (*handler)(int));
60extern int start_fork_tramp(void *arg, unsigned long temp_stack,
61 int clone_flags, int (*tramp)(void *));
62extern int linux_main(int argc, char **argv);
63extern void set_cmdline(char *cmd);
64extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
65extern int get_pty(void);
66extern void *um_kmalloc(int size);
67extern int switcheroo(int fd, int prot, void *from, void *to, int size);
68extern void setup_machinename(char *machine_out);
69extern void setup_hostinfo(void);
70extern void add_arg(char *arg);
71extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
72extern void init_new_thread_signals(int altstack);
73extern void do_exec(int old_pid, int new_pid);
74extern void tracer_panic(char *msg, ...);
75extern char *get_umid(int only_if_set);
76extern void do_longjmp(void *p, int val);
77extern int detach(int pid, int sig);
78extern int attach(int pid);
79extern void kill_child_dead(int pid);
80extern int cont(int pid);
81extern void check_ptrace(void);
82extern void check_sigio(void);
83extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
84extern void write_sigio_workaround(void);
85extern void arch_check_bugs(void);
86extern int cpu_feature(char *what, char *buf, int len);
87extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
88extern int arch_fixup(unsigned long address, void *sc_ptr);
89extern void forward_pending_sigio(int target);
90extern int can_do_skas(void);
91extern void arch_init_thread(void);
92extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
93extern int raw(int fd);
94
95#endif
96
97/*
98 * Overrides for Emacs so that we follow Linus's tabbing style.
99 * Emacs will notice this stuff at the end of the file and automatically
100 * adjust the settings for this buffer only. This must remain at the end
101 * of the file.
102 * ---------------------------------------------------------------------------
103 * Local variables:
104 * c-file-style: "linux"
105 * End:
106 */
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 */
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
new file mode 100644
index 000000000000..4ddf540284ce
--- /dev/null
+++ b/arch/um/os-Linux/Makefile
@@ -0,0 +1,13 @@
1#
2# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6obj-y = elf_aux.o file.o process.o signal.o time.o tty.o user_syms.o drivers/ \
7 sys-$(SUBARCH)/
8
9USER_OBJS := elf_aux.o file.o process.o signal.o time.o tty.o
10
11CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
12
13include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/drivers/Makefile b/arch/um/os-Linux/drivers/Makefile
new file mode 100644
index 000000000000..6c546dc9222b
--- /dev/null
+++ b/arch/um/os-Linux/drivers/Makefile
@@ -0,0 +1,13 @@
1#
2# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6ethertap-objs := ethertap_kern.o ethertap_user.o
7tuntap-objs := tuntap_kern.o tuntap_user.o
8
9obj-y =
10obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o
11obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o
12
13include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h
new file mode 100644
index 000000000000..b84f6c4740f7
--- /dev/null
+++ b/arch/um/os-Linux/drivers/etap.h
@@ -0,0 +1,27 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "net_user.h"
7
8struct ethertap_data {
9 char *dev_name;
10 char *gate_addr;
11 int data_fd;
12 int control_fd;
13 void *dev;
14};
15
16extern struct net_user_info ethertap_user_info;
17
18/*
19 * Overrides for Emacs so that we follow Linus's tabbing style.
20 * Emacs will notice this stuff at the end of the file and automatically
21 * adjust the settings for this buffer only. This must remain at the end
22 * of the file.
23 * ---------------------------------------------------------------------------
24 * Local variables:
25 * c-file-style: "linux"
26 * End:
27 */
diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
new file mode 100644
index 000000000000..6ae4b19d9f50
--- /dev/null
+++ b/arch/um/os-Linux/drivers/ethertap_kern.c
@@ -0,0 +1,119 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
3 * James Leu (jleu@mindspring.net).
4 * Copyright (C) 2001 by various other people who didn't put their name here.
5 * Licensed under the GPL.
6 */
7
8#include "linux/init.h"
9#include "linux/netdevice.h"
10#include "linux/etherdevice.h"
11#include "net_kern.h"
12#include "net_user.h"
13#include "etap.h"
14
15struct ethertap_init {
16 char *dev_name;
17 char *gate_addr;
18};
19
20static void etap_init(struct net_device *dev, void *data)
21{
22 struct uml_net_private *pri;
23 struct ethertap_data *epri;
24 struct ethertap_init *init = data;
25
26 pri = dev->priv;
27 epri = (struct ethertap_data *) pri->user;
28 epri->dev_name = init->dev_name;
29 epri->gate_addr = init->gate_addr;
30 epri->data_fd = -1;
31 epri->control_fd = -1;
32 epri->dev = dev;
33
34 printk("ethertap backend - %s", epri->dev_name);
35 if (epri->gate_addr != NULL)
36 printk(", IP = %s", epri->gate_addr);
37 printk("\n");
38}
39
40static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
41{
42 int len;
43
44 *skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP);
45 if(*skb == NULL) return(-ENOMEM);
46 len = net_recvfrom(fd, (*skb)->mac.raw,
47 (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP);
48 if(len <= 0) return(len);
49 skb_pull(*skb, 2);
50 len -= 2;
51 return(len);
52}
53
54static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
55{
56 if(skb_headroom(*skb) < 2){
57 struct sk_buff *skb2;
58
59 skb2 = skb_realloc_headroom(*skb, 2);
60 dev_kfree_skb(*skb);
61 if (skb2 == NULL) return(-ENOMEM);
62 *skb = skb2;
63 }
64 skb_push(*skb, 2);
65 return(net_send(fd, (*skb)->data, (*skb)->len));
66}
67
68struct net_kern_info ethertap_kern_info = {
69 .init = etap_init,
70 .protocol = eth_protocol,
71 .read = etap_read,
72 .write = etap_write,
73};
74
75int ethertap_setup(char *str, char **mac_out, void *data)
76{
77 struct ethertap_init *init = data;
78
79 *init = ((struct ethertap_init)
80 { .dev_name = NULL,
81 .gate_addr = NULL });
82 if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out,
83 &init->gate_addr))
84 return(0);
85 if(init->dev_name == NULL){
86 printk("ethertap_setup : Missing tap device name\n");
87 return(0);
88 }
89
90 return(1);
91}
92
93static struct transport ethertap_transport = {
94 .list = LIST_HEAD_INIT(ethertap_transport.list),
95 .name = "ethertap",
96 .setup = ethertap_setup,
97 .user = &ethertap_user_info,
98 .kern = &ethertap_kern_info,
99 .private_size = sizeof(struct ethertap_data),
100};
101
102static int register_ethertap(void)
103{
104 register_transport(&ethertap_transport);
105 return(1);
106}
107
108__initcall(register_ethertap);
109
110/*
111 * Overrides for Emacs so that we follow Linus's tabbing style.
112 * Emacs will notice this stuff at the end of the file and automatically
113 * adjust the settings for this buffer only. This must remain at the end
114 * of the file.
115 * ---------------------------------------------------------------------------
116 * Local variables:
117 * c-file-style: "linux"
118 * End:
119 */
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
new file mode 100644
index 000000000000..cd4d6544da71
--- /dev/null
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -0,0 +1,240 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
3 * James Leu (jleu@mindspring.net).
4 * Copyright (C) 2001 by various other people who didn't put their name here.
5 * Licensed under the GPL.
6 */
7
8#include <stdio.h>
9#include <unistd.h>
10#include <stddef.h>
11#include <stdlib.h>
12#include <sys/errno.h>
13#include <sys/socket.h>
14#include <sys/wait.h>
15#include <sys/un.h>
16#include <net/if.h>
17#include "user.h"
18#include "kern_util.h"
19#include "user_util.h"
20#include "net_user.h"
21#include "etap.h"
22#include "helper.h"
23#include "os.h"
24
25#define MAX_PACKET ETH_MAX_PACKET
26
27void etap_user_init(void *data, void *dev)
28{
29 struct ethertap_data *pri = data;
30
31 pri->dev = dev;
32}
33
34struct addr_change {
35 enum { ADD_ADDR, DEL_ADDR } what;
36 unsigned char addr[4];
37 unsigned char netmask[4];
38};
39
40static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
41 int fd)
42{
43 struct addr_change change;
44 void *output;
45 int n;
46
47 change.what = op;
48 memcpy(change.addr, addr, sizeof(change.addr));
49 memcpy(change.netmask, netmask, sizeof(change.netmask));
50 n = os_write_file(fd, &change, sizeof(change));
51 if(n != sizeof(change))
52 printk("etap_change - request failed, err = %d\n", -n);
53 output = um_kmalloc(page_size());
54 if(output == NULL)
55 printk("etap_change : Failed to allocate output buffer\n");
56 read_output(fd, output, page_size());
57 if(output != NULL){
58 printk("%s", output);
59 kfree(output);
60 }
61}
62
63static void etap_open_addr(unsigned char *addr, unsigned char *netmask,
64 void *arg)
65{
66 etap_change(ADD_ADDR, addr, netmask, *((int *) arg));
67}
68
69static void etap_close_addr(unsigned char *addr, unsigned char *netmask,
70 void *arg)
71{
72 etap_change(DEL_ADDR, addr, netmask, *((int *) arg));
73}
74
75struct etap_pre_exec_data {
76 int control_remote;
77 int control_me;
78 int data_me;
79};
80
81static void etap_pre_exec(void *arg)
82{
83 struct etap_pre_exec_data *data = arg;
84
85 dup2(data->control_remote, 1);
86 os_close_file(data->data_me);
87 os_close_file(data->control_me);
88}
89
90static int etap_tramp(char *dev, char *gate, int control_me,
91 int control_remote, int data_me, int data_remote)
92{
93 struct etap_pre_exec_data pe_data;
94 int pid, status, err, n;
95 char version_buf[sizeof("nnnnn\0")];
96 char data_fd_buf[sizeof("nnnnnn\0")];
97 char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
98 char *setup_args[] = { "uml_net", version_buf, "ethertap", dev,
99 data_fd_buf, gate_buf, NULL };
100 char *nosetup_args[] = { "uml_net", version_buf, "ethertap",
101 dev, data_fd_buf, NULL };
102 char **args, c;
103
104 sprintf(data_fd_buf, "%d", data_remote);
105 sprintf(version_buf, "%d", UML_NET_VERSION);
106 if(gate != NULL){
107 strcpy(gate_buf, gate);
108 args = setup_args;
109 }
110 else args = nosetup_args;
111
112 err = 0;
113 pe_data.control_remote = control_remote;
114 pe_data.control_me = control_me;
115 pe_data.data_me = data_me;
116 pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
117
118 if(pid < 0) err = pid;
119 os_close_file(data_remote);
120 os_close_file(control_remote);
121 n = os_read_file(control_me, &c, sizeof(c));
122 if(n != sizeof(c)){
123 printk("etap_tramp : read of status failed, err = %d\n", -n);
124 return(-EINVAL);
125 }
126 if(c != 1){
127 printk("etap_tramp : uml_net failed\n");
128 err = -EINVAL;
129 CATCH_EINTR(n = waitpid(pid, &status, 0));
130 if(n < 0)
131 err = -errno;
132 else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
133 printk("uml_net didn't exit with status 1\n");
134 }
135 return(err);
136}
137
138static int etap_open(void *data)
139{
140 struct ethertap_data *pri = data;
141 char *output;
142 int data_fds[2], control_fds[2], err, output_len;
143
144 err = tap_open_common(pri->dev, pri->gate_addr);
145 if(err) return(err);
146
147 err = os_pipe(data_fds, 0, 0);
148 if(err < 0){
149 printk("data os_pipe failed - err = %d\n", -err);
150 return(err);
151 }
152
153 err = os_pipe(control_fds, 1, 0);
154 if(err < 0){
155 printk("control os_pipe failed - err = %d\n", -err);
156 return(err);
157 }
158
159 err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0],
160 control_fds[1], data_fds[0], data_fds[1]);
161 output_len = page_size();
162 output = um_kmalloc(output_len);
163 read_output(control_fds[0], output, output_len);
164
165 if(output == NULL)
166 printk("etap_open : failed to allocate output buffer\n");
167 else {
168 printk("%s", output);
169 kfree(output);
170 }
171
172 if(err < 0){
173 printk("etap_tramp failed - err = %d\n", -err);
174 return(err);
175 }
176
177 pri->data_fd = data_fds[0];
178 pri->control_fd = control_fds[0];
179 iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
180 return(data_fds[0]);
181}
182
183static void etap_close(int fd, void *data)
184{
185 struct ethertap_data *pri = data;
186
187 iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
188 os_close_file(fd);
189 os_shutdown_socket(pri->data_fd, 1, 1);
190 os_close_file(pri->data_fd);
191 pri->data_fd = -1;
192 os_close_file(pri->control_fd);
193 pri->control_fd = -1;
194}
195
196static int etap_set_mtu(int mtu, void *data)
197{
198 return(mtu);
199}
200
201static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
202 void *data)
203{
204 struct ethertap_data *pri = data;
205
206 tap_check_ips(pri->gate_addr, addr);
207 if(pri->control_fd == -1) return;
208 etap_open_addr(addr, netmask, &pri->control_fd);
209}
210
211static void etap_del_addr(unsigned char *addr, unsigned char *netmask,
212 void *data)
213{
214 struct ethertap_data *pri = data;
215
216 if(pri->control_fd == -1) return;
217 etap_close_addr(addr, netmask, &pri->control_fd);
218}
219
220struct net_user_info ethertap_user_info = {
221 .init = etap_user_init,
222 .open = etap_open,
223 .close = etap_close,
224 .remove = NULL,
225 .set_mtu = etap_set_mtu,
226 .add_address = etap_add_addr,
227 .delete_address = etap_del_addr,
228 .max_packet = MAX_PACKET - ETH_HEADER_ETHERTAP
229};
230
231/*
232 * Overrides for Emacs so that we follow Linus's tabbing style.
233 * Emacs will notice this stuff at the end of the file and automatically
234 * adjust the settings for this buffer only. This must remain at the end
235 * of the file.
236 * ---------------------------------------------------------------------------
237 * Local variables:
238 * c-file-style: "linux"
239 * End:
240 */
diff --git a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h
new file mode 100644
index 000000000000..25d4a2868814
--- /dev/null
+++ b/arch/um/os-Linux/drivers/tuntap.h
@@ -0,0 +1,32 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __UM_TUNTAP_H
7#define __UM_TUNTAP_H
8
9#include "net_user.h"
10
11struct tuntap_data {
12 char *dev_name;
13 int fixed_config;
14 char *gate_addr;
15 int fd;
16 void *dev;
17};
18
19extern struct net_user_info tuntap_user_info;
20
21#endif
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/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c
new file mode 100644
index 000000000000..4202b9ebad4c
--- /dev/null
+++ b/arch/um/os-Linux/drivers/tuntap_kern.c
@@ -0,0 +1,104 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/stddef.h"
7#include "linux/netdevice.h"
8#include "linux/etherdevice.h"
9#include "linux/skbuff.h"
10#include "linux/init.h"
11#include "asm/errno.h"
12#include "net_kern.h"
13#include "net_user.h"
14#include "tuntap.h"
15
16struct tuntap_init {
17 char *dev_name;
18 char *gate_addr;
19};
20
21static void tuntap_init(struct net_device *dev, void *data)
22{
23 struct uml_net_private *pri;
24 struct tuntap_data *tpri;
25 struct tuntap_init *init = data;
26
27 pri = dev->priv;
28 tpri = (struct tuntap_data *) pri->user;
29 tpri->dev_name = init->dev_name;
30 tpri->fixed_config = (init->dev_name != NULL);
31 tpri->gate_addr = init->gate_addr;
32 tpri->fd = -1;
33 tpri->dev = dev;
34
35 printk("TUN/TAP backend - ");
36 if (tpri->gate_addr != NULL)
37 printk("IP = %s", tpri->gate_addr);
38 printk("\n");
39}
40
41static int tuntap_read(int fd, struct sk_buff **skb,
42 struct uml_net_private *lp)
43{
44 *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
45 if(*skb == NULL) return(-ENOMEM);
46 return(net_read(fd, (*skb)->mac.raw,
47 (*skb)->dev->mtu + ETH_HEADER_OTHER));
48}
49
50static int tuntap_write(int fd, struct sk_buff **skb,
51 struct uml_net_private *lp)
52{
53 return(net_write(fd, (*skb)->data, (*skb)->len));
54}
55
56struct net_kern_info tuntap_kern_info = {
57 .init = tuntap_init,
58 .protocol = eth_protocol,
59 .read = tuntap_read,
60 .write = tuntap_write,
61};
62
63int tuntap_setup(char *str, char **mac_out, void *data)
64{
65 struct tuntap_init *init = data;
66
67 *init = ((struct tuntap_init)
68 { .dev_name = NULL,
69 .gate_addr = NULL });
70 if(tap_setup_common(str, "tuntap", &init->dev_name, mac_out,
71 &init->gate_addr))
72 return(0);
73
74 return(1);
75}
76
77static struct transport tuntap_transport = {
78 .list = LIST_HEAD_INIT(tuntap_transport.list),
79 .name = "tuntap",
80 .setup = tuntap_setup,
81 .user = &tuntap_user_info,
82 .kern = &tuntap_kern_info,
83 .private_size = sizeof(struct tuntap_data),
84 .setup_size = sizeof(struct tuntap_init),
85};
86
87static int register_tuntap(void)
88{
89 register_transport(&tuntap_transport);
90 return(1);
91}
92
93__initcall(register_tuntap);
94
95/*
96 * Overrides for Emacs so that we follow Linus's tabbing style.
97 * Emacs will notice this stuff at the end of the file and automatically
98 * adjust the settings for this buffer only. This must remain at the end
99 * of the file.
100 * ---------------------------------------------------------------------------
101 * Local variables:
102 * c-file-style: "linux"
103 * End:
104 */
diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
new file mode 100644
index 000000000000..4b83c6c3f48d
--- /dev/null
+++ b/arch/um/os-Linux/drivers/tuntap_user.c
@@ -0,0 +1,225 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stddef.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <errno.h>
11#include <sys/wait.h>
12#include <sys/socket.h>
13#include <sys/un.h>
14#include <sys/uio.h>
15#include <sys/ioctl.h>
16#include <net/if.h>
17#include <linux/if_tun.h>
18#include "net_user.h"
19#include "tuntap.h"
20#include "kern_util.h"
21#include "user_util.h"
22#include "user.h"
23#include "helper.h"
24#include "os.h"
25
26#define MAX_PACKET ETH_MAX_PACKET
27
28void tuntap_user_init(void *data, void *dev)
29{
30 struct tuntap_data *pri = data;
31
32 pri->dev = dev;
33}
34
35static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
36 void *data)
37{
38 struct tuntap_data *pri = data;
39
40 tap_check_ips(pri->gate_addr, addr);
41 if((pri->fd == -1) || pri->fixed_config) return;
42 open_addr(addr, netmask, pri->dev_name);
43}
44
45static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
46 void *data)
47{
48 struct tuntap_data *pri = data;
49
50 if((pri->fd == -1) || pri->fixed_config) return;
51 close_addr(addr, netmask, pri->dev_name);
52}
53
54struct tuntap_pre_exec_data {
55 int stdout;
56 int close_me;
57};
58
59static void tuntap_pre_exec(void *arg)
60{
61 struct tuntap_pre_exec_data *data = arg;
62
63 dup2(data->stdout, 1);
64 os_close_file(data->close_me);
65}
66
67static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
68 char *buffer, int buffer_len, int *used_out)
69{
70 struct tuntap_pre_exec_data data;
71 char version_buf[sizeof("nnnnn\0")];
72 char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate,
73 NULL };
74 char buf[CMSG_SPACE(sizeof(*fd_out))];
75 struct msghdr msg;
76 struct cmsghdr *cmsg;
77 struct iovec iov;
78 int pid, n;
79
80 sprintf(version_buf, "%d", UML_NET_VERSION);
81
82 data.stdout = remote;
83 data.close_me = me;
84
85 pid = run_helper(tuntap_pre_exec, &data, argv, NULL);
86
87 if(pid < 0) return(-pid);
88
89 os_close_file(remote);
90
91 msg.msg_name = NULL;
92 msg.msg_namelen = 0;
93 if(buffer != NULL){
94 iov = ((struct iovec) { buffer, buffer_len });
95 msg.msg_iov = &iov;
96 msg.msg_iovlen = 1;
97 }
98 else {
99 msg.msg_iov = NULL;
100 msg.msg_iovlen = 0;
101 }
102 msg.msg_control = buf;
103 msg.msg_controllen = sizeof(buf);
104 msg.msg_flags = 0;
105 n = recvmsg(me, &msg, 0);
106 *used_out = n;
107 if(n < 0){
108 printk("tuntap_open_tramp : recvmsg failed - errno = %d\n",
109 errno);
110 return(-errno);
111 }
112 CATCH_EINTR(waitpid(pid, NULL, 0));
113
114 cmsg = CMSG_FIRSTHDR(&msg);
115 if(cmsg == NULL){
116 printk("tuntap_open_tramp : didn't receive a message\n");
117 return(-EINVAL);
118 }
119 if((cmsg->cmsg_level != SOL_SOCKET) ||
120 (cmsg->cmsg_type != SCM_RIGHTS)){
121 printk("tuntap_open_tramp : didn't receive a descriptor\n");
122 return(-EINVAL);
123 }
124 *fd_out = ((int *) CMSG_DATA(cmsg))[0];
125 return(0);
126}
127
128static int tuntap_open(void *data)
129{
130 struct ifreq ifr;
131 struct tuntap_data *pri = data;
132 char *output, *buffer;
133 int err, fds[2], len, used;
134
135 err = tap_open_common(pri->dev, pri->gate_addr);
136 if(err < 0)
137 return(err);
138
139 if(pri->fixed_config){
140 pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0);
141 if(pri->fd < 0){
142 printk("Failed to open /dev/net/tun, err = %d\n",
143 -pri->fd);
144 return(pri->fd);
145 }
146 memset(&ifr, 0, sizeof(ifr));
147 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
148 strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name));
149 if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
150 printk("TUNSETIFF failed, errno = %d\n", errno);
151 os_close_file(pri->fd);
152 return(-errno);
153 }
154 }
155 else {
156 err = os_pipe(fds, 0, 0);
157 if(err < 0){
158 printk("tuntap_open : os_pipe failed - err = %d\n",
159 -err);
160 return(err);
161 }
162
163 buffer = get_output_buffer(&len);
164 if(buffer != NULL) len--;
165 used = 0;
166
167 err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0],
168 fds[1], buffer, len, &used);
169
170 output = buffer;
171 if(err < 0) {
172 printk("%s", output);
173 free_output_buffer(buffer);
174 printk("tuntap_open_tramp failed - err = %d\n", -err);
175 return(err);
176 }
177
178 pri->dev_name = uml_strdup(buffer);
179 output += IFNAMSIZ;
180 printk("%s", output);
181 free_output_buffer(buffer);
182
183 os_close_file(fds[0]);
184 iter_addresses(pri->dev, open_addr, pri->dev_name);
185 }
186
187 return(pri->fd);
188}
189
190static void tuntap_close(int fd, void *data)
191{
192 struct tuntap_data *pri = data;
193
194 if(!pri->fixed_config)
195 iter_addresses(pri->dev, close_addr, pri->dev_name);
196 os_close_file(fd);
197 pri->fd = -1;
198}
199
200static int tuntap_set_mtu(int mtu, void *data)
201{
202 return(mtu);
203}
204
205struct net_user_info tuntap_user_info = {
206 .init = tuntap_user_init,
207 .open = tuntap_open,
208 .close = tuntap_close,
209 .remove = NULL,
210 .set_mtu = tuntap_set_mtu,
211 .add_address = tuntap_add_addr,
212 .delete_address = tuntap_del_addr,
213 .max_packet = MAX_PACKET
214};
215
216/*
217 * Overrides for Emacs so that we follow Linus's tabbing style.
218 * Emacs will notice this stuff at the end of the file and automatically
219 * adjust the settings for this buffer only. This must remain at the end
220 * of the file.
221 * ---------------------------------------------------------------------------
222 * Local variables:
223 * c-file-style: "linux"
224 * End:
225 */
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c
new file mode 100644
index 000000000000..9aee0b62ebca
--- /dev/null
+++ b/arch/um/os-Linux/elf_aux.c
@@ -0,0 +1,66 @@
1/*
2 * arch/um/kernel/elf_aux.c
3 *
4 * Scan the Elf auxiliary vector provided by the host to extract
5 * information about vsyscall-page, etc.
6 *
7 * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
8 * Author: Bodo Stroesser (bodo.stroesser@fujitsu-siemens.com)
9 */
10#include <elf.h>
11#include <stddef.h>
12#include "init.h"
13#include "elf_user.h"
14
15#if ELF_CLASS == ELFCLASS32
16typedef Elf32_auxv_t elf_auxv_t;
17#else
18typedef Elf64_auxv_t elf_auxv_t;
19#endif
20
21char * elf_aux_platform;
22long elf_aux_hwcap;
23
24unsigned long vsyscall_ehdr;
25unsigned long vsyscall_end;
26
27unsigned long __kernel_vsyscall;
28
29__init void scan_elf_aux( char **envp)
30{
31 long page_size = 0;
32 elf_auxv_t * auxv;
33
34 while ( *envp++ != NULL) ;
35
36 for ( auxv = (elf_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) {
37 switch ( auxv->a_type ) {
38 case AT_SYSINFO:
39 __kernel_vsyscall = auxv->a_un.a_val;
40 break;
41 case AT_SYSINFO_EHDR:
42 vsyscall_ehdr = auxv->a_un.a_val;
43 break;
44 case AT_HWCAP:
45 elf_aux_hwcap = auxv->a_un.a_val;
46 break;
47 case AT_PLATFORM:
48 elf_aux_platform = auxv->a_un.a_ptr;
49 break;
50 case AT_PAGESZ:
51 page_size = auxv->a_un.a_val;
52 break;
53 }
54 }
55 if ( ! __kernel_vsyscall || ! vsyscall_ehdr ||
56 ! elf_aux_hwcap || ! elf_aux_platform ||
57 ! page_size || (vsyscall_ehdr % page_size) ) {
58 __kernel_vsyscall = 0;
59 vsyscall_ehdr = 0;
60 elf_aux_hwcap = 0;
61 elf_aux_platform = "i586";
62 }
63 else {
64 vsyscall_end = vsyscall_ehdr + page_size;
65 }
66}
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
new file mode 100644
index 000000000000..77d4066d1af8
--- /dev/null
+++ b/arch/um/os-Linux/file.c
@@ -0,0 +1,680 @@
1/*
2 * Copyright (C) 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 <fcntl.h>
10#include <signal.h>
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <sys/socket.h>
14#include <sys/un.h>
15#include <sys/ioctl.h>
16#include <sys/mount.h>
17#include <sys/uio.h>
18#include "os.h"
19#include "user.h"
20#include "kern_util.h"
21
22static void copy_stat(struct uml_stat *dst, struct stat64 *src)
23{
24 *dst = ((struct uml_stat) {
25 .ust_dev = src->st_dev, /* device */
26 .ust_ino = src->st_ino, /* inode */
27 .ust_mode = src->st_mode, /* protection */
28 .ust_nlink = src->st_nlink, /* number of hard links */
29 .ust_uid = src->st_uid, /* user ID of owner */
30 .ust_gid = src->st_gid, /* group ID of owner */
31 .ust_size = src->st_size, /* total size, in bytes */
32 .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */
33 .ust_blocks = src->st_blocks, /* number of blocks allocated */
34 .ust_atime = src->st_atime, /* time of last access */
35 .ust_mtime = src->st_mtime, /* time of last modification */
36 .ust_ctime = src->st_ctime, /* time of last change */
37 });
38}
39
40int os_stat_fd(const int fd, struct uml_stat *ubuf)
41{
42 struct stat64 sbuf;
43 int err;
44
45 do {
46 err = fstat64(fd, &sbuf);
47 } while((err < 0) && (errno == EINTR)) ;
48
49 if(err < 0)
50 return(-errno);
51
52 if(ubuf != NULL)
53 copy_stat(ubuf, &sbuf);
54 return(err);
55}
56
57int os_stat_file(const char *file_name, struct uml_stat *ubuf)
58{
59 struct stat64 sbuf;
60 int err;
61
62 do {
63 err = stat64(file_name, &sbuf);
64 } while((err < 0) && (errno == EINTR)) ;
65
66 if(err < 0)
67 return(-errno);
68
69 if(ubuf != NULL)
70 copy_stat(ubuf, &sbuf);
71 return(err);
72}
73
74int os_access(const char* file, int mode)
75{
76 int amode, err;
77
78 amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) |
79 (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ;
80
81 err = access(file, amode);
82 if(err < 0)
83 return(-errno);
84
85 return(0);
86}
87
88void os_print_error(int error, const char* str)
89{
90 errno = error < 0 ? -error : error;
91
92 perror(str);
93}
94
95/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */
96int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
97{
98 int err;
99
100 err = ioctl(fd, cmd, arg);
101 if(err < 0)
102 return(-errno);
103
104 return(err);
105}
106
107int os_window_size(int fd, int *rows, int *cols)
108{
109 struct winsize size;
110
111 if(ioctl(fd, TIOCGWINSZ, &size) < 0)
112 return(-errno);
113
114 *rows = size.ws_row;
115 *cols = size.ws_col;
116
117 return(0);
118}
119
120int os_new_tty_pgrp(int fd, int pid)
121{
122 if(ioctl(fd, TIOCSCTTY, 0) < 0){
123 printk("TIOCSCTTY failed, errno = %d\n", errno);
124 return(-errno);
125 }
126
127 if(tcsetpgrp(fd, pid) < 0){
128 printk("tcsetpgrp failed, errno = %d\n", errno);
129 return(-errno);
130 }
131
132 return(0);
133}
134
135/* FIXME: ensure namebuf in os_get_if_name is big enough */
136int os_get_ifname(int fd, char* namebuf)
137{
138 if(ioctl(fd, SIOCGIFNAME, namebuf) < 0)
139 return(-errno);
140
141 return(0);
142}
143
144int os_set_slip(int fd)
145{
146 int disc, sencap;
147
148 disc = N_SLIP;
149 if(ioctl(fd, TIOCSETD, &disc) < 0){
150 printk("Failed to set slip line discipline - "
151 "errno = %d\n", errno);
152 return(-errno);
153 }
154
155 sencap = 0;
156 if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){
157 printk("Failed to set slip encapsulation - "
158 "errno = %d\n", errno);
159 return(-errno);
160 }
161
162 return(0);
163}
164
165int os_set_owner(int fd, int pid)
166{
167 if(fcntl(fd, F_SETOWN, pid) < 0){
168 int save_errno = errno;
169
170 if(fcntl(fd, F_GETOWN, 0) != pid)
171 return(-save_errno);
172 }
173
174 return(0);
175}
176
177/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */
178int os_sigio_async(int master, int slave)
179{
180 int flags;
181
182 flags = fcntl(master, F_GETFL);
183 if(flags < 0) {
184 printk("fcntl F_GETFL failed, errno = %d\n", errno);
185 return(-errno);
186 }
187
188 if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
189 (fcntl(master, F_SETOWN, os_getpid()) < 0)){
190 printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n",
191 errno);
192 return(-errno);
193 }
194
195 if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){
196 printk("fcntl F_SETFL failed, errno = %d\n", errno);
197 return(-errno);
198 }
199
200 return(0);
201}
202
203int os_mode_fd(int fd, int mode)
204{
205 int err;
206
207 do {
208 err = fchmod(fd, mode);
209 } while((err < 0) && (errno==EINTR)) ;
210
211 if(err < 0)
212 return(-errno);
213
214 return(0);
215}
216
217int os_file_type(char *file)
218{
219 struct uml_stat buf;
220 int err;
221
222 err = os_stat_file(file, &buf);
223 if(err < 0)
224 return(err);
225
226 if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR);
227 else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK);
228 else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV);
229 else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV);
230 else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO);
231 else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK);
232 else return(OS_TYPE_FILE);
233}
234
235int os_file_mode(char *file, struct openflags *mode_out)
236{
237 int err;
238
239 *mode_out = OPENFLAGS();
240
241 err = os_access(file, OS_ACC_W_OK);
242 if((err < 0) && (err != -EACCES))
243 return(err);
244
245 *mode_out = of_write(*mode_out);
246
247 err = os_access(file, OS_ACC_R_OK);
248 if((err < 0) && (err != -EACCES))
249 return(err);
250
251 *mode_out = of_read(*mode_out);
252
253 return(0);
254}
255
256int os_open_file(char *file, struct openflags flags, int mode)
257{
258 int fd, f = 0;
259
260 if(flags.r && flags.w) f = O_RDWR;
261 else if(flags.r) f = O_RDONLY;
262 else if(flags.w) f = O_WRONLY;
263 else f = 0;
264
265 if(flags.s) f |= O_SYNC;
266 if(flags.c) f |= O_CREAT;
267 if(flags.t) f |= O_TRUNC;
268 if(flags.e) f |= O_EXCL;
269
270 fd = open64(file, f, mode);
271 if(fd < 0)
272 return(-errno);
273
274 if(flags.cl && fcntl(fd, F_SETFD, 1)){
275 os_close_file(fd);
276 return(-errno);
277 }
278
279 return(fd);
280}
281
282int os_connect_socket(char *name)
283{
284 struct sockaddr_un sock;
285 int fd, err;
286
287 sock.sun_family = AF_UNIX;
288 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
289
290 fd = socket(AF_UNIX, SOCK_STREAM, 0);
291 if(fd < 0)
292 return(fd);
293
294 err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
295 if(err)
296 return(-errno);
297
298 return(fd);
299}
300
301void os_close_file(int fd)
302{
303 close(fd);
304}
305
306int os_seek_file(int fd, __u64 offset)
307{
308 __u64 actual;
309
310 actual = lseek64(fd, offset, SEEK_SET);
311 if(actual != offset)
312 return(-errno);
313 return(0);
314}
315
316static int fault_buffer(void *start, int len,
317 int (*copy_proc)(void *addr, void *buf, int len))
318{
319 int page = getpagesize(), i;
320 char c;
321
322 for(i = 0; i < len; i += page){
323 if((*copy_proc)(start + i, &c, sizeof(c)))
324 return(-EFAULT);
325 }
326 if((len % page) != 0){
327 if((*copy_proc)(start + len - 1, &c, sizeof(c)))
328 return(-EFAULT);
329 }
330 return(0);
331}
332
333static int file_io(int fd, void *buf, int len,
334 int (*io_proc)(int fd, void *buf, int len),
335 int (*copy_user_proc)(void *addr, void *buf, int len))
336{
337 int n, err;
338
339 do {
340 n = (*io_proc)(fd, buf, len);
341 if((n < 0) && (errno == EFAULT)){
342 err = fault_buffer(buf, len, copy_user_proc);
343 if(err)
344 return(err);
345 n = (*io_proc)(fd, buf, len);
346 }
347 } while((n < 0) && (errno == EINTR));
348
349 if(n < 0)
350 return(-errno);
351 return(n);
352}
353
354int os_read_file(int fd, void *buf, int len)
355{
356 return(file_io(fd, buf, len, (int (*)(int, void *, int)) read,
357 copy_from_user_proc));
358}
359
360int os_write_file(int fd, const void *buf, int len)
361{
362 return(file_io(fd, (void *) buf, len,
363 (int (*)(int, void *, int)) write, copy_to_user_proc));
364}
365
366int os_file_size(char *file, long long *size_out)
367{
368 struct uml_stat buf;
369 int err;
370
371 err = os_stat_file(file, &buf);
372 if(err < 0){
373 printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
374 return(err);
375 }
376
377 if(S_ISBLK(buf.ust_mode)){
378 int fd, blocks;
379
380 fd = os_open_file(file, of_read(OPENFLAGS()), 0);
381 if(fd < 0){
382 printk("Couldn't open \"%s\", errno = %d\n", file, -fd);
383 return(fd);
384 }
385 if(ioctl(fd, BLKGETSIZE, &blocks) < 0){
386 printk("Couldn't get the block size of \"%s\", "
387 "errno = %d\n", file, errno);
388 err = -errno;
389 os_close_file(fd);
390 return(err);
391 }
392 *size_out = ((long long) blocks) * 512;
393 os_close_file(fd);
394 return(0);
395 }
396 *size_out = buf.ust_size;
397 return(0);
398}
399
400int os_file_modtime(char *file, unsigned long *modtime)
401{
402 struct uml_stat buf;
403 int err;
404
405 err = os_stat_file(file, &buf);
406 if(err < 0){
407 printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
408 return(err);
409 }
410
411 *modtime = buf.ust_mtime;
412 return(0);
413}
414
415int os_get_exec_close(int fd, int* close_on_exec)
416{
417 int ret;
418
419 do {
420 ret = fcntl(fd, F_GETFD);
421 } while((ret < 0) && (errno == EINTR)) ;
422
423 if(ret < 0)
424 return(-errno);
425
426 *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0;
427 return(ret);
428}
429
430int os_set_exec_close(int fd, int close_on_exec)
431{
432 int flag, err;
433
434 if(close_on_exec) flag = FD_CLOEXEC;
435 else flag = 0;
436
437 do {
438 err = fcntl(fd, F_SETFD, flag);
439 } while((err < 0) && (errno == EINTR)) ;
440
441 if(err < 0)
442 return(-errno);
443 return(err);
444}
445
446int os_pipe(int *fds, int stream, int close_on_exec)
447{
448 int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
449
450 err = socketpair(AF_UNIX, type, 0, fds);
451 if(err < 0)
452 return(-errno);
453
454 if(!close_on_exec)
455 return(0);
456
457 err = os_set_exec_close(fds[0], 1);
458 if(err < 0)
459 goto error;
460
461 err = os_set_exec_close(fds[1], 1);
462 if(err < 0)
463 goto error;
464
465 return(0);
466
467 error:
468 printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err);
469 os_close_file(fds[1]);
470 os_close_file(fds[0]);
471 return(err);
472}
473
474int os_set_fd_async(int fd, int owner)
475{
476 /* XXX This should do F_GETFL first */
477 if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){
478 printk("os_set_fd_async : failed to set O_ASYNC and "
479 "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
480 return(-errno);
481 }
482#ifdef notdef
483 if(fcntl(fd, F_SETFD, 1) < 0){
484 printk("os_set_fd_async : Setting FD_CLOEXEC failed, "
485 "errno = %d\n", errno);
486 }
487#endif
488
489 if((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
490 (fcntl(fd, F_SETOWN, owner) < 0)){
491 printk("os_set_fd_async : Failed to fcntl F_SETOWN "
492 "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd,
493 owner, errno);
494 return(-errno);
495 }
496
497 return(0);
498}
499
500int os_clear_fd_async(int fd)
501{
502 int flags = fcntl(fd, F_GETFL);
503
504 flags &= ~(O_ASYNC | O_NONBLOCK);
505 if(fcntl(fd, F_SETFL, flags) < 0)
506 return(-errno);
507 return(0);
508}
509
510int os_set_fd_block(int fd, int blocking)
511{
512 int flags;
513
514 flags = fcntl(fd, F_GETFL);
515
516 if(blocking) flags &= ~O_NONBLOCK;
517 else flags |= O_NONBLOCK;
518
519 if(fcntl(fd, F_SETFL, flags) < 0){
520 printk("Failed to change blocking on fd # %d, errno = %d\n",
521 fd, errno);
522 return(-errno);
523 }
524 return(0);
525}
526
527int os_accept_connection(int fd)
528{
529 int new;
530
531 new = accept(fd, NULL, 0);
532 if(new < 0)
533 return(-errno);
534 return(new);
535}
536
537#ifndef SHUT_RD
538#define SHUT_RD 0
539#endif
540
541#ifndef SHUT_WR
542#define SHUT_WR 1
543#endif
544
545#ifndef SHUT_RDWR
546#define SHUT_RDWR 2
547#endif
548
549int os_shutdown_socket(int fd, int r, int w)
550{
551 int what, err;
552
553 if(r && w) what = SHUT_RDWR;
554 else if(r) what = SHUT_RD;
555 else if(w) what = SHUT_WR;
556 else {
557 printk("os_shutdown_socket : neither r or w was set\n");
558 return(-EINVAL);
559 }
560 err = shutdown(fd, what);
561 if(err < 0)
562 return(-errno);
563 return(0);
564}
565
566int os_rcv_fd(int fd, int *helper_pid_out)
567{
568 int new, n;
569 char buf[CMSG_SPACE(sizeof(new))];
570 struct msghdr msg;
571 struct cmsghdr *cmsg;
572 struct iovec iov;
573
574 msg.msg_name = NULL;
575 msg.msg_namelen = 0;
576 iov = ((struct iovec) { .iov_base = helper_pid_out,
577 .iov_len = sizeof(*helper_pid_out) });
578 msg.msg_iov = &iov;
579 msg.msg_iovlen = 1;
580 msg.msg_control = buf;
581 msg.msg_controllen = sizeof(buf);
582 msg.msg_flags = 0;
583
584 n = recvmsg(fd, &msg, 0);
585 if(n < 0)
586 return(-errno);
587
588 else if(n != sizeof(iov.iov_len))
589 *helper_pid_out = -1;
590
591 cmsg = CMSG_FIRSTHDR(&msg);
592 if(cmsg == NULL){
593 printk("rcv_fd didn't receive anything, error = %d\n", errno);
594 return(-1);
595 }
596 if((cmsg->cmsg_level != SOL_SOCKET) ||
597 (cmsg->cmsg_type != SCM_RIGHTS)){
598 printk("rcv_fd didn't receive a descriptor\n");
599 return(-1);
600 }
601
602 new = ((int *) CMSG_DATA(cmsg))[0];
603 return(new);
604}
605
606int os_create_unix_socket(char *file, int len, int close_on_exec)
607{
608 struct sockaddr_un addr;
609 int sock, err;
610
611 sock = socket(PF_UNIX, SOCK_DGRAM, 0);
612 if (sock < 0){
613 printk("create_unix_socket - socket failed, errno = %d\n",
614 errno);
615 return(-errno);
616 }
617
618 if(close_on_exec) {
619 err = os_set_exec_close(sock, 1);
620 if(err < 0)
621 printk("create_unix_socket : close_on_exec failed, "
622 "err = %d", -err);
623 }
624
625 addr.sun_family = AF_UNIX;
626
627 /* XXX Be more careful about overflow */
628 snprintf(addr.sun_path, len, "%s", file);
629
630 err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
631 if (err < 0){
632 printk("create_listening_socket at '%s' - bind failed, "
633 "errno = %d\n", file, errno);
634 return(-errno);
635 }
636
637 return(sock);
638}
639
640void os_flush_stdout(void)
641{
642 fflush(stdout);
643}
644
645int os_lock_file(int fd, int excl)
646{
647 int type = excl ? F_WRLCK : F_RDLCK;
648 struct flock lock = ((struct flock) { .l_type = type,
649 .l_whence = SEEK_SET,
650 .l_start = 0,
651 .l_len = 0 } );
652 int err, save;
653
654 err = fcntl(fd, F_SETLK, &lock);
655 if(!err)
656 goto out;
657
658 save = -errno;
659 err = fcntl(fd, F_GETLK, &lock);
660 if(err){
661 err = -errno;
662 goto out;
663 }
664
665 printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid);
666 err = save;
667 out:
668 return(err);
669}
670
671/*
672 * Overrides for Emacs so that we follow Linus's tabbing style.
673 * Emacs will notice this stuff at the end of the file and automatically
674 * adjust the settings for this buffer only. This must remain at the end
675 * of the file.
676 * ---------------------------------------------------------------------------
677 * Local variables:
678 * c-file-style: "linux"
679 * End:
680 */
diff --git a/arch/um/os-Linux/include/file.h b/arch/um/os-Linux/include/file.h
new file mode 100644
index 000000000000..d82711efacfa
--- /dev/null
+++ b/arch/um/os-Linux/include/file.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __OS_FILE_H__
7#define __OS_FILE_H__
8
9#define DEV_NULL "/dev/null"
10
11#endif
12
13/*
14 * Overrides for Emacs so that we follow Linus's tabbing style.
15 * Emacs will notice this stuff at the end of the file and automatically
16 * adjust the settings for this buffer only. This must remain at the end
17 * of the file.
18 * ---------------------------------------------------------------------------
19 * Local variables:
20 * c-file-style: "linux"
21 * End:
22 */
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
new file mode 100644
index 000000000000..ba9ca1cc790a
--- /dev/null
+++ b/arch/um/os-Linux/process.c
@@ -0,0 +1,171 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <stdio.h>
8#include <errno.h>
9#include <signal.h>
10#include <linux/unistd.h>
11#include <sys/mman.h>
12#include <sys/wait.h>
13#include "ptrace_user.h"
14#include "os.h"
15#include "user.h"
16#include "user_util.h"
17
18#define ARBITRARY_ADDR -1
19#define FAILURE_PID -1
20
21#define STAT_PATH_LEN sizeof("/proc/#######/stat\0")
22#define COMM_SCANF "%*[^)])"
23
24unsigned long os_process_pc(int pid)
25{
26 char proc_stat[STAT_PATH_LEN], buf[256];
27 unsigned long pc;
28 int fd, err;
29
30 sprintf(proc_stat, "/proc/%d/stat", pid);
31 fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0);
32 if(fd < 0){
33 printk("os_process_pc - couldn't open '%s', err = %d\n",
34 proc_stat, -fd);
35 return(ARBITRARY_ADDR);
36 }
37 err = os_read_file(fd, buf, sizeof(buf));
38 if(err < 0){
39 printk("os_process_pc - couldn't read '%s', err = %d\n",
40 proc_stat, -err);
41 os_close_file(fd);
42 return(ARBITRARY_ADDR);
43 }
44 os_close_file(fd);
45 pc = ARBITRARY_ADDR;
46 if(sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
47 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
48 "%*d %*d %*d %*d %*d %lu", &pc) != 1){
49 printk("os_process_pc - couldn't find pc in '%s'\n", buf);
50 }
51 return(pc);
52}
53
54int os_process_parent(int pid)
55{
56 char stat[STAT_PATH_LEN];
57 char data[256];
58 int parent, n, fd;
59
60 if(pid == -1) return(-1);
61
62 snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
63 fd = os_open_file(stat, of_read(OPENFLAGS()), 0);
64 if(fd < 0){
65 printk("Couldn't open '%s', err = %d\n", stat, -fd);
66 return(FAILURE_PID);
67 }
68
69 n = os_read_file(fd, data, sizeof(data));
70 os_close_file(fd);
71
72 if(n < 0){
73 printk("Couldn't read '%s', err = %d\n", stat, -n);
74 return(FAILURE_PID);
75 }
76
77 parent = FAILURE_PID;
78 n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
79 if(n != 1)
80 printk("Failed to scan '%s'\n", data);
81
82 return(parent);
83}
84
85void os_stop_process(int pid)
86{
87 kill(pid, SIGSTOP);
88}
89
90void os_kill_process(int pid, int reap_child)
91{
92 kill(pid, SIGKILL);
93 if(reap_child)
94 CATCH_EINTR(waitpid(pid, NULL, 0));
95
96}
97
98/* Kill off a ptraced child by all means available. kill it normally first,
99 * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from
100 * which it can't exit directly.
101 */
102
103void os_kill_ptraced_process(int pid, int reap_child)
104{
105 kill(pid, SIGKILL);
106 ptrace(PTRACE_KILL, pid);
107 ptrace(PTRACE_CONT, pid);
108 if(reap_child)
109 CATCH_EINTR(waitpid(pid, NULL, 0));
110}
111
112void os_usr1_process(int pid)
113{
114 kill(pid, SIGUSR1);
115}
116
117/*Don't use the glibc version, which caches the result in TLS. It misses some
118 * syscalls, and also breaks with clone(), which does not unshare the TLS.*/
119inline _syscall0(pid_t, getpid)
120
121int os_getpid(void)
122{
123 return(getpid());
124}
125
126int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
127 int r, int w, int x)
128{
129 void *loc;
130 int prot;
131
132 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
133 (x ? PROT_EXEC : 0);
134
135 loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
136 fd, off);
137 if(loc == MAP_FAILED)
138 return(-errno);
139 return(0);
140}
141
142int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
143{
144 int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
145 (x ? PROT_EXEC : 0));
146
147 if(mprotect(addr, len, prot) < 0)
148 return(-errno);
149 return(0);
150}
151
152int os_unmap_memory(void *addr, int len)
153{
154 int err;
155
156 err = munmap(addr, len);
157 if(err < 0)
158 return(-errno);
159 return(0);
160}
161
162/*
163 * Overrides for Emacs so that we follow Linus's tabbing style.
164 * Emacs will notice this stuff at the end of the file and automatically
165 * adjust the settings for this buffer only. This must remain at the end
166 * of the file.
167 * ---------------------------------------------------------------------------
168 * Local variables:
169 * c-file-style: "linux"
170 * End:
171 */
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
new file mode 100644
index 000000000000..7eac1baf5975
--- /dev/null
+++ b/arch/um/os-Linux/signal.c
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 2004 PathScale, Inc
3 * Licensed under the GPL
4 */
5
6#include <signal.h>
7#include "time_user.h"
8#include "mode.h"
9#include "sysdep/signal.h"
10
11void sig_handler(int sig)
12{
13 struct sigcontext *sc;
14
15 ARCH_GET_SIGCONTEXT(sc, sig);
16 CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
17 sig, sc);
18}
19
20extern int timer_irq_inited;
21
22void alarm_handler(int sig)
23{
24 struct sigcontext *sc;
25
26 ARCH_GET_SIGCONTEXT(sc, sig);
27 if(!timer_irq_inited) return;
28
29 if(sig == SIGALRM)
30 switch_timers(0);
31
32 CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
33 sig, sc);
34
35 if(sig == SIGALRM)
36 switch_timers(1);
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/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile
new file mode 100644
index 000000000000..340ef26f5944
--- /dev/null
+++ b/arch/um/os-Linux/sys-i386/Makefile
@@ -0,0 +1,10 @@
1#
2# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6obj-$(CONFIG_MODE_SKAS) = registers.o
7
8USER_OBJS := $(obj-y)
9
10include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c
new file mode 100644
index 000000000000..148645b14480
--- /dev/null
+++ b/arch/um/os-Linux/sys-i386/registers.c
@@ -0,0 +1,132 @@
1/*
2 * Copyright (C) 2004 PathScale, Inc
3 * Licensed under the GPL
4 */
5
6#include <errno.h>
7#include <string.h>
8#include "sysdep/ptrace_user.h"
9#include "sysdep/ptrace.h"
10#include "uml-config.h"
11#include "skas_ptregs.h"
12#include "registers.h"
13#include "user.h"
14
15/* These are set once at boot time and not changed thereafter */
16
17static unsigned long exec_regs[HOST_FRAME_SIZE];
18static unsigned long exec_fp_regs[HOST_FP_SIZE];
19static unsigned long exec_fpx_regs[HOST_XFP_SIZE];
20static int have_fpx_regs = 1;
21
22void init_thread_registers(union uml_pt_regs *to)
23{
24 memcpy(to->skas.regs, exec_regs, sizeof(to->skas.regs));
25 memcpy(to->skas.fp, exec_fp_regs, sizeof(to->skas.fp));
26 if(have_fpx_regs)
27 memcpy(to->skas.xfp, exec_fpx_regs, sizeof(to->skas.xfp));
28}
29
30/* XXX These need to use [GS]ETFPXREGS and copy_sc_{to,from}_user_skas needs
31 * to pass in a sufficiently large buffer
32 */
33int save_fp_registers(int pid, unsigned long *fp_regs)
34{
35 if(ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0)
36 return(-errno);
37 return(0);
38}
39
40int restore_fp_registers(int pid, unsigned long *fp_regs)
41{
42 if(ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0)
43 return(-errno);
44 return(0);
45}
46
47static int move_registers(int pid, int int_op, union uml_pt_regs *regs,
48 int fp_op, unsigned long *fp_regs)
49{
50 if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
51 return(-errno);
52
53 if(ptrace(fp_op, pid, 0, fp_regs) < 0)
54 return(-errno);
55
56 return(0);
57}
58
59void save_registers(int pid, union uml_pt_regs *regs)
60{
61 unsigned long *fp_regs;
62 int err, fp_op;
63
64 if(have_fpx_regs){
65 fp_op = PTRACE_GETFPXREGS;
66 fp_regs = regs->skas.xfp;
67 }
68 else {
69 fp_op = PTRACE_GETFPREGS;
70 fp_regs = regs->skas.fp;
71 }
72
73 err = move_registers(pid, PTRACE_GETREGS, regs, fp_op, fp_regs);
74 if(err)
75 panic("save_registers - saving registers failed, errno = %d\n",
76 -err);
77}
78
79void restore_registers(int pid, union uml_pt_regs *regs)
80{
81 unsigned long *fp_regs;
82 int err, fp_op;
83
84 if(have_fpx_regs){
85 fp_op = PTRACE_SETFPXREGS;
86 fp_regs = regs->skas.xfp;
87 }
88 else {
89 fp_op = PTRACE_SETFPREGS;
90 fp_regs = regs->skas.fp;
91 }
92
93 err = move_registers(pid, PTRACE_SETREGS, regs, fp_op, fp_regs);
94 if(err)
95 panic("restore_registers - saving registers failed, "
96 "errno = %d\n", -err);
97}
98
99void init_registers(int pid)
100{
101 int err;
102
103 err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs);
104 if(err)
105 panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
106 err);
107
108 err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs);
109 if(!err)
110 return;
111
112 have_fpx_regs = 0;
113 if(err != EIO)
114 panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
115 err);
116
117 err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
118 if(err)
119 panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d",
120 err);
121}
122
123/*
124 * Overrides for Emacs so that we follow Linus's tabbing style.
125 * Emacs will notice this stuff at the end of the file and automatically
126 * adjust the settings for this buffer only. This must remain at the end
127 * of the file.
128 * ---------------------------------------------------------------------------
129 * Local variables:
130 * c-file-style: "linux"
131 * End:
132 */
diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile
new file mode 100644
index 000000000000..340ef26f5944
--- /dev/null
+++ b/arch/um/os-Linux/sys-x86_64/Makefile
@@ -0,0 +1,10 @@
1#
2# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6obj-$(CONFIG_MODE_SKAS) = registers.o
7
8USER_OBJS := $(obj-y)
9
10include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c
new file mode 100644
index 000000000000..6286c974bbeb
--- /dev/null
+++ b/arch/um/os-Linux/sys-x86_64/registers.c
@@ -0,0 +1,81 @@
1/*
2 * Copyright (C) 2004 PathScale, Inc
3 * Licensed under the GPL
4 */
5
6#include <errno.h>
7#include <string.h>
8#include "ptrace_user.h"
9#include "uml-config.h"
10#include "skas_ptregs.h"
11#include "registers.h"
12#include "user.h"
13
14/* These are set once at boot time and not changed thereafter */
15
16static unsigned long exec_regs[HOST_FRAME_SIZE];
17static unsigned long exec_fp_regs[HOST_FP_SIZE];
18
19void init_thread_registers(union uml_pt_regs *to)
20{
21 memcpy(to->skas.regs, exec_regs, sizeof(to->skas.regs));
22 memcpy(to->skas.fp, exec_fp_regs, sizeof(to->skas.fp));
23}
24
25static int move_registers(int pid, int int_op, int fp_op,
26 union uml_pt_regs *regs)
27{
28 if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
29 return(-errno);
30
31 if(ptrace(fp_op, pid, 0, regs->skas.fp) < 0)
32 return(-errno);
33
34 return(0);
35}
36
37void save_registers(int pid, union uml_pt_regs *regs)
38{
39 int err;
40
41 err = move_registers(pid, PTRACE_GETREGS, PTRACE_GETFPREGS, regs);
42 if(err)
43 panic("save_registers - saving registers failed, errno = %d\n",
44 -err);
45}
46
47void restore_registers(int pid, union uml_pt_regs *regs)
48{
49 int err;
50
51 err = move_registers(pid, PTRACE_SETREGS, PTRACE_SETFPREGS, regs);
52 if(err)
53 panic("restore_registers - saving registers failed, "
54 "errno = %d\n", -err);
55}
56
57void init_registers(int pid)
58{
59 int err;
60
61 err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs);
62 if(err)
63 panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
64 err);
65
66 err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
67 if(err)
68 panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d",
69 err);
70}
71
72/*
73 * Overrides for Emacs so that we follow Linus's tabbing style.
74 * Emacs will notice this stuff at the end of the file and automatically
75 * adjust the settings for this buffer only. This must remain at the end
76 * of the file.
77 * ---------------------------------------------------------------------------
78 * Local variables:
79 * c-file-style: "linux"
80 * End:
81 */
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
new file mode 100644
index 000000000000..cf30a39bc484
--- /dev/null
+++ b/arch/um/os-Linux/time.c
@@ -0,0 +1,21 @@
1#include <stdlib.h>
2#include <sys/time.h>
3
4unsigned long long os_usecs(void)
5{
6 struct timeval tv;
7
8 gettimeofday(&tv, NULL);
9 return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec);
10}
11
12/*
13 * Overrides for Emacs so that we follow Linus's tabbing style.
14 * Emacs will notice this stuff at the end of the file and automatically
15 * adjust the settings for this buffer only. This must remain at the end
16 * of the file.
17 * ---------------------------------------------------------------------------
18 * Local variables:
19 * c-file-style: "linux"
20 * End:
21 */
diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c
new file mode 100644
index 000000000000..4cfdd18ea1ef
--- /dev/null
+++ b/arch/um/os-Linux/tty.c
@@ -0,0 +1,61 @@
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 "os.h"
9#include "user.h"
10#include "kern_util.h"
11
12struct grantpt_info {
13 int fd;
14 int res;
15 int err;
16};
17
18static void grantpt_cb(void *arg)
19{
20 struct grantpt_info *info = arg;
21
22 info->res = grantpt(info->fd);
23 info->err = errno;
24}
25
26int get_pty(void)
27{
28 struct grantpt_info info;
29 int fd;
30
31 fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0);
32 if(fd < 0){
33 printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd);
34 return(fd);
35 }
36
37 info.fd = fd;
38 initial_thread_cb(grantpt_cb, &info);
39
40 if(info.res < 0){
41 printk("get_pty : Couldn't grant pty - errno = %d\n",
42 -info.err);
43 return(-1);
44 }
45 if(unlockpt(fd) < 0){
46 printk("get_pty : Couldn't unlock pty - errno = %d\n", errno);
47 return(-1);
48 }
49 return(fd);
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/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c
new file mode 100644
index 000000000000..75d7af9ae1d2
--- /dev/null
+++ b/arch/um/os-Linux/user_syms.c
@@ -0,0 +1,95 @@
1#include "linux/types.h"
2#include "linux/module.h"
3
4/* Some of this are builtin function (some are not but could in the future),
5 * so I *must* declare good prototypes for them and then EXPORT them.
6 * The kernel code uses the macro defined by include/linux/string.h,
7 * so I undef macros; the userspace code does not include that and I
8 * add an EXPORT for the glibc one.*/
9
10#undef strlen
11#undef strstr
12#undef memcpy
13#undef memset
14
15extern size_t strlen(const char *);
16extern void *memcpy(void *, const void *, size_t);
17extern void *memmove(void *, const void *, size_t);
18extern void *memset(void *, int, size_t);
19extern int printf(const char *, ...);
20
21EXPORT_SYMBOL(strlen);
22EXPORT_SYMBOL(memcpy);
23EXPORT_SYMBOL(memmove);
24EXPORT_SYMBOL(memset);
25EXPORT_SYMBOL(printf);
26
27EXPORT_SYMBOL(strstr);
28
29/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms.
30 * However, the modules will use the CRC defined *here*, no matter if it is
31 * good; so the versions of these symbols will always match
32 */
33#define EXPORT_SYMBOL_PROTO(sym) \
34 int sym(void); \
35 EXPORT_SYMBOL(sym);
36
37#ifdef SUBARCH_i386
38EXPORT_SYMBOL(vsyscall_ehdr);
39EXPORT_SYMBOL(vsyscall_end);
40#endif
41
42EXPORT_SYMBOL_PROTO(__errno_location);
43
44EXPORT_SYMBOL_PROTO(access);
45EXPORT_SYMBOL_PROTO(open);
46EXPORT_SYMBOL_PROTO(open64);
47EXPORT_SYMBOL_PROTO(close);
48EXPORT_SYMBOL_PROTO(read);
49EXPORT_SYMBOL_PROTO(write);
50EXPORT_SYMBOL_PROTO(dup2);
51EXPORT_SYMBOL_PROTO(__xstat);
52EXPORT_SYMBOL_PROTO(__lxstat);
53EXPORT_SYMBOL_PROTO(__lxstat64);
54EXPORT_SYMBOL_PROTO(lseek);
55EXPORT_SYMBOL_PROTO(lseek64);
56EXPORT_SYMBOL_PROTO(chown);
57EXPORT_SYMBOL_PROTO(truncate);
58EXPORT_SYMBOL_PROTO(utime);
59EXPORT_SYMBOL_PROTO(chmod);
60EXPORT_SYMBOL_PROTO(rename);
61EXPORT_SYMBOL_PROTO(__xmknod);
62
63EXPORT_SYMBOL_PROTO(symlink);
64EXPORT_SYMBOL_PROTO(link);
65EXPORT_SYMBOL_PROTO(unlink);
66EXPORT_SYMBOL_PROTO(readlink);
67
68EXPORT_SYMBOL_PROTO(mkdir);
69EXPORT_SYMBOL_PROTO(rmdir);
70EXPORT_SYMBOL_PROTO(opendir);
71EXPORT_SYMBOL_PROTO(readdir);
72EXPORT_SYMBOL_PROTO(closedir);
73EXPORT_SYMBOL_PROTO(seekdir);
74EXPORT_SYMBOL_PROTO(telldir);
75
76EXPORT_SYMBOL_PROTO(ioctl);
77
78EXPORT_SYMBOL_PROTO(pread64);
79EXPORT_SYMBOL_PROTO(pwrite64);
80
81EXPORT_SYMBOL_PROTO(statfs);
82EXPORT_SYMBOL_PROTO(statfs64);
83
84EXPORT_SYMBOL_PROTO(getuid);
85
86/*
87 * Overrides for Emacs so that we follow Linus's tabbing style.
88 * Emacs will notice this stuff at the end of the file and automatically
89 * adjust the settings for this buffer only. This must remain at the end
90 * of the file.
91 * ---------------------------------------------------------------------------
92 * Local variables:
93 * c-file-style: "linux"
94 * End:
95 */
diff --git a/arch/um/os-Linux/util/Makefile b/arch/um/os-Linux/util/Makefile
new file mode 100644
index 000000000000..fb00ddf969bd
--- /dev/null
+++ b/arch/um/os-Linux/util/Makefile
@@ -0,0 +1,4 @@
1hostprogs-y := mk_user_constants
2always := $(hostprogs-y)
3
4mk_user_constants-objs := mk_user_constants.o
diff --git a/arch/um/os-Linux/util/mk_user_constants.c b/arch/um/os-Linux/util/mk_user_constants.c
new file mode 100644
index 000000000000..0933518aa8bd
--- /dev/null
+++ b/arch/um/os-Linux/util/mk_user_constants.c
@@ -0,0 +1,29 @@
1#include <stdio.h>
2#include <asm/types.h>
3/* For some reason, x86_64 nowhere defines u64 and u32, even though they're
4 * used throughout the headers.
5 */
6typedef __u64 u64;
7typedef __u32 u32;
8#include <asm/user.h>
9
10int main(int argc, char **argv)
11{
12 printf("/*\n");
13 printf(" * Generated by mk_user_constants\n");
14 printf(" */\n");
15 printf("\n");
16 printf("#ifndef __UM_USER_CONSTANTS_H\n");
17 printf("#define __UM_USER_CONSTANTS_H\n");
18 printf("\n");
19 /* I'd like to use FRAME_SIZE from ptrace.h here, but that's wrong on
20 * x86_64 (216 vs 168 bytes). user_regs_struct is the correct size on
21 * both x86_64 and i386.
22 */
23 printf("#define UM_FRAME_SIZE %d\n", (int) sizeof(struct user_regs_struct));
24
25 printf("\n");
26 printf("#endif\n");
27
28 return(0);
29}
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
new file mode 100644
index 000000000000..143f6fea0763
--- /dev/null
+++ b/arch/um/scripts/Makefile.rules
@@ -0,0 +1,13 @@
1# ===========================================================================
2# arch/um: Generic definitions
3# ===========================================================================
4
5USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
6USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS))
7
8USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
9
10$(USER_OBJS): c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(notdir $@))
11
12quiet_cmd_make_link = SYMLINK $@
13cmd_make_link = rm -f $@; ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
new file mode 100644
index 000000000000..71b47e618605
--- /dev/null
+++ b/arch/um/sys-i386/Makefile
@@ -0,0 +1,29 @@
1obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
2 ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o
3
4obj-$(CONFIG_HIGHMEM) += highmem.o
5obj-$(CONFIG_MODULES) += module.o
6
7USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
8
9include arch/um/scripts/Makefile.rules
10
11SYMLINKS = bitops.c semaphore.c highmem.c module.c
12
13# this needs to be before the foreach, because clean-files does not accept
14# complete paths like $(src)/$f.
15clean-files := $(SYMLINKS)
16
17targets += $(SYMLINKS)
18
19SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$f)
20
21bitops.c-dir = lib
22semaphore.c-dir = kernel
23highmem.c-dir = mm
24module.c-dir = kernel
25
26$(SYMLINKS): FORCE
27 $(call if_changed,make_link)
28
29subdir- := util
diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
new file mode 100644
index 000000000000..41b0ab2fe830
--- /dev/null
+++ b/arch/um/sys-i386/bugs.c
@@ -0,0 +1,222 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <errno.h>
8#include <string.h>
9#include <sys/signal.h>
10#include <asm/ldt.h>
11#include "kern_util.h"
12#include "user.h"
13#include "sysdep/ptrace.h"
14#include "task.h"
15#include "os.h"
16
17#define MAXTOKEN 64
18
19/* Set during early boot */
20int host_has_cmov = 1;
21int host_has_xmm = 0;
22
23static char token(int fd, char *buf, int len, char stop)
24{
25 int n;
26 char *ptr, *end, c;
27
28 ptr = buf;
29 end = &buf[len];
30 do {
31 n = os_read_file(fd, ptr, sizeof(*ptr));
32 c = *ptr++;
33 if(n != sizeof(*ptr)){
34 if(n == 0) return(0);
35 printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
36 if(n < 0)
37 return(n);
38 else
39 return(-EIO);
40 }
41 } while((c != '\n') && (c != stop) && (ptr < end));
42
43 if(ptr == end){
44 printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
45 return(-1);
46 }
47 *(ptr - 1) = '\0';
48 return(c);
49}
50
51static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
52{
53 int n;
54 char c;
55
56 scratch[len - 1] = '\0';
57 while(1){
58 c = token(fd, scratch, len - 1, ':');
59 if(c <= 0)
60 return(0);
61 else if(c != ':'){
62 printk("Failed to find ':' in /proc/cpuinfo\n");
63 return(0);
64 }
65
66 if(!strncmp(scratch, key, strlen(key)))
67 return(1);
68
69 do {
70 n = os_read_file(fd, &c, sizeof(c));
71 if(n != sizeof(c)){
72 printk("Failed to find newline in "
73 "/proc/cpuinfo, err = %d\n", -n);
74 return(0);
75 }
76 } while(c != '\n');
77 }
78 return(0);
79}
80
81int cpu_feature(char *what, char *buf, int len)
82{
83 int fd, ret = 0;
84
85 fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
86 if(fd < 0){
87 printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
88 return(0);
89 }
90
91 if(!find_cpuinfo_line(fd, what, buf, len)){
92 printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
93 goto out_close;
94 }
95
96 token(fd, buf, len, '\n');
97 ret = 1;
98
99 out_close:
100 os_close_file(fd);
101 return(ret);
102}
103
104static int check_cpu_flag(char *feature, int *have_it)
105{
106 char buf[MAXTOKEN], c;
107 int fd, len = sizeof(buf)/sizeof(buf[0]);
108
109 printk("Checking for host processor %s support...", feature);
110 fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
111 if(fd < 0){
112 printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
113 return(0);
114 }
115
116 *have_it = 0;
117 if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0])))
118 goto out;
119
120 c = token(fd, buf, len - 1, ' ');
121 if(c < 0) goto out;
122 else if(c != ' '){
123 printk("Failed to find ' ' in /proc/cpuinfo\n");
124 goto out;
125 }
126
127 while(1){
128 c = token(fd, buf, len - 1, ' ');
129 if(c < 0) goto out;
130 else if(c == '\n') break;
131
132 if(!strcmp(buf, feature)){
133 *have_it = 1;
134 goto out;
135 }
136 }
137 out:
138 if(*have_it == 0) printk("No\n");
139 else if(*have_it == 1) printk("Yes\n");
140 os_close_file(fd);
141 return(1);
142}
143
144#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
145 * for some people.
146 */
147static void disable_lcall(void)
148{
149 struct modify_ldt_ldt_s ldt;
150 int err;
151
152 bzero(&ldt, sizeof(ldt));
153 ldt.entry_number = 7;
154 ldt.base_addr = 0;
155 ldt.limit = 0;
156 err = modify_ldt(1, &ldt, sizeof(ldt));
157 if(err)
158 printk("Failed to disable lcall7 - errno = %d\n", errno);
159}
160#endif
161
162void arch_init_thread(void)
163{
164#if 0
165 disable_lcall();
166#endif
167}
168
169void arch_check_bugs(void)
170{
171 int have_it;
172
173 if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){
174 printk("/proc/cpuinfo not available - skipping CPU capability "
175 "checks\n");
176 return;
177 }
178 if(check_cpu_flag("cmov", &have_it))
179 host_has_cmov = have_it;
180 if(check_cpu_flag("xmm", &have_it))
181 host_has_xmm = have_it;
182}
183
184int arch_handle_signal(int sig, union uml_pt_regs *regs)
185{
186 unsigned char tmp[2];
187
188 /* This is testing for a cmov (0x0f 0x4x) instruction causing a
189 * SIGILL in init.
190 */
191 if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
192
193 if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
194 panic("SIGILL in init, could not read instructions!\n");
195 if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
196 return(0);
197
198 if(host_has_cmov == 0)
199 panic("SIGILL caused by cmov, which this processor doesn't "
200 "implement, boot a filesystem compiled for older "
201 "processors");
202 else if(host_has_cmov == 1)
203 panic("SIGILL caused by cmov, which this processor claims to "
204 "implement");
205 else if(host_has_cmov == -1)
206 panic("SIGILL caused by cmov, couldn't tell if this processor "
207 "implements it, boot a filesystem compiled for older "
208 "processors");
209 else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
210 return(0);
211}
212
213/*
214 * Overrides for Emacs so that we follow Linus's tabbing style.
215 * Emacs will notice this stuff at the end of the file and automatically
216 * adjust the settings for this buffer only. This must remain at the end
217 * of the file.
218 * ---------------------------------------------------------------------------
219 * Local variables:
220 * c-file-style: "linux"
221 * End:
222 */
diff --git a/arch/um/sys-i386/checksum.S b/arch/um/sys-i386/checksum.S
new file mode 100644
index 000000000000..a11171fb6223
--- /dev/null
+++ b/arch/um/sys-i386/checksum.S
@@ -0,0 +1,460 @@
1/*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * IP/TCP/UDP checksumming routines
7 *
8 * Authors: Jorge Cwik, <jorge@laser.satlink.net>
9 * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
10 * Tom May, <ftom@netcom.com>
11 * Pentium Pro/II routines:
12 * Alexander Kjeldaas <astor@guardian.no>
13 * Finn Arne Gangstad <finnag@guardian.no>
14 * Lots of code moved from tcp.c and ip.c; see those files
15 * for more names.
16 *
17 * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception
18 * handling.
19 * Andi Kleen, add zeroing on error
20 * converted to pure assembler
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version
25 * 2 of the License, or (at your option) any later version.
26 */
27
28#include <linux/config.h>
29#include <asm/errno.h>
30
31/*
32 * computes a partial checksum, e.g. for TCP/UDP fragments
33 */
34
35/*
36unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
37 */
38
39.text
40.align 4
41.globl arch_csum_partial
42
43#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
44
45 /*
46 * Experiments with Ethernet and SLIP connections show that buff
47 * is aligned on either a 2-byte or 4-byte boundary. We get at
48 * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
49 * Fortunately, it is easy to convert 2-byte alignment to 4-byte
50 * alignment for the unrolled loop.
51 */
52arch_csum_partial:
53 pushl %esi
54 pushl %ebx
55 movl 20(%esp),%eax # Function arg: unsigned int sum
56 movl 16(%esp),%ecx # Function arg: int len
57 movl 12(%esp),%esi # Function arg: unsigned char *buff
58 testl $2, %esi # Check alignment.
59 jz 2f # Jump if alignment is ok.
60 subl $2, %ecx # Alignment uses up two bytes.
61 jae 1f # Jump if we had at least two bytes.
62 addl $2, %ecx # ecx was < 2. Deal with it.
63 jmp 4f
641: movw (%esi), %bx
65 addl $2, %esi
66 addw %bx, %ax
67 adcl $0, %eax
682:
69 movl %ecx, %edx
70 shrl $5, %ecx
71 jz 2f
72 testl %esi, %esi
731: movl (%esi), %ebx
74 adcl %ebx, %eax
75 movl 4(%esi), %ebx
76 adcl %ebx, %eax
77 movl 8(%esi), %ebx
78 adcl %ebx, %eax
79 movl 12(%esi), %ebx
80 adcl %ebx, %eax
81 movl 16(%esi), %ebx
82 adcl %ebx, %eax
83 movl 20(%esi), %ebx
84 adcl %ebx, %eax
85 movl 24(%esi), %ebx
86 adcl %ebx, %eax
87 movl 28(%esi), %ebx
88 adcl %ebx, %eax
89 lea 32(%esi), %esi
90 dec %ecx
91 jne 1b
92 adcl $0, %eax
932: movl %edx, %ecx
94 andl $0x1c, %edx
95 je 4f
96 shrl $2, %edx # This clears CF
973: adcl (%esi), %eax
98 lea 4(%esi), %esi
99 dec %edx
100 jne 3b
101 adcl $0, %eax
1024: andl $3, %ecx
103 jz 7f
104 cmpl $2, %ecx
105 jb 5f
106 movw (%esi),%cx
107 leal 2(%esi),%esi
108 je 6f
109 shll $16,%ecx
1105: movb (%esi),%cl
1116: addl %ecx,%eax
112 adcl $0, %eax
1137:
114 popl %ebx
115 popl %esi
116 ret
117
118#else
119
120/* Version for PentiumII/PPro */
121
122arch_csum_partial:
123 pushl %esi
124 pushl %ebx
125 movl 20(%esp),%eax # Function arg: unsigned int sum
126 movl 16(%esp),%ecx # Function arg: int len
127 movl 12(%esp),%esi # Function arg: const unsigned char *buf
128
129 testl $2, %esi
130 jnz 30f
13110:
132 movl %ecx, %edx
133 movl %ecx, %ebx
134 andl $0x7c, %ebx
135 shrl $7, %ecx
136 addl %ebx,%esi
137 shrl $2, %ebx
138 negl %ebx
139 lea 45f(%ebx,%ebx,2), %ebx
140 testl %esi, %esi
141 jmp *%ebx
142
143 # Handle 2-byte-aligned regions
14420: addw (%esi), %ax
145 lea 2(%esi), %esi
146 adcl $0, %eax
147 jmp 10b
148
14930: subl $2, %ecx
150 ja 20b
151 je 32f
152 movzbl (%esi),%ebx # csumming 1 byte, 2-aligned
153 addl %ebx, %eax
154 adcl $0, %eax
155 jmp 80f
15632:
157 addw (%esi), %ax # csumming 2 bytes, 2-aligned
158 adcl $0, %eax
159 jmp 80f
160
16140:
162 addl -128(%esi), %eax
163 adcl -124(%esi), %eax
164 adcl -120(%esi), %eax
165 adcl -116(%esi), %eax
166 adcl -112(%esi), %eax
167 adcl -108(%esi), %eax
168 adcl -104(%esi), %eax
169 adcl -100(%esi), %eax
170 adcl -96(%esi), %eax
171 adcl -92(%esi), %eax
172 adcl -88(%esi), %eax
173 adcl -84(%esi), %eax
174 adcl -80(%esi), %eax
175 adcl -76(%esi), %eax
176 adcl -72(%esi), %eax
177 adcl -68(%esi), %eax
178 adcl -64(%esi), %eax
179 adcl -60(%esi), %eax
180 adcl -56(%esi), %eax
181 adcl -52(%esi), %eax
182 adcl -48(%esi), %eax
183 adcl -44(%esi), %eax
184 adcl -40(%esi), %eax
185 adcl -36(%esi), %eax
186 adcl -32(%esi), %eax
187 adcl -28(%esi), %eax
188 adcl -24(%esi), %eax
189 adcl -20(%esi), %eax
190 adcl -16(%esi), %eax
191 adcl -12(%esi), %eax
192 adcl -8(%esi), %eax
193 adcl -4(%esi), %eax
19445:
195 lea 128(%esi), %esi
196 adcl $0, %eax
197 dec %ecx
198 jge 40b
199 movl %edx, %ecx
20050: andl $3, %ecx
201 jz 80f
202
203 # Handle the last 1-3 bytes without jumping
204 notl %ecx # 1->2, 2->1, 3->0, higher bits are masked
205 movl $0xffffff,%ebx # by the shll and shrl instructions
206 shll $3,%ecx
207 shrl %cl,%ebx
208 andl -128(%esi),%ebx # esi is 4-aligned so should be ok
209 addl %ebx,%eax
210 adcl $0,%eax
21180:
212 popl %ebx
213 popl %esi
214 ret
215
216#endif
217
218/*
219unsigned int csum_partial_copy_generic (const char *src, char *dst,
220 int len, int sum, int *src_err_ptr, int *dst_err_ptr)
221 */
222
223/*
224 * Copy from ds while checksumming, otherwise like csum_partial
225 *
226 * The macros SRC and DST specify the type of access for the instruction.
227 * thus we can call a custom exception handler for all access types.
228 *
229 * FIXME: could someone double-check whether I haven't mixed up some SRC and
230 * DST definitions? It's damn hard to trigger all cases. I hope I got
231 * them all but there's no guarantee.
232 */
233
234#define SRC(y...) \
235 9999: y; \
236 .section __ex_table, "a"; \
237 .long 9999b, 6001f ; \
238 .previous
239
240#define DST(y...) \
241 9999: y; \
242 .section __ex_table, "a"; \
243 .long 9999b, 6002f ; \
244 .previous
245
246.align 4
247.globl csum_partial_copy_generic_i386
248
249#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
250
251#define ARGBASE 16
252#define FP 12
253
254csum_partial_copy_generic_i386:
255 subl $4,%esp
256 pushl %edi
257 pushl %esi
258 pushl %ebx
259 movl ARGBASE+16(%esp),%eax # sum
260 movl ARGBASE+12(%esp),%ecx # len
261 movl ARGBASE+4(%esp),%esi # src
262 movl ARGBASE+8(%esp),%edi # dst
263
264 testl $2, %edi # Check alignment.
265 jz 2f # Jump if alignment is ok.
266 subl $2, %ecx # Alignment uses up two bytes.
267 jae 1f # Jump if we had at least two bytes.
268 addl $2, %ecx # ecx was < 2. Deal with it.
269 jmp 4f
270SRC(1: movw (%esi), %bx )
271 addl $2, %esi
272DST( movw %bx, (%edi) )
273 addl $2, %edi
274 addw %bx, %ax
275 adcl $0, %eax
2762:
277 movl %ecx, FP(%esp)
278 shrl $5, %ecx
279 jz 2f
280 testl %esi, %esi
281SRC(1: movl (%esi), %ebx )
282SRC( movl 4(%esi), %edx )
283 adcl %ebx, %eax
284DST( movl %ebx, (%edi) )
285 adcl %edx, %eax
286DST( movl %edx, 4(%edi) )
287
288SRC( movl 8(%esi), %ebx )
289SRC( movl 12(%esi), %edx )
290 adcl %ebx, %eax
291DST( movl %ebx, 8(%edi) )
292 adcl %edx, %eax
293DST( movl %edx, 12(%edi) )
294
295SRC( movl 16(%esi), %ebx )
296SRC( movl 20(%esi), %edx )
297 adcl %ebx, %eax
298DST( movl %ebx, 16(%edi) )
299 adcl %edx, %eax
300DST( movl %edx, 20(%edi) )
301
302SRC( movl 24(%esi), %ebx )
303SRC( movl 28(%esi), %edx )
304 adcl %ebx, %eax
305DST( movl %ebx, 24(%edi) )
306 adcl %edx, %eax
307DST( movl %edx, 28(%edi) )
308
309 lea 32(%esi), %esi
310 lea 32(%edi), %edi
311 dec %ecx
312 jne 1b
313 adcl $0, %eax
3142: movl FP(%esp), %edx
315 movl %edx, %ecx
316 andl $0x1c, %edx
317 je 4f
318 shrl $2, %edx # This clears CF
319SRC(3: movl (%esi), %ebx )
320 adcl %ebx, %eax
321DST( movl %ebx, (%edi) )
322 lea 4(%esi), %esi
323 lea 4(%edi), %edi
324 dec %edx
325 jne 3b
326 adcl $0, %eax
3274: andl $3, %ecx
328 jz 7f
329 cmpl $2, %ecx
330 jb 5f
331SRC( movw (%esi), %cx )
332 leal 2(%esi), %esi
333DST( movw %cx, (%edi) )
334 leal 2(%edi), %edi
335 je 6f
336 shll $16,%ecx
337SRC(5: movb (%esi), %cl )
338DST( movb %cl, (%edi) )
3396: addl %ecx, %eax
340 adcl $0, %eax
3417:
3425000:
343
344# Exception handler:
345.section .fixup, "ax"
346
3476001:
348 movl ARGBASE+20(%esp), %ebx # src_err_ptr
349 movl $-EFAULT, (%ebx)
350
351 # zero the complete destination - computing the rest
352 # is too much work
353 movl ARGBASE+8(%esp), %edi # dst
354 movl ARGBASE+12(%esp), %ecx # len
355 xorl %eax,%eax
356 rep ; stosb
357
358 jmp 5000b
359
3606002:
361 movl ARGBASE+24(%esp), %ebx # dst_err_ptr
362 movl $-EFAULT,(%ebx)
363 jmp 5000b
364
365.previous
366
367 popl %ebx
368 popl %esi
369 popl %edi
370 popl %ecx # equivalent to addl $4,%esp
371 ret
372
373#else
374
375/* Version for PentiumII/PPro */
376
377#define ROUND1(x) \
378 SRC(movl x(%esi), %ebx ) ; \
379 addl %ebx, %eax ; \
380 DST(movl %ebx, x(%edi) ) ;
381
382#define ROUND(x) \
383 SRC(movl x(%esi), %ebx ) ; \
384 adcl %ebx, %eax ; \
385 DST(movl %ebx, x(%edi) ) ;
386
387#define ARGBASE 12
388
389csum_partial_copy_generic_i386:
390 pushl %ebx
391 pushl %edi
392 pushl %esi
393 movl ARGBASE+4(%esp),%esi #src
394 movl ARGBASE+8(%esp),%edi #dst
395 movl ARGBASE+12(%esp),%ecx #len
396 movl ARGBASE+16(%esp),%eax #sum
397# movl %ecx, %edx
398 movl %ecx, %ebx
399 movl %esi, %edx
400 shrl $6, %ecx
401 andl $0x3c, %ebx
402 negl %ebx
403 subl %ebx, %esi
404 subl %ebx, %edi
405 lea -1(%esi),%edx
406 andl $-32,%edx
407 lea 3f(%ebx,%ebx), %ebx
408 testl %esi, %esi
409 jmp *%ebx
4101: addl $64,%esi
411 addl $64,%edi
412 SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
413 ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
414 ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
415 ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
416 ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4)
4173: adcl $0,%eax
418 addl $64, %edx
419 dec %ecx
420 jge 1b
4214: movl ARGBASE+12(%esp),%edx #len
422 andl $3, %edx
423 jz 7f
424 cmpl $2, %edx
425 jb 5f
426SRC( movw (%esi), %dx )
427 leal 2(%esi), %esi
428DST( movw %dx, (%edi) )
429 leal 2(%edi), %edi
430 je 6f
431 shll $16,%edx
4325:
433SRC( movb (%esi), %dl )
434DST( movb %dl, (%edi) )
4356: addl %edx, %eax
436 adcl $0, %eax
4377:
438.section .fixup, "ax"
4396001: movl ARGBASE+20(%esp), %ebx # src_err_ptr
440 movl $-EFAULT, (%ebx)
441 # zero the complete destination (computing the rest is too much work)
442 movl ARGBASE+8(%esp),%edi # dst
443 movl ARGBASE+12(%esp),%ecx # len
444 xorl %eax,%eax
445 rep; stosb
446 jmp 7b
4476002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr
448 movl $-EFAULT, (%ebx)
449 jmp 7b
450.previous
451
452 popl %esi
453 popl %edi
454 popl %ebx
455 ret
456
457#undef ROUND
458#undef ROUND1
459
460#endif
diff --git a/arch/um/sys-i386/delay.c b/arch/um/sys-i386/delay.c
new file mode 100644
index 000000000000..20d37dbbaf08
--- /dev/null
+++ b/arch/um/sys-i386/delay.c
@@ -0,0 +1,14 @@
1void __delay(unsigned long time)
2{
3 /* Stolen from the i386 __loop_delay */
4 int d0;
5 __asm__ __volatile__(
6 "\tjmp 1f\n"
7 ".align 16\n"
8 "1:\tjmp 2f\n"
9 ".align 16\n"
10 "2:\tdecl %0\n\tjns 2b"
11 :"=&a" (d0)
12 :"0" (time));
13}
14
diff --git a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c
new file mode 100644
index 000000000000..d0bbcdfdb53f
--- /dev/null
+++ b/arch/um/sys-i386/fault.c
@@ -0,0 +1,42 @@
1/*
2 * Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <signal.h>
7#include "sysdep/ptrace.h"
8#include "sysdep/sigcontext.h"
9
10/* These two are from asm-um/uaccess.h and linux/module.h, check them. */
11struct exception_table_entry
12{
13 unsigned long insn;
14 unsigned long fixup;
15};
16
17const struct exception_table_entry *search_exception_tables(unsigned long add);
18
19/* Compare this to arch/i386/mm/extable.c:fixup_exception() */
20int arch_fixup(unsigned long address, void *sc_ptr)
21{
22 struct sigcontext *sc = sc_ptr;
23 const struct exception_table_entry *fixup;
24
25 fixup = search_exception_tables(address);
26 if(fixup != 0){
27 sc->eip = fixup->fixup;
28 return(1);
29 }
30 return(0);
31}
32
33/*
34 * Overrides for Emacs so that we follow Linus's tabbing style.
35 * Emacs will notice this stuff at the end of the file and automatically
36 * adjust the settings for this buffer only. This must remain at the end
37 * of the file.
38 * ---------------------------------------------------------------------------
39 * Local variables:
40 * c-file-style: "linux"
41 * End:
42 */
diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c
new file mode 100644
index 000000000000..74f70a120458
--- /dev/null
+++ b/arch/um/sys-i386/ksyms.c
@@ -0,0 +1,17 @@
1#include "linux/module.h"
2#include "linux/in6.h"
3#include "linux/rwsem.h"
4#include "asm/byteorder.h"
5#include "asm/semaphore.h"
6#include "asm/uaccess.h"
7#include "asm/checksum.h"
8#include "asm/errno.h"
9
10EXPORT_SYMBOL(__down_failed);
11EXPORT_SYMBOL(__down_failed_interruptible);
12EXPORT_SYMBOL(__down_failed_trylock);
13EXPORT_SYMBOL(__up_wakeup);
14
15/* Networking helper routines. */
16EXPORT_SYMBOL(csum_partial_copy_from);
17EXPORT_SYMBOL(csum_partial_copy_to);
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
new file mode 100644
index 000000000000..31bcb2f997d4
--- /dev/null
+++ b/arch/um/sys-i386/ldt.c
@@ -0,0 +1,98 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/slab.h"
8#include "asm/uaccess.h"
9#include "asm/ptrace.h"
10#include "choose-mode.h"
11#include "kern.h"
12
13#ifdef CONFIG_MODE_TT
14extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
15
16/* XXX this needs copy_to_user and copy_from_user */
17
18int sys_modify_ldt_tt(int func, void __user *ptr, unsigned long bytecount)
19{
20 if (!access_ok(VERIFY_READ, ptr, bytecount))
21 return -EFAULT;
22
23 return modify_ldt(func, ptr, bytecount);
24}
25#endif
26
27#ifdef CONFIG_MODE_SKAS
28extern int userspace_pid;
29
30#include "skas_ptrace.h"
31
32int sys_modify_ldt_skas(int func, void __user *ptr, unsigned long bytecount)
33{
34 struct ptrace_ldt ldt;
35 void *buf;
36 int res, n;
37
38 buf = kmalloc(bytecount, GFP_KERNEL);
39 if(buf == NULL)
40 return(-ENOMEM);
41
42 res = 0;
43
44 switch(func){
45 case 1:
46 case 0x11:
47 res = copy_from_user(buf, ptr, bytecount);
48 break;
49 }
50
51 if(res != 0){
52 res = -EFAULT;
53 goto out;
54 }
55
56 ldt = ((struct ptrace_ldt) { .func = func,
57 .ptr = buf,
58 .bytecount = bytecount });
59 res = ptrace(PTRACE_LDT, userspace_pid, 0, (unsigned long) &ldt);
60 if(res < 0)
61 goto out;
62
63 switch(func){
64 case 0:
65 case 2:
66 n = res;
67 res = copy_to_user(ptr, buf, n);
68 if(res != 0)
69 res = -EFAULT;
70 else
71 res = n;
72 break;
73 }
74
75 out:
76 kfree(buf);
77 return(res);
78}
79#endif
80
81int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
82{
83 return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func,
84 ptr, bytecount));
85}
86
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/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
new file mode 100644
index 000000000000..e470d28cdf84
--- /dev/null
+++ b/arch/um/sys-i386/ptrace.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/config.h>
7#include <linux/compiler.h>
8#include "linux/sched.h"
9#include "asm/elf.h"
10#include "asm/ptrace.h"
11#include "asm/uaccess.h"
12#include "asm/unistd.h"
13#include "sysdep/ptrace.h"
14#include "sysdep/sigcontext.h"
15#include "sysdep/sc.h"
16
17void arch_switch(void)
18{
19 update_debugregs(current->thread.arch.debugregs_seq);
20}
21
22int is_syscall(unsigned long addr)
23{
24 unsigned short instr;
25 int n;
26
27 n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
28 if(n){
29 printk("is_syscall : failed to read instruction from 0x%lx\n",
30 addr);
31 return(0);
32 }
33 /* int 0x80 or sysenter */
34 return((instr == 0x80cd) || (instr == 0x340f));
35}
36
37/* determines which flags the user has access to. */
38/* 1 = access 0 = no access */
39#define FLAG_MASK 0x00044dd5
40
41int putreg(struct task_struct *child, int regno, unsigned long value)
42{
43 regno >>= 2;
44 switch (regno) {
45 case FS:
46 if (value && (value & 3) != 3)
47 return -EIO;
48 PT_REGS_FS(&child->thread.regs) = value;
49 return 0;
50 case GS:
51 if (value && (value & 3) != 3)
52 return -EIO;
53 PT_REGS_GS(&child->thread.regs) = value;
54 return 0;
55 case DS:
56 case ES:
57 if (value && (value & 3) != 3)
58 return -EIO;
59 value &= 0xffff;
60 break;
61 case SS:
62 case CS:
63 if ((value & 3) != 3)
64 return -EIO;
65 value &= 0xffff;
66 break;
67 case EFL:
68 value &= FLAG_MASK;
69 value |= PT_REGS_EFLAGS(&child->thread.regs);
70 break;
71 }
72 PT_REGS_SET(&child->thread.regs, regno, value);
73 return 0;
74}
75
76unsigned long getreg(struct task_struct *child, int regno)
77{
78 unsigned long retval = ~0UL;
79
80 regno >>= 2;
81 switch (regno) {
82 case FS:
83 case GS:
84 case DS:
85 case ES:
86 case SS:
87 case CS:
88 retval = 0xffff;
89 /* fall through */
90 default:
91 retval &= PT_REG(&child->thread.regs, regno);
92 }
93 return retval;
94}
95
96struct i387_fxsave_struct {
97 unsigned short cwd;
98 unsigned short swd;
99 unsigned short twd;
100 unsigned short fop;
101 long fip;
102 long fcs;
103 long foo;
104 long fos;
105 long mxcsr;
106 long reserved;
107 long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
108 long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
109 long padding[56];
110};
111
112/*
113 * FPU tag word conversions.
114 */
115
116static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
117{
118 unsigned int tmp; /* to avoid 16 bit prefixes in the code */
119
120 /* Transform each pair of bits into 01 (valid) or 00 (empty) */
121 tmp = ~twd;
122 tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
123 /* and move the valid bits to the lower byte. */
124 tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
125 tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
126 tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
127 return tmp;
128}
129
130static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave )
131{
132 struct _fpxreg *st = NULL;
133 unsigned long twd = (unsigned long) fxsave->twd;
134 unsigned long tag;
135 unsigned long ret = 0xffff0000;
136 int i;
137
138#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16);
139
140 for ( i = 0 ; i < 8 ; i++ ) {
141 if ( twd & 0x1 ) {
142 st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
143
144 switch ( st->exponent & 0x7fff ) {
145 case 0x7fff:
146 tag = 2; /* Special */
147 break;
148 case 0x0000:
149 if ( !st->significand[0] &&
150 !st->significand[1] &&
151 !st->significand[2] &&
152 !st->significand[3] ) {
153 tag = 1; /* Zero */
154 } else {
155 tag = 2; /* Special */
156 }
157 break;
158 default:
159 if ( st->significand[3] & 0x8000 ) {
160 tag = 0; /* Valid */
161 } else {
162 tag = 2; /* Special */
163 }
164 break;
165 }
166 } else {
167 tag = 3; /* Empty */
168 }
169 ret |= (tag << (2 * i));
170 twd = twd >> 1;
171 }
172 return ret;
173}
174
175/*
176 * FXSR floating point environment conversions.
177 */
178
179#ifdef CONFIG_MODE_TT
180static inline int convert_fxsr_to_user_tt(struct _fpstate __user *buf,
181 struct pt_regs *regs)
182{
183 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
184 unsigned long env[7];
185 struct _fpreg __user *to;
186 struct _fpxreg *from;
187 int i;
188
189 env[0] = (unsigned long)fxsave->cwd | 0xffff0000;
190 env[1] = (unsigned long)fxsave->swd | 0xffff0000;
191 env[2] = twd_fxsr_to_i387(fxsave);
192 env[3] = fxsave->fip;
193 env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
194 env[5] = fxsave->foo;
195 env[6] = fxsave->fos;
196
197 if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
198 return 1;
199
200 to = &buf->_st[0];
201 from = (struct _fpxreg *) &fxsave->st_space[0];
202 for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
203 if ( __copy_to_user( to, from, sizeof(*to) ) )
204 return 1;
205 }
206 return 0;
207}
208#endif
209
210static inline int convert_fxsr_to_user(struct _fpstate __user *buf,
211 struct pt_regs *regs)
212{
213 return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0));
214}
215
216#ifdef CONFIG_MODE_TT
217static inline int convert_fxsr_from_user_tt(struct pt_regs *regs,
218 struct _fpstate __user *buf)
219{
220 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
221 unsigned long env[7];
222 struct _fpxreg *to;
223 struct _fpreg __user *from;
224 int i;
225
226 if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
227 return 1;
228
229 fxsave->cwd = (unsigned short)(env[0] & 0xffff);
230 fxsave->swd = (unsigned short)(env[1] & 0xffff);
231 fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
232 fxsave->fip = env[3];
233 fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16);
234 fxsave->fcs = (env[4] & 0xffff);
235 fxsave->foo = env[5];
236 fxsave->fos = env[6];
237
238 to = (struct _fpxreg *) &fxsave->st_space[0];
239 from = &buf->_st[0];
240 for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
241 if ( __copy_from_user( to, from, sizeof(*from) ) )
242 return 1;
243 }
244 return 0;
245}
246#endif
247
248static inline int convert_fxsr_from_user(struct pt_regs *regs,
249 struct _fpstate __user *buf)
250{
251 return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0));
252}
253
254int get_fpregs(unsigned long buf, struct task_struct *child)
255{
256 int err;
257
258 err = convert_fxsr_to_user((struct _fpstate __user *) buf,
259 &child->thread.regs);
260 if(err) return(-EFAULT);
261 else return(0);
262}
263
264int set_fpregs(unsigned long buf, struct task_struct *child)
265{
266 int err;
267
268 err = convert_fxsr_from_user(&child->thread.regs,
269 (struct _fpstate __user *) buf);
270 if(err) return(-EFAULT);
271 else return(0);
272}
273
274#ifdef CONFIG_MODE_TT
275int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
276{
277 struct pt_regs *regs = &tsk->thread.regs;
278 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
279 int err;
280
281 err = __copy_to_user((void __user *) buf, fxsave,
282 sizeof(struct user_fxsr_struct));
283 if(err) return -EFAULT;
284 else return 0;
285}
286#endif
287
288int get_fpxregs(unsigned long buf, struct task_struct *tsk)
289{
290 return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0));
291}
292
293#ifdef CONFIG_MODE_TT
294int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
295{
296 struct pt_regs *regs = &tsk->thread.regs;
297 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
298 int err;
299
300 err = __copy_from_user(fxsave, (void __user *) buf,
301 sizeof(struct user_fxsr_struct) );
302 if(err) return -EFAULT;
303 else return 0;
304}
305#endif
306
307int set_fpxregs(unsigned long buf, struct task_struct *tsk)
308{
309 return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0));
310}
311
312#ifdef notdef
313int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
314{
315 fpu->cwd = (((SC_FP_CW(PT_REGS_SC(regs)) & 0xffff) << 16) |
316 (SC_FP_SW(PT_REGS_SC(regs)) & 0xffff));
317 fpu->swd = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
318 fpu->twd = SC_FP_IPOFF(PT_REGS_SC(regs));
319 fpu->fip = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
320 fpu->fcs = SC_FP_DATAOFF(PT_REGS_SC(regs));
321 fpu->foo = SC_FP_DATASEL(PT_REGS_SC(regs));
322 fpu->fos = 0;
323 memcpy(fpu->st_space, (void *) SC_FP_ST(PT_REGS_SC(regs)),
324 sizeof(fpu->st_space));
325 return(1);
326}
327#endif
328
329#ifdef CONFIG_MODE_TT
330static inline void copy_fpu_fxsave_tt(struct pt_regs *regs,
331 struct user_i387_struct *buf)
332{
333 struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs));
334 unsigned short *to;
335 unsigned short *from;
336 int i;
337
338 memcpy( buf, fpu, 7 * sizeof(long) );
339
340 to = (unsigned short *) &buf->st_space[0];
341 from = (unsigned short *) &fpu->st_space[0];
342 for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) {
343 memcpy( to, from, 5 * sizeof(unsigned short) );
344 }
345}
346#endif
347
348static inline void copy_fpu_fxsave(struct pt_regs *regs,
349 struct user_i387_struct *buf)
350{
351 (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0);
352}
353
354int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
355{
356 copy_fpu_fxsave(regs, (struct user_i387_struct *) fpu);
357 return(1);
358}
359
360/*
361 * Overrides for Emacs so that we follow Linus's tabbing style.
362 * Emacs will notice this stuff at the end of the file and automatically
363 * adjust the settings for this buffer only. This must remain at the end
364 * of the file.
365 * ---------------------------------------------------------------------------
366 * Local variables:
367 * c-file-style: "linux"
368 * End:
369 */
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
new file mode 100644
index 000000000000..7c376c95de50
--- /dev/null
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -0,0 +1,131 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <errno.h>
8#include <unistd.h>
9#include <linux/stddef.h>
10#include "ptrace_user.h"
11/* Grr, asm/user.h includes asm/ptrace.h, so has to follow ptrace_user.h */
12#include <asm/user.h>
13#include "kern_util.h"
14#include "sysdep/thread.h"
15#include "user.h"
16#include "os.h"
17
18int ptrace_getregs(long pid, unsigned long *regs_out)
19{
20 if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0)
21 return -errno;
22 return 0;
23}
24
25int ptrace_setregs(long pid, unsigned long *regs)
26{
27 if (ptrace(PTRACE_SETREGS, pid, 0, regs) < 0)
28 return -errno;
29 return 0;
30}
31
32int ptrace_getfpregs(long pid, unsigned long *regs)
33{
34 if (ptrace(PTRACE_GETFPREGS, pid, 0, regs) < 0)
35 return -errno;
36 return 0;
37}
38
39int ptrace_setfpregs(long pid, unsigned long *regs)
40{
41 if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0)
42 return -errno;
43 return 0;
44}
45
46static void write_debugregs(int pid, unsigned long *regs)
47{
48 struct user *dummy;
49 int nregs, i;
50
51 dummy = NULL;
52 nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
53 for(i = 0; i < nregs; i++){
54 if((i == 4) || (i == 5)) continue;
55 if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i],
56 regs[i]) < 0)
57 printk("write_debugregs - ptrace failed on "
58 "register %d, value = 0x%x, errno = %d\n", i,
59 regs[i], errno);
60 }
61}
62
63static void read_debugregs(int pid, unsigned long *regs)
64{
65 struct user *dummy;
66 int nregs, i;
67
68 dummy = NULL;
69 nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
70 for(i = 0; i < nregs; i++){
71 regs[i] = ptrace(PTRACE_PEEKUSR, pid,
72 &dummy->u_debugreg[i], 0);
73 }
74}
75
76/* Accessed only by the tracing thread */
77static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 };
78static int debugregs_seq = 0;
79
80void arch_enter_kernel(void *task, int pid)
81{
82 read_debugregs(pid, TASK_DEBUGREGS(task));
83 write_debugregs(pid, kernel_debugregs);
84}
85
86void arch_leave_kernel(void *task, int pid)
87{
88 read_debugregs(pid, kernel_debugregs);
89 write_debugregs(pid, TASK_DEBUGREGS(task));
90}
91
92void ptrace_pokeuser(unsigned long addr, unsigned long data)
93{
94 if((addr < offsetof(struct user, u_debugreg[0])) ||
95 (addr > offsetof(struct user, u_debugreg[7])))
96 return;
97 addr -= offsetof(struct user, u_debugreg[0]);
98 addr = addr >> 2;
99 if(kernel_debugregs[addr] == data) return;
100
101 kernel_debugregs[addr] = data;
102 debugregs_seq++;
103}
104
105static void update_debugregs_cb(void *arg)
106{
107 int pid = *((int *) arg);
108
109 write_debugregs(pid, kernel_debugregs);
110}
111
112void update_debugregs(int seq)
113{
114 int me;
115
116 if(seq == debugregs_seq) return;
117
118 me = os_getpid();
119 initial_thread_cb(update_debugregs_cb, &me);
120}
121
122/*
123 * Overrides for Emacs so that we follow Linus's tabbing style.
124 * Emacs will notice this stuff at the end of the file and automatically
125 * adjust the settings for this buffer only. This must remain at the end
126 * of the file.
127 * ---------------------------------------------------------------------------
128 * Local variables:
129 * c-file-style: "linux"
130 * End:
131 */
diff --git a/arch/um/sys-i386/sigcontext.c b/arch/um/sys-i386/sigcontext.c
new file mode 100644
index 000000000000..467d489c31cd
--- /dev/null
+++ b/arch/um/sys-i386/sigcontext.c
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stddef.h>
7#include <string.h>
8#include <asm/ptrace.h>
9#include <asm/sigcontext.h>
10#include "sysdep/ptrace.h"
11#include "kern_util.h"
12
13void sc_to_sc(void *to_ptr, void *from_ptr)
14{
15 struct sigcontext *to = to_ptr, *from = from_ptr;
16
17 memcpy(to, from, sizeof(*to) + sizeof(struct _fpstate));
18 if(from->fpstate != NULL)
19 to->fpstate = (struct _fpstate *) (to + 1);
20}
21
22unsigned long *sc_sigmask(void *sc_ptr)
23{
24 struct sigcontext *sc = sc_ptr;
25 return &sc->oldmask;
26}
27
28int sc_get_fpregs(unsigned long buf, void *sc_ptr)
29{
30 struct sigcontext *sc = sc_ptr;
31 struct _fpstate *from = sc->fpstate, *to = (struct _fpstate *) buf;
32 int err = 0;
33
34 if(from == NULL){
35 err |= clear_user_proc(&to->cw, sizeof(to->cw));
36 err |= clear_user_proc(&to->sw, sizeof(to->sw));
37 err |= clear_user_proc(&to->tag, sizeof(to->tag));
38 err |= clear_user_proc(&to->ipoff, sizeof(to->ipoff));
39 err |= clear_user_proc(&to->cssel, sizeof(to->cssel));
40 err |= clear_user_proc(&to->dataoff, sizeof(to->dataoff));
41 err |= clear_user_proc(&to->datasel, sizeof(to->datasel));
42 err |= clear_user_proc(&to->_st, sizeof(to->_st));
43 }
44 else {
45 err |= copy_to_user_proc(&to->cw, &from->cw, sizeof(to->cw));
46 err |= copy_to_user_proc(&to->sw, &from->sw, sizeof(to->sw));
47 err |= copy_to_user_proc(&to->tag, &from->tag,
48 sizeof(to->tag));
49 err |= copy_to_user_proc(&to->ipoff, &from->ipoff,
50 sizeof(to->ipoff));
51 err |= copy_to_user_proc(&to->cssel,& from->cssel,
52 sizeof(to->cssel));
53 err |= copy_to_user_proc(&to->dataoff, &from->dataoff,
54 sizeof(to->dataoff));
55 err |= copy_to_user_proc(&to->datasel, &from->datasel,
56 sizeof(to->datasel));
57 err |= copy_to_user_proc(to->_st, from->_st, sizeof(to->_st));
58 }
59 return(err);
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/sys-i386/signal.c b/arch/um/sys-i386/signal.c
new file mode 100644
index 000000000000..76ba87254b25
--- /dev/null
+++ b/arch/um/sys-i386/signal.c
@@ -0,0 +1,382 @@
1/*
2 * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/signal.h"
7#include "linux/ptrace.h"
8#include "asm/current.h"
9#include "asm/ucontext.h"
10#include "asm/uaccess.h"
11#include "asm/unistd.h"
12#include "frame_kern.h"
13#include "signal_user.h"
14#include "sigcontext.h"
15#include "registers.h"
16#include "mode.h"
17
18#ifdef CONFIG_MODE_SKAS
19
20#include "skas.h"
21
22static int copy_sc_from_user_skas(struct pt_regs *regs,
23 struct sigcontext *from)
24{
25 struct sigcontext sc;
26 unsigned long fpregs[HOST_FP_SIZE];
27 int err;
28
29 err = copy_from_user(&sc, from, sizeof(sc));
30 err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs));
31 if(err)
32 return(err);
33
34 REGS_GS(regs->regs.skas.regs) = sc.gs;
35 REGS_FS(regs->regs.skas.regs) = sc.fs;
36 REGS_ES(regs->regs.skas.regs) = sc.es;
37 REGS_DS(regs->regs.skas.regs) = sc.ds;
38 REGS_EDI(regs->regs.skas.regs) = sc.edi;
39 REGS_ESI(regs->regs.skas.regs) = sc.esi;
40 REGS_EBP(regs->regs.skas.regs) = sc.ebp;
41 REGS_SP(regs->regs.skas.regs) = sc.esp;
42 REGS_EBX(regs->regs.skas.regs) = sc.ebx;
43 REGS_EDX(regs->regs.skas.regs) = sc.edx;
44 REGS_ECX(regs->regs.skas.regs) = sc.ecx;
45 REGS_EAX(regs->regs.skas.regs) = sc.eax;
46 REGS_IP(regs->regs.skas.regs) = sc.eip;
47 REGS_CS(regs->regs.skas.regs) = sc.cs;
48 REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags;
49 REGS_SS(regs->regs.skas.regs) = sc.ss;
50 regs->regs.skas.fault_addr = sc.cr2;
51 regs->regs.skas.fault_type = FAULT_WRITE(sc.err);
52 regs->regs.skas.trap_type = sc.trapno;
53
54 err = restore_fp_registers(userspace_pid[0], fpregs);
55 if(err < 0){
56 printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, "
57 "errno = %d\n", err);
58 return(1);
59 }
60
61 return(0);
62}
63
64int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
65 struct pt_regs *regs, unsigned long fault_addr,
66 int fault_type)
67{
68 struct sigcontext sc;
69 unsigned long fpregs[HOST_FP_SIZE];
70 int err;
71
72 sc.gs = REGS_GS(regs->regs.skas.regs);
73 sc.fs = REGS_FS(regs->regs.skas.regs);
74 sc.es = REGS_ES(regs->regs.skas.regs);
75 sc.ds = REGS_DS(regs->regs.skas.regs);
76 sc.edi = REGS_EDI(regs->regs.skas.regs);
77 sc.esi = REGS_ESI(regs->regs.skas.regs);
78 sc.ebp = REGS_EBP(regs->regs.skas.regs);
79 sc.esp = REGS_SP(regs->regs.skas.regs);
80 sc.ebx = REGS_EBX(regs->regs.skas.regs);
81 sc.edx = REGS_EDX(regs->regs.skas.regs);
82 sc.ecx = REGS_ECX(regs->regs.skas.regs);
83 sc.eax = REGS_EAX(regs->regs.skas.regs);
84 sc.eip = REGS_IP(regs->regs.skas.regs);
85 sc.cs = REGS_CS(regs->regs.skas.regs);
86 sc.eflags = REGS_EFLAGS(regs->regs.skas.regs);
87 sc.esp_at_signal = regs->regs.skas.regs[UESP];
88 sc.ss = regs->regs.skas.regs[SS];
89 sc.cr2 = fault_addr;
90 sc.err = TO_SC_ERR(fault_type);
91 sc.trapno = regs->regs.skas.trap_type;
92
93 err = save_fp_registers(userspace_pid[0], fpregs);
94 if(err < 0){
95 printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, "
96 "errno = %d\n", err);
97 return(1);
98 }
99 to_fp = (to_fp ? to_fp : (struct _fpstate *) (to + 1));
100 sc.fpstate = to_fp;
101
102 if(err)
103 return(err);
104
105 return(copy_to_user(to, &sc, sizeof(sc)) ||
106 copy_to_user(to_fp, fpregs, sizeof(fpregs)));
107}
108#endif
109
110#ifdef CONFIG_MODE_TT
111
112/* These copy a sigcontext to/from userspace. They copy the fpstate pointer,
113 * blowing away the old, good one. So, that value is saved, and then restored
114 * after the sigcontext copy. In copy_from, the variable holding the saved
115 * fpstate pointer, and the sigcontext that it should be restored to are both
116 * in the kernel, so we can just restore using an assignment. In copy_to, the
117 * saved pointer is in the kernel, but the sigcontext is in userspace, so we
118 * copy_to_user it.
119 */
120int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
121 int fpsize)
122{
123 struct _fpstate *to_fp, *from_fp;
124 unsigned long sigs;
125 int err;
126
127 to_fp = to->fpstate;
128 from_fp = from->fpstate;
129 sigs = to->oldmask;
130 err = copy_from_user(to, from, sizeof(*to));
131 to->oldmask = sigs;
132 to->fpstate = to_fp;
133 if(to_fp != NULL)
134 err |= copy_from_user(to_fp, from_fp, fpsize);
135 return(err);
136}
137
138int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
139 struct sigcontext *from, int fpsize)
140{
141 struct _fpstate *to_fp, *from_fp;
142 int err;
143
144 to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
145 from_fp = from->fpstate;
146 err = copy_to_user(to, from, sizeof(*to));
147 if(from_fp != NULL){
148 err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
149 err |= copy_to_user(to_fp, from_fp, fpsize);
150 }
151 return(err);
152}
153#endif
154
155static int copy_sc_from_user(struct pt_regs *to, void __user *from)
156{
157 int ret;
158
159 ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from,
160 sizeof(struct _fpstate)),
161 copy_sc_from_user_skas(to, from));
162 return(ret);
163}
164
165static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp,
166 struct pt_regs *from)
167{
168 return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
169 sizeof(*fp)),
170 copy_sc_to_user_skas(to, fp, from,
171 current->thread.cr2,
172 current->thread.err)));
173}
174
175static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp,
176 sigset_t *set, unsigned long sp)
177{
178 int err = 0;
179
180 err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
181 err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
182 err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
183 err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs);
184 err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
185 return(err);
186}
187
188struct sigframe
189{
190 char *pretcode;
191 int sig;
192 struct sigcontext sc;
193 struct _fpstate fpstate;
194 unsigned long extramask[_NSIG_WORDS-1];
195 char retcode[8];
196};
197
198struct rt_sigframe
199{
200 char *pretcode;
201 int sig;
202 struct siginfo *pinfo;
203 void *puc;
204 struct siginfo info;
205 struct ucontext uc;
206 struct _fpstate fpstate;
207 char retcode[8];
208};
209
210int setup_signal_stack_sc(unsigned long stack_top, int sig,
211 struct k_sigaction *ka, struct pt_regs *regs,
212 sigset_t *mask)
213{
214 struct sigframe __user *frame;
215 void *restorer;
216 int err = 0;
217
218 stack_top &= -8UL;
219 frame = (struct sigframe *) stack_top - 1;
220 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
221 return 1;
222
223 restorer = (void *) frame->retcode;
224 if(ka->sa.sa_flags & SA_RESTORER)
225 restorer = ka->sa.sa_restorer;
226
227 err |= __put_user(restorer, &frame->pretcode);
228 err |= __put_user(sig, &frame->sig);
229 err |= copy_sc_to_user(&frame->sc, NULL, regs);
230 err |= __put_user(mask->sig[0], &frame->sc.oldmask);
231 if (_NSIG_WORDS > 1)
232 err |= __copy_to_user(&frame->extramask, &mask->sig[1],
233 sizeof(frame->extramask));
234
235 /*
236 * This is popl %eax ; movl $,%eax ; int $0x80
237 *
238 * WE DO NOT USE IT ANY MORE! It's only left here for historical
239 * reasons and because gdb uses it as a signature to notice
240 * signal handler stack frames.
241 */
242 err |= __put_user(0xb858, (short __user *)(frame->retcode+0));
243 err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2));
244 err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
245
246 if(err)
247 return(err);
248
249 PT_REGS_SP(regs) = (unsigned long) frame;
250 PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
251 PT_REGS_EAX(regs) = (unsigned long) sig;
252 PT_REGS_EDX(regs) = (unsigned long) 0;
253 PT_REGS_ECX(regs) = (unsigned long) 0;
254
255 if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
256 ptrace_notify(SIGTRAP);
257 return(0);
258}
259
260int setup_signal_stack_si(unsigned long stack_top, int sig,
261 struct k_sigaction *ka, struct pt_regs *regs,
262 siginfo_t *info, sigset_t *mask)
263{
264 struct rt_sigframe __user *frame;
265 void *restorer;
266 int err = 0;
267
268 stack_top &= -8UL;
269 frame = (struct rt_sigframe *) stack_top - 1;
270 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
271 return 1;
272
273 restorer = (void *) frame->retcode;
274 if(ka->sa.sa_flags & SA_RESTORER)
275 restorer = ka->sa.sa_restorer;
276
277 err |= __put_user(restorer, &frame->pretcode);
278 err |= __put_user(sig, &frame->sig);
279 err |= __put_user(&frame->info, &frame->pinfo);
280 err |= __put_user(&frame->uc, &frame->puc);
281 err |= copy_siginfo_to_user(&frame->info, info);
282 err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask,
283 PT_REGS_SP(regs));
284
285 /*
286 * This is movl $,%eax ; int $0x80
287 *
288 * WE DO NOT USE IT ANY MORE! It's only left here for historical
289 * reasons and because gdb uses it as a signature to notice
290 * signal handler stack frames.
291 */
292 err |= __put_user(0xb8, (char __user *)(frame->retcode+0));
293 err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1));
294 err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
295
296 if(err)
297 return(err);
298
299 PT_REGS_SP(regs) = (unsigned long) frame;
300 PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
301 PT_REGS_EAX(regs) = (unsigned long) sig;
302 PT_REGS_EDX(regs) = (unsigned long) &frame->info;
303 PT_REGS_ECX(regs) = (unsigned long) &frame->uc;
304
305 if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
306 ptrace_notify(SIGTRAP);
307 return(0);
308}
309
310long sys_sigreturn(struct pt_regs regs)
311{
312 unsigned long sp = PT_REGS_SP(&current->thread.regs);
313 struct sigframe __user *frame = (struct sigframe *)(sp - 8);
314 sigset_t set;
315 struct sigcontext __user *sc = &frame->sc;
316 unsigned long __user *oldmask = &sc->oldmask;
317 unsigned long __user *extramask = frame->extramask;
318 int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
319
320 if(copy_from_user(&set.sig[0], oldmask, sizeof(&set.sig[0])) ||
321 copy_from_user(&set.sig[1], extramask, sig_size))
322 goto segfault;
323
324 sigdelsetmask(&set, ~_BLOCKABLE);
325
326 spin_lock_irq(&current->sighand->siglock);
327 current->blocked = set;
328 recalc_sigpending();
329 spin_unlock_irq(&current->sighand->siglock);
330
331 if(copy_sc_from_user(&current->thread.regs, sc))
332 goto segfault;
333
334 /* Avoid ERESTART handling */
335 PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
336 return(PT_REGS_SYSCALL_RET(&current->thread.regs));
337
338 segfault:
339 force_sig(SIGSEGV, current);
340 return 0;
341}
342
343long sys_rt_sigreturn(struct pt_regs regs)
344{
345 unsigned long __user sp = PT_REGS_SP(&current->thread.regs);
346 struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4);
347 sigset_t set;
348 struct ucontext __user *uc = &frame->uc;
349 int sig_size = _NSIG_WORDS * sizeof(unsigned long);
350
351 if(copy_from_user(&set, &uc->uc_sigmask, sig_size))
352 goto segfault;
353
354 sigdelsetmask(&set, ~_BLOCKABLE);
355
356 spin_lock_irq(&current->sighand->siglock);
357 current->blocked = set;
358 recalc_sigpending();
359 spin_unlock_irq(&current->sighand->siglock);
360
361 if(copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext))
362 goto segfault;
363
364 /* Avoid ERESTART handling */
365 PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
366 return(PT_REGS_SYSCALL_RET(&current->thread.regs));
367
368 segfault:
369 force_sig(SIGSEGV, current);
370 return 0;
371}
372
373/*
374 * Overrides for Emacs so that we follow Linus's tabbing style.
375 * Emacs will notice this stuff at the end of the file and automatically
376 * adjust the settings for this buffer only. This must remain at the end
377 * of the file.
378 * ---------------------------------------------------------------------------
379 * Local variables:
380 * c-file-style: "linux"
381 * End:
382 */
diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c
new file mode 100644
index 000000000000..335e2d89504d
--- /dev/null
+++ b/arch/um/sys-i386/syscalls.c
@@ -0,0 +1,210 @@
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/shm.h"
8#include "asm/ipc.h"
9#include "asm/mman.h"
10#include "asm/uaccess.h"
11#include "asm/unistd.h"
12
13/*
14 * Perform the select(nd, in, out, ex, tv) and mmap() system
15 * calls. Linux/i386 didn't use to be able to handle more than
16 * 4 system call parameters, so these system calls used a memory
17 * block for parameter passing..
18 */
19
20struct mmap_arg_struct {
21 unsigned long addr;
22 unsigned long len;
23 unsigned long prot;
24 unsigned long flags;
25 unsigned long fd;
26 unsigned long offset;
27};
28
29extern int old_mmap(unsigned long addr, unsigned long len,
30 unsigned long prot, unsigned long flags,
31 unsigned long fd, unsigned long offset);
32
33long old_mmap_i386(struct mmap_arg_struct __user *arg)
34{
35 struct mmap_arg_struct a;
36 int err = -EFAULT;
37
38 if (copy_from_user(&a, arg, sizeof(a)))
39 goto out;
40
41 err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
42 out:
43 return err;
44}
45
46struct sel_arg_struct {
47 unsigned long n;
48 fd_set __user *inp;
49 fd_set __user *outp;
50 fd_set __user *exp;
51 struct timeval __user *tvp;
52};
53
54long old_select(struct sel_arg_struct __user *arg)
55{
56 struct sel_arg_struct a;
57
58 if (copy_from_user(&a, arg, sizeof(a)))
59 return -EFAULT;
60 /* sys_select() does the appropriate kernel locking */
61 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
62}
63
64/* The i386 version skips reading from %esi, the fourth argument. So we must do
65 * this, too.
66 */
67long sys_clone(unsigned long clone_flags, unsigned long newsp,
68 int __user *parent_tid, int unused, int __user *child_tid)
69{
70 long ret;
71
72 /* XXX: normal arch do here this pass, and also pass the regs to
73 * do_fork, instead of NULL. Currently the arch-independent code
74 * ignores these values, while the UML code (actually it's
75 * copy_thread) does the right thing. But this should change,
76 probably. */
77 /*if (!newsp)
78 newsp = UPT_SP(current->thread.regs);*/
79 current->thread.forking = 1;
80 ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
81 current->thread.forking = 0;
82 return(ret);
83}
84
85/*
86 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
87 *
88 * This is really horribly ugly.
89 */
90long sys_ipc (uint call, int first, int second,
91 int third, void __user *ptr, long fifth)
92{
93 int version, ret;
94
95 version = call >> 16; /* hack for backward compatibility */
96 call &= 0xffff;
97
98 switch (call) {
99 case SEMOP:
100 return sys_semtimedop(first, (struct sembuf *) ptr, second,
101 NULL);
102 case SEMTIMEDOP:
103 return sys_semtimedop(first, (struct sembuf *) ptr, second,
104 (const struct timespec *) fifth);
105 case SEMGET:
106 return sys_semget (first, second, third);
107 case SEMCTL: {
108 union semun fourth;
109 if (!ptr)
110 return -EINVAL;
111 if (get_user(fourth.__pad, (void **) ptr))
112 return -EFAULT;
113 return sys_semctl (first, second, third, fourth);
114 }
115
116 case MSGSND:
117 return sys_msgsnd (first, (struct msgbuf *) ptr,
118 second, third);
119 case MSGRCV:
120 switch (version) {
121 case 0: {
122 struct ipc_kludge tmp;
123 if (!ptr)
124 return -EINVAL;
125
126 if (copy_from_user(&tmp,
127 (struct ipc_kludge *) ptr,
128 sizeof (tmp)))
129 return -EFAULT;
130 return sys_msgrcv (first, tmp.msgp, second,
131 tmp.msgtyp, third);
132 }
133 default:
134 panic("msgrcv with version != 0");
135 return sys_msgrcv (first,
136 (struct msgbuf *) ptr,
137 second, fifth, third);
138 }
139 case MSGGET:
140 return sys_msgget ((key_t) first, second);
141 case MSGCTL:
142 return sys_msgctl (first, second, (struct msqid_ds *) ptr);
143
144 case SHMAT:
145 switch (version) {
146 default: {
147 ulong raddr;
148 ret = do_shmat (first, (char *) ptr, second, &raddr);
149 if (ret)
150 return ret;
151 return put_user (raddr, (ulong *) third);
152 }
153 case 1: /* iBCS2 emulator entry point */
154 if (!segment_eq(get_fs(), get_ds()))
155 return -EINVAL;
156 return do_shmat (first, (char *) ptr, second, (ulong *) third);
157 }
158 case SHMDT:
159 return sys_shmdt ((char *)ptr);
160 case SHMGET:
161 return sys_shmget (first, second, third);
162 case SHMCTL:
163 return sys_shmctl (first, second,
164 (struct shmid_ds *) ptr);
165 default:
166 return -ENOSYS;
167 }
168}
169
170long sys_sigaction(int sig, const struct old_sigaction __user *act,
171 struct old_sigaction __user *oact)
172{
173 struct k_sigaction new_ka, old_ka;
174 int ret;
175
176 if (act) {
177 old_sigset_t mask;
178 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
179 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
180 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
181 return -EFAULT;
182 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
183 __get_user(mask, &act->sa_mask);
184 siginitset(&new_ka.sa.sa_mask, mask);
185 }
186
187 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
188
189 if (!ret && oact) {
190 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
191 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
192 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
193 return -EFAULT;
194 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
195 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
196 }
197
198 return ret;
199}
200
201/*
202 * Overrides for Emacs so that we follow Linus's tabbing style.
203 * Emacs will notice this stuff at the end of the file and automatically
204 * adjust the settings for this buffer only. This must remain at the end
205 * of the file.
206 * ---------------------------------------------------------------------------
207 * Local variables:
208 * c-file-style: "linux"
209 * End:
210 */
diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c
new file mode 100644
index 000000000000..281fc7b8ca00
--- /dev/null
+++ b/arch/um/sys-i386/sysrq.c
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "linux/smp.h"
8#include "linux/sched.h"
9#include "asm/ptrace.h"
10#include "sysrq.h"
11
12void show_regs(struct pt_regs *regs)
13{
14 printk("\n");
15 printk("EIP: %04lx:[<%08lx>] CPU: %d %s",
16 0xffff & PT_REGS_CS(regs), PT_REGS_IP(regs),
17 smp_processor_id(), print_tainted());
18 if (PT_REGS_CS(regs) & 3)
19 printk(" ESP: %04lx:%08lx", 0xffff & PT_REGS_SS(regs),
20 PT_REGS_SP(regs));
21 printk(" EFLAGS: %08lx\n %s\n", PT_REGS_EFLAGS(regs),
22 print_tainted());
23 printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
24 PT_REGS_EAX(regs), PT_REGS_EBX(regs),
25 PT_REGS_ECX(regs),
26 PT_REGS_EDX(regs));
27 printk("ESI: %08lx EDI: %08lx EBP: %08lx",
28 PT_REGS_ESI(regs), PT_REGS_EDI(regs),
29 PT_REGS_EBP(regs));
30 printk(" DS: %04lx ES: %04lx\n",
31 0xffff & PT_REGS_DS(regs),
32 0xffff & PT_REGS_ES(regs));
33
34 show_trace((unsigned long *) &regs);
35}
diff --git a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile
new file mode 100644
index 000000000000..34860f9ca7b0
--- /dev/null
+++ b/arch/um/sys-i386/util/Makefile
@@ -0,0 +1,8 @@
1
2hostprogs-y := mk_sc mk_thread
3always := $(hostprogs-y)
4
5mk_thread-objs := mk_thread_kern.o mk_thread_user.o
6
7HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS)
8HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS)
diff --git a/arch/um/sys-i386/util/mk_sc.c b/arch/um/sys-i386/util/mk_sc.c
new file mode 100644
index 000000000000..85cbd30396f7
--- /dev/null
+++ b/arch/um/sys-i386/util/mk_sc.c
@@ -0,0 +1,52 @@
1#include <stdio.h>
2#include <signal.h>
3#include <linux/stddef.h>
4
5#define SC_OFFSET(name, field) \
6 printf("#define " name "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\
7 offsetof(struct sigcontext, field))
8
9#define SC_FP_OFFSET(name, field) \
10 printf("#define " name \
11 "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
12 offsetof(struct _fpstate, field))
13
14#define SC_FP_OFFSET_PTR(name, field, type) \
15 printf("#define " name \
16 "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
17 offsetof(struct _fpstate, field))
18
19int main(int argc, char **argv)
20{
21 SC_OFFSET("SC_IP", eip);
22 SC_OFFSET("SC_SP", esp);
23 SC_OFFSET("SC_FS", fs);
24 SC_OFFSET("SC_GS", gs);
25 SC_OFFSET("SC_DS", ds);
26 SC_OFFSET("SC_ES", es);
27 SC_OFFSET("SC_SS", ss);
28 SC_OFFSET("SC_CS", cs);
29 SC_OFFSET("SC_EFLAGS", eflags);
30 SC_OFFSET("SC_EAX", eax);
31 SC_OFFSET("SC_EBX", ebx);
32 SC_OFFSET("SC_ECX", ecx);
33 SC_OFFSET("SC_EDX", edx);
34 SC_OFFSET("SC_EDI", edi);
35 SC_OFFSET("SC_ESI", esi);
36 SC_OFFSET("SC_EBP", ebp);
37 SC_OFFSET("SC_TRAPNO", trapno);
38 SC_OFFSET("SC_ERR", err);
39 SC_OFFSET("SC_CR2", cr2);
40 SC_OFFSET("SC_FPSTATE", fpstate);
41 SC_OFFSET("SC_SIGMASK", oldmask);
42 SC_FP_OFFSET("SC_FP_CW", cw);
43 SC_FP_OFFSET("SC_FP_SW", sw);
44 SC_FP_OFFSET("SC_FP_TAG", tag);
45 SC_FP_OFFSET("SC_FP_IPOFF", ipoff);
46 SC_FP_OFFSET("SC_FP_CSSEL", cssel);
47 SC_FP_OFFSET("SC_FP_DATAOFF", dataoff);
48 SC_FP_OFFSET("SC_FP_DATASEL", datasel);
49 SC_FP_OFFSET_PTR("SC_FP_ST", _st, "struct _fpstate");
50 SC_FP_OFFSET_PTR("SC_FXSR_ENV", _fxsr_env, "void");
51 return(0);
52}
diff --git a/arch/um/sys-i386/util/mk_thread_kern.c b/arch/um/sys-i386/util/mk_thread_kern.c
new file mode 100644
index 000000000000..948b1ce85230
--- /dev/null
+++ b/arch/um/sys-i386/util/mk_thread_kern.c
@@ -0,0 +1,22 @@
1#include "linux/config.h"
2#include "linux/stddef.h"
3#include "linux/sched.h"
4
5extern void print_head(void);
6extern void print_constant_ptr(char *name, int value);
7extern void print_constant(char *name, char *type, int value);
8extern void print_tail(void);
9
10#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field)
11
12int main(int argc, char **argv)
13{
14 print_head();
15 print_constant_ptr("TASK_DEBUGREGS", THREAD_OFFSET(arch.debugregs));
16#ifdef CONFIG_MODE_TT
17 print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid));
18#endif
19 print_tail();
20 return(0);
21}
22
diff --git a/arch/um/sys-i386/util/mk_thread_user.c b/arch/um/sys-i386/util/mk_thread_user.c
new file mode 100644
index 000000000000..2620cd6aa1f1
--- /dev/null
+++ b/arch/um/sys-i386/util/mk_thread_user.c
@@ -0,0 +1,30 @@
1#include <stdio.h>
2
3void print_head(void)
4{
5 printf("/*\n");
6 printf(" * Generated by mk_thread\n");
7 printf(" */\n");
8 printf("\n");
9 printf("#ifndef __UM_THREAD_H\n");
10 printf("#define __UM_THREAD_H\n");
11 printf("\n");
12}
13
14void print_constant_ptr(char *name, int value)
15{
16 printf("#define %s(task) ((unsigned long *) "
17 "&(((char *) (task))[%d]))\n", name, value);
18}
19
20void print_constant(char *name, char *type, int value)
21{
22 printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
23 value);
24}
25
26void print_tail(void)
27{
28 printf("\n");
29 printf("#endif\n");
30}
diff --git a/arch/um/sys-ia64/Makefile b/arch/um/sys-ia64/Makefile
new file mode 100644
index 000000000000..d02f4c265232
--- /dev/null
+++ b/arch/um/sys-ia64/Makefile
@@ -0,0 +1,11 @@
1OBJ = built-in.o
2
3OBJS =
4
5all: $(OBJ)
6
7$(OBJ): $(OBJS)
8 rm -f $@
9 $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
10
11clean-files := $(OBJS) link.ld
diff --git a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile
new file mode 100644
index 000000000000..af200268fddb
--- /dev/null
+++ b/arch/um/sys-ppc/Makefile
@@ -0,0 +1,69 @@
1OBJ = built-in.o
2
3.S.o:
4 $(CC) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
5
6OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \
7 ptrace_user.o sysrq.o
8
9EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(TOPDIR)/arch/ppc/kernel
10
11all: $(OBJ)
12
13$(OBJ): $(OBJS)
14 rm -f $@
15 $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
16
17ptrace_user.o: ptrace_user.c
18 $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
19
20sigcontext.o: sigcontext.c
21 $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
22
23semaphore.c:
24 rm -f $@
25 ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
26
27checksum.S:
28 rm -f $@
29 ln -s $(TOPDIR)/arch/ppc/lib/$@ $@
30
31mk_defs.c:
32 rm -f $@
33 ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
34
35ppc_defs.head:
36 rm -f $@
37 ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
38
39ppc_defs.h: mk_defs.c ppc_defs.head \
40 $(TOPDIR)/include/asm-ppc/mmu.h \
41 $(TOPDIR)/include/asm-ppc/processor.h \
42 $(TOPDIR)/include/asm-ppc/pgtable.h \
43 $(TOPDIR)/include/asm-ppc/ptrace.h
44# $(CC) $(CFLAGS) -S mk_defs.c
45 cp ppc_defs.head ppc_defs.h
46# for bk, this way we can write to the file even if it's not checked out
47 echo '#define THREAD 608' >> ppc_defs.h
48 echo '#define PT_REGS 8' >> ppc_defs.h
49 echo '#define CLONE_VM 256' >> ppc_defs.h
50# chmod u+w ppc_defs.h
51# grep '^#define' mk_defs.s >> ppc_defs.h
52# rm mk_defs.s
53
54# the asm link is horrible, and breaks the other targets. This is also
55# not going to work with parallel makes.
56
57checksum.o: checksum.S
58 rm -f asm
59 ln -s $(TOPDIR)/include/asm-ppc asm
60 $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
61 rm -f asm
62
63misc.o: misc.S ppc_defs.h
64 rm -f asm
65 ln -s $(TOPDIR)/include/asm-ppc asm
66 $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
67 rm -f asm
68
69clean-files := $(OBJS) ppc_defs.h checksum.S semaphore.c mk_defs.c
diff --git a/arch/um/sys-ppc/misc.S b/arch/um/sys-ppc/misc.S
new file mode 100644
index 000000000000..11b7bd768cfd
--- /dev/null
+++ b/arch/um/sys-ppc/misc.S
@@ -0,0 +1,116 @@
1/*
2 * This file contains miscellaneous low-level functions.
3 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
4 *
5 * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
6 * and Paul Mackerras.
7 *
8 * A couple of functions stolen from arch/ppc/kernel/misc.S for UML
9 * by Chris Emerson.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 *
16 */
17
18#include <linux/config.h>
19#include <asm/processor.h>
20#include "ppc_asm.h"
21
22#if defined(CONFIG_4xx) || defined(CONFIG_8xx)
23#define CACHE_LINE_SIZE 16
24#define LG_CACHE_LINE_SIZE 4
25#define MAX_COPY_PREFETCH 1
26#elif !defined(CONFIG_PPC64BRIDGE)
27#define CACHE_LINE_SIZE 32
28#define LG_CACHE_LINE_SIZE 5
29#define MAX_COPY_PREFETCH 4
30#else
31#define CACHE_LINE_SIZE 128
32#define LG_CACHE_LINE_SIZE 7
33#define MAX_COPY_PREFETCH 1
34#endif /* CONFIG_4xx || CONFIG_8xx */
35
36 .text
37
38/*
39 * Clear a page using the dcbz instruction, which doesn't cause any
40 * memory traffic (except to write out any cache lines which get
41 * displaced). This only works on cacheable memory.
42 */
43_GLOBAL(clear_page)
44 li r0,4096/CACHE_LINE_SIZE
45 mtctr r0
46#ifdef CONFIG_8xx
47 li r4, 0
481: stw r4, 0(r3)
49 stw r4, 4(r3)
50 stw r4, 8(r3)
51 stw r4, 12(r3)
52#else
531: dcbz 0,r3
54#endif
55 addi r3,r3,CACHE_LINE_SIZE
56 bdnz 1b
57 blr
58
59/*
60 * Copy a whole page. We use the dcbz instruction on the destination
61 * to reduce memory traffic (it eliminates the unnecessary reads of
62 * the destination into cache). This requires that the destination
63 * is cacheable.
64 */
65#define COPY_16_BYTES \
66 lwz r6,4(r4); \
67 lwz r7,8(r4); \
68 lwz r8,12(r4); \
69 lwzu r9,16(r4); \
70 stw r6,4(r3); \
71 stw r7,8(r3); \
72 stw r8,12(r3); \
73 stwu r9,16(r3)
74
75_GLOBAL(copy_page)
76 addi r3,r3,-4
77 addi r4,r4,-4
78 li r5,4
79
80#ifndef CONFIG_8xx
81#if MAX_COPY_PREFETCH > 1
82 li r0,MAX_COPY_PREFETCH
83 li r11,4
84 mtctr r0
8511: dcbt r11,r4
86 addi r11,r11,CACHE_LINE_SIZE
87 bdnz 11b
88#else /* MAX_COPY_PREFETCH == 1 */
89 dcbt r5,r4
90 li r11,CACHE_LINE_SIZE+4
91#endif /* MAX_COPY_PREFETCH */
92#endif /* CONFIG_8xx */
93
94 li r0,4096/CACHE_LINE_SIZE
95 mtctr r0
961:
97#ifndef CONFIG_8xx
98 dcbt r11,r4
99 dcbz r5,r3
100#endif
101 COPY_16_BYTES
102#if CACHE_LINE_SIZE >= 32
103 COPY_16_BYTES
104#if CACHE_LINE_SIZE >= 64
105 COPY_16_BYTES
106 COPY_16_BYTES
107#if CACHE_LINE_SIZE >= 128
108 COPY_16_BYTES
109 COPY_16_BYTES
110 COPY_16_BYTES
111 COPY_16_BYTES
112#endif
113#endif
114#endif
115 bdnz 1b
116 blr
diff --git a/arch/um/sys-ppc/miscthings.c b/arch/um/sys-ppc/miscthings.c
new file mode 100644
index 000000000000..373061c50129
--- /dev/null
+++ b/arch/um/sys-ppc/miscthings.c
@@ -0,0 +1,53 @@
1#include "linux/threads.h"
2#include "linux/stddef.h" // for NULL
3#include "linux/elf.h" // for AT_NULL
4
5/* The following function nicked from arch/ppc/kernel/process.c and
6 * adapted slightly */
7/*
8 * XXX ld.so expects the auxiliary table to start on
9 * a 16-byte boundary, so we have to find it and
10 * move it up. :-(
11 */
12void shove_aux_table(unsigned long sp)
13{
14 int argc;
15 char *p;
16 unsigned long e;
17 unsigned long aux_start, offset;
18
19 argc = *(int *)sp;
20 sp += sizeof(int) + (argc + 1) * sizeof(char *);
21 /* skip over the environment pointers */
22 do {
23 p = *(char **)sp;
24 sp += sizeof(char *);
25 } while (p != NULL);
26 aux_start = sp;
27 /* skip to the end of the auxiliary table */
28 do {
29 e = *(unsigned long *)sp;
30 sp += 2 * sizeof(unsigned long);
31 } while (e != AT_NULL);
32 offset = ((aux_start + 15) & ~15) - aux_start;
33 if (offset != 0) {
34 do {
35 sp -= sizeof(unsigned long);
36 e = *(unsigned long *)sp;
37 *(unsigned long *)(sp + offset) = e;
38 } while (sp > aux_start);
39 }
40}
41/* END stuff taken from arch/ppc/kernel/process.c */
42
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/sys-ppc/ptrace.c b/arch/um/sys-ppc/ptrace.c
new file mode 100644
index 000000000000..a971366d3277
--- /dev/null
+++ b/arch/um/sys-ppc/ptrace.c
@@ -0,0 +1,28 @@
1#include "linux/sched.h"
2#include "asm/ptrace.h"
3
4int putreg(struct task_struct *child, unsigned long regno,
5 unsigned long value)
6{
7 child->thread.process_regs.regs[regno >> 2] = value;
8 return 0;
9}
10
11unsigned long getreg(struct task_struct *child, unsigned long regno)
12{
13 unsigned long retval = ~0UL;
14
15 retval &= child->thread.process_regs.regs[regno >> 2];
16 return retval;
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/sys-ppc/ptrace_user.c b/arch/um/sys-ppc/ptrace_user.c
new file mode 100644
index 000000000000..ff0b9c077a13
--- /dev/null
+++ b/arch/um/sys-ppc/ptrace_user.c
@@ -0,0 +1,39 @@
1#include <errno.h>
2#include <asm/ptrace.h>
3#include "sysdep/ptrace.h"
4
5int ptrace_getregs(long pid, unsigned long *regs_out)
6{
7 int i;
8 for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
9 errno = 0;
10 regs_out->regs[i] = ptrace(PTRACE_PEEKUSR, pid, i*4, 0);
11 if (errno) {
12 return -errno;
13 }
14 }
15 return 0;
16}
17
18int ptrace_setregs(long pid, unsigned long *regs_in)
19{
20 int i;
21 for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
22 if (i != 34 /* FIXME: PT_ORIG_R3 */ && i <= PT_MQ) {
23 if (ptrace(PTRACE_POKEUSR, pid, i*4, regs_in->regs[i]) < 0) {
24 return -errno;
25 }
26 }
27 }
28 return 0;
29}
30/*
31 * Overrides for Emacs so that we follow Linus's tabbing style.
32 * Emacs will notice this stuff at the end of the file and automatically
33 * adjust the settings for this buffer only. This must remain at the end
34 * of the file.
35 * ---------------------------------------------------------------------------
36 * Local variables:
37 * c-file-style: "linux"
38 * End:
39 */
diff --git a/arch/um/sys-ppc/sigcontext.c b/arch/um/sys-ppc/sigcontext.c
new file mode 100644
index 000000000000..5d430fc994af
--- /dev/null
+++ b/arch/um/sys-ppc/sigcontext.c
@@ -0,0 +1,15 @@
1#include "asm/ptrace.h"
2#include "asm/sigcontext.h"
3#include "sysdep/ptrace.h"
4#include "user_util.h"
5
6/*
7 * Overrides for Emacs so that we follow Linus's tabbing style.
8 * Emacs will notice this stuff at the end of the file and automatically
9 * adjust the settings for this buffer only. This must remain at the end
10 * of the file.
11 * ---------------------------------------------------------------------------
12 * Local variables:
13 * c-file-style: "linux"
14 * End:
15 */
diff --git a/arch/um/sys-ppc/sysrq.c b/arch/um/sys-ppc/sysrq.c
new file mode 100644
index 000000000000..82d6e9335bb6
--- /dev/null
+++ b/arch/um/sys-ppc/sysrq.c
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "linux/smp.h"
8#include "asm/ptrace.h"
9#include "sysrq.h"
10
11void show_regs(struct pt_regs_subarch *regs)
12{
13 printk("\n");
14 printk("show_regs(): insert regs here.\n");
15#if 0
16 printk("\n");
17 printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs, regs->eip,
18 smp_processor_id());
19 if (regs->xcs & 3)
20 printk(" ESP: %04x:%08lx",0xffff & regs->xss, regs->esp);
21 printk(" EFLAGS: %08lx\n", regs->eflags);
22 printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
23 regs->eax, regs->ebx, regs->ecx, regs->edx);
24 printk("ESI: %08lx EDI: %08lx EBP: %08lx",
25 regs->esi, regs->edi, regs->ebp);
26 printk(" DS: %04x ES: %04x\n",
27 0xffff & regs->xds, 0xffff & regs->xes);
28#endif
29
30 show_trace(&regs->gpr[1]);
31}
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/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
new file mode 100644
index 000000000000..2129e3143559
--- /dev/null
+++ b/arch/um/sys-x86_64/Makefile
@@ -0,0 +1,37 @@
1#
2# Copyright 2003 PathScale, Inc.
3#
4# Licensed under the GPL
5#
6
7lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
8 ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \
9 syscalls.o sysrq.o thunk.o
10
11USER_OBJS := ptrace_user.o sigcontext.o
12
13include arch/um/scripts/Makefile.rules
14
15SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \
16 semaphore.c thunk.S
17
18# this needs to be before the foreach, because clean-files does not accept
19# complete paths like $(src)/$f.
20clean-files := $(SYMLINKS)
21
22targets += $(SYMLINKS)
23
24SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$f)
25
26bitops.c-dir = lib
27csum-copy.S-dir = lib
28csum-partial.c-dir = lib
29csum-wrappers.c-dir = lib
30memcpy.S-dir = lib
31semaphore.c-dir = kernel
32thunk.S-dir = lib
33
34$(SYMLINKS): FORCE
35 $(call if_changed,make_link)
36
37CFLAGS_csum-partial.o := -Dcsum_partial=arch_csum_partial
diff --git a/arch/um/sys-x86_64/bugs.c b/arch/um/sys-x86_64/bugs.c
new file mode 100644
index 000000000000..fdce7ea98ca7
--- /dev/null
+++ b/arch/um/sys-x86_64/bugs.c
@@ -0,0 +1,122 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#include "linux/sched.h"
8#include "linux/errno.h"
9#include "asm/system.h"
10#include "asm/pda.h"
11#include "sysdep/ptrace.h"
12#include "os.h"
13
14void arch_init_thread(void)
15{
16}
17
18void arch_check_bugs(void)
19{
20}
21
22int arch_handle_signal(int sig, union uml_pt_regs *regs)
23{
24 return(0);
25}
26
27#define MAXTOKEN 64
28
29/* Set during early boot */
30int host_has_cmov = 1;
31int host_has_xmm = 0;
32
33static char token(int fd, char *buf, int len, char stop)
34{
35 int n;
36 char *ptr, *end, c;
37
38 ptr = buf;
39 end = &buf[len];
40 do {
41 n = os_read_file(fd, ptr, sizeof(*ptr));
42 c = *ptr++;
43 if(n != sizeof(*ptr)){
44 if(n == 0) return(0);
45 printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
46 if(n < 0)
47 return(n);
48 else
49 return(-EIO);
50 }
51 } while((c != '\n') && (c != stop) && (ptr < end));
52
53 if(ptr == end){
54 printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
55 return(-1);
56 }
57 *(ptr - 1) = '\0';
58 return(c);
59}
60
61static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
62{
63 int n;
64 char c;
65
66 scratch[len - 1] = '\0';
67 while(1){
68 c = token(fd, scratch, len - 1, ':');
69 if(c <= 0)
70 return(0);
71 else if(c != ':'){
72 printk("Failed to find ':' in /proc/cpuinfo\n");
73 return(0);
74 }
75
76 if(!strncmp(scratch, key, strlen(key)))
77 return(1);
78
79 do {
80 n = os_read_file(fd, &c, sizeof(c));
81 if(n != sizeof(c)){
82 printk("Failed to find newline in "
83 "/proc/cpuinfo, err = %d\n", -n);
84 return(0);
85 }
86 } while(c != '\n');
87 }
88 return(0);
89}
90
91int cpu_feature(char *what, char *buf, int len)
92{
93 int fd, ret = 0;
94
95 fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
96 if(fd < 0){
97 printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
98 return(0);
99 }
100
101 if(!find_cpuinfo_line(fd, what, buf, len)){
102 printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
103 goto out_close;
104 }
105
106 token(fd, buf, len, '\n');
107 ret = 1;
108
109 out_close:
110 os_close_file(fd);
111 return(ret);
112}
113
114/* Overrides for Emacs so that we follow Linus's tabbing style.
115 * Emacs will notice this stuff at the end of the file and automatically
116 * adjust the settings for this buffer only. This must remain at the end
117 * of the file.
118 * ---------------------------------------------------------------------------
119 * Local variables:
120 * c-file-style: "linux"
121 * End:
122 */
diff --git a/arch/um/sys-x86_64/delay.c b/arch/um/sys-x86_64/delay.c
new file mode 100644
index 000000000000..f3b5187942b4
--- /dev/null
+++ b/arch/um/sys-x86_64/delay.c
@@ -0,0 +1,26 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 * Copied from arch/x86_64
4 *
5 * Licensed under the GPL
6 */
7
8#include "asm/processor.h"
9
10void __delay(unsigned long loops)
11{
12 unsigned long i;
13
14 for(i = 0; i < loops; i++) ;
15}
16
17/*
18 * Overrides for Emacs so that we follow Linus's tabbing style.
19 * Emacs will notice this stuff at the end of the file and automatically
20 * adjust the settings for this buffer only. This must remain at the end
21 * of the file.
22 * ---------------------------------------------------------------------------
23 * Local variables:
24 * c-file-style: "linux"
25 * End:
26 */
diff --git a/arch/um/sys-x86_64/fault.c b/arch/um/sys-x86_64/fault.c
new file mode 100644
index 000000000000..cee1513c5c31
--- /dev/null
+++ b/arch/um/sys-x86_64/fault.c
@@ -0,0 +1,23 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#include "user.h"
8
9int arch_fixup(unsigned long address, void *sc_ptr)
10{
11 /* XXX search_exception_tables() */
12 return(0);
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/sys-x86_64/mem.c b/arch/um/sys-x86_64/mem.c
new file mode 100644
index 000000000000..3f59a0a4f156
--- /dev/null
+++ b/arch/um/sys-x86_64/mem.c
@@ -0,0 +1,25 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#include "linux/mm.h"
8#include "asm/page.h"
9#include "asm/mman.h"
10
11unsigned long vm_stack_flags = __VM_STACK_FLAGS;
12unsigned long vm_stack_flags32 = __VM_STACK_FLAGS;
13unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS;
14unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS;
15unsigned long vm_force_exec32 = PROT_EXEC;
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/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c
new file mode 100644
index 000000000000..8c146b2a1e00
--- /dev/null
+++ b/arch/um/sys-x86_64/ptrace.c
@@ -0,0 +1,138 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#define __FRAME_OFFSETS
8#include "asm/ptrace.h"
9#include "linux/sched.h"
10#include "linux/errno.h"
11#include "asm/elf.h"
12
13/* XXX x86_64 */
14unsigned long not_ss;
15unsigned long not_ds;
16unsigned long not_es;
17
18#define SC_SS(r) (not_ss)
19#define SC_DS(r) (not_ds)
20#define SC_ES(r) (not_es)
21
22/* determines which flags the user has access to. */
23/* 1 = access 0 = no access */
24#define FLAG_MASK 0x44dd5UL
25
26int putreg(struct task_struct *child, int regno, unsigned long value)
27{
28 unsigned long tmp;
29
30#ifdef TIF_IA32
31 /* Some code in the 64bit emulation may not be 64bit clean.
32 Don't take any chances. */
33 if (test_tsk_thread_flag(child, TIF_IA32))
34 value &= 0xffffffff;
35#endif
36 switch (regno){
37 case FS:
38 case GS:
39 case DS:
40 case ES:
41 case SS:
42 case CS:
43 if (value && (value & 3) != 3)
44 return -EIO;
45 value &= 0xffff;
46 break;
47
48 case FS_BASE:
49 case GS_BASE:
50 if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
51 return -EIO;
52 break;
53
54 case EFLAGS:
55 value &= FLAG_MASK;
56 tmp = PT_REGS_EFLAGS(&child->thread.regs) & ~FLAG_MASK;
57 value |= tmp;
58 break;
59 }
60
61 PT_REGS_SET(&child->thread.regs, regno, value);
62 return 0;
63}
64
65unsigned long getreg(struct task_struct *child, int regno)
66{
67 unsigned long retval = ~0UL;
68 switch (regno) {
69 case FS:
70 case GS:
71 case DS:
72 case ES:
73 case SS:
74 case CS:
75 retval = 0xffff;
76 /* fall through */
77 default:
78 retval &= PT_REG(&child->thread.regs, regno);
79#ifdef TIF_IA32
80 if (test_tsk_thread_flag(child, TIF_IA32))
81 retval &= 0xffffffff;
82#endif
83 }
84 return retval;
85}
86
87void arch_switch(void)
88{
89/* XXX
90 printk("arch_switch\n");
91*/
92}
93
94int is_syscall(unsigned long addr)
95{
96 panic("is_syscall");
97}
98
99int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
100{
101 panic("dump_fpu");
102 return(1);
103}
104
105int get_fpregs(unsigned long buf, struct task_struct *child)
106{
107 panic("get_fpregs");
108 return(0);
109}
110
111int set_fpregs(unsigned long buf, struct task_struct *child)
112{
113 panic("set_fpregs");
114 return(0);
115}
116
117int get_fpxregs(unsigned long buf, struct task_struct *tsk)
118{
119 panic("get_fpxregs");
120 return(0);
121}
122
123int set_fpxregs(unsigned long buf, struct task_struct *tsk)
124{
125 panic("set_fxpregs");
126 return(0);
127}
128
129/*
130 * Overrides for Emacs so that we follow Linus's tabbing style.
131 * Emacs will notice this stuff at the end of the file and automatically
132 * adjust the settings for this buffer only. This must remain at the end
133 * of the file.
134 * ---------------------------------------------------------------------------
135 * Local variables:
136 * c-file-style: "linux"
137 * End:
138 */
diff --git a/arch/um/sys-x86_64/ptrace_user.c b/arch/um/sys-x86_64/ptrace_user.c
new file mode 100644
index 000000000000..12e404c6fa46
--- /dev/null
+++ b/arch/um/sys-x86_64/ptrace_user.c
@@ -0,0 +1,51 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#include <stddef.h>
8#include <errno.h>
9#include "ptrace_user.h"
10#include "user.h"
11#include "kern_constants.h"
12
13int ptrace_getregs(long pid, unsigned long *regs_out)
14{
15 if(ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0)
16 return(-errno);
17 return(0);
18}
19
20int ptrace_setregs(long pid, unsigned long *regs)
21{
22 if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0)
23 return(-errno);
24 return(0);
25}
26
27void ptrace_pokeuser(unsigned long addr, unsigned long data)
28{
29 panic("ptrace_pokeuser");
30}
31
32#define DS 184
33#define ES 192
34#define __USER_DS 0x2b
35
36void arch_enter_kernel(void *task, int pid)
37{
38}
39
40void arch_leave_kernel(void *task, int pid)
41{
42#ifdef UM_USER_CS
43 if(ptrace(PTRACE_POKEUSR, pid, CS, UM_USER_CS) < 0)
44 printk("POKEUSR CS failed");
45#endif
46
47 if(ptrace(PTRACE_POKEUSR, pid, DS, __USER_DS) < 0)
48 printk("POKEUSR DS failed");
49 if(ptrace(PTRACE_POKEUSR, pid, ES, __USER_DS) < 0)
50 printk("POKEUSR ES failed");
51}
diff --git a/arch/um/sys-x86_64/sigcontext.c b/arch/um/sys-x86_64/sigcontext.c
new file mode 100644
index 000000000000..c88e64def6f2
--- /dev/null
+++ b/arch/um/sys-x86_64/sigcontext.c
@@ -0,0 +1,39 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#include <stdio.h>
8#include <string.h>
9#include <signal.h>
10#include "user.h"
11
12void sc_to_sc(void *to_ptr, void *from_ptr)
13{
14 struct sigcontext *to = to_ptr, *from = from_ptr;
15 int size = sizeof(*to); /* + sizeof(struct _fpstate); */
16
17 memcpy(to, from, size);
18 if(from->fpstate != NULL)
19 to->fpstate = (struct _fpstate *) (to + 1);
20
21 to->fpstate = NULL;
22}
23
24unsigned long *sc_sigmask(void *sc_ptr)
25{
26 struct sigcontext *sc = sc_ptr;
27
28 return(&sc->oldmask);
29}
30
31/* Overrides for Emacs so that we follow Linus's tabbing style.
32 * Emacs will notice this stuff at the end of the file and automatically
33 * adjust the settings for this buffer only. This must remain at the end
34 * of the file.
35 * ---------------------------------------------------------------------------
36 * Local variables:
37 * c-file-style: "linux"
38 * End:
39 */
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
new file mode 100644
index 000000000000..5bc5a0d796e5
--- /dev/null
+++ b/arch/um/sys-x86_64/signal.c
@@ -0,0 +1,276 @@
1/*
2 * Copyright (C) 2003 PathScale, Inc.
3 * Licensed under the GPL
4 */
5
6#include "linux/stddef.h"
7#include "linux/errno.h"
8#include "linux/personality.h"
9#include "linux/ptrace.h"
10#include "asm/current.h"
11#include "asm/uaccess.h"
12#include "asm/sigcontext.h"
13#include "asm/ptrace.h"
14#include "asm/arch/ucontext.h"
15#include "choose-mode.h"
16#include "sysdep/ptrace.h"
17#include "frame_kern.h"
18
19#ifdef CONFIG_MODE_SKAS
20
21#include "skas.h"
22
23static int copy_sc_from_user_skas(struct pt_regs *regs,
24 struct sigcontext *from)
25{
26 int err = 0;
27
28#define GETREG(regs, regno, sc, regname) \
29 __get_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \
30 &(sc)->regname)
31
32 err |= GETREG(regs, R8, from, r8);
33 err |= GETREG(regs, R9, from, r9);
34 err |= GETREG(regs, R10, from, r10);
35 err |= GETREG(regs, R11, from, r11);
36 err |= GETREG(regs, R12, from, r12);
37 err |= GETREG(regs, R13, from, r13);
38 err |= GETREG(regs, R14, from, r14);
39 err |= GETREG(regs, R15, from, r15);
40 err |= GETREG(regs, RDI, from, rdi);
41 err |= GETREG(regs, RSI, from, rsi);
42 err |= GETREG(regs, RBP, from, rbp);
43 err |= GETREG(regs, RBX, from, rbx);
44 err |= GETREG(regs, RDX, from, rdx);
45 err |= GETREG(regs, RAX, from, rax);
46 err |= GETREG(regs, RCX, from, rcx);
47 err |= GETREG(regs, RSP, from, rsp);
48 err |= GETREG(regs, RIP, from, rip);
49 err |= GETREG(regs, EFLAGS, from, eflags);
50 err |= GETREG(regs, CS, from, cs);
51
52#undef GETREG
53
54 return(err);
55}
56
57int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
58 struct pt_regs *regs, unsigned long mask)
59{
60 unsigned long eflags;
61 int err = 0;
62
63 err |= __put_user(0, &to->gs);
64 err |= __put_user(0, &to->fs);
65
66#define PUTREG(regs, regno, sc, regname) \
67 __put_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \
68 &(sc)->regname)
69
70 err |= PUTREG(regs, RDI, to, rdi);
71 err |= PUTREG(regs, RSI, to, rsi);
72 err |= PUTREG(regs, RBP, to, rbp);
73 err |= PUTREG(regs, RSP, to, rsp);
74 err |= PUTREG(regs, RBX, to, rbx);
75 err |= PUTREG(regs, RDX, to, rdx);
76 err |= PUTREG(regs, RCX, to, rcx);
77 err |= PUTREG(regs, RAX, to, rax);
78 err |= PUTREG(regs, R8, to, r8);
79 err |= PUTREG(regs, R9, to, r9);
80 err |= PUTREG(regs, R10, to, r10);
81 err |= PUTREG(regs, R11, to, r11);
82 err |= PUTREG(regs, R12, to, r12);
83 err |= PUTREG(regs, R13, to, r13);
84 err |= PUTREG(regs, R14, to, r14);
85 err |= PUTREG(regs, R15, to, r15);
86 err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */
87 err |= __put_user(current->thread.err, &to->err);
88 err |= __put_user(current->thread.trap_no, &to->trapno);
89 err |= PUTREG(regs, RIP, to, rip);
90 err |= PUTREG(regs, EFLAGS, to, eflags);
91#undef PUTREG
92
93 err |= __put_user(mask, &to->oldmask);
94 err |= __put_user(current->thread.cr2, &to->cr2);
95
96 return(err);
97}
98
99#endif
100
101#ifdef CONFIG_MODE_TT
102int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
103 int fpsize)
104{
105 struct _fpstate *to_fp, *from_fp;
106 unsigned long sigs;
107 int err;
108
109 to_fp = to->fpstate;
110 from_fp = from->fpstate;
111 sigs = to->oldmask;
112 err = copy_from_user(to, from, sizeof(*to));
113 to->oldmask = sigs;
114 return(err);
115}
116
117int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
118 struct sigcontext *from, int fpsize)
119{
120 struct _fpstate *to_fp, *from_fp;
121 int err;
122
123 to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
124 from_fp = from->fpstate;
125 err = copy_to_user(to, from, sizeof(*to));
126 return(err);
127}
128
129#endif
130
131static int copy_sc_from_user(struct pt_regs *to, void __user *from)
132{
133 int ret;
134
135 ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from,
136 sizeof(struct _fpstate)),
137 copy_sc_from_user_skas(to, from));
138 return(ret);
139}
140
141static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp,
142 struct pt_regs *from, unsigned long mask)
143{
144 return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
145 sizeof(*fp)),
146 copy_sc_to_user_skas(to, fp, from, mask)));
147}
148
149struct rt_sigframe
150{
151 char *pretcode;
152 struct ucontext uc;
153 struct siginfo info;
154};
155
156#define round_down(m, n) (((m) / (n)) * (n))
157
158int setup_signal_stack_si(unsigned long stack_top, int sig,
159 struct k_sigaction *ka, struct pt_regs * regs,
160 siginfo_t *info, sigset_t *set)
161{
162 struct rt_sigframe __user *frame;
163 struct _fpstate __user *fp = NULL;
164 int err = 0;
165 struct task_struct *me = current;
166
167 frame = (struct rt_sigframe __user *)
168 round_down(stack_top - sizeof(struct rt_sigframe), 16) - 8;
169 frame -= 128;
170
171 if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
172 goto out;
173
174#if 0 /* XXX */
175 if (save_i387(fp) < 0)
176 err |= -1;
177#endif
178 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
179 goto out;
180
181 if (ka->sa.sa_flags & SA_SIGINFO) {
182 err |= copy_siginfo_to_user(&frame->info, info);
183 if (err)
184 goto out;
185 }
186
187 /* Create the ucontext. */
188 err |= __put_user(0, &frame->uc.uc_flags);
189 err |= __put_user(0, &frame->uc.uc_link);
190 err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
191 err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)),
192 &frame->uc.uc_stack.ss_flags);
193 err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
194 err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
195 err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate);
196 if (sizeof(*set) == 16) {
197 __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
198 __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
199 }
200 else
201 err |= __copy_to_user(&frame->uc.uc_sigmask, set,
202 sizeof(*set));
203
204 /* Set up to return from userspace. If provided, use a stub
205 already in userspace. */
206 /* x86-64 should always use SA_RESTORER. */
207 if (ka->sa.sa_flags & SA_RESTORER)
208 err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
209 else
210 /* could use a vstub here */
211 goto out;
212
213 if (err)
214 goto out;
215
216 /* Set up registers for signal handler */
217 {
218 struct exec_domain *ed = current_thread_info()->exec_domain;
219 if (unlikely(ed && ed->signal_invmap && sig < 32))
220 sig = ed->signal_invmap[sig];
221 }
222
223 PT_REGS_RDI(regs) = sig;
224 /* In case the signal handler was declared without prototypes */
225 PT_REGS_RAX(regs) = 0;
226
227 /* This also works for non SA_SIGINFO handlers because they expect the
228 next argument after the signal number on the stack. */
229 PT_REGS_RSI(regs) = (unsigned long) &frame->info;
230 PT_REGS_RDX(regs) = (unsigned long) &frame->uc;
231 PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler;
232
233 PT_REGS_RSP(regs) = (unsigned long) frame;
234 out:
235 return(err);
236}
237
238long sys_rt_sigreturn(struct pt_regs *regs)
239{
240 unsigned long sp = PT_REGS_SP(&current->thread.regs);
241 struct rt_sigframe __user *frame =
242 (struct rt_sigframe __user *)(sp - 8);
243 struct ucontext __user *uc = &frame->uc;
244 sigset_t set;
245
246 if(copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
247 goto segfault;
248
249 sigdelsetmask(&set, ~_BLOCKABLE);
250
251 spin_lock_irq(&current->sighand->siglock);
252 current->blocked = set;
253 recalc_sigpending();
254 spin_unlock_irq(&current->sighand->siglock);
255
256 if(copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext))
257 goto segfault;
258
259 /* Avoid ERESTART handling */
260 PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
261 return(PT_REGS_SYSCALL_RET(&current->thread.regs));
262
263 segfault:
264 force_sig(SIGSEGV, current);
265 return 0;
266}
267/*
268 * Overrides for Emacs so that we follow Linus's tabbing style.
269 * Emacs will notice this stuff at the end of the file and automatically
270 * adjust the settings for this buffer only. This must remain at the end
271 * of the file.
272 * ---------------------------------------------------------------------------
273 * Local variables:
274 * c-file-style: "linux"
275 * End:
276 */
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c
new file mode 100644
index 000000000000..68205a03364c
--- /dev/null
+++ b/arch/um/sys-x86_64/syscalls.c
@@ -0,0 +1,186 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#include "linux/linkage.h"
8#include "linux/slab.h"
9#include "linux/shm.h"
10#include "asm/uaccess.h"
11#define __FRAME_OFFSETS
12#include "asm/ptrace.h"
13#include "asm/unistd.h"
14#include "asm/prctl.h" /* XXX This should get the constants from libc */
15#include "choose-mode.h"
16
17asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg)
18{
19 unsigned long raddr;
20
21 return do_shmat(shmid, shmaddr, shmflg, &raddr) ?: (long) raddr;
22}
23
24#ifdef CONFIG_MODE_TT
25extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
26
27long sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount)
28{
29 /* XXX This should check VERIFY_WRITE depending on func, check this
30 * in i386 as well.
31 */
32 if (!access_ok(VERIFY_READ, ptr, bytecount))
33 return -EFAULT;
34 return(modify_ldt(func, ptr, bytecount));
35}
36#endif
37
38#ifdef CONFIG_MODE_SKAS
39extern int userspace_pid[];
40
41long sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount)
42{
43 struct ptrace_ldt ldt;
44 void *buf;
45 int res, n;
46
47 buf = kmalloc(bytecount, GFP_KERNEL);
48 if(buf == NULL)
49 return(-ENOMEM);
50
51 res = 0;
52
53 switch(func){
54 case 1:
55 case 0x11:
56 res = copy_from_user(buf, ptr, bytecount);
57 break;
58 }
59
60 if(res != 0){
61 res = -EFAULT;
62 goto out;
63 }
64
65 ldt = ((struct ptrace_ldt) { .func = func,
66 .ptr = buf,
67 .bytecount = bytecount });
68#warning Need to look up userspace_pid by cpu
69 res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt);
70 if(res < 0)
71 goto out;
72
73 switch(func){
74 case 0:
75 case 2:
76 n = res;
77 res = copy_to_user(ptr, buf, n);
78 if(res != 0)
79 res = -EFAULT;
80 else
81 res = n;
82 break;
83 }
84
85 out:
86 kfree(buf);
87 return(res);
88}
89#endif
90
91long sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
92{
93 return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func,
94 ptr, bytecount));
95}
96
97#ifdef CONFIG_MODE_TT
98extern long arch_prctl(int code, unsigned long addr);
99
100static long arch_prctl_tt(int code, unsigned long addr)
101{
102 unsigned long tmp;
103 long ret;
104
105 switch(code){
106 case ARCH_SET_GS:
107 case ARCH_SET_FS:
108 ret = arch_prctl(code, addr);
109 break;
110 case ARCH_GET_FS:
111 case ARCH_GET_GS:
112 ret = arch_prctl(code, (unsigned long) &tmp);
113 if(!ret)
114 ret = put_user(tmp, &addr);
115 break;
116 default:
117 ret = -EINVAL;
118 break;
119 }
120
121 return(ret);
122}
123#endif
124
125#ifdef CONFIG_MODE_SKAS
126
127static long arch_prctl_skas(int code, unsigned long addr)
128{
129 long ret = 0;
130
131 switch(code){
132 case ARCH_SET_GS:
133 current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr;
134 break;
135 case ARCH_SET_FS:
136 current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr;
137 break;
138 case ARCH_GET_FS:
139 ret = put_user(current->thread.regs.regs.skas.regs[GS / sizeof(unsigned long)], &addr);
140 break;
141 case ARCH_GET_GS:
142 ret = put_user(current->thread.regs.regs.skas.regs[FS / sizeof(unsigned \
143long)], &addr);
144 break;
145 default:
146 ret = -EINVAL;
147 break;
148 }
149
150 return(ret);
151}
152#endif
153
154long sys_arch_prctl(int code, unsigned long addr)
155{
156 return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr));
157}
158
159long sys_clone(unsigned long clone_flags, unsigned long newsp,
160 void __user *parent_tid, void __user *child_tid)
161{
162 long ret;
163
164 /* XXX: normal arch do here this pass, and also pass the regs to
165 * do_fork, instead of NULL. Currently the arch-independent code
166 * ignores these values, while the UML code (actually it's
167 * copy_thread) does the right thing. But this should change,
168 probably. */
169 /*if (!newsp)
170 newsp = UPT_SP(current->thread.regs);*/
171 current->thread.forking = 1;
172 ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
173 current->thread.forking = 0;
174 return(ret);
175}
176
177/*
178 * Overrides for Emacs so that we follow Linus's tabbing style.
179 * Emacs will notice this stuff at the end of the file and automatically
180 * adjust the settings for this buffer only. This must remain at the end
181 * of the file.
182 * ---------------------------------------------------------------------------
183 * Local variables:
184 * c-file-style: "linux"
185 * End:
186 */
diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c
new file mode 100644
index 000000000000..ddf74691a610
--- /dev/null
+++ b/arch/um/sys-x86_64/sysrq.c
@@ -0,0 +1,49 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#include "linux/kernel.h"
8#include "linux/utsname.h"
9#include "linux/module.h"
10#include "asm/current.h"
11#include "asm/ptrace.h"
12#include "sysrq.h"
13
14void __show_regs(struct pt_regs * regs)
15{
16 printk("\n");
17 print_modules();
18 printk("Pid: %d, comm: %.20s %s %s\n",
19 current->pid, current->comm, print_tainted(), system_utsname.release);
20 printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff,
21 PT_REGS_RIP(regs));
22 printk("\nRSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs),
23 PT_REGS_EFLAGS(regs));
24 printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
25 PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs));
26 printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
27 PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs));
28 printk("RBP: %016lx R08: %016lx R09: %016lx\n",
29 PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs));
30 printk("R10: %016lx R11: %016lx R12: %016lx\n",
31 PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs));
32 printk("R13: %016lx R14: %016lx R15: %016lx\n",
33 PT_REGS_R13(regs), PT_REGS_R14(regs), PT_REGS_R15(regs));
34}
35
36void show_regs(struct pt_regs *regs)
37{
38 __show_regs(regs);
39 show_trace((unsigned long *) &regs);
40}
41
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/sys-x86_64/util/Makefile b/arch/um/sys-x86_64/util/Makefile
new file mode 100644
index 000000000000..002607980864
--- /dev/null
+++ b/arch/um/sys-x86_64/util/Makefile
@@ -0,0 +1,10 @@
1# Copyright 2003 - 2004 Pathscale, Inc
2# Released under the GPL
3
4hostprogs-y := mk_sc mk_thread
5always := $(hostprogs-y)
6
7mk_thread-objs := mk_thread_kern.o mk_thread_user.o
8
9HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS)
10HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS)
diff --git a/arch/um/sys-x86_64/util/mk_sc.c b/arch/um/sys-x86_64/util/mk_sc.c
new file mode 100644
index 000000000000..c236e213918d
--- /dev/null
+++ b/arch/um/sys-x86_64/util/mk_sc.c
@@ -0,0 +1,58 @@
1/* Copyright (C) 2003 - 2004 PathScale, Inc
2 * Released under the GPL
3 */
4
5#include <stdio.h>
6#include <signal.h>
7#include <linux/stddef.h>
8
9#define SC_OFFSET(name, field) \
10 printf("#define " name \
11 "(sc) *((unsigned long *) &(((char *) (sc))[%ld]))\n",\
12 offsetof(struct sigcontext, field))
13
14#define SC_FP_OFFSET(name, field) \
15 printf("#define " name \
16 "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%ld]))\n",\
17 offsetof(struct _fpstate, field))
18
19#define SC_FP_OFFSET_PTR(name, field, type) \
20 printf("#define " name \
21 "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
22 offsetof(struct _fpstate, field))
23
24int main(int argc, char **argv)
25{
26 SC_OFFSET("SC_RBX", rbx);
27 SC_OFFSET("SC_RCX", rcx);
28 SC_OFFSET("SC_RDX", rdx);
29 SC_OFFSET("SC_RSI", rsi);
30 SC_OFFSET("SC_RDI", rdi);
31 SC_OFFSET("SC_RBP", rbp);
32 SC_OFFSET("SC_RAX", rax);
33 SC_OFFSET("SC_R8", r8);
34 SC_OFFSET("SC_R9", r9);
35 SC_OFFSET("SC_R10", r10);
36 SC_OFFSET("SC_R11", r11);
37 SC_OFFSET("SC_R12", r12);
38 SC_OFFSET("SC_R13", r13);
39 SC_OFFSET("SC_R14", r14);
40 SC_OFFSET("SC_R15", r15);
41 SC_OFFSET("SC_IP", rip);
42 SC_OFFSET("SC_SP", rsp);
43 SC_OFFSET("SC_CR2", cr2);
44 SC_OFFSET("SC_ERR", err);
45 SC_OFFSET("SC_TRAPNO", trapno);
46 SC_OFFSET("SC_CS", cs);
47 SC_OFFSET("SC_FS", fs);
48 SC_OFFSET("SC_GS", gs);
49 SC_OFFSET("SC_EFLAGS", eflags);
50 SC_OFFSET("SC_SIGMASK", oldmask);
51#if 0
52 SC_OFFSET("SC_ORIG_RAX", orig_rax);
53 SC_OFFSET("SC_DS", ds);
54 SC_OFFSET("SC_ES", es);
55 SC_OFFSET("SC_SS", ss);
56#endif
57 return(0);
58}
diff --git a/arch/um/sys-x86_64/util/mk_thread_kern.c b/arch/um/sys-x86_64/util/mk_thread_kern.c
new file mode 100644
index 000000000000..a281673f02b2
--- /dev/null
+++ b/arch/um/sys-x86_64/util/mk_thread_kern.c
@@ -0,0 +1,21 @@
1#include "linux/config.h"
2#include "linux/stddef.h"
3#include "linux/sched.h"
4
5extern void print_head(void);
6extern void print_constant_ptr(char *name, int value);
7extern void print_constant(char *name, char *type, int value);
8extern void print_tail(void);
9
10#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field)
11
12int main(int argc, char **argv)
13{
14 print_head();
15#ifdef CONFIG_MODE_TT
16 print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid));
17#endif
18 print_tail();
19 return(0);
20}
21
diff --git a/arch/um/sys-x86_64/util/mk_thread_user.c b/arch/um/sys-x86_64/util/mk_thread_user.c
new file mode 100644
index 000000000000..7989725568b8
--- /dev/null
+++ b/arch/um/sys-x86_64/util/mk_thread_user.c
@@ -0,0 +1,30 @@
1#include <stdio.h>
2
3void print_head(void)
4{
5 printf("/*\n");
6 printf(" * Generated by mk_thread\n");
7 printf(" */\n");
8 printf("\n");
9 printf("#ifndef __UM_THREAD_H\n");
10 printf("#define __UM_THREAD_H\n");
11 printf("\n");
12}
13
14void print_constant_ptr(char *name, int value)
15{
16 printf("#define %s(task) ((unsigned long *) "
17 "&(((char *) (task))[%d]))\n", name, value);
18}
19
20void print_constant(char *name, char *type, int value)
21{
22 printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
23 value);
24}
25
26void print_tail(void)
27{
28 printf("\n");
29 printf("#endif\n");
30}
diff --git a/arch/um/util/Makefile b/arch/um/util/Makefile
new file mode 100644
index 000000000000..e2ab71209f3f
--- /dev/null
+++ b/arch/um/util/Makefile
@@ -0,0 +1,8 @@
1hostprogs-y := mk_task mk_constants
2always := $(hostprogs-y)
3
4mk_task-objs := mk_task_user.o mk_task_kern.o
5mk_constants-objs := mk_constants_user.o mk_constants_kern.o
6
7HOSTCFLAGS_mk_task_kern.o := $(CFLAGS) $(CPPFLAGS)
8HOSTCFLAGS_mk_constants_kern.o := $(CFLAGS) $(CPPFLAGS)
diff --git a/arch/um/util/mk_constants_kern.c b/arch/um/util/mk_constants_kern.c
new file mode 100644
index 000000000000..cdcb1232a1ea
--- /dev/null
+++ b/arch/um/util/mk_constants_kern.c
@@ -0,0 +1,28 @@
1#include "linux/kernel.h"
2#include "linux/stringify.h"
3#include "linux/time.h"
4#include "asm/page.h"
5
6extern void print_head(void);
7extern void print_constant_str(char *name, char *value);
8extern void print_constant_int(char *name, int value);
9extern void print_tail(void);
10
11int main(int argc, char **argv)
12{
13 print_head();
14 print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE);
15
16 print_constant_str("UM_KERN_EMERG", KERN_EMERG);
17 print_constant_str("UM_KERN_ALERT", KERN_ALERT);
18 print_constant_str("UM_KERN_CRIT", KERN_CRIT);
19 print_constant_str("UM_KERN_ERR", KERN_ERR);
20 print_constant_str("UM_KERN_WARNING", KERN_WARNING);
21 print_constant_str("UM_KERN_NOTICE", KERN_NOTICE);
22 print_constant_str("UM_KERN_INFO", KERN_INFO);
23 print_constant_str("UM_KERN_DEBUG", KERN_DEBUG);
24
25 print_constant_int("UM_NSEC_PER_SEC", NSEC_PER_SEC);
26 print_tail();
27 return(0);
28}
diff --git a/arch/um/util/mk_constants_user.c b/arch/um/util/mk_constants_user.c
new file mode 100644
index 000000000000..8f4d7e50be7c
--- /dev/null
+++ b/arch/um/util/mk_constants_user.c
@@ -0,0 +1,28 @@
1#include <stdio.h>
2
3void print_head(void)
4{
5 printf("/*\n");
6 printf(" * Generated by mk_constants\n");
7 printf(" */\n");
8 printf("\n");
9 printf("#ifndef __UM_CONSTANTS_H\n");
10 printf("#define __UM_CONSTANTS_H\n");
11 printf("\n");
12}
13
14void print_constant_str(char *name, char *value)
15{
16 printf("#define %s \"%s\"\n", name, value);
17}
18
19void print_constant_int(char *name, int value)
20{
21 printf("#define %s %d\n", name, value);
22}
23
24void print_tail(void)
25{
26 printf("\n");
27 printf("#endif\n");
28}
diff --git a/arch/um/util/mk_task_kern.c b/arch/um/util/mk_task_kern.c
new file mode 100644
index 000000000000..c218103315ed
--- /dev/null
+++ b/arch/um/util/mk_task_kern.c
@@ -0,0 +1,17 @@
1#include "linux/sched.h"
2#include "linux/stddef.h"
3
4extern void print(char *name, char *type, int offset);
5extern void print_ptr(char *name, char *type, int offset);
6extern void print_head(void);
7extern void print_tail(void);
8
9int main(int argc, char **argv)
10{
11 print_head();
12 print_ptr("TASK_REGS", "union uml_pt_regs",
13 offsetof(struct task_struct, thread.regs));
14 print("TASK_PID", "int", offsetof(struct task_struct, pid));
15 print_tail();
16 return(0);
17}
diff --git a/arch/um/util/mk_task_user.c b/arch/um/util/mk_task_user.c
new file mode 100644
index 000000000000..9db849f3f3ac
--- /dev/null
+++ b/arch/um/util/mk_task_user.c
@@ -0,0 +1,30 @@
1#include <stdio.h>
2
3void print(char *name, char *type, int offset)
4{
5 printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
6 offset);
7}
8
9void print_ptr(char *name, char *type, int offset)
10{
11 printf("#define %s(task) ((%s *) &(((char *) (task))[%d]))\n", name, type,
12 offset);
13}
14
15void print_head(void)
16{
17 printf("/*\n");
18 printf(" * Generated by mk_task\n");
19 printf(" */\n");
20 printf("\n");
21 printf("#ifndef __TASK_H\n");
22 printf("#define __TASK_H\n");
23 printf("\n");
24}
25
26void print_tail(void)
27{
28 printf("\n");
29 printf("#endif\n");
30}