diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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')
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 | ||
2 | config GENERIC_HARDIRQS | ||
3 | bool | ||
4 | default y | ||
5 | |||
6 | config UML | ||
7 | bool | ||
8 | default y | ||
9 | |||
10 | # XXX: does UM have a mmu/swap? | ||
11 | config MMU | ||
12 | bool | ||
13 | default y | ||
14 | |||
15 | mainmenu "Linux/Usermode Kernel Configuration" | ||
16 | |||
17 | config ISA | ||
18 | bool | ||
19 | |||
20 | config SBUS | ||
21 | bool | ||
22 | |||
23 | config PCI | ||
24 | bool | ||
25 | |||
26 | config UID16 | ||
27 | bool | ||
28 | default y | ||
29 | |||
30 | config RWSEM_GENERIC_SPINLOCK | ||
31 | bool | ||
32 | default y | ||
33 | |||
34 | config GENERIC_CALIBRATE_DELAY | ||
35 | bool | ||
36 | default y | ||
37 | |||
38 | menu "UML-specific options" | ||
39 | |||
40 | config 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 | |||
49 | config 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 | |||
61 | config 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 | |||
71 | source "arch/um/Kconfig_arch" | ||
72 | |||
73 | config LD_SCRIPT_STATIC | ||
74 | bool | ||
75 | default y | ||
76 | depends on MODE_TT || STATIC_LINK | ||
77 | |||
78 | config LD_SCRIPT_DYN | ||
79 | bool | ||
80 | default y | ||
81 | depends on !LD_SCRIPT_STATIC | ||
82 | |||
83 | config 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 | |||
100 | source "fs/Kconfig.binfmt" | ||
101 | |||
102 | config 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 | |||
123 | config 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 | |||
141 | config 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 | |||
158 | config 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 | |||
177 | config 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 | |||
190 | config 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 | |||
214 | config NR_CPUS | ||
215 | int "Maximum number of CPUs (2-32)" | ||
216 | range 2 32 | ||
217 | depends on SMP | ||
218 | default "32" | ||
219 | |||
220 | config 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 | |||
236 | config 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 | |||
245 | config HIGHMEM | ||
246 | bool "Highmem support" | ||
247 | |||
248 | config 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 | |||
256 | config 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 | |||
267 | endmenu | ||
268 | |||
269 | source "init/Kconfig" | ||
270 | |||
271 | source "drivers/base/Kconfig" | ||
272 | |||
273 | source "arch/um/Kconfig_char" | ||
274 | |||
275 | source "drivers/block/Kconfig" | ||
276 | |||
277 | config NETDEVICES | ||
278 | bool | ||
279 | default NET | ||
280 | |||
281 | source "arch/um/Kconfig_net" | ||
282 | |||
283 | source "net/Kconfig" | ||
284 | |||
285 | source "fs/Kconfig" | ||
286 | |||
287 | source "security/Kconfig" | ||
288 | |||
289 | source "crypto/Kconfig" | ||
290 | |||
291 | source "lib/Kconfig" | ||
292 | |||
293 | menu "SCSI support" | ||
294 | depends on BROKEN | ||
295 | |||
296 | config SCSI | ||
297 | tristate "SCSI support" | ||
298 | |||
299 | # This gives us free_dma, which scsi.c wants. | ||
300 | config GENERIC_ISA_DMA | ||
301 | bool | ||
302 | depends on SCSI | ||
303 | default y | ||
304 | |||
305 | source "arch/um/Kconfig_scsi" | ||
306 | |||
307 | endmenu | ||
308 | |||
309 | source "drivers/md/Kconfig" | ||
310 | |||
311 | if BROKEN | ||
312 | source "drivers/mtd/Kconfig" | ||
313 | endif | ||
314 | |||
315 | #This is just to shut up some Kconfig warnings, so no prompt. | ||
316 | config INPUT | ||
317 | bool | ||
318 | default n | ||
319 | |||
320 | source "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 @@ | |||
1 | menu "Kernel hacking" | ||
2 | |||
3 | source "lib/Kconfig.debug" | ||
4 | |||
5 | config FRAME_POINTER | ||
6 | bool | ||
7 | default y if DEBUG_INFO | ||
8 | |||
9 | config 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 | |||
17 | config 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 | |||
30 | config 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 | |||
43 | config 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 | |||
53 | endmenu | ||
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 | |||
2 | menu "Character Devices" | ||
3 | |||
4 | config STDERR_CONSOLE | ||
5 | bool "stderr console" | ||
6 | default y | ||
7 | help | ||
8 | console driver which dumps all printk messages to stderr. | ||
9 | |||
10 | config STDIO_CONSOLE | ||
11 | bool | ||
12 | default y | ||
13 | |||
14 | config 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 | |||
26 | config 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 | |||
33 | config 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 | |||
43 | config 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 | |||
53 | config 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 | |||
62 | config 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 | |||
72 | config NOCONFIG_CHAN | ||
73 | bool | ||
74 | default !(XTERM_CHAN && TTY_CHAN && PTY_CHAN && PORT_CHAN && NULL_CHAN) | ||
75 | |||
76 | config 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 | |||
86 | config 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 | |||
98 | config 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 | |||
110 | config 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 | |||
132 | config 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 | |||
150 | config 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 | |||
162 | config WATCHDOG | ||
163 | bool "Watchdog Timer Support" | ||
164 | |||
165 | config WATCHDOG_NOWAYOUT | ||
166 | bool "Disable watchdog shutdown on close" | ||
167 | depends on WATCHDOG | ||
168 | |||
169 | config SOFT_WATCHDOG | ||
170 | tristate "Software Watchdog" | ||
171 | depends on WATCHDOG | ||
172 | |||
173 | config UML_WATCHDOG | ||
174 | tristate "UML watchdog" | ||
175 | depends on WATCHDOG | ||
176 | |||
177 | config 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 | |||
185 | config SOUND | ||
186 | tristate | ||
187 | default UML_SOUND | ||
188 | |||
189 | config HOSTAUDIO | ||
190 | tristate | ||
191 | default UML_SOUND | ||
192 | |||
193 | config 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 | |||
207 | endmenu | ||
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 @@ | |||
1 | config 64_BIT | ||
2 | bool | ||
3 | default n | ||
4 | |||
5 | config TOP_ADDR | ||
6 | hex | ||
7 | default 0xc0000000 if !HOST_2G_2G | ||
8 | default 0x80000000 if HOST_2G_2G | ||
9 | |||
10 | config 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 | |||
18 | config ARCH_HAS_SC_SIGNALS | ||
19 | bool | ||
20 | default y | ||
21 | |||
22 | config 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 | |||
2 | menu "UML Network Devices" | ||
3 | depends on NET | ||
4 | |||
5 | # UML virtual driver | ||
6 | config 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 | |||
24 | config 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 | |||
51 | config 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 | |||
63 | config 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 | |||
87 | config 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 | |||
111 | config 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 | |||
136 | config 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 | |||
152 | config 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 | |||
179 | endmenu | ||
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 @@ | |||
1 | comment "SCSI support type (disk, tape, CD-ROM)" | ||
2 | depends on SCSI | ||
3 | |||
4 | config BLK_DEV_SD | ||
5 | tristate "SCSI disk support" | ||
6 | depends on SCSI | ||
7 | |||
8 | config 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 | |||
13 | config CHR_DEV_ST | ||
14 | tristate "SCSI tape support" | ||
15 | depends on SCSI | ||
16 | |||
17 | config BLK_DEV_SR | ||
18 | tristate "SCSI CD-ROM support" | ||
19 | depends on SCSI | ||
20 | |||
21 | config BLK_DEV_SR_VENDOR | ||
22 | bool "Enable vendor-specific extensions (for SCSI CDROM)" | ||
23 | depends on BLK_DEV_SR | ||
24 | |||
25 | config 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 | |||
30 | config CHR_DEV_SG | ||
31 | tristate "SCSI generic support" | ||
32 | depends on SCSI | ||
33 | |||
34 | comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" | ||
35 | depends on SCSI | ||
36 | |||
37 | #if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then | ||
38 | config SCSI_DEBUG_QUEUES | ||
39 | bool "Enable extra checks in new queueing code" | ||
40 | depends on SCSI | ||
41 | |||
42 | #fi | ||
43 | config SCSI_MULTI_LUN | ||
44 | bool "Probe all LUNs on each SCSI device" | ||
45 | depends on SCSI | ||
46 | |||
47 | config SCSI_CONSTANTS | ||
48 | bool "Verbose SCSI error reporting (kernel size +=12K)" | ||
49 | depends on SCSI | ||
50 | |||
51 | config SCSI_LOGGING | ||
52 | bool "SCSI logging facility" | ||
53 | depends on SCSI | ||
54 | |||
55 | config 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 @@ | |||
1 | config 64_BIT | ||
2 | bool | ||
3 | default y | ||
4 | |||
5 | config 3_LEVEL_PGTABLES | ||
6 | bool | ||
7 | default y | ||
8 | |||
9 | config ARCH_HAS_SC_SIGNALS | ||
10 | bool | ||
11 | default n | ||
12 | |||
13 | config 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 | |||
6 | ARCH_DIR := arch/um | ||
7 | OS := $(shell uname -s) | ||
8 | # We require bash because the vmlinux link and loader script cpp use bash | ||
9 | # features. | ||
10 | SHELL := /bin/bash | ||
11 | |||
12 | filechk_gen_header = $< | ||
13 | |||
14 | core-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. | ||
19 | SYMLINK_HEADERS := archparam.h system.h sigcontext.h processor.h ptrace.h \ | ||
20 | arch-signal.h module.h vm-flags.h | ||
21 | SYMLINK_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! | ||
28 | ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ | ||
29 | $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h | ||
30 | |||
31 | GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h | ||
32 | |||
33 | um-modes-$(CONFIG_MODE_TT) += tt | ||
34 | um-modes-$(CONFIG_MODE_SKAS) += skas | ||
35 | |||
36 | MODE_INCLUDE += $(foreach mode,$(um-modes-y),\ | ||
37 | -I$(srctree)/$(ARCH_DIR)/kernel/$(mode)/include) | ||
38 | |||
39 | MAKEFILES-INCL += $(foreach mode,$(um-modes-y),\ | ||
40 | $(srctree)/$(ARCH_DIR)/Makefile-$(mode)) | ||
41 | |||
42 | ifneq ($(MAKEFILES-INCL),) | ||
43 | include $(MAKEFILES-INCL) | ||
44 | endif | ||
45 | |||
46 | ARCH_INCLUDE := -I$(ARCH_DIR)/include | ||
47 | SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH) | ||
48 | |||
49 | include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH) | ||
50 | |||
51 | core-y += $(SUBARCH_CORE) | ||
52 | libs-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 | |||
59 | CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ | ||
60 | $(ARCH_INCLUDE) $(MODE_INCLUDE) | ||
61 | |||
62 | USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) | ||
63 | USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ | ||
64 | $(MODE_INCLUDE) $(ARCH_USER_CFLAGS) | ||
65 | CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask | ||
66 | CFLAGS += $(call cc-option,-fno-unit-at-a-time,) | ||
67 | |||
68 | #This will adjust *FLAGS accordingly to the platform. | ||
69 | include $(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 | |||
74 | CONFIG_NEST_LEVEL ?= 0 | ||
75 | CONFIG_KERNEL_HALF_GIGS ?= 0 | ||
76 | |||
77 | SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000) | ||
78 | |||
79 | ifeq ($(CONFIG_MODE_SKAS), y) | ||
80 | $(SYS_HEADERS) : $(ARCH_DIR)/include/skas_ptregs.h | ||
81 | endif | ||
82 | |||
83 | .PHONY: linux | ||
84 | |||
85 | all: linux | ||
86 | |||
87 | linux: vmlinux | ||
88 | ln -f $< $@ | ||
89 | |||
90 | define 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.' | ||
95 | endef | ||
96 | |||
97 | $(shell cd $(ARCH_DIR) && ln -sf Kconfig_$(SUBARCH) Kconfig_arch) | ||
98 | |||
99 | prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) \ | ||
100 | $(ARCH_DIR)/kernel/vmlinux.lds.S | ||
101 | |||
102 | LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static | ||
103 | LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib | ||
104 | |||
105 | LD_SCRIPT-$(CONFIG_LD_SCRIPT_STATIC) := uml.lds.S | ||
106 | LD_SCRIPT-$(CONFIG_LD_SCRIPT_DYN) := dyn.lds.S | ||
107 | |||
108 | CPP_MODE-$(CONFIG_MODE_TT) := -DMODE_TT | ||
109 | CONFIG_KERNEL_STACK_ORDER ?= 2 | ||
110 | STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] ) | ||
111 | |||
112 | ifndef START | ||
113 | START = $$(($(TOP_ADDR) - $(SIZE))) | ||
114 | endif | ||
115 | |||
116 | CPPFLAGS_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. | ||
122 | LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc | ||
123 | |||
124 | CFLAGS_vmlinux = $(LINK-y) $(LINK_WRAPS) | ||
125 | define 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 | ||
132 | endef | ||
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. | ||
136 | CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \ | ||
137 | $(GEN_HEADERS) $(ARCH_DIR)/include/skas_ptregs.h | ||
138 | |||
139 | MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ | ||
140 | $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os \ | ||
141 | $(ARCH_DIR)/Kconfig_arch | ||
142 | |||
143 | archclean: | ||
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 | |||
162 | include/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 | ||
175 | define filechk_umlconfig | ||
176 | sed 's/ CONFIG/ UML_CONFIG/' | ||
177 | endef | ||
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 | |||
210 | export 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 @@ | |||
1 | SUBARCH_CORE := arch/um/sys-i386/ | ||
2 | |||
3 | TOP_ADDR := $(CONFIG_TOP_ADDR) | ||
4 | |||
5 | ifeq ($(CONFIG_MODE_SKAS),y) | ||
6 | ifneq ($(CONFIG_MODE_TT),y) | ||
7 | START := 0x8048000 | ||
8 | endif | ||
9 | endif | ||
10 | |||
11 | CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) | ||
12 | ARCH_USER_CFLAGS := | ||
13 | |||
14 | ifneq ($(CONFIG_GPROF),y) | ||
15 | ARCH_CFLAGS += -DUM_FASTCALL | ||
16 | endif | ||
17 | |||
18 | ELF_ARCH := $(SUBARCH) | ||
19 | ELF_FORMAT := elf32-$(SUBARCH) | ||
20 | |||
21 | OBJCOPYFLAGS := -O binary -R .note -R .comment -S | ||
22 | |||
23 | SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/util | ||
24 | |||
25 | SYS_HEADERS := $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h | ||
26 | |||
27 | prepare: $(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 | |||
44 | CLEAN_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 | ||
7 | USER_CFLAGS += -D_GNU_SOURCE -D_LARGEFILE64_SOURCE | ||
8 | CFLAGS += -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 @@ | |||
1 | ifeq ($(CONFIG_HOST_2G_2G), y) | ||
2 | START_ADDR = 0x80000000 | ||
3 | else | ||
4 | START_ADDR = 0xc0000000 | ||
5 | endif | ||
6 | ARCH_CFLAGS = -U__powerpc__ -D__UM_PPC__ | ||
7 | |||
8 | # The arch is ppc, but the elf32 name is powerpc | ||
9 | ELF_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 | |||
6 | GPROF_OPT += -pg | ||
7 | GCOV_OPT += -fprofile-arcs -ftest-coverage | ||
8 | |||
9 | CFLAGS-$(CONFIG_GCOV) += $(GCOV_OPT) | ||
10 | CFLAGS-$(CONFIG_GPROF) += $(GPROF_OPT) | ||
11 | LINK-$(CONFIG_GCOV) += $(GCOV_OPT) | ||
12 | LINK-$(CONFIG_GPROF) += $(GPROF_OPT) | ||
13 | |||
14 | GEN_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 | |||
4 | SUBARCH_LIBS := arch/um/sys-x86_64/ | ||
5 | START := 0x60000000 | ||
6 | |||
7 | CFLAGS += -U__$(SUBARCH)__ -fno-builtin | ||
8 | ARCH_USER_CFLAGS := -D__x86_64__ | ||
9 | |||
10 | ELF_ARCH := i386:x86-64 | ||
11 | ELF_FORMAT := elf64-x86-64 | ||
12 | |||
13 | SYS_UTIL_DIR := $(ARCH_DIR)/sys-x86_64/util | ||
14 | SYS_DIR := $(ARCH_DIR)/include/sysdep-x86_64 | ||
15 | |||
16 | SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h | ||
17 | |||
18 | prepare: $(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 | |||
32 | CLEAN_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 | # | ||
4 | CONFIG_USERMODE=y | ||
5 | # CONFIG_ISA is not set | ||
6 | # CONFIG_SBUS is not set | ||
7 | # CONFIG_PCI is not set | ||
8 | CONFIG_UID16=y | ||
9 | CONFIG_RWSEM_XCHGADD_ALGORITHM=y | ||
10 | |||
11 | # | ||
12 | # Code maturity level options | ||
13 | # | ||
14 | CONFIG_EXPERIMENTAL=y | ||
15 | |||
16 | # | ||
17 | # General Setup | ||
18 | # | ||
19 | CONFIG_STDIO_CONSOLE=y | ||
20 | CONFIG_NET=y | ||
21 | CONFIG_SYSVIPC=y | ||
22 | CONFIG_BSD_PROCESS_ACCT=y | ||
23 | CONFIG_SYSCTL=y | ||
24 | CONFIG_BINFMT_AOUT=y | ||
25 | CONFIG_BINFMT_ELF=y | ||
26 | CONFIG_BINFMT_MISC=y | ||
27 | CONFIG_UNIX98_PTYS=y | ||
28 | CONFIG_UNIX98_PTY_COUNT=256 | ||
29 | CONFIG_SSL=y | ||
30 | CONFIG_HOSTFS=y | ||
31 | CONFIG_MCONSOLE=y | ||
32 | CONFIG_MAGIC_SYSRQ=y | ||
33 | # CONFIG_HOST_2G_2G is not set | ||
34 | # CONFIG_UML_SMP is not set | ||
35 | # CONFIG_SMP is not set | ||
36 | CONFIG_CON_ZERO_CHAN="fd:0,fd:1" | ||
37 | CONFIG_CON_CHAN="xterm" | ||
38 | CONFIG_SSL_CHAN="pty" | ||
39 | CONFIG_NEST_LEVEL=0 | ||
40 | CONFIG_KERNEL_HALF_GIGS=1 | ||
41 | |||
42 | # | ||
43 | # Loadable module support | ||
44 | # | ||
45 | CONFIG_MODULES=y | ||
46 | CONFIG_KMOD=y | ||
47 | |||
48 | # | ||
49 | # Devices | ||
50 | # | ||
51 | CONFIG_BLK_DEV_UBD=y | ||
52 | # CONFIG_BLK_DEV_UBD_SYNC is not set | ||
53 | CONFIG_BLK_DEV_LOOP=y | ||
54 | CONFIG_BLK_DEV_NBD=y | ||
55 | CONFIG_BLK_DEV_RAM=y | ||
56 | CONFIG_BLK_DEV_RAM_SIZE=4096 | ||
57 | CONFIG_BLK_DEV_INITRD=y | ||
58 | # CONFIG_MMAPPER is not set | ||
59 | CONFIG_UML_SOUND=y | ||
60 | CONFIG_SOUND=y | ||
61 | CONFIG_HOSTAUDIO=y | ||
62 | # CONFIG_UML_WATCHDOG is not set | ||
63 | # CONFIG_TTY_LOG is not set | ||
64 | CONFIG_FD_CHAN=y | ||
65 | # CONFIG_NULL_CHAN is not set | ||
66 | CONFIG_PORT_CHAN=y | ||
67 | CONFIG_PTY_CHAN=y | ||
68 | CONFIG_TTY_CHAN=y | ||
69 | CONFIG_XTERM_CHAN=y | ||
70 | |||
71 | # | ||
72 | # Networking options | ||
73 | # | ||
74 | CONFIG_PACKET=y | ||
75 | CONFIG_PACKET_MMAP=y | ||
76 | # CONFIG_NETLINK_DEV is not set | ||
77 | # CONFIG_NETFILTER is not set | ||
78 | # CONFIG_FILTER is not set | ||
79 | CONFIG_UNIX=y | ||
80 | CONFIG_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 | # | ||
117 | CONFIG_UML_NET=y | ||
118 | CONFIG_UML_NET_ETHERTAP=y | ||
119 | CONFIG_UML_NET_TUNTAP=y | ||
120 | CONFIG_UML_NET_SLIP=y | ||
121 | CONFIG_UML_NET_DAEMON=y | ||
122 | CONFIG_UML_NET_MCAST=y | ||
123 | CONFIG_NETDEVICES=y | ||
124 | |||
125 | # | ||
126 | # ARCnet devices | ||
127 | # | ||
128 | # CONFIG_ARCNET is not set | ||
129 | CONFIG_DUMMY=y | ||
130 | CONFIG_BONDING=m | ||
131 | CONFIG_EQUALIZER=m | ||
132 | CONFIG_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 | ||
152 | CONFIG_PLIP=m | ||
153 | CONFIG_PPP=m | ||
154 | CONFIG_PPP_MULTILINK=y | ||
155 | # CONFIG_PPP_FILTER is not set | ||
156 | # CONFIG_PPP_ASYNC is not set | ||
157 | CONFIG_PPP_SYNC_TTY=m | ||
158 | CONFIG_PPP_DEFLATE=m | ||
159 | CONFIG_PPP_BSDCOMP=m | ||
160 | CONFIG_PPPOE=m | ||
161 | CONFIG_SLIP=m | ||
162 | CONFIG_SLIP_COMPRESSED=y | ||
163 | CONFIG_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 | ||
177 | CONFIG_SHAPER=m | ||
178 | |||
179 | # | ||
180 | # Wan interfaces | ||
181 | # | ||
182 | # CONFIG_WAN is not set | ||
183 | |||
184 | # | ||
185 | # File systems | ||
186 | # | ||
187 | CONFIG_QUOTA=y | ||
188 | CONFIG_AUTOFS_FS=m | ||
189 | CONFIG_AUTOFS4_FS=m | ||
190 | CONFIG_REISERFS_FS=m | ||
191 | # CONFIG_REISERFS_CHECK is not set | ||
192 | # CONFIG_REISERFS_PROC_INFO is not set | ||
193 | CONFIG_ADFS_FS=m | ||
194 | # CONFIG_ADFS_FS_RW is not set | ||
195 | CONFIG_AFFS_FS=m | ||
196 | CONFIG_HFS_FS=m | ||
197 | CONFIG_BFS_FS=m | ||
198 | CONFIG_EXT3_FS=y | ||
199 | CONFIG_JBD=y | ||
200 | # CONFIG_JBD_DEBUG is not set | ||
201 | CONFIG_FAT_FS=y | ||
202 | CONFIG_MSDOS_FS=y | ||
203 | CONFIG_UMSDOS_FS=y | ||
204 | CONFIG_VFAT_FS=y | ||
205 | CONFIG_EFS_FS=m | ||
206 | # CONFIG_JFFS_FS is not set | ||
207 | # CONFIG_JFFS2_FS is not set | ||
208 | CONFIG_CRAMFS=m | ||
209 | CONFIG_TMPFS=y | ||
210 | CONFIG_RAMFS=m | ||
211 | CONFIG_ISO9660_FS=y | ||
212 | # CONFIG_JOLIET is not set | ||
213 | # CONFIG_ZISOFS is not set | ||
214 | CONFIG_MINIX_FS=m | ||
215 | CONFIG_VXFS_FS=m | ||
216 | # CONFIG_NTFS_FS is not set | ||
217 | # CONFIG_NTFS_RW is not set | ||
218 | CONFIG_HPFS_FS=m | ||
219 | CONFIG_PROC_FS=y | ||
220 | CONFIG_DEVFS_FS=y | ||
221 | CONFIG_DEVFS_MOUNT=y | ||
222 | # CONFIG_DEVFS_DEBUG is not set | ||
223 | CONFIG_DEVPTS_FS=y | ||
224 | CONFIG_QNX4FS_FS=m | ||
225 | # CONFIG_QNX4FS_RW is not set | ||
226 | CONFIG_ROMFS_FS=m | ||
227 | CONFIG_EXT2_FS=y | ||
228 | CONFIG_SYSV_FS=m | ||
229 | CONFIG_UDF_FS=m | ||
230 | CONFIG_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 | ||
238 | CONFIG_NFS_FS=y | ||
239 | CONFIG_NFS_V3=y | ||
240 | # CONFIG_ROOT_NFS is not set | ||
241 | CONFIG_NFSD=y | ||
242 | CONFIG_NFSD_V3=y | ||
243 | CONFIG_SUNRPC=y | ||
244 | CONFIG_LOCKD=y | ||
245 | CONFIG_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 | ||
257 | CONFIG_ZLIB_FS_INFLATE=m | ||
258 | |||
259 | # | ||
260 | # Partition Types | ||
261 | # | ||
262 | # CONFIG_PARTITION_ADVANCED is not set | ||
263 | CONFIG_MSDOS_PARTITION=y | ||
264 | # CONFIG_SMB_NLS is not set | ||
265 | CONFIG_NLS=y | ||
266 | |||
267 | # | ||
268 | # Native Language Support | ||
269 | # | ||
270 | CONFIG_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 | # | ||
6 | CONFIG_GENERIC_HARDIRQS=y | ||
7 | CONFIG_UML=y | ||
8 | CONFIG_MMU=y | ||
9 | CONFIG_UID16=y | ||
10 | CONFIG_RWSEM_GENERIC_SPINLOCK=y | ||
11 | CONFIG_GENERIC_CALIBRATE_DELAY=y | ||
12 | |||
13 | # | ||
14 | # UML-specific options | ||
15 | # | ||
16 | CONFIG_MODE_TT=y | ||
17 | CONFIG_MODE_SKAS=y | ||
18 | # CONFIG_64_BIT is not set | ||
19 | CONFIG_TOP_ADDR=0xc0000000 | ||
20 | # CONFIG_3_LEVEL_PGTABLES is not set | ||
21 | CONFIG_ARCH_HAS_SC_SIGNALS=y | ||
22 | CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y | ||
23 | CONFIG_LD_SCRIPT_STATIC=y | ||
24 | CONFIG_NET=y | ||
25 | CONFIG_BINFMT_ELF=y | ||
26 | CONFIG_BINFMT_MISC=m | ||
27 | CONFIG_HOSTFS=y | ||
28 | CONFIG_MCONSOLE=y | ||
29 | # CONFIG_MAGIC_SYSRQ is not set | ||
30 | # CONFIG_HOST_2G_2G is not set | ||
31 | # CONFIG_SMP is not set | ||
32 | CONFIG_NEST_LEVEL=0 | ||
33 | CONFIG_KERNEL_HALF_GIGS=1 | ||
34 | # CONFIG_HIGHMEM is not set | ||
35 | CONFIG_KERNEL_STACK_ORDER=2 | ||
36 | CONFIG_UML_REAL_TIME_CLOCK=y | ||
37 | |||
38 | # | ||
39 | # Code maturity level options | ||
40 | # | ||
41 | CONFIG_EXPERIMENTAL=y | ||
42 | CONFIG_CLEAN_COMPILE=y | ||
43 | CONFIG_BROKEN_ON_SMP=y | ||
44 | |||
45 | # | ||
46 | # General setup | ||
47 | # | ||
48 | CONFIG_LOCALVERSION="" | ||
49 | CONFIG_SWAP=y | ||
50 | CONFIG_SYSVIPC=y | ||
51 | CONFIG_POSIX_MQUEUE=y | ||
52 | CONFIG_BSD_PROCESS_ACCT=y | ||
53 | # CONFIG_BSD_PROCESS_ACCT_V3 is not set | ||
54 | CONFIG_SYSCTL=y | ||
55 | # CONFIG_AUDIT is not set | ||
56 | # CONFIG_HOTPLUG is not set | ||
57 | CONFIG_KOBJECT_UEVENT=y | ||
58 | CONFIG_IKCONFIG=y | ||
59 | CONFIG_IKCONFIG_PROC=y | ||
60 | # CONFIG_EMBEDDED is not set | ||
61 | CONFIG_KALLSYMS=y | ||
62 | # CONFIG_KALLSYMS_ALL is not set | ||
63 | CONFIG_KALLSYMS_EXTRA_PASS=y | ||
64 | CONFIG_BASE_FULL=y | ||
65 | CONFIG_FUTEX=y | ||
66 | CONFIG_EPOLL=y | ||
67 | CONFIG_SHMEM=y | ||
68 | CONFIG_CC_ALIGN_FUNCTIONS=0 | ||
69 | CONFIG_CC_ALIGN_LABELS=0 | ||
70 | CONFIG_CC_ALIGN_LOOPS=0 | ||
71 | CONFIG_CC_ALIGN_JUMPS=0 | ||
72 | # CONFIG_TINY_SHMEM is not set | ||
73 | CONFIG_BASE_SMALL=0 | ||
74 | |||
75 | # | ||
76 | # Loadable module support | ||
77 | # | ||
78 | CONFIG_MODULES=y | ||
79 | CONFIG_MODULE_UNLOAD=y | ||
80 | # CONFIG_MODULE_FORCE_UNLOAD is not set | ||
81 | CONFIG_OBSOLETE_MODPARM=y | ||
82 | # CONFIG_MODULE_SRCVERSION_ALL is not set | ||
83 | CONFIG_KMOD=y | ||
84 | |||
85 | # | ||
86 | # Generic Driver Options | ||
87 | # | ||
88 | CONFIG_STANDALONE=y | ||
89 | CONFIG_PREVENT_FIRMWARE_BUILD=y | ||
90 | # CONFIG_FW_LOADER is not set | ||
91 | # CONFIG_DEBUG_DRIVER is not set | ||
92 | |||
93 | # | ||
94 | # Character Devices | ||
95 | # | ||
96 | CONFIG_STDERR_CONSOLE=y | ||
97 | CONFIG_STDIO_CONSOLE=y | ||
98 | CONFIG_SSL=y | ||
99 | CONFIG_NULL_CHAN=y | ||
100 | CONFIG_PORT_CHAN=y | ||
101 | CONFIG_PTY_CHAN=y | ||
102 | CONFIG_TTY_CHAN=y | ||
103 | CONFIG_XTERM_CHAN=y | ||
104 | # CONFIG_NOCONFIG_CHAN is not set | ||
105 | CONFIG_CON_ZERO_CHAN="fd:0,fd:1" | ||
106 | CONFIG_CON_CHAN="xterm" | ||
107 | CONFIG_SSL_CHAN="pty" | ||
108 | CONFIG_UNIX98_PTYS=y | ||
109 | CONFIG_LEGACY_PTYS=y | ||
110 | CONFIG_LEGACY_PTY_COUNT=256 | ||
111 | # CONFIG_WATCHDOG is not set | ||
112 | CONFIG_UML_SOUND=m | ||
113 | CONFIG_SOUND=m | ||
114 | CONFIG_HOSTAUDIO=m | ||
115 | CONFIG_UML_RANDOM=y | ||
116 | |||
117 | # | ||
118 | # Block devices | ||
119 | # | ||
120 | CONFIG_BLK_DEV_UBD=y | ||
121 | CONFIG_BLK_DEV_UBD_SYNC=y | ||
122 | CONFIG_BLK_DEV_COW_COMMON=y | ||
123 | CONFIG_BLK_DEV_LOOP=m | ||
124 | # CONFIG_BLK_DEV_CRYPTOLOOP is not set | ||
125 | CONFIG_BLK_DEV_NBD=m | ||
126 | # CONFIG_BLK_DEV_RAM is not set | ||
127 | CONFIG_BLK_DEV_RAM_COUNT=16 | ||
128 | CONFIG_INITRAMFS_SOURCE="" | ||
129 | # CONFIG_LBD is not set | ||
130 | |||
131 | # | ||
132 | # IO Schedulers | ||
133 | # | ||
134 | CONFIG_IOSCHED_NOOP=y | ||
135 | CONFIG_IOSCHED_AS=y | ||
136 | CONFIG_IOSCHED_DEADLINE=y | ||
137 | CONFIG_IOSCHED_CFQ=y | ||
138 | # CONFIG_ATA_OVER_ETH is not set | ||
139 | CONFIG_NETDEVICES=y | ||
140 | |||
141 | # | ||
142 | # UML Network Devices | ||
143 | # | ||
144 | CONFIG_UML_NET=y | ||
145 | CONFIG_UML_NET_ETHERTAP=y | ||
146 | CONFIG_UML_NET_TUNTAP=y | ||
147 | CONFIG_UML_NET_SLIP=y | ||
148 | CONFIG_UML_NET_DAEMON=y | ||
149 | CONFIG_UML_NET_MCAST=y | ||
150 | CONFIG_UML_NET_SLIRP=y | ||
151 | |||
152 | # | ||
153 | # Networking support | ||
154 | # | ||
155 | |||
156 | # | ||
157 | # Networking options | ||
158 | # | ||
159 | CONFIG_PACKET=y | ||
160 | CONFIG_PACKET_MMAP=y | ||
161 | # CONFIG_NETLINK_DEV is not set | ||
162 | CONFIG_UNIX=y | ||
163 | # CONFIG_NET_KEY is not set | ||
164 | CONFIG_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 | ||
176 | CONFIG_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 | ||
213 | CONFIG_DUMMY=m | ||
214 | # CONFIG_BONDING is not set | ||
215 | # CONFIG_EQUALIZER is not set | ||
216 | CONFIG_TUN=m | ||
217 | |||
218 | # | ||
219 | # Wan interfaces | ||
220 | # | ||
221 | # CONFIG_WAN is not set | ||
222 | CONFIG_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 | ||
230 | CONFIG_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 | # | ||
240 | CONFIG_EXT2_FS=y | ||
241 | # CONFIG_EXT2_FS_XATTR is not set | ||
242 | CONFIG_EXT3_FS=y | ||
243 | # CONFIG_EXT3_FS_XATTR is not set | ||
244 | CONFIG_JBD=y | ||
245 | # CONFIG_JBD_DEBUG is not set | ||
246 | CONFIG_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 | ||
258 | CONFIG_QUOTA=y | ||
259 | # CONFIG_QFMT_V1 is not set | ||
260 | # CONFIG_QFMT_V2 is not set | ||
261 | CONFIG_QUOTACTL=y | ||
262 | CONFIG_DNOTIFY=y | ||
263 | CONFIG_AUTOFS_FS=m | ||
264 | CONFIG_AUTOFS4_FS=m | ||
265 | |||
266 | # | ||
267 | # CD-ROM/DVD Filesystems | ||
268 | # | ||
269 | CONFIG_ISO9660_FS=m | ||
270 | CONFIG_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 | # | ||
284 | CONFIG_PROC_FS=y | ||
285 | CONFIG_PROC_KCORE=y | ||
286 | CONFIG_SYSFS=y | ||
287 | # CONFIG_DEVFS_FS is not set | ||
288 | # CONFIG_DEVPTS_FS_XATTR is not set | ||
289 | CONFIG_TMPFS=y | ||
290 | # CONFIG_TMPFS_XATTR is not set | ||
291 | # CONFIG_HUGETLB_PAGE is not set | ||
292 | CONFIG_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 | ||
326 | CONFIG_MSDOS_PARTITION=y | ||
327 | |||
328 | # | ||
329 | # Native Language Support | ||
330 | # | ||
331 | CONFIG_NLS=y | ||
332 | CONFIG_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 | ||
391 | CONFIG_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 | ||
404 | CONFIG_DEBUG_KERNEL=y | ||
405 | CONFIG_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 | ||
411 | CONFIG_DEBUG_INFO=y | ||
412 | # CONFIG_DEBUG_FS is not set | ||
413 | CONFIG_FRAME_POINTER=y | ||
414 | CONFIG_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 | |||
9 | slip-objs := slip_kern.o slip_user.o | ||
10 | slirp-objs := slirp_kern.o slirp_user.o | ||
11 | daemon-objs := daemon_kern.o daemon_user.o | ||
12 | mcast-objs := mcast_kern.o mcast_user.o | ||
13 | #pcap-objs := pcap_kern.o pcap_user.o $(PCAP) | ||
14 | net-objs := net_kern.o net_user.o | ||
15 | mconsole-objs := mconsole_kern.o mconsole_user.o | ||
16 | hostaudio-objs := hostaudio_kern.o | ||
17 | ubd-objs := ubd_kern.o ubd_user.o | ||
18 | port-objs := port_kern.o port_user.o | ||
19 | harddog-objs := harddog_kern.o harddog_user.o | ||
20 | |||
21 | obj-y := stdio_console.o fd.o chan_kern.o chan_user.o line.o | ||
22 | obj-$(CONFIG_SSL) += ssl.o | ||
23 | obj-$(CONFIG_STDERR_CONSOLE) += stderr_console.o | ||
24 | |||
25 | obj-$(CONFIG_UML_NET_SLIP) += slip.o | ||
26 | obj-$(CONFIG_UML_NET_SLIRP) += slirp.o | ||
27 | obj-$(CONFIG_UML_NET_DAEMON) += daemon.o | ||
28 | obj-$(CONFIG_UML_NET_MCAST) += mcast.o | ||
29 | #obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP) | ||
30 | obj-$(CONFIG_UML_NET) += net.o | ||
31 | obj-$(CONFIG_MCONSOLE) += mconsole.o | ||
32 | obj-$(CONFIG_MMAPPER) += mmapper_kern.o | ||
33 | obj-$(CONFIG_BLK_DEV_UBD) += ubd.o | ||
34 | obj-$(CONFIG_HOSTAUDIO) += hostaudio.o | ||
35 | obj-$(CONFIG_NULL_CHAN) += null.o | ||
36 | obj-$(CONFIG_PORT_CHAN) += port.o | ||
37 | obj-$(CONFIG_PTY_CHAN) += pty.o | ||
38 | obj-$(CONFIG_TTY_CHAN) += tty.o | ||
39 | obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o | ||
40 | obj-$(CONFIG_UML_WATCHDOG) += harddog.o | ||
41 | obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o | ||
42 | obj-$(CONFIG_UML_RANDOM) += random.o | ||
43 | |||
44 | USER_OBJS := fd.o null.o pty.o tty.o xterm.o | ||
45 | |||
46 | include 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 | ||
23 | static 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 | |||
30 | static 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 | |||
38 | static 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 | |||
44 | static 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 | |||
51 | static 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 | |||
58 | static 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 | |||
66 | static 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 | |||
74 | static 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 | |||
80 | static 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 | |||
93 | void generic_close(int fd, void *unused) | ||
94 | { | ||
95 | os_close_file(fd); | ||
96 | } | ||
97 | |||
98 | int 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 | |||
113 | int generic_write(int fd, const char *buf, int n, void *unused) | ||
114 | { | ||
115 | return(os_write_file(fd, buf, n)); | ||
116 | } | ||
117 | |||
118 | int 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 | |||
136 | void generic_free(void *data) | ||
137 | { | ||
138 | kfree(data); | ||
139 | } | ||
140 | |||
141 | static 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 | |||
162 | static 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 | |||
177 | int 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 | |||
192 | void 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 | |||
206 | void 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 | |||
219 | void 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 | |||
237 | int 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 | |||
258 | int 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 | |||
274 | int 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 | |||
288 | int 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 | |||
305 | void 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 | |||
315 | void 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 | |||
326 | static 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 | |||
349 | static 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 | |||
372 | int 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 | |||
391 | struct chan_type { | ||
392 | char *key; | ||
393 | struct chan_ops *ops; | ||
394 | }; | ||
395 | |||
396 | struct chan_type chan_table[] = { | ||
397 | { "fd", &fd_ops }, | ||
398 | |||
399 | #ifdef CONFIG_NULL_CHAN | ||
400 | { "null", &null_ops }, | ||
401 | #else | ||
402 | { "null", ¬_configged_ops }, | ||
403 | #endif | ||
404 | |||
405 | #ifdef CONFIG_PORT_CHAN | ||
406 | { "port", &port_ops }, | ||
407 | #else | ||
408 | { "port", ¬_configged_ops }, | ||
409 | #endif | ||
410 | |||
411 | #ifdef CONFIG_PTY_CHAN | ||
412 | { "pty", &pty_ops }, | ||
413 | { "pts", &pts_ops }, | ||
414 | #else | ||
415 | { "pty", ¬_configged_ops }, | ||
416 | { "pts", ¬_configged_ops }, | ||
417 | #endif | ||
418 | |||
419 | #ifdef CONFIG_TTY_CHAN | ||
420 | { "tty", &tty_ops }, | ||
421 | #else | ||
422 | { "tty", ¬_configged_ops }, | ||
423 | #endif | ||
424 | |||
425 | #ifdef CONFIG_XTERM_CHAN | ||
426 | { "xterm", &xterm_ops }, | ||
427 | #else | ||
428 | { "xterm", ¬_configged_ops }, | ||
429 | #endif | ||
430 | }; | ||
431 | |||
432 | static 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 | |||
474 | int 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 | |||
512 | int 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 | |||
525 | void 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 | |||
24 | int 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); | ||
48 | error: | ||
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 | |||
70 | static void winch_handler(int sig) | ||
71 | { | ||
72 | } | ||
73 | |||
74 | struct winch_data { | ||
75 | int pty_fd; | ||
76 | int pipe_fd; | ||
77 | int close_me; | ||
78 | }; | ||
79 | |||
80 | static 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 | |||
142 | static 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 | |||
176 | void 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 | |||
16 | extern 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 | |||
20 | extern int file_reader(__u64 offset, char *buf, int len, void *arg); | ||
21 | extern 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 | |||
27 | extern int write_cow_header(char *cow_file, int fd, char *backing_file, | ||
28 | int sectorsize, int alignment, | ||
29 | unsigned long long *size); | ||
30 | |||
31 | extern 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 | |||
9 | static inline void *cow_malloc(int size) | ||
10 | { | ||
11 | return(um_kmalloc(size)); | ||
12 | } | ||
13 | |||
14 | static inline void cow_free(void *ptr) | ||
15 | { | ||
16 | kfree(ptr); | ||
17 | } | ||
18 | |||
19 | #define cow_printf printk | ||
20 | |||
21 | static inline char *cow_strdup(char *str) | ||
22 | { | ||
23 | return(uml_strdup(str)); | ||
24 | } | ||
25 | |||
26 | static inline int cow_seek_file(int fd, unsigned long long offset) | ||
27 | { | ||
28 | return(os_seek_file(fd, offset)); | ||
29 | } | ||
30 | |||
31 | static inline int cow_file_size(char *file, unsigned long long *size_out) | ||
32 | { | ||
33 | return(os_file_size(file, size_out)); | ||
34 | } | ||
35 | |||
36 | static 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 | |||
21 | struct 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 | |||
32 | struct 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 | |||
70 | struct 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 | |||
84 | union 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 | |||
96 | void 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 | |||
117 | static 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 | |||
164 | int 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 | |||
231 | int 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 | |||
240 | int 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 | |||
331 | int 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 | |||
10 | struct 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 | |||
21 | extern struct net_user_info daemon_user_info; | ||
22 | |||
23 | extern 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 | |||
16 | struct daemon_init { | ||
17 | char *sock_type; | ||
18 | char *ctl_sock; | ||
19 | }; | ||
20 | |||
21 | void 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 | |||
40 | static 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 | |||
49 | static 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 | |||
56 | static 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 | |||
63 | int 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 | |||
81 | static 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 | |||
91 | static 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 | |||
23 | enum request_type { REQ_NEW_CONTROL }; | ||
24 | |||
25 | #define SWITCH_MAGIC 0xfeedface | ||
26 | |||
27 | struct request_v3 { | ||
28 | uint32_t magic; | ||
29 | uint32_t version; | ||
30 | enum request_type type; | ||
31 | struct sockaddr_un sock; | ||
32 | }; | ||
33 | |||
34 | static 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 | |||
48 | static 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 | |||
122 | static 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 | |||
148 | static int daemon_open(void *data) | ||
149 | { | ||
150 | struct daemon_data *pri = data; | ||
151 | return(pri->fd); | ||
152 | } | ||
153 | |||
154 | static 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 | |||
165 | int 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 | |||
172 | static int daemon_set_mtu(int mtu, void *data) | ||
173 | { | ||
174 | return(mtu); | ||
175 | } | ||
176 | |||
177 | struct 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 | |||
15 | struct fd_chan { | ||
16 | int fd; | ||
17 | int raw; | ||
18 | struct termios tt; | ||
19 | char str[sizeof("1234567890\0")]; | ||
20 | }; | ||
21 | |||
22 | static 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 | |||
46 | static 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 | |||
65 | static 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 | |||
79 | static 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 | |||
86 | struct 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 | |||
52 | MODULE_LICENSE("GPL"); | ||
53 | |||
54 | /* Locked by the BKL in harddog_open and harddog_release */ | ||
55 | static int timer_alive; | ||
56 | static int harddog_in_fd = -1; | ||
57 | static int harddog_out_fd = -1; | ||
58 | |||
59 | /* | ||
60 | * Allow only one person to hold it open | ||
61 | */ | ||
62 | |||
63 | extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock); | ||
64 | |||
65 | static 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 | |||
88 | extern void stop_watchdog(int in_fd, int out_fd); | ||
89 | |||
90 | static 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 | |||
106 | extern int ping_watchdog(int fd); | ||
107 | |||
108 | static 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 | |||
119 | static 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 | |||
143 | static 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 | |||
151 | static struct miscdevice harddog_miscdev = { | ||
152 | .minor = WATCHDOG_MINOR, | ||
153 | .name = "watchdog", | ||
154 | .fops = &harddog_fops, | ||
155 | }; | ||
156 | |||
157 | static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n"; | ||
158 | |||
159 | static 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 | |||
173 | static void __exit harddog_exit(void) | ||
174 | { | ||
175 | misc_deregister(&harddog_miscdev); | ||
176 | } | ||
177 | |||
178 | module_init(harddog_init); | ||
179 | module_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 | |||
17 | struct dog_data { | ||
18 | int stdin; | ||
19 | int stdout; | ||
20 | int close_me[2]; | ||
21 | }; | ||
22 | |||
23 | static 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 | |||
36 | int 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 | |||
112 | void stop_watchdog(int in_fd, int out_fd) | ||
113 | { | ||
114 | os_close_file(in_fd); | ||
115 | os_close_file(out_fd); | ||
116 | } | ||
117 | |||
118 | int 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 | |||
18 | struct hostaudio_state { | ||
19 | int fd; | ||
20 | }; | ||
21 | |||
22 | struct 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 */ | ||
30 | char *dsp = HOSTAUDIO_DEV_DSP; | ||
31 | char *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 | ||
42 | static 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 | |||
50 | static 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 | |||
60 | MODULE_PARM(dsp, "s"); | ||
61 | MODULE_PARM_DESC(dsp, DSP_HELP); | ||
62 | |||
63 | MODULE_PARM(mixer, "s"); | ||
64 | MODULE_PARM_DESC(mixer, MIXER_HELP); | ||
65 | |||
66 | #endif | ||
67 | |||
68 | /* /dev/dsp file operations */ | ||
69 | |||
70 | static 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 | |||
97 | static 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 | |||
126 | static 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 | |||
138 | static 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 | |||
181 | static 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 | |||
209 | static 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 | |||
225 | static 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 | |||
237 | static 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 | |||
266 | static 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 | |||
283 | static 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 | |||
295 | static 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 | |||
303 | struct { | ||
304 | int dev_audio; | ||
305 | int dev_mixer; | ||
306 | } module_data; | ||
307 | |||
308 | MODULE_AUTHOR("Steve Schmidtke"); | ||
309 | MODULE_DESCRIPTION("UML Audio Relay"); | ||
310 | MODULE_LICENSE("GPL"); | ||
311 | |||
312 | static 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 | |||
334 | static 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 | |||
340 | module_init(hostaudio_init_module); | ||
341 | module_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 | |||
24 | static 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 | |||
34 | static 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 | |||
42 | static 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 | |||
55 | static 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 | |||
87 | static 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 | |||
117 | int 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 | |||
152 | void line_put_char(struct tty_struct *tty, unsigned char ch) | ||
153 | { | ||
154 | line_write(tty, &ch, sizeof(ch)); | ||
155 | } | ||
156 | |||
157 | void line_set_termios(struct tty_struct *tty, struct termios * old) | ||
158 | { | ||
159 | /* nothing */ | ||
160 | } | ||
161 | |||
162 | int line_chars_in_buffer(struct tty_struct *tty) | ||
163 | { | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static 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 | |||
193 | int 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 | |||
256 | static 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 | |||
289 | int 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 | |||
306 | void 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 | |||
330 | int 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 | |||
364 | out: | ||
365 | up(&line->sem); | ||
366 | return(err); | ||
367 | } | ||
368 | |||
369 | void 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 | |||
382 | void 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 | |||
390 | int 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 | |||
446 | int 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 | |||
457 | int 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 | |||
488 | int 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 | |||
496 | int 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 | |||
510 | struct 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 | |||
548 | void 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 | |||
566 | struct winch { | ||
567 | struct list_head list; | ||
568 | int fd; | ||
569 | int tty_fd; | ||
570 | int pid; | ||
571 | struct tty_struct *tty; | ||
572 | }; | ||
573 | |||
574 | irqreturn_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 | |||
609 | DECLARE_MUTEX(winch_handler_sem); | ||
610 | LIST_HEAD(winch_handlers); | ||
611 | |||
612 | void 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 | |||
636 | static 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 | |||
653 | char *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 | |||
8 | struct mcast_data { | ||
9 | char *addr; | ||
10 | unsigned short port; | ||
11 | void *mcast_addr; | ||
12 | int ttl; | ||
13 | void *dev; | ||
14 | }; | ||
15 | |||
16 | extern struct net_user_info mcast_user_info; | ||
17 | |||
18 | extern 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 | |||
23 | struct mcast_init { | ||
24 | char *addr; | ||
25 | int port; | ||
26 | int ttl; | ||
27 | }; | ||
28 | |||
29 | void 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 | |||
49 | static 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 | |||
57 | static 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 | |||
64 | static 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 | |||
71 | int 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 | |||
116 | static 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 | |||
126 | static 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 | |||
30 | static 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 | |||
45 | static 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 | |||
53 | static 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 | |||
128 | static 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 | |||
145 | int 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 | |||
152 | static int mcast_set_mtu(int mtu, void *data) | ||
153 | { | ||
154 | return(mtu); | ||
155 | } | ||
156 | |||
157 | struct 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 | |||
36 | static int do_unlink_socket(struct notifier_block *notifier, | ||
37 | unsigned long what, void *data) | ||
38 | { | ||
39 | return(mconsole_unlink_socket()); | ||
40 | } | ||
41 | |||
42 | |||
43 | static 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 | |||
53 | LIST_HEAD(mc_requests); | ||
54 | |||
55 | static 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 | |||
71 | DECLARE_WORK(mconsole_work, mc_work_proc, NULL); | ||
72 | |||
73 | static 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 | |||
101 | void 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 | |||
111 | void 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 | ||
128 | void 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 | |||
208 | void 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 | |||
281 | void mconsole_help(struct mc_request *req) | ||
282 | { | ||
283 | mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0); | ||
284 | } | ||
285 | |||
286 | void mconsole_halt(struct mc_request *req) | ||
287 | { | ||
288 | mconsole_reply(req, "", 0, 0); | ||
289 | machine_halt(); | ||
290 | } | ||
291 | |||
292 | void mconsole_reboot(struct mc_request *req) | ||
293 | { | ||
294 | mconsole_reply(req, "", 0, 0); | ||
295 | machine_restart(NULL); | ||
296 | } | ||
297 | |||
298 | extern void ctrl_alt_del(void); | ||
299 | |||
300 | void mconsole_cad(struct mc_request *req) | ||
301 | { | ||
302 | mconsole_reply(req, "", 0, 0); | ||
303 | ctrl_alt_del(); | ||
304 | } | ||
305 | |||
306 | void mconsole_go(struct mc_request *req) | ||
307 | { | ||
308 | mconsole_reply(req, "Not stopped", 1, 0); | ||
309 | } | ||
310 | |||
311 | void 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 | |||
327 | LIST_HEAD(mconsole_devices); | ||
328 | |||
329 | void mconsole_register_dev(struct mc_device *new) | ||
330 | { | ||
331 | list_add(&new->list, &mconsole_devices); | ||
332 | } | ||
333 | |||
334 | static 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 | |||
349 | static 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 | |||
393 | void 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 | |||
419 | void 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 | ||
437 | void 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, ¤t->thread.regs, NULL); | ||
446 | } | ||
447 | #else | ||
448 | void 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 | */ | ||
457 | static char *notify_socket = NULL; | ||
458 | |||
459 | int 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 | |||
502 | static 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 | |||
524 | static 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 | |||
541 | static DEFINE_SPINLOCK(notify_spinlock); | ||
542 | |||
543 | void lock_notify(void) | ||
544 | { | ||
545 | spin_lock(¬ify_spinlock); | ||
546 | } | ||
547 | |||
548 | void unlock_notify(void) | ||
549 | { | ||
550 | spin_unlock(¬ify_spinlock); | ||
551 | } | ||
552 | |||
553 | __initcall(create_proc_mconsole); | ||
554 | |||
555 | #define NOTIFY "=notify:" | ||
556 | |||
557 | static 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 | |||
577 | static 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 | |||
589 | static struct notifier_block panic_exit_notifier = { | ||
590 | .notifier_call = notify_panic, | ||
591 | .next = NULL, | ||
592 | .priority = 1 | ||
593 | }; | ||
594 | |||
595 | static 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 | |||
603 | char *mconsole_notify_socket(void) | ||
604 | { | ||
605 | return(notify_socket); | ||
606 | } | ||
607 | |||
608 | EXPORT_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 | |||
20 | static 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 */ | ||
36 | char mconsole_socket_name[256]; | ||
37 | |||
38 | int 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 | |||
57 | static 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 | |||
77 | int 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 | |||
124 | int 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 | |||
157 | int mconsole_unlink_socket(void) | ||
158 | { | ||
159 | unlink(mconsole_socket_name); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int notify_sock = -1; | ||
164 | |||
165 | int 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 */ | ||
28 | static unsigned long mmapper_size; | ||
29 | static unsigned long p_buf = 0; | ||
30 | static char *v_buf = NULL; | ||
31 | |||
32 | static ssize_t | ||
33 | mmapper_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 | |||
49 | static ssize_t | ||
50 | mmapper_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 | |||
66 | static int | ||
67 | mmapper_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
68 | unsigned long arg) | ||
69 | { | ||
70 | return(-ENOIOCTLCMD); | ||
71 | } | ||
72 | |||
73 | static int | ||
74 | mmapper_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; | ||
93 | out: | ||
94 | unlock_kernel(); | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | static int | ||
99 | mmapper_open(struct inode *inode, struct file *file) | ||
100 | { | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int | ||
105 | mmapper_release(struct inode *inode, struct file *file) | ||
106 | { | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static 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 | |||
120 | static 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 | |||
136 | static void mmapper_exit(void) | ||
137 | { | ||
138 | } | ||
139 | |||
140 | module_init(mmapper_init); | ||
141 | module_exit(mmapper_exit); | ||
142 | |||
143 | MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>"); | ||
144 | MODULE_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 | |||
35 | static DEFINE_SPINLOCK(opened_lock); | ||
36 | LIST_HEAD(opened); | ||
37 | |||
38 | static 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 | |||
70 | irqreturn_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 | |||
95 | static 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 | |||
142 | static 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 | |||
159 | static 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 | |||
196 | static 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 | |||
202 | static 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 | |||
209 | static void uml_net_tx_timeout(struct net_device *dev) | ||
210 | { | ||
211 | dev->trans_start = jiffies; | ||
212 | netif_wake_queue(dev); | ||
213 | } | ||
214 | |||
215 | static 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 | |||
227 | static 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 | |||
247 | static 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(ðcmd, 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 | |||
275 | void 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 | |||
285 | static DEFINE_SPINLOCK(devices_lock); | ||
286 | static struct list_head devices = LIST_HEAD_INIT(devices); | ||
287 | |||
288 | static struct device_driver uml_net_driver = { | ||
289 | .name = DRIVER_NAME, | ||
290 | .bus = &platform_bus_type, | ||
291 | }; | ||
292 | static int driver_registered; | ||
293 | |||
294 | static 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(¨_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 | |||
420 | static 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 | |||
437 | static 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 | |||
468 | struct 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 | */ | ||
477 | struct list_head transports = LIST_HEAD_INIT(transports); | ||
478 | |||
479 | /* Filled in during early boot */ | ||
480 | struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line); | ||
481 | |||
482 | static 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 | |||
508 | void 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, ð_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(ð->list); | ||
529 | } | ||
530 | } | ||
531 | |||
532 | static 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 | |||
552 | static 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, ð_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 | ||
581 | static int eth_init(void) | ||
582 | { | ||
583 | struct list_head *ele, *next; | ||
584 | struct eth_init *eth; | ||
585 | |||
586 | list_for_each_safe(ele, next, ð_cmd_line){ | ||
587 | eth = list_entry(ele, struct eth_init, list); | ||
588 | |||
589 | if(eth_setup_common(eth->init, eth->index)) | ||
590 | list_del(ð->list); | ||
591 | } | ||
592 | |||
593 | return(1); | ||
594 | } | ||
595 | __initcall(eth_init); | ||
596 | #endif | ||
597 | |||
598 | static 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 | |||
616 | static 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 | |||
645 | static struct mc_device net_mc = { | ||
646 | .name = "eth", | ||
647 | .config = net_config, | ||
648 | .get_config = NULL, | ||
649 | .remove = net_remove, | ||
650 | }; | ||
651 | |||
652 | static 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 | |||
690 | struct notifier_block uml_inetaddr_notifier = { | ||
691 | .notifier_call = uml_inetaddr_event, | ||
692 | }; | ||
693 | |||
694 | static 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(¨_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 | |||
724 | static 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 | |||
739 | int 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 | |||
766 | void 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 | |||
789 | void 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 | |||
796 | struct 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 | |||
809 | void 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 | |||
834 | int 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 | |||
852 | void *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 | |||
862 | void free_output_buffer(void *buffer) | ||
863 | { | ||
864 | free_pages((unsigned long) buffer, 0); | ||
865 | } | ||
866 | |||
867 | int 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 | |||
882 | unsigned 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 | |||
22 | int 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 | |||
35 | void 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 | |||
51 | void 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 | |||
81 | int 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 | |||
94 | int 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 | |||
109 | int 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 | |||
122 | int 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 | |||
135 | int 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 | |||
149 | struct change_pre_exec_data { | ||
150 | int close_me; | ||
151 | int stdout; | ||
152 | }; | ||
153 | |||
154 | static 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 | |||
162 | static 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 | |||
185 | static 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 | |||
215 | void open_addr(unsigned char *addr, unsigned char *netmask, void *arg) | ||
216 | { | ||
217 | change(arg, "add", addr, netmask); | ||
218 | } | ||
219 | |||
220 | void close_addr(unsigned char *addr, unsigned char *netmask, void *arg) | ||
221 | { | ||
222 | change(arg, "del", addr, netmask); | ||
223 | } | ||
224 | |||
225 | char *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 | |||
11 | static int null_chan; | ||
12 | |||
13 | static void *null_init(char *str, int device, struct chan_opts *opts) | ||
14 | { | ||
15 | return(&null_chan); | ||
16 | } | ||
17 | |||
18 | static 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 | |||
25 | static int null_read(int fd, char *c_out, void *unused) | ||
26 | { | ||
27 | return(-ENODEV); | ||
28 | } | ||
29 | |||
30 | static void null_free(void *data) | ||
31 | { | ||
32 | } | ||
33 | |||
34 | struct 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 | |||
13 | struct pcap_init { | ||
14 | char *host_if; | ||
15 | int promisc; | ||
16 | int optimize; | ||
17 | char *filter; | ||
18 | }; | ||
19 | |||
20 | void 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 | |||
34 | static 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 | |||
44 | static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp) | ||
45 | { | ||
46 | return(-EPERM); | ||
47 | } | ||
48 | |||
49 | static 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 | |||
56 | int 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 | |||
96 | static 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 | |||
106 | static 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 | |||
20 | static 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 | |||
37 | static 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 | |||
79 | static 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 | |||
89 | struct pcap_handler_data { | ||
90 | char *buffer; | ||
91 | int len; | ||
92 | }; | ||
93 | |||
94 | static 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 | |||
106 | int 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 | |||
123 | struct 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 | |||
8 | struct 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 | |||
18 | extern struct net_user_info pcap_user_info; | ||
19 | |||
20 | extern 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 | |||
9 | extern void *port_data(int port); | ||
10 | extern int port_wait(void *data); | ||
11 | extern void port_kern_close(void *d); | ||
12 | extern int port_connection(int fd, int *socket_out, int *pid_out); | ||
13 | extern int port_listen_fd(int port); | ||
14 | extern void port_read(int fd, void *data); | ||
15 | extern void port_kern_free(void *d); | ||
16 | extern int port_rcv_fd(int fd); | ||
17 | extern 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 | |||
24 | struct 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 | |||
36 | struct port_dev { | ||
37 | struct port_list *port; | ||
38 | int helper_pid; | ||
39 | int telnetd_pid; | ||
40 | }; | ||
41 | |||
42 | struct 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 | |||
51 | static 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 | |||
82 | static 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 | |||
133 | DECLARE_MUTEX(ports_sem); | ||
134 | struct list_head ports = LIST_HEAD_INIT(ports); | ||
135 | |||
136 | void 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 | |||
154 | DECLARE_WORK(port_work, port_work_proc, NULL); | ||
155 | |||
156 | static 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 | |||
165 | void *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 | |||
229 | int 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 | |||
277 | void 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 | |||
289 | void port_kern_free(void *d) | ||
290 | { | ||
291 | struct port_dev *dev = d; | ||
292 | |||
293 | port_remove_dev(dev); | ||
294 | kfree(dev); | ||
295 | } | ||
296 | |||
297 | static 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 | |||
24 | struct port_chan { | ||
25 | int raw; | ||
26 | struct termios tt; | ||
27 | void *kernel_data; | ||
28 | char dev[sizeof("32768\0")]; | ||
29 | }; | ||
30 | |||
31 | static 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 | |||
68 | static 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 | |||
76 | static 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 | |||
96 | static 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 | |||
104 | static 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 | |||
111 | struct 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 | |||
124 | int 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 | |||
162 | struct port_pre_exec_data { | ||
163 | int sock_fd; | ||
164 | int pipe_fd; | ||
165 | }; | ||
166 | |||
167 | void 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 | |||
180 | int 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 | |||
17 | struct 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 | |||
25 | static 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 | |||
37 | static 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 | |||
67 | static 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 | |||
96 | static 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 | |||
120 | static 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 | |||
127 | struct 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 | |||
140 | struct 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 | |||
20 | static int random_fd = -1; | ||
21 | |||
22 | static 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 | |||
33 | static 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 | |||
70 | static struct file_operations rng_chrdev_ops = { | ||
71 | .owner = THIS_MODULE, | ||
72 | .open = rng_dev_open, | ||
73 | .read = rng_dev_read, | ||
74 | }; | ||
75 | |||
76 | static 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 | */ | ||
85 | static 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 | */ | ||
116 | static void __exit rng_cleanup (void) | ||
117 | { | ||
118 | misc_deregister (&rng_miscdev); | ||
119 | } | ||
120 | |||
121 | module_init (rng_init); | ||
122 | module_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 | |||
9 | struct 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 | |||
22 | extern struct net_user_info slip_user_info; | ||
23 | |||
24 | extern int set_umn_addr(int fd, char *addr, char *ptp_addr); | ||
25 | extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri); | ||
26 | extern 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 | |||
12 | struct slip_init { | ||
13 | char *gate_addr; | ||
14 | }; | ||
15 | |||
16 | void 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 | |||
44 | static unsigned short slip_protocol(struct sk_buff *skbuff) | ||
45 | { | ||
46 | return(htons(ETH_P_IP)); | ||
47 | } | ||
48 | |||
49 | static 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 | |||
56 | static 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 | |||
63 | struct net_kern_info slip_kern_info = { | ||
64 | .init = slip_init, | ||
65 | .protocol = slip_protocol, | ||
66 | .read = slip_read, | ||
67 | .write = slip_write, | ||
68 | }; | ||
69 | |||
70 | static 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 | |||
82 | static 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 | |||
92 | static 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 | |||
15 | static 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 | |||
45 | static 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 | |||
20 | void slip_user_init(void *data, void *dev) | ||
21 | { | ||
22 | struct slip_data *pri = data; | ||
23 | |||
24 | pri->dev = dev; | ||
25 | } | ||
26 | |||
27 | static 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 | |||
56 | struct slip_pre_exec_data { | ||
57 | int stdin; | ||
58 | int stdout; | ||
59 | int close_me; | ||
60 | }; | ||
61 | |||
62 | static 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 | |||
71 | static 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 | |||
117 | static 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 | |||
169 | static 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 | |||
191 | int 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 | |||
227 | int 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 | |||
237 | static int slip_set_mtu(int mtu, void *data) | ||
238 | { | ||
239 | return(mtu); | ||
240 | } | ||
241 | |||
242 | static 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 | |||
251 | static 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 | |||
260 | struct 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 | */ | ||
20 | struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; }; | ||
21 | |||
22 | struct 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 | |||
34 | extern struct net_user_info slirp_user_info; | ||
35 | |||
36 | extern int set_umn_addr(int fd, char *addr, char *ptp_addr); | ||
37 | extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri); | ||
38 | extern 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 | |||
11 | struct slirp_init { | ||
12 | struct arg_list_dummy_wrapper argw; /* XXX should be simpler... */ | ||
13 | }; | ||
14 | |||
15 | void 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 | |||
50 | static unsigned short slirp_protocol(struct sk_buff *skbuff) | ||
51 | { | ||
52 | return(htons(ETH_P_IP)); | ||
53 | } | ||
54 | |||
55 | static 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 | |||
62 | static 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 | |||
69 | struct net_kern_info slirp_kern_info = { | ||
70 | .init = slirp_init, | ||
71 | .protocol = slirp_protocol, | ||
72 | .read = slirp_read, | ||
73 | .write = slirp_write, | ||
74 | }; | ||
75 | |||
76 | static 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 | |||
108 | static 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 | |||
118 | static 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 | |||
19 | void slirp_user_init(void *data, void *dev) | ||
20 | { | ||
21 | struct slirp_data *pri = data; | ||
22 | |||
23 | pri->dev = dev; | ||
24 | } | ||
25 | |||
26 | struct slirp_pre_exec_data { | ||
27 | int stdin; | ||
28 | int stdout; | ||
29 | }; | ||
30 | |||
31 | static 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 | |||
39 | static 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 */ | ||
52 | static 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 | |||
67 | static 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 | |||
94 | static 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 | |||
130 | int 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 | |||
166 | int 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 | |||
176 | static int slirp_set_mtu(int mtu, void *data) | ||
177 | { | ||
178 | return(mtu); | ||
179 | } | ||
180 | |||
181 | struct 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 | |||
27 | static int ssl_version = 1; | ||
28 | |||
29 | /* Referenced only by tty_driver below - presumably it's locked correctly | ||
30 | * by the tty driver. | ||
31 | */ | ||
32 | |||
33 | static struct tty_driver *ssl_driver; | ||
34 | |||
35 | #define NR_PORTS 64 | ||
36 | |||
37 | void 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 | |||
43 | static 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 | |||
51 | static int ssl_config(char *str); | ||
52 | static int ssl_get_config(char *dev, char *str, int size, char **error_out); | ||
53 | static int ssl_remove(char *str); | ||
54 | |||
55 | static 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 | */ | ||
80 | static struct line serial_lines[NR_PORTS] = | ||
81 | { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) }; | ||
82 | |||
83 | static struct lines lines = LINES_INIT(NR_PORTS); | ||
84 | |||
85 | static int ssl_config(char *str) | ||
86 | { | ||
87 | return(line_config(serial_lines, | ||
88 | sizeof(serial_lines)/sizeof(serial_lines[0]), str)); | ||
89 | } | ||
90 | |||
91 | static 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 | |||
98 | static int ssl_remove(char *str) | ||
99 | { | ||
100 | return(line_remove(serial_lines, | ||
101 | sizeof(serial_lines)/sizeof(serial_lines[0]), str)); | ||
102 | } | ||
103 | |||
104 | int ssl_open(struct tty_struct *tty, struct file *filp) | ||
105 | { | ||
106 | return line_open(serial_lines, tty, &opts); | ||
107 | } | ||
108 | |||
109 | #if 0 | ||
110 | static int ssl_chars_in_buffer(struct tty_struct *tty) | ||
111 | { | ||
112 | return(0); | ||
113 | } | ||
114 | |||
115 | static void ssl_flush_buffer(struct tty_struct *tty) | ||
116 | { | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | static void ssl_throttle(struct tty_struct * tty) | ||
121 | { | ||
122 | printk(KERN_ERR "Someone should implement ssl_throttle\n"); | ||
123 | } | ||
124 | |||
125 | static void ssl_unthrottle(struct tty_struct * tty) | ||
126 | { | ||
127 | printk(KERN_ERR "Someone should implement ssl_unthrottle\n"); | ||
128 | } | ||
129 | |||
130 | static void ssl_stop(struct tty_struct *tty) | ||
131 | { | ||
132 | printk(KERN_ERR "Someone should implement ssl_stop\n"); | ||
133 | } | ||
134 | |||
135 | static void ssl_start(struct tty_struct *tty) | ||
136 | { | ||
137 | printk(KERN_ERR "Someone should implement ssl_start\n"); | ||
138 | } | ||
139 | |||
140 | void ssl_hangup(struct tty_struct *tty) | ||
141 | { | ||
142 | } | ||
143 | #endif | ||
144 | |||
145 | static 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 | */ | ||
168 | static int ssl_init_done = 0; | ||
169 | |||
170 | static 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 | |||
180 | static struct tty_driver *ssl_console_device(struct console *c, int *index) | ||
181 | { | ||
182 | *index = c->index; | ||
183 | return ssl_driver; | ||
184 | } | ||
185 | |||
186 | static 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 | |||
193 | static 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 | |||
202 | int 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 | } | ||
221 | late_initcall(ssl_init); | ||
222 | |||
223 | static 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 | |||
232 | static 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 | |||
9 | extern int ssl_read(int fd, int line); | ||
10 | extern 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 | */ | ||
16 | static int use_stderr_console = 0; | ||
17 | |||
18 | static void stderr_console_write(struct console *console, const char *string, | ||
19 | unsigned len) | ||
20 | { | ||
21 | generic_write(2 /* stderr */, string, len, NULL); | ||
22 | } | ||
23 | |||
24 | static struct console stderr_console = { | ||
25 | .name "stderr", | ||
26 | .write stderr_console_write, | ||
27 | .flags CON_PRINTBUFFER, | ||
28 | }; | ||
29 | |||
30 | static int __init stderr_console_init(void) | ||
31 | { | ||
32 | if (use_stderr_console) | ||
33 | register_console(&stderr_console); | ||
34 | return 0; | ||
35 | } | ||
36 | console_initcall(stderr_console_init); | ||
37 | |||
38 | static 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 | |||
41 | static struct tty_driver *console_driver; | ||
42 | |||
43 | void 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 | |||
49 | static 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 | |||
57 | static int con_config(char *str); | ||
58 | static int con_get_config(char *dev, char *str, int size, char **error_out); | ||
59 | static int con_remove(char *str); | ||
60 | |||
61 | static 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 | |||
83 | static 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 | */ | ||
88 | struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), | ||
89 | [ 1 ... MAX_TTYS - 1 ] = | ||
90 | LINE_INIT(CONFIG_CON_CHAN, &driver) }; | ||
91 | |||
92 | static int con_config(char *str) | ||
93 | { | ||
94 | return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str)); | ||
95 | } | ||
96 | |||
97 | static 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 | |||
103 | static int con_remove(char *str) | ||
104 | { | ||
105 | return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str)); | ||
106 | } | ||
107 | |||
108 | static int con_open(struct tty_struct *tty, struct file *filp) | ||
109 | { | ||
110 | return line_open(vts, tty, &opts); | ||
111 | } | ||
112 | |||
113 | static int con_init_done = 0; | ||
114 | |||
115 | static 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 | |||
125 | static 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 | |||
135 | static struct tty_driver *uml_console_device(struct console *c, int *index) | ||
136 | { | ||
137 | *index = c->index; | ||
138 | return console_driver; | ||
139 | } | ||
140 | |||
141 | static 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 | |||
148 | static 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 | |||
158 | int 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 | } | ||
179 | late_initcall(stdio_init); | ||
180 | |||
181 | static 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 | |||
189 | static 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 | |||
9 | extern 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 | |||
15 | struct tty_chan { | ||
16 | char *dev; | ||
17 | int raw; | ||
18 | struct termios tt; | ||
19 | }; | ||
20 | |||
21 | static 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 | |||
41 | static 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 | |||
63 | static 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 | |||
70 | struct 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 | |||
58 | enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP }; | ||
59 | |||
60 | struct 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 | |||
76 | extern 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); | ||
80 | extern 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); | ||
85 | extern int read_cow_bitmap(int fd, void *buf, int offset, int len); | ||
86 | extern void do_io(struct io_thread_req *req); | ||
87 | |||
88 | static 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 | |||
99 | static 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 | |||
113 | static DEFINE_SPINLOCK(ubd_io_lock); | ||
114 | static DEFINE_SPINLOCK(ubd_lock); | ||
115 | |||
116 | static void (*do_ubd)(void); | ||
117 | |||
118 | static int ubd_open(struct inode * inode, struct file * filp); | ||
119 | static int ubd_release(struct inode * inode, struct file * file); | ||
120 | static 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 */ | ||
126 | static int ubd_do_mmap = 0; | ||
127 | #define UBD_MMAP_BLOCK_SIZE PAGE_SIZE | ||
128 | |||
129 | static 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 */ | ||
137 | static request_queue_t *ubd_queue; | ||
138 | |||
139 | /* Protected by ubd_lock */ | ||
140 | static int fake_major = MAJOR_NR; | ||
141 | |||
142 | static struct gendisk *ubd_gendisk[MAX_DEV]; | ||
143 | static 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 | */ | ||
156 | static struct openflags global_openflags = OPEN_FLAGS; | ||
157 | |||
158 | struct 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 | |||
167 | struct 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 | |||
209 | struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; | ||
210 | |||
211 | static 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 */ | ||
223 | static int fake_ide = 0; | ||
224 | static struct proc_dir_entry *proc_ide_root = NULL; | ||
225 | static struct proc_dir_entry *proc_ide = NULL; | ||
226 | |||
227 | static 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 | |||
233 | static 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 | |||
250 | static 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 | |||
270 | static 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 | |||
283 | static 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 | |||
302 | static 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 | |||
402 | break_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; | ||
422 | out: | ||
423 | spin_unlock(&ubd_lock); | ||
424 | return(err); | ||
425 | } | ||
426 | |||
427 | static 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 | |||
456 | static 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 | |||
472 | static int fakehd_set = 0; | ||
473 | static 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 | |||
486 | static void do_ubd_request(request_queue_t * q); | ||
487 | |||
488 | /* Only changed by ubd_init, which is an initcall. */ | ||
489 | int thread_fd = -1; | ||
490 | |||
491 | /* Changed by ubd_handler, which is serialized because interrupts only | ||
492 | * happen on CPU 0. | ||
493 | */ | ||
494 | int intr_count = 0; | ||
495 | |||
496 | /* call ubd_finish if you need to serialize */ | ||
497 | static 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 | |||
514 | static 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 */ | ||
522 | static 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 | |||
558 | static 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. */ | ||
565 | static int io_pid = -1; | ||
566 | |||
567 | void 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 | |||
575 | static 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 | |||
583 | static 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 | |||
598 | static 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 | |||
658 | static 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 | |||
707 | static 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 | |||
741 | static 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 | |||
766 | static 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 | |||
798 | static 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 | |||
836 | static struct mc_device ubd_mc = { | ||
837 | .name = "ubd", | ||
838 | .config = ubd_config, | ||
839 | .get_config = ubd_get_config, | ||
840 | .remove = ubd_remove, | ||
841 | }; | ||
842 | |||
843 | static int ubd_mc_init(void) | ||
844 | { | ||
845 | mconsole_register_dev(&ubd_mc); | ||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | __initcall(ubd_mc_init); | ||
850 | |||
851 | static struct device_driver ubd_driver = { | ||
852 | .name = DRIVER_NAME, | ||
853 | .bus = &platform_bus_type, | ||
854 | }; | ||
855 | |||
856 | int 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 | |||
884 | late_initcall(ubd_init); | ||
885 | |||
886 | int 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 | |||
913 | device_initcall(ubd_driver_init); | ||
914 | |||
915 | static 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 | |||
938 | static 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 | |||
948 | static 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 | |||
987 | static 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 | |||
1008 | static 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 | |||
1048 | static 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 */ | ||
1090 | static 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 */ | ||
1153 | static 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 | |||
1183 | static 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 | |||
1226 | static 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 | |||
1347 | static struct remapper ubd_remapper = { | ||
1348 | .list = LIST_HEAD_INIT(ubd_remapper.list), | ||
1349 | .proc = ubd_check_remapped, | ||
1350 | }; | ||
1351 | |||
1352 | static 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 | |||
1362 | static 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 | |||
1389 | static 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 | |||
1424 | int 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 | |||
1439 | int 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, §orsize, &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 | |||
1507 | int 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 | |||
1532 | static 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 | |||
1556 | void 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 | */ | ||
1628 | int kernel_fd = -1; | ||
1629 | |||
1630 | /* Only changed by the io thread */ | ||
1631 | int io_count = 0; | ||
1632 | |||
1633 | int 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 | |||
29 | void ignore_sigwinch_sig(void) | ||
30 | { | ||
31 | signal(SIGWINCH, SIG_IGN); | ||
32 | } | ||
33 | |||
34 | int 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 | |||
23 | struct 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 */ | ||
35 | void *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 */ | ||
52 | static char *terminal_emulator = "xterm"; | ||
53 | static char *title_switch = "-T"; | ||
54 | static char *exec_switch = "-e"; | ||
55 | |||
56 | static 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 | */ | ||
90 | int 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 */ | ||
178 | void 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 | |||
191 | static void xterm_free(void *d) | ||
192 | { | ||
193 | free(d); | ||
194 | } | ||
195 | |||
196 | static 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 | |||
203 | struct 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 | |||
9 | extern 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 | |||
18 | struct xterm_wait { | ||
19 | struct completion ready; | ||
20 | int fd; | ||
21 | int pid; | ||
22 | int new_fd; | ||
23 | }; | ||
24 | |||
25 | static 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 | |||
39 | int 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 | |||
15 | struct 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 | |||
28 | extern void chan_interrupt(struct list_head *chans, struct work_struct *task, | ||
29 | struct tty_struct *tty, int irq); | ||
30 | extern int parse_chan_pair(char *str, struct list_head *chans, int pri, | ||
31 | int device, struct chan_opts *opts); | ||
32 | extern int open_chan(struct list_head *chans); | ||
33 | extern int write_chan(struct list_head *chans, const char *buf, int len, | ||
34 | int write_irq); | ||
35 | extern int console_write_chan(struct list_head *chans, const char *buf, | ||
36 | int len); | ||
37 | extern int console_open_chan(struct line *line, struct console *co, | ||
38 | struct chan_opts *opts); | ||
39 | extern void close_chan(struct list_head *chans); | ||
40 | extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); | ||
41 | extern void enable_chan(struct list_head *chans, struct tty_struct *tty); | ||
42 | extern int chan_window_size(struct list_head *chans, | ||
43 | unsigned short *rows_out, | ||
44 | unsigned short *cols_out); | ||
45 | extern int chan_out_fd(struct list_head *chans); | ||
46 | extern 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 | |||
11 | struct 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 | |||
19 | enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; | ||
20 | |||
21 | struct 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 | |||
34 | extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops, | ||
35 | xterm_ops; | ||
36 | |||
37 | extern void generic_close(int fd, void *unused); | ||
38 | extern int generic_read(int fd, char *c_out, void *unused); | ||
39 | extern int generic_write(int fd, const char *buf, int n, void *unused); | ||
40 | extern int generic_console_write(int fd, const char *buf, int n, void *state); | ||
41 | extern int generic_window_size(int fd, void *unused, unsigned short *rows_out, | ||
42 | unsigned short *cols_out); | ||
43 | extern void generic_free(void *data); | ||
44 | |||
45 | struct tty_struct; | ||
46 | extern void register_winch(int fd, struct tty_struct *tty); | ||
47 | extern 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 | |||
24 | extern int mode_tt; | ||
25 | static 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 | |||
12 | extern 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); | ||
16 | extern 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 | |||
9 | extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, | ||
10 | unsigned long *stack_out); | ||
11 | extern int run_helper_thread(int (*proc)(void *), void *arg, | ||
12 | unsigned int flags, unsigned long *stack_out, | ||
13 | int stack_order); | ||
14 | extern 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 | ||
40 | typedef int (*initcall_t)(void); | ||
41 | typedef 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 | ||
59 | struct uml_param { | ||
60 | const char *str; | ||
61 | int (*setup_func)(char *, int *); | ||
62 | }; | ||
63 | |||
64 | extern initcall_t __uml_initcall_start, __uml_initcall_end; | ||
65 | extern initcall_t __uml_postsetup_start, __uml_postsetup_end; | ||
66 | extern 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 | |||
75 | extern 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 | |||
9 | extern 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 | |||
11 | extern 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 | |||
9 | enum { IRQ_READ, IRQ_WRITE }; | ||
10 | |||
11 | extern void sigio_handler(int sig, union uml_pt_regs *regs); | ||
12 | extern int activate_fd(int irq, int fd, int type, void *dev_id); | ||
13 | extern void free_irq_by_irq_and_dev(unsigned int irq, void *dev_id); | ||
14 | extern void free_irq_by_fd(int fd); | ||
15 | extern void reactivate_fd(int fd, int irqnum); | ||
16 | extern void deactivate_fd(int fd, int irqnum); | ||
17 | extern int deactivate_all_fds(void); | ||
18 | extern void forward_interrupts(int pid); | ||
19 | extern void init_irq_signals(int on_sigstack); | ||
20 | extern void forward_ipi(int fd, int pid); | ||
21 | extern void free_irq_later(int irq, void *dev_id); | ||
22 | extern int activate_ipi(int fd, int pid); | ||
23 | extern unsigned long irq_lock(void); | ||
24 | extern 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 | |||
16 | extern int errno; | ||
17 | |||
18 | extern int clone(int (*proc)(void *), void *sp, int flags, void *data); | ||
19 | extern int sleep(int); | ||
20 | extern int printf(char *fmt, ...); | ||
21 | extern char *strerror(int errnum); | ||
22 | extern char *ptsname(int __fd); | ||
23 | extern int munmap(void *, int); | ||
24 | extern void *sbrk(int increment); | ||
25 | extern void *malloc(int size); | ||
26 | extern void perror(char *err); | ||
27 | extern int kill(int pid, int sig); | ||
28 | extern int getuid(void); | ||
29 | extern int getgid(void); | ||
30 | extern int pause(void); | ||
31 | extern int write(int, const void *, int); | ||
32 | extern int exit(int); | ||
33 | extern int close(int); | ||
34 | extern int read(unsigned int, char *, int); | ||
35 | extern int pipe(int *); | ||
36 | extern int sched_yield(void); | ||
37 | extern 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 | |||
12 | extern int ncpus; | ||
13 | extern char *linux_prog; | ||
14 | extern char *gdb_init; | ||
15 | extern int kmalloc_ok; | ||
16 | extern int timer_irq_inited; | ||
17 | extern int jail; | ||
18 | extern int nsyscalls; | ||
19 | |||
20 | extern 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 | |||
26 | extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg); | ||
27 | extern unsigned long stack_sp(unsigned long page); | ||
28 | extern int kernel_thread_proc(void *data); | ||
29 | extern void syscall_segv(int sig); | ||
30 | extern int current_pid(void); | ||
31 | extern unsigned long alloc_stack(int order, int atomic); | ||
32 | extern int do_signal(void); | ||
33 | extern int is_stack_fault(unsigned long sp); | ||
34 | extern unsigned long segv(unsigned long address, unsigned long ip, | ||
35 | int is_write, int is_user, void *sc); | ||
36 | extern int handle_page_fault(unsigned long address, unsigned long ip, | ||
37 | int is_write, int is_user, int *code_out); | ||
38 | extern void syscall_ready(void); | ||
39 | extern void set_tracing(void *t, int tracing); | ||
40 | extern int is_tracing(void *task); | ||
41 | extern int segv_syscall(void); | ||
42 | extern void kern_finish_exec(void *task, int new_pid, unsigned long stack); | ||
43 | extern int page_size(void); | ||
44 | extern unsigned long page_mask(void); | ||
45 | extern int need_finish_fork(void); | ||
46 | extern void free_stack(unsigned long stack, int order); | ||
47 | extern void add_input_request(int op, void (*proc)(int), void *arg); | ||
48 | extern char *current_cmd(void); | ||
49 | extern void timer_handler(int sig, union uml_pt_regs *regs); | ||
50 | extern int set_signals(int enable); | ||
51 | extern void force_sigbus(void); | ||
52 | extern int pid_to_processor_id(int pid); | ||
53 | extern void block_signals(void); | ||
54 | extern void unblock_signals(void); | ||
55 | extern void deliver_signals(void *t); | ||
56 | extern int next_syscall_index(int max); | ||
57 | extern int next_trap_index(int max); | ||
58 | extern void default_idle(void); | ||
59 | extern void finish_fork(void); | ||
60 | extern void paging_init(void); | ||
61 | extern void init_flush_vm(void); | ||
62 | extern void *syscall_sp(void *t); | ||
63 | extern void syscall_trace(union uml_pt_regs *regs, int entryexit); | ||
64 | extern int hz(void); | ||
65 | extern void uml_idle_timer(void); | ||
66 | extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs); | ||
67 | extern int external_pid(void *t); | ||
68 | extern void boot_timer_handler(int sig); | ||
69 | extern void interrupt_end(void); | ||
70 | extern void initial_thread_cb(void (*proc)(void *), void *arg); | ||
71 | extern int debugger_signal(int status, int pid); | ||
72 | extern void debugger_parent_signal(int status, int pid); | ||
73 | extern void child_signal(int pid, int status); | ||
74 | extern int init_ptrace_proxy(int idle_pid, int startup, int stop); | ||
75 | extern int init_parent_proxy(int pid); | ||
76 | extern int singlestepping(void *t); | ||
77 | extern void check_stack_overflow(void *ptr); | ||
78 | extern void relay_signal(int sig, union uml_pt_regs *regs); | ||
79 | extern void not_implemented(void); | ||
80 | extern int user_context(unsigned long sp); | ||
81 | extern void timer_irq(union uml_pt_regs *regs); | ||
82 | extern void unprotect_stack(unsigned long stack); | ||
83 | extern void do_uml_exitcalls(void); | ||
84 | extern int attach_debugger(int idle_pid, int pid, int stop); | ||
85 | extern void bad_segv(unsigned long address, unsigned long ip, int is_write); | ||
86 | extern int config_gdb(char *str); | ||
87 | extern int remove_gdb(void); | ||
88 | extern char *uml_strdup(char *string); | ||
89 | extern void unprotect_kernel_mem(void); | ||
90 | extern void protect_kernel_mem(void); | ||
91 | extern void uml_cleanup(void); | ||
92 | extern void set_current(void *t); | ||
93 | extern void lock_signalled_task(void *t); | ||
94 | extern void IPI_handler(int cpu); | ||
95 | extern int jail_setup(char *line, int *add); | ||
96 | extern void *get_init_task(void); | ||
97 | extern int clear_user_proc(void *buf, int size); | ||
98 | extern int copy_to_user_proc(void *to, void *from, int size); | ||
99 | extern int copy_from_user_proc(void *to, void *from, int size); | ||
100 | extern int strlen_user_proc(char *str); | ||
101 | extern void bus_handler(int sig, union uml_pt_regs *regs); | ||
102 | extern void winch(int sig, union uml_pt_regs *regs); | ||
103 | extern long execute_syscall(void *r); | ||
104 | extern int smp_sigio_handler(void); | ||
105 | extern void *get_current(void); | ||
106 | extern struct task_struct *get_task(int pid, int require); | ||
107 | extern void machine_halt(void); | ||
108 | extern int is_syscall(unsigned long addr); | ||
109 | extern void arch_switch(void); | ||
110 | extern void free_irq(unsigned int, void *); | ||
111 | extern int um_in_interrupt(void); | ||
112 | extern 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 | |||
17 | struct 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 | |||
34 | struct 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 | |||
63 | struct lines { | ||
64 | int num; | ||
65 | }; | ||
66 | |||
67 | #define LINES_INIT(n) { num : n } | ||
68 | |||
69 | extern void line_close(struct tty_struct *tty, struct file * filp); | ||
70 | extern int line_open(struct line *lines, struct tty_struct *tty, | ||
71 | struct chan_opts *opts); | ||
72 | extern int line_setup(struct line *lines, int num, char *init, | ||
73 | int all_allowed); | ||
74 | extern int line_write(struct tty_struct *tty, const unsigned char *buf, int len); | ||
75 | extern void line_put_char(struct tty_struct *tty, unsigned char ch); | ||
76 | extern void line_set_termios(struct tty_struct *tty, struct termios * old); | ||
77 | extern int line_chars_in_buffer(struct tty_struct *tty); | ||
78 | extern int line_write_room(struct tty_struct *tty); | ||
79 | extern int line_ioctl(struct tty_struct *tty, struct file * file, | ||
80 | unsigned int cmd, unsigned long arg); | ||
81 | extern char *add_xterm_umid(char *base); | ||
82 | extern int line_setup_irq(int fd, int input, int output, struct tty_struct *tty); | ||
83 | extern void line_close_chan(struct line *line); | ||
84 | extern void line_disable(struct tty_struct *tty, int current_irq); | ||
85 | extern 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); | ||
90 | extern void lines_init(struct line *lines, int nlines); | ||
91 | extern void close_lines(struct line *lines, int nlines); | ||
92 | extern int line_config(struct line *lines, int num, char *str); | ||
93 | extern int line_remove(struct line *lines, int num, char *str); | ||
94 | extern 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 | |||
19 | struct mconsole_request { | ||
20 | u32 magic; | ||
21 | u32 version; | ||
22 | u32 len; | ||
23 | char data[MCONSOLE_MAX_DATA]; | ||
24 | }; | ||
25 | |||
26 | struct mconsole_reply { | ||
27 | u32 err; | ||
28 | u32 more; | ||
29 | u32 len; | ||
30 | char data[MCONSOLE_MAX_DATA]; | ||
31 | }; | ||
32 | |||
33 | struct 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 | |||
42 | struct mc_request; | ||
43 | |||
44 | enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC }; | ||
45 | |||
46 | struct mconsole_command | ||
47 | { | ||
48 | char *command; | ||
49 | void (*handler)(struct mc_request *req); | ||
50 | enum mc_context context; | ||
51 | }; | ||
52 | |||
53 | struct 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 | |||
66 | extern char mconsole_socket_name[]; | ||
67 | |||
68 | extern int mconsole_unlink_socket(void); | ||
69 | extern int mconsole_reply(struct mc_request *req, char *reply, int err, | ||
70 | int more); | ||
71 | |||
72 | extern void mconsole_version(struct mc_request *req); | ||
73 | extern void mconsole_help(struct mc_request *req); | ||
74 | extern void mconsole_halt(struct mc_request *req); | ||
75 | extern void mconsole_reboot(struct mc_request *req); | ||
76 | extern void mconsole_config(struct mc_request *req); | ||
77 | extern void mconsole_remove(struct mc_request *req); | ||
78 | extern void mconsole_sysrq(struct mc_request *req); | ||
79 | extern void mconsole_cad(struct mc_request *req); | ||
80 | extern void mconsole_stop(struct mc_request *req); | ||
81 | extern void mconsole_go(struct mc_request *req); | ||
82 | extern void mconsole_log(struct mc_request *req); | ||
83 | extern void mconsole_proc(struct mc_request *req); | ||
84 | |||
85 | extern int mconsole_get_request(int fd, struct mc_request *req); | ||
86 | extern int mconsole_notify(char *sock_name, int type, const void *data, | ||
87 | int len); | ||
88 | extern char *mconsole_notify_socket(void); | ||
89 | extern void lock_notify(void); | ||
90 | extern 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 | |||
13 | struct mconsole_entry { | ||
14 | struct list_head list; | ||
15 | struct mc_request request; | ||
16 | }; | ||
17 | |||
18 | struct 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) \ | ||
27 | do { \ | ||
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 | |||
41 | extern void mconsole_register_dev(struct mc_device *new); | ||
42 | |||
43 | #else | ||
44 | |||
45 | static 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 | |||
11 | extern int phys_mapping(unsigned long phys, __u64 *offset_out); | ||
12 | extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w); | ||
13 | extern int is_remapped(void *virt); | ||
14 | extern int physmem_remove_mapping(void *virt); | ||
15 | extern 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 | |||
12 | struct remapper { | ||
13 | struct list_head list; | ||
14 | int (*proc)(int, unsigned long, int, __u64); | ||
15 | }; | ||
16 | |||
17 | extern 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 | |||
35 | struct 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 | |||
44 | extern struct iomem_region *iomem_regions; | ||
45 | extern int iomem_size; | ||
46 | |||
47 | #define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1)) | ||
48 | |||
49 | extern unsigned long host_task_size; | ||
50 | extern unsigned long task_size; | ||
51 | |||
52 | extern void check_devanon(void); | ||
53 | extern int init_mem_user(void); | ||
54 | extern int create_mem_file(unsigned long len); | ||
55 | extern void setup_memory(void *entry); | ||
56 | extern unsigned long find_iomem(char *driver, unsigned long *len_out); | ||
57 | extern int init_maps(unsigned long physmem, unsigned long iomem, | ||
58 | unsigned long highmem); | ||
59 | extern unsigned long get_vm(unsigned long len); | ||
60 | extern void setup_physmem(unsigned long start, unsigned long usable, | ||
61 | unsigned long len, unsigned long highmem); | ||
62 | extern void add_iomem(char *name, int fd, unsigned long size); | ||
63 | extern unsigned long phys_offset(unsigned long phys); | ||
64 | extern void unmap_physmem(void); | ||
65 | extern void map_memory(unsigned long virt, unsigned long phys, | ||
66 | unsigned long len, int r, int w, int x); | ||
67 | extern int protect_memory(unsigned long addr, unsigned long len, | ||
68 | int r, int w, int x, int must_succeed); | ||
69 | extern unsigned long get_kmem_end(void); | ||
70 | extern 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 | |||
14 | struct 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 | |||
23 | struct 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 | |||
45 | struct 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 | |||
52 | struct 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 | |||
62 | extern struct net_device *ether_init(int); | ||
63 | extern unsigned short ether_protocol(struct sk_buff *); | ||
64 | extern int setup_etheraddr(char *str, unsigned char *addr); | ||
65 | extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra); | ||
66 | extern int tap_setup_common(char *str, char *type, char **dev_name, | ||
67 | char **mac_out, char **gate_addr); | ||
68 | extern void register_transport(struct transport *new); | ||
69 | extern 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 | |||
16 | struct 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 | |||
27 | extern void ether_user_init(void *data, void *dev); | ||
28 | extern void dev_ip_addr(void *d, char *buf, char *bin_buf); | ||
29 | extern void set_ether_mac(void *d, unsigned char *addr); | ||
30 | extern void iter_addresses(void *d, void (*cb)(unsigned char *, | ||
31 | unsigned char *, void *), | ||
32 | void *arg); | ||
33 | |||
34 | extern void *get_output_buffer(int *len_out); | ||
35 | extern void free_output_buffer(void *buffer); | ||
36 | |||
37 | extern int tap_open_common(void *dev, char *gate_addr); | ||
38 | extern void tap_check_ips(char *gate_addr, char *eth_addr); | ||
39 | |||
40 | extern void read_output(int fd, char *output_out, int len); | ||
41 | |||
42 | extern int net_read(int fd, void *buf, int len); | ||
43 | extern int net_recvfrom(int fd, void *buf, int len); | ||
44 | extern int net_write(int fd, void *buf, int len); | ||
45 | extern int net_send(int fd, void *buf, int len); | ||
46 | extern int net_sendto(int fd, void *buf, int len, void *to, int sock_len); | ||
47 | |||
48 | extern void open_addr(unsigned char *addr, unsigned char *netmask, void *arg); | ||
49 | extern void close_addr(unsigned char *addr, unsigned char *netmask, void *arg); | ||
50 | |||
51 | extern char *split_if_spec(char *str, ...); | ||
52 | |||
53 | extern 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 | */ | ||
31 | struct 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 | |||
46 | struct 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 | |||
60 | static inline struct openflags of_read(struct openflags flags) | ||
61 | { | ||
62 | flags.r = 1; | ||
63 | return(flags); | ||
64 | } | ||
65 | |||
66 | static inline struct openflags of_write(struct openflags flags) | ||
67 | { | ||
68 | flags.w = 1; | ||
69 | return(flags); | ||
70 | } | ||
71 | |||
72 | static inline struct openflags of_rdwr(struct openflags flags) | ||
73 | { | ||
74 | return(of_read(of_write(flags))); | ||
75 | } | ||
76 | |||
77 | static 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 | |||
84 | static inline struct openflags of_sync(struct openflags flags) | ||
85 | { | ||
86 | flags.s = 1; | ||
87 | return(flags); | ||
88 | } | ||
89 | |||
90 | static inline struct openflags of_create(struct openflags flags) | ||
91 | { | ||
92 | flags.c = 1; | ||
93 | return(flags); | ||
94 | } | ||
95 | |||
96 | static inline struct openflags of_trunc(struct openflags flags) | ||
97 | { | ||
98 | flags.t = 1; | ||
99 | return(flags); | ||
100 | } | ||
101 | |||
102 | static inline struct openflags of_append(struct openflags flags) | ||
103 | { | ||
104 | flags.a = 1; | ||
105 | return(flags); | ||
106 | } | ||
107 | |||
108 | static inline struct openflags of_excl(struct openflags flags) | ||
109 | { | ||
110 | flags.e = 1; | ||
111 | return(flags); | ||
112 | } | ||
113 | |||
114 | static inline struct openflags of_cloexec(struct openflags flags) | ||
115 | { | ||
116 | flags.cl = 1; | ||
117 | return(flags); | ||
118 | } | ||
119 | |||
120 | extern int os_stat_file(const char *file_name, struct uml_stat *buf); | ||
121 | extern int os_stat_fd(const int fd, struct uml_stat *buf); | ||
122 | extern int os_access(const char *file, int mode); | ||
123 | extern void os_print_error(int error, const char* str); | ||
124 | extern int os_get_exec_close(int fd, int *close_on_exec); | ||
125 | extern int os_set_exec_close(int fd, int close_on_exec); | ||
126 | extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); | ||
127 | extern int os_window_size(int fd, int *rows, int *cols); | ||
128 | extern int os_new_tty_pgrp(int fd, int pid); | ||
129 | extern int os_get_ifname(int fd, char *namebuf); | ||
130 | extern int os_set_slip(int fd); | ||
131 | extern int os_set_owner(int fd, int pid); | ||
132 | extern int os_sigio_async(int master, int slave); | ||
133 | extern int os_mode_fd(int fd, int mode); | ||
134 | |||
135 | extern int os_seek_file(int fd, __u64 offset); | ||
136 | extern int os_open_file(char *file, struct openflags flags, int mode); | ||
137 | extern int os_read_file(int fd, void *buf, int len); | ||
138 | extern int os_write_file(int fd, const void *buf, int count); | ||
139 | extern int os_file_size(char *file, long long *size_out); | ||
140 | extern int os_file_modtime(char *file, unsigned long *modtime); | ||
141 | extern int os_pipe(int *fd, int stream, int close_on_exec); | ||
142 | extern int os_set_fd_async(int fd, int owner); | ||
143 | extern int os_clear_fd_async(int fd); | ||
144 | extern int os_set_fd_block(int fd, int blocking); | ||
145 | extern int os_accept_connection(int fd); | ||
146 | extern int os_create_unix_socket(char *file, int len, int close_on_exec); | ||
147 | extern int os_shutdown_socket(int fd, int r, int w); | ||
148 | extern void os_close_file(int fd); | ||
149 | extern int os_rcv_fd(int fd, int *helper_pid_out); | ||
150 | extern int create_unix_socket(char *file, int len, int close_on_exec); | ||
151 | extern int os_connect_socket(char *name); | ||
152 | extern int os_file_type(char *file); | ||
153 | extern int os_file_mode(char *file, struct openflags *mode_out); | ||
154 | extern int os_lock_file(int fd, int excl); | ||
155 | |||
156 | extern unsigned long os_process_pc(int pid); | ||
157 | extern int os_process_parent(int pid); | ||
158 | extern void os_stop_process(int pid); | ||
159 | extern void os_kill_process(int pid, int reap_child); | ||
160 | extern void os_kill_ptraced_process(int pid, int reap_child); | ||
161 | extern void os_usr1_process(int pid); | ||
162 | extern int os_getpid(void); | ||
163 | |||
164 | extern int os_map_memory(void *virt, int fd, unsigned long long off, | ||
165 | unsigned long len, int r, int w, int x); | ||
166 | extern int os_protect_memory(void *addr, unsigned long len, | ||
167 | int r, int w, int x); | ||
168 | extern int os_unmap_memory(void *addr, int len); | ||
169 | extern void os_flush_stdout(void); | ||
170 | extern 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 | |||
11 | extern void sig_handler(int sig, struct sigcontext sc); | ||
12 | extern 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 | |||
11 | extern int ptrace_getregs(long pid, unsigned long *regs_out); | ||
12 | extern int ptrace_setregs(long pid, unsigned long *regs_in); | ||
13 | extern int ptrace_getfpregs(long pid, unsigned long *regs_out); | ||
14 | extern int ptrace_setfpregs(long pid, unsigned long *regs); | ||
15 | extern void arch_enter_kernel(void *task, int pid); | ||
16 | extern void arch_leave_kernel(void *task, int pid); | ||
17 | extern 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 | |||
49 | void set_using_sysemu(int value); | ||
50 | int get_using_sysemu(void); | ||
51 | extern 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 | |||
11 | extern void init_thread_registers(union uml_pt_regs *to); | ||
12 | extern int save_fp_registers(int pid, unsigned long *fp_regs); | ||
13 | extern int restore_fp_registers(int pid, unsigned long *fp_regs); | ||
14 | extern void save_registers(int pid, union uml_pt_regs *regs); | ||
15 | extern void restore_registers(int pid, union uml_pt_regs *regs); | ||
16 | extern 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 | |||
11 | extern int sc_size(void *data); | ||
12 | extern 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 | |||
9 | extern int write_sigio_irq(int fd); | ||
10 | extern int register_sigio_fd(int fd); | ||
11 | extern int read_sigio_fd(int fd); | ||
12 | extern int add_sigio_fd(int fd, int read); | ||
13 | extern int ignore_sigio_fd(int fd); | ||
14 | extern void sigio_lock(void); | ||
15 | extern 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 | |||
9 | extern 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 | |||
9 | extern int signal_stack_size; | ||
10 | |||
11 | extern int change_sig(int signal, int on); | ||
12 | extern void set_sigstack(void *stack, int size); | ||
13 | extern void set_handler(int sig, void (*handler)(int), int flags, ...); | ||
14 | extern int set_signals(int enable); | ||
15 | extern 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 | |||
9 | struct ptrace_faultinfo { | ||
10 | int is_write; | ||
11 | unsigned long addr; | ||
12 | }; | ||
13 | |||
14 | struct 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 | |||
9 | extern int record_syscall_start(int syscall); | ||
10 | extern 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 | */ | ||
23 | unsigned 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 | |||
34 | unsigned int csum_partial_copy_to(const unsigned char *src, unsigned char *dst, | ||
35 | int len, int sum, int *err_ptr); | ||
36 | unsigned 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 | |||
47 | static __inline__ | ||
48 | unsigned 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 | |||
55 | static __inline__ | ||
56 | unsigned 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 | ||
70 | unsigned 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 | */ | ||
79 | static 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 | |||
115 | static 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 | |||
126 | static 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 | */ | ||
146 | static 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 | |||
160 | static 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 | ||
166 | static __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 | ||
195 | static __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 | |||
15 | extern 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 | |||
23 | void set_using_sysemu(int value); | ||
24 | int get_using_sysemu(void); | ||
25 | extern 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 | |||
69 | union 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 | |||
92 | extern 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 | |||
137 | extern 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 | |||
142 | struct 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 | |||
36 | extern unsigned long *sc_sigmask(void *sc_ptr); | ||
37 | extern 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 | |||
9 | typedef 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 | */ | ||
14 | extern syscall_handler_t sys_ptrace; | ||
15 | extern syscall_handler_t sys_rt_sigaction; | ||
16 | |||
17 | extern syscall_handler_t old_mmap_i386; | ||
18 | |||
19 | #define EXECUTE_SYSCALL(syscall, regs) \ | ||
20 | ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) | ||
21 | |||
22 | extern 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 | |||
9 | struct 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 | ||
18 | struct 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 | |||
37 | struct 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) \ | ||
73 | do { \ | ||
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 | |||
82 | extern 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 | |||
6 | typedef 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(®s), \ | ||
12 | UM_SYSCALL_ARG2(®s), \ | ||
13 | UM_SYSCALL_ARG3(®s), \ | ||
14 | UM_SYSCALL_ARG4(®s), \ | ||
15 | UM_SYSCALL_ARG5(®s), \ | ||
16 | UM_SYSCALL_ARG6(®s)) | ||
17 | |||
18 | extern syscall_handler_t sys_mincore; | ||
19 | extern syscall_handler_t sys_madvise; | ||
20 | |||
21 | /* old_mmap needs the correct prototype since syscall_kern.c includes | ||
22 | * this file. | ||
23 | */ | ||
24 | int 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 | |||
12 | extern unsigned int csum_partial_copy_from(const unsigned char *src, unsigned char *dst, int len, | ||
13 | int sum, int *err_ptr); | ||
14 | extern 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 | |||
25 | static __inline__ | ||
26 | unsigned 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 | |||
33 | static __inline__ | ||
34 | unsigned 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 | */ | ||
48 | static 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 | */ | ||
70 | static inline unsigned long | ||
71 | csum_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 | */ | ||
87 | static 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 | */ | ||
101 | static 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 | |||
131 | static 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 */ | ||
80 | union 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 */ | ||
105 | extern 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 | |||
139 | extern 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 | |||
151 | struct 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 | |||
35 | extern 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 | |||
13 | typedef long syscall_handler_t(void); | ||
14 | |||
15 | extern 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(®s->regs), \ | ||
20 | UPT_SYSCALL_ARG2(®s->regs), \ | ||
21 | UPT_SYSCALL_ARG3(®s->regs), \ | ||
22 | UPT_SYSCALL_ARG4(®s->regs), \ | ||
23 | UPT_SYSCALL_ARG5(®s->regs), \ | ||
24 | UPT_SYSCALL_ARG6(®s->regs))) | ||
25 | |||
26 | extern long old_mmap(unsigned long addr, unsigned long len, | ||
27 | unsigned long prot, unsigned long flags, | ||
28 | unsigned long fd, unsigned long pgoff); | ||
29 | extern syscall_handler_t wrap_sys_shmat; | ||
30 | extern syscall_handler_t sys_modify_ldt; | ||
31 | extern 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 | |||
4 | extern 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 | |||
9 | extern 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 | |||
9 | extern void timer(void); | ||
10 | extern void switch_timers(int to_real); | ||
11 | extern void set_interval(int timer_type); | ||
12 | extern void idle_sleep(int secs); | ||
13 | extern void enable_timer(void); | ||
14 | extern void disable_timer(void); | ||
15 | extern unsigned long time_lock(void); | ||
16 | extern 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 | |||
11 | struct 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 | |||
37 | extern void mprotect_kernel_vm(int w); | ||
38 | extern void force_flush_all(void); | ||
39 | extern 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)); | ||
42 | extern int flush_tlb_kernel_range_common(unsigned long start, | ||
43 | unsigned long end); | ||
44 | |||
45 | extern 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)); | ||
49 | extern 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)); | ||
52 | extern 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 | |||
10 | extern void ignore_sigwinch_sig(void); | ||
11 | extern int start_io_thread(unsigned long sp, int *fds_out); | ||
12 | extern int io_thread(void *arg); | ||
13 | extern 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 | |||
20 | typedef 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 */ | ||
24 | static 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 | |||
30 | static 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 | |||
36 | static 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 | |||
61 | static 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 | */ | ||
78 | static 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 | */ | ||
93 | static 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 | */ | ||
109 | static 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 | |||
9 | extern 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 | |||
9 | extern int __do_copy_to_user(void *to, const void *from, int n, | ||
10 | void **fault_addr, void **fault_catcher); | ||
11 | extern 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); | ||
15 | void __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 | |||
9 | extern void panic(const char *fmt, ...); | ||
10 | extern int printk(const char *fmt, ...); | ||
11 | extern void schedule(void); | ||
12 | extern void *um_kmalloc(int size); | ||
13 | extern void *um_kmalloc_atomic(int size); | ||
14 | extern void kfree(void *ptr); | ||
15 | extern int in_aton(char *str); | ||
16 | extern int open_gdb_chan(void); | ||
17 | extern int strlcpy(char *, const char *, int); | ||
18 | extern void *um_vmalloc(int size); | ||
19 | extern 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 | |||
13 | extern int mode_tt; | ||
14 | |||
15 | extern int grantpt(int __fd); | ||
16 | extern int unlockpt(int __fd); | ||
17 | extern char *ptsname(int __fd); | ||
18 | |||
19 | struct cpu_task { | ||
20 | int pid; | ||
21 | void *task; | ||
22 | }; | ||
23 | |||
24 | extern struct cpu_task cpu_tasks[]; | ||
25 | |||
26 | struct signal_info { | ||
27 | void (*handler)(int, union uml_pt_regs *); | ||
28 | int is_irq; | ||
29 | }; | ||
30 | |||
31 | extern struct signal_info sig_info[]; | ||
32 | |||
33 | extern unsigned long low_physmem; | ||
34 | extern unsigned long high_physmem; | ||
35 | extern unsigned long uml_physmem; | ||
36 | extern unsigned long uml_reserved; | ||
37 | extern unsigned long end_vm; | ||
38 | extern unsigned long start_vm; | ||
39 | extern unsigned long highmem; | ||
40 | |||
41 | extern char host_info[]; | ||
42 | |||
43 | extern char saved_command_line[]; | ||
44 | extern char command_line[]; | ||
45 | |||
46 | extern char *tempdir; | ||
47 | |||
48 | extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; | ||
49 | extern unsigned long _unprotected_end; | ||
50 | extern unsigned long brk_start; | ||
51 | |||
52 | extern int pty_output_sigio; | ||
53 | extern int pty_close_sigio; | ||
54 | |||
55 | extern void stop(void); | ||
56 | extern void stack_protections(unsigned long address); | ||
57 | extern void task_protections(unsigned long address); | ||
58 | extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); | ||
59 | extern void *add_signal_handler(int sig, void (*handler)(int)); | ||
60 | extern int start_fork_tramp(void *arg, unsigned long temp_stack, | ||
61 | int clone_flags, int (*tramp)(void *)); | ||
62 | extern int linux_main(int argc, char **argv); | ||
63 | extern void set_cmdline(char *cmd); | ||
64 | extern void input_cb(void (*proc)(void *), void *arg, int arg_len); | ||
65 | extern int get_pty(void); | ||
66 | extern void *um_kmalloc(int size); | ||
67 | extern int switcheroo(int fd, int prot, void *from, void *to, int size); | ||
68 | extern void setup_machinename(char *machine_out); | ||
69 | extern void setup_hostinfo(void); | ||
70 | extern void add_arg(char *arg); | ||
71 | extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); | ||
72 | extern void init_new_thread_signals(int altstack); | ||
73 | extern void do_exec(int old_pid, int new_pid); | ||
74 | extern void tracer_panic(char *msg, ...); | ||
75 | extern char *get_umid(int only_if_set); | ||
76 | extern void do_longjmp(void *p, int val); | ||
77 | extern int detach(int pid, int sig); | ||
78 | extern int attach(int pid); | ||
79 | extern void kill_child_dead(int pid); | ||
80 | extern int cont(int pid); | ||
81 | extern void check_ptrace(void); | ||
82 | extern void check_sigio(void); | ||
83 | extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); | ||
84 | extern void write_sigio_workaround(void); | ||
85 | extern void arch_check_bugs(void); | ||
86 | extern int cpu_feature(char *what, char *buf, int len); | ||
87 | extern int arch_handle_signal(int sig, union uml_pt_regs *regs); | ||
88 | extern int arch_fixup(unsigned long address, void *sc_ptr); | ||
89 | extern void forward_pending_sigio(int target); | ||
90 | extern int can_do_skas(void); | ||
91 | extern void arch_init_thread(void); | ||
92 | extern int setjmp_wrapper(void (*proc)(void *, void *), ...); | ||
93 | extern 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 | |||
6 | extra-y := vmlinux.lds | ||
7 | clean-files := vmlinux.lds.S config.tmp | ||
8 | |||
9 | obj-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 | |||
17 | obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o | ||
18 | obj-$(CONFIG_GPROF) += gprof_syms.o | ||
19 | obj-$(CONFIG_GCOV) += gmon_syms.o | ||
20 | obj-$(CONFIG_TTY_LOG) += tty_log.o | ||
21 | obj-$(CONFIG_SYSCALL_DEBUG) += syscall_user.o | ||
22 | |||
23 | obj-$(CONFIG_MODE_TT) += tt/ | ||
24 | obj-$(CONFIG_MODE_SKAS) += skas/ | ||
25 | |||
26 | # This needs be compiled with frame pointers regardless of how the rest of the | ||
27 | # kernel is built. | ||
28 | CFLAGS_frame.o := -fno-omit-frame-pointer | ||
29 | |||
30 | user-objs-$(CONFIG_TTY_LOG) += tty_log.o | ||
31 | |||
32 | USER_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 | |||
35 | include arch/um/scripts/Makefile.rules | ||
36 | |||
37 | targets += 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 | |||
45 | quiet_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 | |||
52 | quiet_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 | |||
5 | unsigned int arch_csum_partial(const unsigned char *buff, int len, int sum); | ||
6 | |||
7 | unsigned int csum_partial(unsigned char *buff, int len, int sum) | ||
8 | { | ||
9 | return arch_csum_partial(buff, len, sum); | ||
10 | } | ||
11 | |||
12 | EXPORT_SYMBOL(csum_partial); | ||
13 | |||
14 | unsigned 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 | |||
26 | unsigned 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 | |||
10 | static __initdata char *config = "CONFIG"; | ||
11 | |||
12 | static 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 | |||
3 | OUTPUT_FORMAT(ELF_FORMAT) | ||
4 | OUTPUT_ARCH(ELF_ARCH) | ||
5 | ENTRY(_start) | ||
6 | jiffies = jiffies_64; | ||
7 | |||
8 | SECTIONS | ||
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 | |||
25 | void flush_thread(void) | ||
26 | { | ||
27 | CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); | ||
28 | } | ||
29 | |||
30 | void 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 | |||
35 | extern void log_exec(char **argv, void *tty); | ||
36 | |||
37 | static 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, ¤t->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 | |||
55 | long 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 | |||
65 | long 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 | */ | ||
14 | int uml_exitcode = 0; | ||
15 | |||
16 | static 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 | |||
30 | static 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 | |||
45 | static 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 | |||
8 | extern void __bb_init_func(void *); | ||
9 | EXPORT_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 | |||
19 | extern void __gcov_init(void *) __attribute__((weak)); | ||
20 | EXPORT_SYMBOL(__gcov_init); | ||
21 | |||
22 | extern void __gcov_merge_add(void *) __attribute__((weak)); | ||
23 | EXPORT_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 | |||
8 | extern void mcount(void); | ||
9 | EXPORT_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 | |||
18 | struct 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 */ | ||
26 | int helper_pause = 0; | ||
27 | |||
28 | static void helper_hup(int sig) | ||
29 | { | ||
30 | } | ||
31 | |||
32 | static 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 */ | ||
54 | int 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 | |||
109 | out_close: | ||
110 | if (fds[1] != -1) | ||
111 | os_close_file(fds[1]); | ||
112 | os_close_file(fds[0]); | ||
113 | out_free: | ||
114 | if(stack_out == NULL) | ||
115 | free_stack(stack, 0); | ||
116 | else *stack_out = stack; | ||
117 | return(ret); | ||
118 | } | ||
119 | |||
120 | int 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 | |||
152 | int 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 | |||
17 | static struct fs_struct init_fs = INIT_FS; | ||
18 | struct mm_struct init_mm = INIT_MM(init_mm); | ||
19 | static struct files_struct init_files = INIT_FILES; | ||
20 | static struct signal_struct init_signals = INIT_SIGNALS(init_signals); | ||
21 | static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); | ||
22 | EXPORT_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 | |||
30 | struct task_struct init_task = INIT_TASK(init_task); | ||
31 | |||
32 | EXPORT_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 | |||
42 | union thread_union init_thread_union | ||
43 | __attribute__((__section__(".data.init_task"))) = | ||
44 | { INIT_THREAD_INFO(init_task) }; | ||
45 | |||
46 | void 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 */ | ||
17 | static char *initrd __initdata = NULL; | ||
18 | |||
19 | static 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 | |||
38 | static 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 | |||
17 | int 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 | |||
40 | int 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'); | ||
72 | skip: | ||
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 | */ | ||
86 | unsigned 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 | |||
94 | int 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 | } | ||
109 | EXPORT_SYMBOL(um_request_irq); | ||
110 | EXPORT_SYMBOL(reactivate_fd); | ||
111 | |||
112 | static DEFINE_SPINLOCK(irq_spinlock); | ||
113 | |||
114 | unsigned long irq_lock(void) | ||
115 | { | ||
116 | unsigned long flags; | ||
117 | |||
118 | spin_lock_irqsave(&irq_spinlock, flags); | ||
119 | return(flags); | ||
120 | } | ||
121 | |||
122 | void 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 */ | ||
129 | static void dummy(unsigned int irq) | ||
130 | { | ||
131 | } | ||
132 | |||
133 | static struct hw_interrupt_type SIGIO_irq_type = { | ||
134 | .typename = "SIGIO", | ||
135 | .disable = dummy, | ||
136 | .enable = dummy, | ||
137 | .ack = dummy, | ||
138 | .end = dummy | ||
139 | }; | ||
140 | |||
141 | static 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 | |||
150 | void __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 | |||
23 | struct 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 | |||
35 | static struct irq_fd *active_fds = NULL; | ||
36 | static struct irq_fd **last_irq_ptr = &active_fds; | ||
37 | |||
38 | static struct pollfd *pollfds = NULL; | ||
39 | static int pollfds_num = 0; | ||
40 | static int pollfds_size = 0; | ||
41 | |||
42 | extern int io_count, intr_count; | ||
43 | |||
44 | void 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 | |||
96 | int activate_ipi(int fd, int pid) | ||
97 | { | ||
98 | return(os_set_fd_async(fd, pid)); | ||
99 | } | ||
100 | |||
101 | static 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 | |||
115 | int 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 | |||
221 | static 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 | |||
257 | struct irq_and_dev { | ||
258 | int irq; | ||
259 | void *dev; | ||
260 | }; | ||
261 | |||
262 | static 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 | |||
269 | void 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 | |||
277 | static int same_fd(struct irq_fd *irq, void *fd) | ||
278 | { | ||
279 | return(irq->fd == *((int *) fd)); | ||
280 | } | ||
281 | |||
282 | void free_irq_by_fd(int fd) | ||
283 | { | ||
284 | free_irq_by_cb(same_fd, &fd); | ||
285 | } | ||
286 | |||
287 | static 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 | |||
312 | void 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 | |||
332 | void 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 | |||
355 | void 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 | |||
370 | int 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 | |||
386 | void 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 | |||
396 | void 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 | |||
418 | void 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 | |||
26 | EXPORT_SYMBOL(stop); | ||
27 | EXPORT_SYMBOL(uml_physmem); | ||
28 | EXPORT_SYMBOL(set_signals); | ||
29 | EXPORT_SYMBOL(get_signals); | ||
30 | EXPORT_SYMBOL(kernel_thread); | ||
31 | EXPORT_SYMBOL(__const_udelay); | ||
32 | EXPORT_SYMBOL(__udelay); | ||
33 | EXPORT_SYMBOL(sys_waitpid); | ||
34 | EXPORT_SYMBOL(task_size); | ||
35 | EXPORT_SYMBOL(flush_tlb_range); | ||
36 | EXPORT_SYMBOL(host_task_size); | ||
37 | EXPORT_SYMBOL(arch_validate); | ||
38 | EXPORT_SYMBOL(get_kmem_end); | ||
39 | |||
40 | EXPORT_SYMBOL(page_to_phys); | ||
41 | EXPORT_SYMBOL(phys_to_page); | ||
42 | EXPORT_SYMBOL(high_physmem); | ||
43 | EXPORT_SYMBOL(empty_zero_page); | ||
44 | EXPORT_SYMBOL(um_virt_to_phys); | ||
45 | EXPORT_SYMBOL(__virt_to_page); | ||
46 | EXPORT_SYMBOL(to_phys); | ||
47 | EXPORT_SYMBOL(to_virt); | ||
48 | EXPORT_SYMBOL(mode_tt); | ||
49 | EXPORT_SYMBOL(handle_page_fault); | ||
50 | EXPORT_SYMBOL(find_iomem); | ||
51 | EXPORT_SYMBOL(end_iomem); | ||
52 | |||
53 | #ifdef CONFIG_MODE_TT | ||
54 | EXPORT_SYMBOL(strncpy_from_user_tt); | ||
55 | EXPORT_SYMBOL(copy_from_user_tt); | ||
56 | EXPORT_SYMBOL(copy_to_user_tt); | ||
57 | #endif | ||
58 | |||
59 | #ifdef CONFIG_MODE_SKAS | ||
60 | EXPORT_SYMBOL(strncpy_from_user_skas); | ||
61 | EXPORT_SYMBOL(copy_to_user_skas); | ||
62 | EXPORT_SYMBOL(copy_from_user_skas); | ||
63 | #endif | ||
64 | EXPORT_SYMBOL(uml_strdup); | ||
65 | |||
66 | EXPORT_SYMBOL(os_stat_fd); | ||
67 | EXPORT_SYMBOL(os_stat_file); | ||
68 | EXPORT_SYMBOL(os_access); | ||
69 | EXPORT_SYMBOL(os_print_error); | ||
70 | EXPORT_SYMBOL(os_get_exec_close); | ||
71 | EXPORT_SYMBOL(os_set_exec_close); | ||
72 | EXPORT_SYMBOL(os_getpid); | ||
73 | EXPORT_SYMBOL(os_open_file); | ||
74 | EXPORT_SYMBOL(os_read_file); | ||
75 | EXPORT_SYMBOL(os_write_file); | ||
76 | EXPORT_SYMBOL(os_seek_file); | ||
77 | EXPORT_SYMBOL(os_lock_file); | ||
78 | EXPORT_SYMBOL(os_ioctl_generic); | ||
79 | EXPORT_SYMBOL(os_pipe); | ||
80 | EXPORT_SYMBOL(os_file_type); | ||
81 | EXPORT_SYMBOL(os_file_mode); | ||
82 | EXPORT_SYMBOL(os_file_size); | ||
83 | EXPORT_SYMBOL(os_flush_stdout); | ||
84 | EXPORT_SYMBOL(os_close_file); | ||
85 | EXPORT_SYMBOL(os_set_fd_async); | ||
86 | EXPORT_SYMBOL(os_set_fd_block); | ||
87 | EXPORT_SYMBOL(helper_wait); | ||
88 | EXPORT_SYMBOL(os_shutdown_socket); | ||
89 | EXPORT_SYMBOL(os_create_unix_socket); | ||
90 | EXPORT_SYMBOL(os_connect_socket); | ||
91 | EXPORT_SYMBOL(os_accept_connection); | ||
92 | EXPORT_SYMBOL(os_rcv_fd); | ||
93 | EXPORT_SYMBOL(run_helper); | ||
94 | EXPORT_SYMBOL(start_thread); | ||
95 | EXPORT_SYMBOL(dump_thread); | ||
96 | |||
97 | EXPORT_SYMBOL(do_gettimeofday); | ||
98 | EXPORT_SYMBOL(do_settimeofday); | ||
99 | |||
100 | /* This is here because UML expands open to sys_open, not to a system | ||
101 | * call instruction. | ||
102 | */ | ||
103 | EXPORT_SYMBOL(sys_open); | ||
104 | EXPORT_SYMBOL(sys_lseek); | ||
105 | EXPORT_SYMBOL(sys_read); | ||
106 | EXPORT_SYMBOL(sys_wait4); | ||
107 | |||
108 | #ifdef CONFIG_SMP | ||
109 | |||
110 | /* required for SMP */ | ||
111 | |||
112 | extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); | ||
113 | EXPORT_SYMBOL(__write_lock_failed); | ||
114 | |||
115 | extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); | ||
116 | EXPORT_SYMBOL(__read_lock_failed); | ||
117 | |||
118 | #endif | ||
119 | |||
120 | #ifdef CONFIG_HIGHMEM | ||
121 | EXPORT_SYMBOL(kmap); | ||
122 | EXPORT_SYMBOL(kunmap); | ||
123 | EXPORT_SYMBOL(kmap_atomic); | ||
124 | EXPORT_SYMBOL(kunmap_atomic); | ||
125 | EXPORT_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 | */ | ||
34 | unsigned long stacksizelim; | ||
35 | |||
36 | /* Set in main */ | ||
37 | char *linux_prog; | ||
38 | |||
39 | #define PGD_BOUND (4 * 1024 * 1024) | ||
40 | #define STACKSIZE (8 * 1024 * 1024) | ||
41 | #define THREAD_NAME_LEN (256) | ||
42 | |||
43 | static 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 | |||
61 | static __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 | |||
72 | static 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 | |||
82 | extern int uml_exitcode; | ||
83 | |||
84 | extern void scan_elf_aux( char **envp); | ||
85 | |||
86 | int 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 | |||
195 | extern void *__real_malloc(int); | ||
196 | |||
197 | void *__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 | |||
216 | void *__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 | |||
225 | extern void __real_free(void *); | ||
226 | |||
227 | extern unsigned long high_physmem; | ||
228 | |||
229 | void __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 | |||
23 | extern char __binary_start; | ||
24 | |||
25 | /* Changed during early boot */ | ||
26 | unsigned long *empty_zero_page = NULL; | ||
27 | unsigned long *empty_bad_page = NULL; | ||
28 | pgd_t swapper_pg_dir[PTRS_PER_PGD]; | ||
29 | unsigned long highmem; | ||
30 | int kmalloc_ok = 0; | ||
31 | |||
32 | static unsigned long brk_end; | ||
33 | |||
34 | void unmap_physmem(void) | ||
35 | { | ||
36 | os_unmap_memory((void *) brk_end, uml_reserved - brk_end); | ||
37 | } | ||
38 | |||
39 | static 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 | ||
45 | static 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 | |||
63 | void 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 | |||
103 | static 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 | ||
134 | pte_t *kmap_pte; | ||
135 | pgprot_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 | |||
141 | static 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 | |||
152 | static 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 | |||
176 | static 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 | |||
203 | void 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 | |||
230 | struct 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 | ¤t->thread.fault_addr, | ||
245 | ¤t->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 | |||
261 | void free_initmem(void) | ||
262 | { | ||
263 | } | ||
264 | |||
265 | #ifdef CONFIG_BLK_DEV_INITRD | ||
266 | |||
267 | void 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 | |||
282 | void 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 | |||
316 | pgd_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 | |||
329 | void pgd_free(pgd_t *pgd) | ||
330 | { | ||
331 | free_page((unsigned long) pgd); | ||
332 | } | ||
333 | |||
334 | pte_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 | |||
342 | struct 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 | |||
53 | static 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 | |||
84 | void 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 | |||
106 | static int have_devanon = 0; | ||
107 | |||
108 | void 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 | |||
123 | static 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 | |||
144 | int 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 | |||
158 | struct iomem_region *iomem_regions = NULL; | ||
159 | int iomem_size = 0; | ||
160 | |||
161 | static 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 | |||
217 | int 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 | |||
237 | int logging = 1; | ||
238 | int logging_fd = -1; | ||
239 | |||
240 | int logging_line = 0; | ||
241 | char logging_buf[512]; | ||
242 | |||
243 | void 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 | |||
23 | struct 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 | |||
32 | static struct rb_root phys_mappings = RB_ROOT; | ||
33 | |||
34 | static 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 | |||
53 | static 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 | |||
63 | static 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 | |||
75 | LIST_HEAD(descriptor_mappings); | ||
76 | |||
77 | struct desc_mapping { | ||
78 | int fd; | ||
79 | struct list_head list; | ||
80 | struct list_head pages; | ||
81 | }; | ||
82 | |||
83 | static 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 | |||
97 | static 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 | |||
118 | int 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 | |||
160 | static int physmem_fd = -1; | ||
161 | |||
162 | static 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 | |||
177 | int 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 | |||
190 | void 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 | |||
224 | EXPORT_SYMBOL(physmem_forget_descriptor); | ||
225 | EXPORT_SYMBOL(physmem_remove_mapping); | ||
226 | EXPORT_SYMBOL(physmem_subst_mapping); | ||
227 | |||
228 | void 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 | |||
239 | int 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 */ | ||
247 | unsigned long high_physmem; | ||
248 | |||
249 | extern unsigned long physmem_size; | ||
250 | |||
251 | void *to_virt(unsigned long phys) | ||
252 | { | ||
253 | return((void *) uml_physmem + phys); | ||
254 | } | ||
255 | |||
256 | unsigned long to_phys(void *virt) | ||
257 | { | ||
258 | return(((unsigned long) virt) - uml_physmem); | ||
259 | } | ||
260 | |||
261 | int 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 | |||
301 | struct page *phys_to_page(const unsigned long phys) | ||
302 | { | ||
303 | return(&mem_map[phys >> PAGE_SHIFT]); | ||
304 | } | ||
305 | |||
306 | struct page *__virt_to_page(const unsigned long virt) | ||
307 | { | ||
308 | return(&mem_map[__pa(virt) >> PAGE_SHIFT]); | ||
309 | } | ||
310 | |||
311 | phys_t page_to_phys(struct page *page) | ||
312 | { | ||
313 | return((page - mem_map) << PAGE_SHIFT); | ||
314 | } | ||
315 | |||
316 | pte_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 */ | ||
327 | static unsigned long kmem_top = 0; | ||
328 | |||
329 | unsigned 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 | |||
336 | void 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 | |||
356 | void 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 | |||
379 | int 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 | |||
413 | static 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 | |||
429 | unsigned 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 | |||
443 | int 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 | |||
42 | void 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 | |||
54 | void 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 | |||
77 | struct 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 | |||
87 | int sigkill = SIGKILL; | ||
88 | |||
89 | int 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 | |||
102 | int 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 | |||
136 | static 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 | |||
165 | static 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!*/ | ||
194 | static 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 | |||
222 | static int force_sysemu_disabled = 0; | ||
223 | |||
224 | static 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 | |||
238 | static 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 | |||
306 | fail: | ||
307 | stop_ptraced_child(pid, stack, 1, 0); | ||
308 | fail_stopped: | ||
309 | printk("missing\n"); | ||
310 | } | ||
311 | |||
312 | void __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 | |||
350 | int 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 | |||
363 | void 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 | ||
374 | static 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 | |||
401 | int 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(); | ||
415 | out: | ||
416 | return ret; | ||
417 | } | ||
418 | #else | ||
419 | int 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 | */ | ||
56 | struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; | ||
57 | |||
58 | struct 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 | |||
70 | int 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 | |||
77 | int 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 | |||
87 | void free_stack(unsigned long stack, int order) | ||
88 | { | ||
89 | free_pages(stack, order); | ||
90 | } | ||
91 | |||
92 | unsigned 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 | |||
105 | int 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 | |||
118 | void 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 | |||
128 | void 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 | |||
136 | void *_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 | |||
142 | void interrupt_end(void) | ||
143 | { | ||
144 | if(need_resched()) schedule(); | ||
145 | if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal(); | ||
146 | } | ||
147 | |||
148 | void release_thread(struct task_struct *task) | ||
149 | { | ||
150 | CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task)); | ||
151 | } | ||
152 | |||
153 | void exit_thread(void) | ||
154 | { | ||
155 | CHOOSE_MODE(exit_thread_tt(), exit_thread_skas()); | ||
156 | unprotect_stack((unsigned long) current_thread); | ||
157 | } | ||
158 | |||
159 | void *get_current(void) | ||
160 | { | ||
161 | return(current); | ||
162 | } | ||
163 | |||
164 | void prepare_to_copy(struct task_struct *tsk) | ||
165 | { | ||
166 | } | ||
167 | |||
168 | int 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 | |||
177 | void 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 | |||
187 | unsigned long stack_sp(unsigned long page) | ||
188 | { | ||
189 | return(page + PAGE_SIZE - sizeof(void *)); | ||
190 | } | ||
191 | |||
192 | int current_pid(void) | ||
193 | { | ||
194 | return(current->pid); | ||
195 | } | ||
196 | |||
197 | void 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 | |||
220 | void cpu_idle(void) | ||
221 | { | ||
222 | CHOOSE_MODE(init_idle_tt(), init_idle_skas()); | ||
223 | } | ||
224 | |||
225 | int page_size(void) | ||
226 | { | ||
227 | return(PAGE_SIZE); | ||
228 | } | ||
229 | |||
230 | unsigned long page_mask(void) | ||
231 | { | ||
232 | return(PAGE_MASK); | ||
233 | } | ||
234 | |||
235 | void *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 | |||
266 | char *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 | |||
276 | void 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(¤t->pending.signal, SIGBUS); | ||
282 | recalc_sigpending(); | ||
283 | current->flags |= PF_SIGNALED; | ||
284 | do_exit(SIGBUS | 0x80); | ||
285 | } | ||
286 | |||
287 | void dump_thread(struct pt_regs *regs, struct user *u) | ||
288 | { | ||
289 | } | ||
290 | |||
291 | void enable_hlt(void) | ||
292 | { | ||
293 | panic("enable_hlt"); | ||
294 | } | ||
295 | |||
296 | EXPORT_SYMBOL(enable_hlt); | ||
297 | |||
298 | void disable_hlt(void) | ||
299 | { | ||
300 | panic("disable_hlt"); | ||
301 | } | ||
302 | |||
303 | EXPORT_SYMBOL(disable_hlt); | ||
304 | |||
305 | void *um_kmalloc(int size) | ||
306 | { | ||
307 | return(kmalloc(size, GFP_KERNEL)); | ||
308 | } | ||
309 | |||
310 | void *um_kmalloc_atomic(int size) | ||
311 | { | ||
312 | return(kmalloc(size, GFP_ATOMIC)); | ||
313 | } | ||
314 | |||
315 | void *um_vmalloc(int size) | ||
316 | { | ||
317 | return(vmalloc(size)); | ||
318 | } | ||
319 | |||
320 | unsigned long get_fault_addr(void) | ||
321 | { | ||
322 | return((unsigned long) current->thread.fault_addr); | ||
323 | } | ||
324 | |||
325 | EXPORT_SYMBOL(get_fault_addr); | ||
326 | |||
327 | void not_implemented(void) | ||
328 | { | ||
329 | printk(KERN_DEBUG "Something isn't implemented in here\n"); | ||
330 | } | ||
331 | |||
332 | EXPORT_SYMBOL(not_implemented); | ||
333 | |||
334 | int 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 | |||
342 | extern void remove_umid_dir(void); | ||
343 | |||
344 | __uml_exitcall(remove_umid_dir); | ||
345 | |||
346 | extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; | ||
347 | |||
348 | void 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 | |||
357 | char *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 | |||
367 | void *get_init_task(void) | ||
368 | { | ||
369 | return(&init_thread_union.thread_info.task); | ||
370 | } | ||
371 | |||
372 | int copy_to_user_proc(void __user *to, void *from, int size) | ||
373 | { | ||
374 | return(copy_to_user(to, from, size)); | ||
375 | } | ||
376 | |||
377 | int copy_from_user_proc(void *to, void __user *from, int size) | ||
378 | { | ||
379 | return(copy_from_user(to, from, size)); | ||
380 | } | ||
381 | |||
382 | int clear_user_proc(void __user *buf, int size) | ||
383 | { | ||
384 | return(clear_user(buf, size)); | ||
385 | } | ||
386 | |||
387 | int strlen_user_proc(char __user *str) | ||
388 | { | ||
389 | return(strlen_user(str)); | ||
390 | } | ||
391 | |||
392 | int 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 | |||
403 | int um_in_interrupt(void) | ||
404 | { | ||
405 | return(in_interrupt()); | ||
406 | } | ||
407 | |||
408 | int cpu(void) | ||
409 | { | ||
410 | return(current_thread->cpu); | ||
411 | } | ||
412 | |||
413 | static atomic_t using_sysemu = ATOMIC_INIT(0); | ||
414 | int sysemu_supported; | ||
415 | |||
416 | void set_using_sysemu(int value) | ||
417 | { | ||
418 | if (value > sysemu_supported) | ||
419 | return; | ||
420 | atomic_set(&using_sysemu, value); | ||
421 | } | ||
422 | |||
423 | int get_using_sysemu(void) | ||
424 | { | ||
425 | return atomic_read(&using_sysemu); | ||
426 | } | ||
427 | |||
428 | static 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 | |||
436 | static 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 | |||
448 | int __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 | |||
468 | late_initcall(make_proc_sysemu); | ||
469 | |||
470 | int 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 | |||
483 | unsigned 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 | */ | ||
25 | void ptrace_disable(struct task_struct *child) | ||
26 | { | ||
27 | child->ptrace &= ~PT_DTRACE; | ||
28 | child->thread.singlestep_syscall = 0; | ||
29 | } | ||
30 | |||
31 | long 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 | |||
314 | void 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 | */ | ||
333 | void 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(®s->regs), | ||
342 | UPT_SYSCALL_ARG1(®s->regs), | ||
343 | UPT_SYSCALL_ARG2(®s->regs), | ||
344 | UPT_SYSCALL_ARG3(®s->regs), | ||
345 | UPT_SYSCALL_ARG4(®s->regs)); | ||
346 | else | ||
347 | audit_syscall_exit(current, | ||
348 | UPT_SYSCALL_RET(®s->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 | ||
16 | static 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 | |||
31 | static 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 | |||
39 | void uml_cleanup(void) | ||
40 | { | ||
41 | kill_off_processes(); | ||
42 | do_uml_exitcalls(); | ||
43 | } | ||
44 | |||
45 | void machine_restart(char * __unused) | ||
46 | { | ||
47 | do_uml_exitcalls(); | ||
48 | kill_off_processes(); | ||
49 | CHOOSE_MODE(reboot_tt(), reboot_skas()); | ||
50 | } | ||
51 | |||
52 | EXPORT_SYMBOL(machine_restart); | ||
53 | |||
54 | void machine_power_off(void) | ||
55 | { | ||
56 | do_uml_exitcalls(); | ||
57 | kill_off_processes(); | ||
58 | CHOOSE_MODE(halt_tt(), halt_skas()); | ||
59 | } | ||
60 | |||
61 | EXPORT_SYMBOL(machine_power_off); | ||
62 | |||
63 | void machine_halt(void) | ||
64 | { | ||
65 | machine_power_off(); | ||
66 | } | ||
67 | |||
68 | EXPORT_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 | |||
8 | unsigned 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 */ | ||
17 | static int sigio_irq_fd = -1; | ||
18 | |||
19 | static 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 | |||
26 | int 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 | |||
42 | static DEFINE_SPINLOCK(sigio_spinlock); | ||
43 | |||
44 | void sigio_lock(void) | ||
45 | { | ||
46 | spin_lock(&sigio_spinlock); | ||
47 | } | ||
48 | |||
49 | void 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 */ | ||
25 | int pty_output_sigio = 0; | ||
26 | int pty_close_sigio = 0; | ||
27 | |||
28 | /* Used as a flag during SIGIO testing early in boot */ | ||
29 | static volatile int got_sigio = 0; | ||
30 | |||
31 | void __init handler(int sig) | ||
32 | { | ||
33 | got_sigio = 1; | ||
34 | } | ||
35 | |||
36 | struct openpty_arg { | ||
37 | int master; | ||
38 | int slave; | ||
39 | int err; | ||
40 | }; | ||
41 | |||
42 | static 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 | |||
51 | void __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 | |||
97 | static 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 | |||
121 | static 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 | |||
133 | void __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 | */ | ||
148 | static 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 | */ | ||
154 | static int write_sigio_fds[2] = { -1, -1 }; | ||
155 | static int sigio_private[2] = { -1, -1 }; | ||
156 | |||
157 | struct 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 | */ | ||
166 | struct pollfds current_poll = { | ||
167 | .poll = NULL, | ||
168 | .size = 0, | ||
169 | .used = 0 | ||
170 | }; | ||
171 | |||
172 | struct pollfds next_poll = { | ||
173 | .poll = NULL, | ||
174 | .size = 0, | ||
175 | .used = 0 | ||
176 | }; | ||
177 | |||
178 | static 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 = ¤t_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 | |||
221 | static 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. */ | ||
242 | static 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 | |||
276 | int 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 | |||
306 | int 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 = ¤t_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 | |||
338 | static 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 | |||
356 | void 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 | |||
404 | int 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 | |||
423 | static 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 | |||
31 | EXPORT_SYMBOL(block_signals); | ||
32 | EXPORT_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 | */ | ||
41 | static 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(¤t->sighand->siglock); | ||
86 | current->blocked = *oldset; | ||
87 | recalc_sigpending(); | ||
88 | spin_unlock_irq(¤t->sighand->siglock); | ||
89 | force_sigsegv(signr, current); | ||
90 | } | ||
91 | else if(!(ka->sa.sa_flags & SA_NODEFER)){ | ||
92 | spin_lock_irq(¤t->sighand->siglock); | ||
93 | sigorsets(¤t->blocked, ¤t->blocked, | ||
94 | &ka->sa.sa_mask); | ||
95 | sigaddset(¤t->blocked, signr); | ||
96 | recalc_sigpending(); | ||
97 | spin_unlock_irq(¤t->sighand->siglock); | ||
98 | } | ||
99 | |||
100 | return err; | ||
101 | } | ||
102 | |||
103 | static 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(¤t->thread.regs)); | ||
141 | return(handled_sig); | ||
142 | } | ||
143 | |||
144 | int do_signal(void) | ||
145 | { | ||
146 | return(kern_do_signal(¤t->thread.regs, ¤t->blocked)); | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * Atomically swap in the new signal mask, and wait for a signal. | ||
151 | */ | ||
152 | long sys_sigsuspend(int history0, int history1, old_sigset_t mask) | ||
153 | { | ||
154 | sigset_t saveset; | ||
155 | |||
156 | mask &= _BLOCKABLE; | ||
157 | spin_lock_irq(¤t->sighand->siglock); | ||
158 | saveset = current->blocked; | ||
159 | siginitset(¤t->blocked, mask); | ||
160 | recalc_sigpending(); | ||
161 | spin_unlock_irq(¤t->sighand->siglock); | ||
162 | |||
163 | PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR; | ||
164 | while (1) { | ||
165 | current->state = TASK_INTERRUPTIBLE; | ||
166 | schedule(); | ||
167 | if(kern_do_signal(¤t->thread.regs, &saveset)) | ||
168 | return(-EINTR); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | long 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(¤t->sighand->siglock); | ||
185 | saveset = current->blocked; | ||
186 | current->blocked = newset; | ||
187 | recalc_sigpending(); | ||
188 | spin_unlock_irq(¤t->sighand->siglock); | ||
189 | |||
190 | PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR; | ||
191 | while (1) { | ||
192 | current->state = TASK_INTERRUPTIBLE; | ||
193 | schedule(); | ||
194 | if (kern_do_signal(¤t->thread.regs, &saveset)) | ||
195 | return(-EINTR); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) | ||
200 | { | ||
201 | return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->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 | |||
22 | void 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 | |||
32 | void 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 | |||
51 | int 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 | |||
65 | static 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 | |||
77 | void block_signals(void) | ||
78 | { | ||
79 | change_signals(SIG_BLOCK); | ||
80 | } | ||
81 | |||
82 | void 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 | |||
96 | static 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 | |||
106 | int 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 | |||
115 | int 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 | |||
6 | obj-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 | |||
9 | subdir- := util | ||
10 | |||
11 | USER_OBJS := process.o time.o | ||
12 | |||
13 | include 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 | |||
18 | void flush_thread_skas(void) | ||
19 | { | ||
20 | force_flush_all(); | ||
21 | switch_mm_skas(current->mm->context.skas.mm_fd); | ||
22 | } | ||
23 | |||
24 | void 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 | |||
9 | struct 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 | |||
11 | extern unsigned long exec_regs[]; | ||
12 | extern unsigned long exec_fp_regs[]; | ||
13 | extern unsigned long exec_fpx_regs[]; | ||
14 | extern int have_fpx_regs; | ||
15 | |||
16 | extern void user_time_init_skas(void); | ||
17 | extern void sig_handler_common_skas(int sig, void *sc_ptr); | ||
18 | extern void halt_skas(void); | ||
19 | extern void reboot_skas(void); | ||
20 | extern void kill_off_processes_skas(void); | ||
21 | extern 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 | |||
13 | extern void flush_thread_skas(void); | ||
14 | extern void *switch_to_skas(void *prev, void *next); | ||
15 | extern void start_thread_skas(struct pt_regs *regs, unsigned long eip, | ||
16 | unsigned long esp); | ||
17 | extern 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); | ||
20 | extern void release_thread_skas(struct task_struct *task); | ||
21 | extern void exit_thread_skas(void); | ||
22 | extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); | ||
23 | extern void init_idle_skas(void); | ||
24 | extern void flush_tlb_kernel_range_skas(unsigned long start, | ||
25 | unsigned long end); | ||
26 | extern void flush_tlb_kernel_vm_skas(void); | ||
27 | extern void __flush_tlb_one_skas(unsigned long addr); | ||
28 | extern void flush_tlb_range_skas(struct vm_area_struct *vma, | ||
29 | unsigned long start, unsigned long end); | ||
30 | extern void flush_tlb_mm_skas(struct mm_struct *mm); | ||
31 | extern void force_flush_all_skas(void); | ||
32 | extern long execute_syscall_skas(void *r); | ||
33 | extern void before_mem_skas(unsigned long unused); | ||
34 | extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, | ||
35 | unsigned long *task_size_out); | ||
36 | extern int start_uml_skas(void); | ||
37 | extern int external_pid_skas(struct task_struct *task); | ||
38 | extern 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 | |||
14 | struct 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 | |||
23 | struct mm_munmap { | ||
24 | unsigned long addr; | ||
25 | unsigned long len; | ||
26 | }; | ||
27 | |||
28 | struct mm_mprotect { | ||
29 | unsigned long addr; | ||
30 | unsigned long len; | ||
31 | unsigned int prot; | ||
32 | }; | ||
33 | |||
34 | struct 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 | |||
11 | extern int userspace_pid[]; | ||
12 | |||
13 | extern void switch_threads(void *me, void *next); | ||
14 | extern void thread_wait(void *sw, void *fb); | ||
15 | extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, | ||
16 | void (*handler)(int)); | ||
17 | extern int start_idle_thread(void *stack, void *switch_buf_ptr, | ||
18 | void **fork_buf_ptr); | ||
19 | extern int user_thread(unsigned long stack, int flags); | ||
20 | extern void userspace(union uml_pt_regs *regs); | ||
21 | extern void new_thread_proc(void *stack, void (*handler)(int sig)); | ||
22 | extern void remove_sigstack(void); | ||
23 | extern void new_thread_handler(int sig); | ||
24 | extern void handle_syscall(union uml_pt_regs *regs); | ||
25 | extern void map(int fd, unsigned long virt, unsigned long len, int r, int w, | ||
26 | int x, int phys_fd, unsigned long long offset); | ||
27 | extern int unmap(int fd, void *addr, unsigned long len); | ||
28 | extern int protect(int fd, unsigned long addr, unsigned long len, | ||
29 | int r, int w, int x); | ||
30 | extern void user_signal(int sig, union uml_pt_regs *regs); | ||
31 | extern int new_mm(int from); | ||
32 | extern void start_userspace(int cpu); | ||
33 | extern 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 | |||
21 | static 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 | |||
27 | extern int copy_from_user_skas(void *to, const void *from, int n); | ||
28 | extern int copy_to_user_skas(void *to, const void *from, int n); | ||
29 | extern int strncpy_from_user_skas(char *dst, const char *src, int count); | ||
30 | extern int __clear_user_skas(void *mem, int len); | ||
31 | extern int clear_user_skas(void *mem, int len); | ||
32 | extern 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 | |||
10 | unsigned 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 | |||
14 | void 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 | |||
39 | int 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 | |||
60 | int 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 | |||
89 | void 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 | |||
16 | int 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 | |||
34 | void 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 | |||
31 | int 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 | |||
40 | static 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)*/ | ||
54 | static 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 | |||
83 | static 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 | ||
95 | int userspace_pid[NR_CPUS]; | ||
96 | |||
97 | void 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 | |||
135 | void 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 | |||
194 | void 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 | |||
221 | void 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 | |||
231 | void 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 | |||
240 | static sigjmp_buf initial_jmpbuf; | ||
241 | |||
242 | /* XXX Make these percpu */ | ||
243 | static void (*cb_proc)(void *arg); | ||
244 | static void *cb_arg; | ||
245 | static sigjmp_buf *cb_back; | ||
246 | |||
247 | int 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 | |||
273 | void 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 | |||
283 | void 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 | |||
301 | void halt_skas(void) | ||
302 | { | ||
303 | block_signals(); | ||
304 | siglongjmp(initial_jmpbuf, 3); | ||
305 | } | ||
306 | |||
307 | void reboot_skas(void) | ||
308 | { | ||
309 | block_signals(); | ||
310 | siglongjmp(initial_jmpbuf, 4); | ||
311 | } | ||
312 | |||
313 | void 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 | |||
324 | void 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 | |||
27 | void *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 | |||
50 | extern void schedule_tail(struct task_struct *prev); | ||
51 | |||
52 | void 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(¤t->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, ¤t->thread.exec_buf); | ||
71 | if(n == 1) | ||
72 | userspace(¤t->thread.regs.regs); | ||
73 | else do_exit(0); | ||
74 | } | ||
75 | |||
76 | void 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 | |||
82 | void release_thread_skas(struct task_struct *task) | ||
83 | { | ||
84 | } | ||
85 | |||
86 | void exit_thread_skas(void) | ||
87 | { | ||
88 | } | ||
89 | |||
90 | void fork_handler(int sig) | ||
91 | { | ||
92 | change_sig(SIGUSR1, 1); | ||
93 | thread_wait(¤t->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(¤t->thread.regs.regs); | ||
104 | } | ||
105 | |||
106 | int 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 | ¤t->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 | |||
132 | int 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, ©, 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 | |||
154 | void init_idle_skas(void) | ||
155 | { | ||
156 | cpu_tasks[current_thread->cpu].pid = os_getpid(); | ||
157 | default_idle(); | ||
158 | } | ||
159 | |||
160 | extern void start_kernel(void); | ||
161 | |||
162 | static 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 | |||
178 | int 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 | |||
192 | int 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 | |||
198 | int 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 | |||
15 | extern syscall_handler_t *sys_call_table[]; | ||
16 | |||
17 | long 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(®s->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 | |||
15 | void 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 | |||
12 | void 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 | |||
20 | static 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 | |||
49 | static 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 | |||
57 | void __flush_tlb_one_skas(unsigned long addr) | ||
58 | { | ||
59 | flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE); | ||
60 | } | ||
61 | |||
62 | void 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 | |||
70 | void 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 | |||
82 | void 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 | |||
15 | void 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 | |||
48 | void 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 | |||
17 | extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, | ||
18 | pte_t *pte_out); | ||
19 | |||
20 | static 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 | |||
37 | static 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 | |||
55 | static 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 | |||
113 | static 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 | |||
127 | static 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 | |||
136 | int 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 | |||
148 | static 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 | |||
157 | int 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 | |||
169 | static 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 | |||
183 | int 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 | |||
203 | static int clear_chunk(unsigned long addr, int len, void *unused) | ||
204 | { | ||
205 | memset((void *) addr, 0, len); | ||
206 | return(0); | ||
207 | } | ||
208 | |||
209 | int __clear_user_skas(void __user *mem, int len) | ||
210 | { | ||
211 | return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL)); | ||
212 | } | ||
213 | |||
214 | int 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 | |||
225 | static 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 | |||
237 | int 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 @@ | |||
1 | hostprogs-y := mk_ptregs | ||
2 | always := $(hostprogs-y) | ||
3 | |||
4 | mk_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 | |||
7 | int 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 | |||
14 | int 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. */ | ||
12 | DEFINE_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 */ | ||
32 | cpumask_t cpu_online_map = CPU_MASK_NONE; | ||
33 | cpumask_t cpu_possible_map = CPU_MASK_NONE; | ||
34 | |||
35 | EXPORT_SYMBOL(cpu_online_map); | ||
36 | EXPORT_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 | */ | ||
42 | struct cpuinfo_um cpu_data[NR_CPUS]; | ||
43 | |||
44 | /* A statistic, can be a little off */ | ||
45 | int num_reschedules_sent = 0; | ||
46 | |||
47 | /* Not changed after boot */ | ||
48 | struct task_struct *idle_threads[NR_CPUS]; | ||
49 | |||
50 | void smp_send_reschedule(int cpu) | ||
51 | { | ||
52 | os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1); | ||
53 | num_reschedules_sent++; | ||
54 | } | ||
55 | |||
56 | void 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 | |||
69 | static cpumask_t smp_commenced_mask = CPU_MASK_NONE; | ||
70 | static cpumask_t cpu_callin_map = CPU_MASK_NONE; | ||
71 | |||
72 | static 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 | |||
97 | static 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 | |||
119 | void 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 | |||
158 | void smp_prepare_boot_cpu(void) | ||
159 | { | ||
160 | cpu_set(smp_processor_id(), cpu_online_map); | ||
161 | } | ||
162 | |||
163 | int __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 | |||
171 | int setup_profiling_timer(unsigned int multiplier) | ||
172 | { | ||
173 | printk(KERN_INFO "setup_profiling_timer\n"); | ||
174 | return(0); | ||
175 | } | ||
176 | |||
177 | void smp_call_function_slave(int cpu); | ||
178 | |||
179 | void 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 | |||
208 | int hard_smp_processor_id(void) | ||
209 | { | ||
210 | return(pid_to_processor_id(os_getpid())); | ||
211 | } | ||
212 | |||
213 | static DEFINE_SPINLOCK(call_lock); | ||
214 | static atomic_t scf_started; | ||
215 | static atomic_t scf_finished; | ||
216 | static void (*func)(void *info); | ||
217 | static void *info; | ||
218 | |||
219 | void smp_call_function_slave(int cpu) | ||
220 | { | ||
221 | atomic_inc(&scf_started); | ||
222 | (*func)(info); | ||
223 | atomic_inc(&scf_finished); | ||
224 | } | ||
225 | |||
226 | int 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 | |||
31 | extern syscall_handler_t sys_fork; | ||
32 | extern syscall_handler_t sys_execve; | ||
33 | extern syscall_handler_t um_time; | ||
34 | extern syscall_handler_t um_stime; | ||
35 | extern syscall_handler_t sys_pipe; | ||
36 | extern syscall_handler_t sys_olduname; | ||
37 | extern syscall_handler_t sys_sigaction; | ||
38 | extern syscall_handler_t sys_sigsuspend; | ||
39 | extern syscall_handler_t old_readdir; | ||
40 | extern syscall_handler_t sys_uname; | ||
41 | extern syscall_handler_t sys_ipc; | ||
42 | extern syscall_handler_t sys_sigreturn; | ||
43 | extern syscall_handler_t sys_clone; | ||
44 | extern syscall_handler_t sys_rt_sigreturn; | ||
45 | extern syscall_handler_t sys_sigaltstack; | ||
46 | extern syscall_handler_t sys_vfork; | ||
47 | extern syscall_handler_t old_select; | ||
48 | extern syscall_handler_t sys_modify_ldt; | ||
49 | extern syscall_handler_t sys_rt_sigsuspend; | ||
50 | extern syscall_handler_t sys_mbind; | ||
51 | extern syscall_handler_t sys_get_mempolicy; | ||
52 | extern syscall_handler_t sys_set_mempolicy; | ||
53 | extern syscall_handler_t sys_sys_setaltroot; | ||
54 | |||
55 | syscall_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 */ | ||
28 | int nsyscalls = 0; | ||
29 | |||
30 | long 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 | |||
40 | long 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 */ | ||
52 | long 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(¤t->mm->mmap_sem); | ||
67 | error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | ||
68 | up_write(¤t->mm->mmap_sem); | ||
69 | |||
70 | if (file) | ||
71 | fput(file); | ||
72 | out: | ||
73 | return error; | ||
74 | } | ||
75 | |||
76 | long 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 | */ | ||
92 | long 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 | |||
106 | long 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 | |||
117 | long 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 | |||
151 | DEFINE_SPINLOCK(syscall_lock); | ||
152 | |||
153 | static int syscall_index = 0; | ||
154 | |||
155 | int 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 | |||
11 | struct { | ||
12 | int syscall; | ||
13 | int pid; | ||
14 | long result; | ||
15 | struct timeval start; | ||
16 | struct timeval end; | ||
17 | } syscall_record[1024]; | ||
18 | |||
19 | int 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 | |||
33 | void 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 | |||
15 | void 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 | */ | ||
43 | void dump_stack(void) | ||
44 | { | ||
45 | unsigned long stack; | ||
46 | |||
47 | show_trace(&stack); | ||
48 | } | ||
49 | EXPORT_SYMBOL(dump_stack); | ||
50 | |||
51 | /*Stolen from arch/i386/kernel/traps.c */ | ||
52 | static int kstack_depth_to_print = 24; | ||
53 | |||
54 | /* This recently started being used in arch-independent code too, as in | ||
55 | * kernel/sched.c.*/ | ||
56 | void 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 */ | ||
15 | static char *tempdir = NULL; | ||
16 | |||
17 | static 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 | |||
42 | int 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 | */ | ||
24 | extern struct timespec wall_to_monotonic; | ||
25 | |||
26 | extern struct timeval xtime; | ||
27 | |||
28 | struct timeval local_offset = { 0, 0 }; | ||
29 | |||
30 | void timer(void) | ||
31 | { | ||
32 | gettimeofday(&xtime, NULL); | ||
33 | timeradd(&xtime, &local_offset, &xtime); | ||
34 | } | ||
35 | |||
36 | void 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 | |||
46 | void 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 | |||
56 | void 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 | |||
68 | void 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 | |||
90 | void 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 | |||
100 | extern int do_posix_clock_monotonic_gettime(struct timespec *tp); | ||
101 | |||
102 | void 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 */ | ||
116 | extern void clock_was_set(void); | ||
117 | |||
118 | void 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 | |||
129 | int 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 | |||
149 | void 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 | |||
25 | u64 jiffies_64 = INITIAL_JIFFIES; | ||
26 | |||
27 | EXPORT_SYMBOL(jiffies_64); | ||
28 | |||
29 | int hz(void) | ||
30 | { | ||
31 | return(HZ); | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * Scheduler clock - returns current time in nanosec units. | ||
36 | */ | ||
37 | unsigned long long sched_clock(void) | ||
38 | { | ||
39 | return (unsigned long long)jiffies_64 * (1000000000 / HZ); | ||
40 | } | ||
41 | |||
42 | /* Changed at early boot */ | ||
43 | int timer_irq_inited = 0; | ||
44 | |||
45 | static int first_tick; | ||
46 | static unsigned long long prev_usecs; | ||
47 | #ifdef CONFIG_UML_REAL_TIME_CLOCK | ||
48 | static long long delta; /* Deviation per interval */ | ||
49 | #endif | ||
50 | |||
51 | #define MILLION 1000000 | ||
52 | |||
53 | void 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 | |||
93 | void boot_timer_handler(int sig) | ||
94 | { | ||
95 | struct pt_regs regs; | ||
96 | |||
97 | CHOOSE_MODE((void) | ||
98 | (UPT_SC(®s.regs) = (struct sigcontext *) (&sig + 1)), | ||
99 | (void) (regs.regs.skas.is_user = 0)); | ||
100 | do_timer(®s); | ||
101 | } | ||
102 | |||
103 | irqreturn_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 | |||
114 | long 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 | |||
126 | long 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 | |||
139 | void __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 | |||
147 | void __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 | |||
155 | void 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 | |||
164 | static DEFINE_SPINLOCK(timer_spinlock); | ||
165 | |||
166 | unsigned long time_lock(void) | ||
167 | { | ||
168 | unsigned long flags; | ||
169 | |||
170 | spin_lock_irqsave(&timer_spinlock, flags); | ||
171 | return(flags); | ||
172 | } | ||
173 | |||
174 | void time_unlock(unsigned long flags) | ||
175 | { | ||
176 | spin_unlock_irqrestore(&timer_spinlock, flags); | ||
177 | } | ||
178 | |||
179 | int __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 | |||
20 | void 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 | |||
113 | int 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 | |||
198 | void 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 | |||
204 | void flush_tlb_all(void) | ||
205 | { | ||
206 | flush_tlb_mm(current->mm); | ||
207 | } | ||
208 | |||
209 | void 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 | |||
215 | void 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 | |||
221 | void __flush_tlb_one(unsigned long addr) | ||
222 | { | ||
223 | CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); | ||
224 | } | ||
225 | |||
226 | void 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 | |||
233 | void flush_tlb_mm(struct mm_struct *mm) | ||
234 | { | ||
235 | CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); | ||
236 | } | ||
237 | |||
238 | void force_flush_all(void) | ||
239 | { | ||
240 | CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); | ||
241 | } | ||
242 | |||
243 | pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) | ||
244 | { | ||
245 | return(pgd_offset(mm, address)); | ||
246 | } | ||
247 | |||
248 | pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address) | ||
249 | { | ||
250 | return(pud_offset(pgd, address)); | ||
251 | } | ||
252 | |||
253 | pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address) | ||
254 | { | ||
255 | return(pmd_offset(pud, address)); | ||
256 | } | ||
257 | |||
258 | pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address) | ||
259 | { | ||
260 | return(pte_offset_kernel(pmd, address)); | ||
261 | } | ||
262 | |||
263 | pte_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 | |||
272 | int 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 | |||
312 | int 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 | |||
339 | int 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 | |||
30 | int 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 | */ | ||
99 | out_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 | |||
109 | LIST_HEAD(physmem_remappers); | ||
110 | |||
111 | void register_remapper(struct remapper *info) | ||
112 | { | ||
113 | list_add(&info->list, &physmem_remappers); | ||
114 | } | ||
115 | |||
116 | static 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 | |||
136 | unsigned 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 | |||
190 | void 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 | |||
202 | void 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 | |||
210 | void 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 | |||
217 | void winch(int sig, union uml_pt_regs *regs) | ||
218 | { | ||
219 | do_IRQ(WINCH_IRQ, regs); | ||
220 | } | ||
221 | |||
222 | void trap_init(void) | ||
223 | { | ||
224 | } | ||
225 | |||
226 | DEFINE_SPINLOCK(trap_lock); | ||
227 | |||
228 | static int trap_index = 0; | ||
229 | |||
230 | int 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 | |||
29 | void 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 */ | ||
44 | int nsegfaults = 0; | ||
45 | |||
46 | struct { | ||
47 | unsigned long address; | ||
48 | int is_write; | ||
49 | int pid; | ||
50 | unsigned long sp; | ||
51 | int is_user; | ||
52 | } segfault_record[1024]; | ||
53 | |||
54 | void 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 | |||
76 | void usr2_handler(int sig, union uml_pt_regs *regs) | ||
77 | { | ||
78 | CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); | ||
79 | } | ||
80 | |||
81 | struct 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 | |||
104 | void 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 | |||
6 | extra-y := unmap_fin.o | ||
7 | clean-files := unmap_tmp.o | ||
8 | |||
9 | obj-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 | |||
13 | obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/ | ||
14 | |||
15 | USER_OBJS := gdb.o time.o tracer.o | ||
16 | |||
17 | include arch/um/scripts/Makefile.rules | ||
18 | |||
19 | UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS)) | ||
20 | UNMAP_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 | |||
23 | static 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 | |||
31 | void 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 | |||
68 | void 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 | |||
19 | void 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 | |||
24 | extern int debugger_pid; | ||
25 | extern int debugger_fd; | ||
26 | extern int debugger_parent; | ||
27 | |||
28 | int detach(int pid, int sig) | ||
29 | { | ||
30 | return(ptrace(PTRACE_DETACH, pid, 0, sig)); | ||
31 | } | ||
32 | |||
33 | int 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 | |||
42 | int cont(int pid) | ||
43 | { | ||
44 | return(ptrace(PTRACE_CONT, pid, 0, 0)); | ||
45 | } | ||
46 | |||
47 | #ifdef UML_CONFIG_PT_PROXY | ||
48 | |||
49 | int debugger_signal(int status, pid_t pid) | ||
50 | { | ||
51 | return(debugger_proxy(status, pid)); | ||
52 | } | ||
53 | |||
54 | void child_signal(pid_t pid, int status) | ||
55 | { | ||
56 | child_proxy(pid, status); | ||
57 | } | ||
58 | |||
59 | static void gdb_announce(char *dev_name, int dev) | ||
60 | { | ||
61 | printf("gdb assigned device '%s'\n", dev_name); | ||
62 | } | ||
63 | |||
64 | static 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 */ | ||
73 | static void *xterm_data; | ||
74 | static int xterm_fd; | ||
75 | |||
76 | extern void *xterm_init(char *, int, struct chan_opts *); | ||
77 | extern int xterm_open(int, int, int, void *, char **); | ||
78 | extern void xterm_close(int, void *); | ||
79 | |||
80 | int 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 | |||
90 | static 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 | |||
105 | static void exit_debugger(void) | ||
106 | { | ||
107 | initial_thread_cb(exit_debugger_cb, NULL); | ||
108 | } | ||
109 | |||
110 | __uml_exitcall(exit_debugger); | ||
111 | |||
112 | struct gdb_data { | ||
113 | char *str; | ||
114 | int err; | ||
115 | }; | ||
116 | |||
117 | static 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 | |||
141 | int 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 | |||
151 | void remove_gdb_cb(void *unused) | ||
152 | { | ||
153 | exit_debugger_cb(NULL); | ||
154 | } | ||
155 | |||
156 | int gdb_remove(char *unused) | ||
157 | { | ||
158 | initial_thread_cb(remove_gdb_cb, NULL); | ||
159 | return(0); | ||
160 | } | ||
161 | |||
162 | void 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 | |||
172 | int 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 | |||
186 | int 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 */ | ||
201 | static 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 | |||
212 | static 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 | |||
227 | int debugger_signal(int status, pid_t pid){ return(0); } | ||
228 | void child_signal(pid_t pid, int status){ } | ||
229 | int 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 | |||
236 | void signal_usr1(int sig) | ||
237 | { | ||
238 | printf("debug requested when CONFIG_PT_PROXY is off\n"); | ||
239 | } | ||
240 | |||
241 | int 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 | |||
248 | int config_gdb(char *str) | ||
249 | { | ||
250 | return(-1); | ||
251 | } | ||
252 | |||
253 | int remove_gdb(void) | ||
254 | { | ||
255 | return(-1); | ||
256 | } | ||
257 | |||
258 | int init_parent_proxy(int pid) | ||
259 | { | ||
260 | return(-1); | ||
261 | } | ||
262 | |||
263 | void 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 | |||
12 | extern int gdb_config(char *str); | ||
13 | extern int gdb_remove(char *unused); | ||
14 | |||
15 | static struct mc_device gdb_mc = { | ||
16 | .name = "gdb", | ||
17 | .config = gdb_config, | ||
18 | .remove = gdb_remove, | ||
19 | }; | ||
20 | |||
21 | int 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 | |||
10 | extern int debugger_proxy(int status, pid_t pid); | ||
11 | extern void child_proxy(pid_t pid, int status); | ||
12 | extern void init_proxy (pid_t pid, int waiting, int status); | ||
13 | extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); | ||
14 | extern void fake_child_exit(void); | ||
15 | extern int gdb_config(char *str); | ||
16 | extern 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 | |||
9 | struct 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 | |||
11 | enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; | ||
12 | |||
13 | extern int tracing_pid; | ||
14 | |||
15 | extern int tracer(int (*init_proc)(void *), void *sp); | ||
16 | extern void user_time_init_tt(void); | ||
17 | extern void sig_handler_common_tt(int sig, void *sc); | ||
18 | extern void syscall_handler_tt(int sig, union uml_pt_regs *regs); | ||
19 | extern void reboot_tt(void); | ||
20 | extern void halt_tt(void); | ||
21 | extern int is_tracer_winch(int pid, int fd, void *data); | ||
22 | extern 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 | |||
14 | extern void *switch_to_tt(void *prev, void *next); | ||
15 | extern void flush_thread_tt(void); | ||
16 | extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, | ||
17 | unsigned long esp); | ||
18 | extern 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); | ||
21 | extern void release_thread_tt(struct task_struct *task); | ||
22 | extern void exit_thread_tt(void); | ||
23 | extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); | ||
24 | extern void init_idle_tt(void); | ||
25 | extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end); | ||
26 | extern void flush_tlb_kernel_vm_tt(void); | ||
27 | extern void __flush_tlb_one_tt(unsigned long addr); | ||
28 | extern void flush_tlb_range_tt(struct vm_area_struct *vma, | ||
29 | unsigned long start, unsigned long end); | ||
30 | extern void flush_tlb_mm_tt(struct mm_struct *mm); | ||
31 | extern void force_flush_all_tt(void); | ||
32 | extern long execute_syscall_tt(void *r); | ||
33 | extern void before_mem_tt(unsigned long brk_start); | ||
34 | extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, | ||
35 | unsigned long *task_size_out); | ||
36 | extern int start_uml_tt(void); | ||
37 | extern int external_pid_tt(struct task_struct *task); | ||
38 | extern 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 | |||
11 | extern int gdb_pid; | ||
12 | extern int debug; | ||
13 | extern int debug_stop; | ||
14 | extern int debug_trace; | ||
15 | |||
16 | extern int honeypot; | ||
17 | |||
18 | extern int fork_tramp(void *sig_stack); | ||
19 | extern int do_proc_op(void *t, int proc_id); | ||
20 | extern int tracer(int (*init_proc)(void *), void *sp); | ||
21 | extern void attach_process(int pid); | ||
22 | extern void tracer_panic(char *format, ...); | ||
23 | extern void set_init_pid(int pid); | ||
24 | extern int set_user_mode(void *task); | ||
25 | extern void set_tracing(void *t, int tracing); | ||
26 | extern int is_tracing(void *task); | ||
27 | extern void syscall_handler(int sig, union uml_pt_regs *regs); | ||
28 | extern void exit_kernel(int pid, void *task); | ||
29 | extern void do_syscall(void *task, int pid, int local_using_sysemu); | ||
30 | extern void do_sigtrap(void *task); | ||
31 | extern int is_valid_pid(int pid); | ||
32 | extern void remap_data(void *segment_start, void *segment_end, int w); | ||
33 | extern 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 | |||
19 | extern unsigned long end_vm; | ||
20 | extern 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 | |||
36 | static 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 | |||
42 | extern unsigned long get_fault_addr(void); | ||
43 | |||
44 | extern int __do_copy_from_user(void *to, const void *from, int n, | ||
45 | void **fault_addr, void **fault_catcher); | ||
46 | extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, | ||
47 | void **fault_addr, void **fault_catcher); | ||
48 | extern int __do_clear_user(void *mem, size_t len, void **fault_addr, | ||
49 | void **fault_catcher); | ||
50 | extern int __do_strnlen_user(const char *str, unsigned long n, | ||
51 | void **fault_addr, void **fault_catcher); | ||
52 | |||
53 | extern int copy_from_user_tt(void *to, const void *from, int n); | ||
54 | extern int copy_to_user_tt(void *to, const void *from, int n); | ||
55 | extern int strncpy_from_user_tt(char *dst, const char *src, int count); | ||
56 | extern int __clear_user_tt(void *mem, int len); | ||
57 | extern int clear_user_tt(void *mem, int len); | ||
58 | extern 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 | |||
10 | EXPORT_SYMBOL(__do_copy_from_user); | ||
11 | EXPORT_SYMBOL(__do_copy_to_user); | ||
12 | EXPORT_SYMBOL(__do_strncpy_from_user); | ||
13 | EXPORT_SYMBOL(__do_strnlen_user); | ||
14 | EXPORT_SYMBOL(__do_clear_user); | ||
15 | |||
16 | EXPORT_SYMBOL(tracing_pid); | ||
17 | EXPORT_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 | |||
16 | void 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 | |||
33 | unsigned 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 | |||
16 | void 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 | |||
29 | void *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 | |||
100 | void 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 | |||
108 | void 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 | |||
114 | void 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 | |||
125 | void schedule_tail(task_t *prev); | ||
126 | |||
127 | static 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(¤t->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(¤t->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, ¤t->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 | |||
167 | static 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 | |||
200 | void finish_fork_handler(int sig) | ||
201 | { | ||
202 | UPT_SC(¤t->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 | |||
224 | int 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 | |||
235 | int 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(¤t->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 | |||
294 | void reboot_tt(void) | ||
295 | { | ||
296 | current->thread.request.op = OP_REBOOT; | ||
297 | os_usr1_process(os_getpid()); | ||
298 | change_sig(SIGUSR1, 1); | ||
299 | } | ||
300 | |||
301 | void halt_tt(void) | ||
302 | { | ||
303 | current->thread.request.op = OP_HALT; | ||
304 | os_usr1_process(os_getpid()); | ||
305 | change_sig(SIGUSR1, 1); | ||
306 | } | ||
307 | |||
308 | void 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 | |||
322 | void 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 | |||
338 | int 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 | |||
374 | void init_idle_tt(void) | ||
375 | { | ||
376 | default_idle(); | ||
377 | } | ||
378 | |||
379 | extern void start_kernel(void); | ||
380 | |||
381 | static 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 | |||
398 | void set_tracing(void *task, int tracing) | ||
399 | { | ||
400 | ((struct task_struct *) task)->thread.mode.tt.tracing = tracing; | ||
401 | } | ||
402 | |||
403 | int is_tracing(void *t) | ||
404 | { | ||
405 | return (((struct task_struct *) t)->thread.mode.tt.tracing); | ||
406 | } | ||
407 | |||
408 | int 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 | |||
420 | void 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 | |||
431 | int 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 | |||
442 | int external_pid_tt(struct task_struct *task) | ||
443 | { | ||
444 | return(task->thread.mode.tt.extern_pid); | ||
445 | } | ||
446 | |||
447 | int thread_pid_tt(struct task_struct *task) | ||
448 | { | ||
449 | return(task->thread.mode.tt.extern_pid); | ||
450 | } | ||
451 | |||
452 | int 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 | |||
6 | obj-y = proxy.o ptrace.o sysdep.o wait.o | ||
7 | |||
8 | USER_OBJS := $(obj-y) | ||
9 | |||
10 | include 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 | /********************************************************************** | ||
2 | proxy.c | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms and conditions. | ||
6 | |||
7 | Jeff 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 | |||
34 | static 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 | |||
73 | int 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 */ | ||
128 | static debugger_state parent; | ||
129 | static int parent_syscall(debugger_state *debugger, int pid); | ||
130 | |||
131 | int 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 | |||
144 | int 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 | |||
151 | static 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 | |||
170 | int 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 | |||
177 | void 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 */ | ||
185 | static debugger_state debugger; | ||
186 | static debugee_state debugee; | ||
187 | |||
188 | void 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 | |||
207 | int 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 | |||
245 | void 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 | |||
264 | void 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 | |||
275 | void 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 | |||
300 | char gdb_init_string[] = | ||
301 | "att 1 \n\ | ||
302 | b panic \n\ | ||
303 | b stop \n\ | ||
304 | handle SIGWINCH nostop noprint pass \n\ | ||
305 | "; | ||
306 | |||
307 | int 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 | /********************************************************************** | ||
2 | ptproxy.h | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms and conditions. | ||
6 | **********************************************************************/ | ||
7 | |||
8 | #ifndef __PTPROXY_H | ||
9 | #define __PTPROXY_H | ||
10 | |||
11 | #include <sys/types.h> | ||
12 | |||
13 | typedef struct debugger debugger_state; | ||
14 | typedef struct debugee debugee_state; | ||
15 | |||
16 | struct 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 | |||
29 | struct 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 | |||
43 | extern int debugger_syscall(debugger_state *debugger, pid_t pid); | ||
44 | extern int debugger_normal_return (debugger_state *debugger, pid_t unused); | ||
45 | |||
46 | extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t, | ||
47 | int *strace_out); | ||
48 | extern 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 | /********************************************************************** | ||
2 | ptrace.c | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms and conditions. | ||
6 | |||
7 | Jeff 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 | |||
24 | long 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 | /********************************************************************** | ||
2 | sysdep.c | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms 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 | |||
19 | int 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 | |||
30 | void 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 | |||
42 | void syscall_set_result(pid_t pid, long result) | ||
43 | { | ||
44 | ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result); | ||
45 | } | ||
46 | |||
47 | void syscall_continue(pid_t pid) | ||
48 | { | ||
49 | ptrace(PTRACE_SYSCALL, pid, 0, 0); | ||
50 | } | ||
51 | |||
52 | int 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 | /********************************************************************** | ||
2 | sysdep.h | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. | ||
5 | Copyright (C) 2001 Jeff Dike (jdike@karaya.com) | ||
6 | See the file COPYING for licensing terms and conditions. | ||
7 | **********************************************************************/ | ||
8 | |||
9 | extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, | ||
10 | long *arg4, long *arg5); | ||
11 | extern void syscall_cancel (pid_t pid, long result); | ||
12 | extern void syscall_set_result (pid_t pid, long result); | ||
13 | extern void syscall_continue (pid_t pid); | ||
14 | extern 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 | /********************************************************************** | ||
2 | wait.c | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms 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 | |||
21 | int 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 | |||
49 | int parent_wait_return(struct debugger *debugger, pid_t unused) | ||
50 | { | ||
51 | return(debugger_normal_return(debugger, -1)); | ||
52 | } | ||
53 | |||
54 | int 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 | /********************************************************************** | ||
2 | wait.h | ||
3 | |||
4 | Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing | ||
5 | terms and conditions. | ||
6 | **********************************************************************/ | ||
7 | |||
8 | #ifndef __PTPROXY_WAIT_H | ||
9 | #define __PTPROXY_WAIT_H | ||
10 | |||
11 | extern int proxy_wait_return(struct debugger *debugger, pid_t unused); | ||
12 | extern int real_wait_return(struct debugger *debugger); | ||
13 | extern 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 | |||
17 | extern syscall_handler_t *sys_call_table[]; | ||
18 | |||
19 | long 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(®s->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 | |||
20 | void 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 | |||
52 | void do_sigtrap(void *task) | ||
53 | { | ||
54 | UPT_SYSCALL_NR(TASK_REGS(task)) = -1; | ||
55 | } | ||
56 | |||
57 | void 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 | |||
12 | void 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 | |||
20 | static 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 | |||
50 | static 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 | |||
61 | atomic_t vmchange_seq = ATOMIC_INIT(1); | ||
62 | |||
63 | void 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 | |||
69 | static 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 | |||
82 | void 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 | |||
105 | void flush_tlb_kernel_vm_tt(void) | ||
106 | { | ||
107 | flush_tlb_kernel_range(start_vm, end_vm); | ||
108 | } | ||
109 | |||
110 | void __flush_tlb_one_tt(unsigned long addr) | ||
111 | { | ||
112 | flush_tlb_kernel_range(addr, addr + PAGE_SIZE); | ||
113 | } | ||
114 | |||
115 | void 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 | |||
130 | void 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 | |||
145 | void 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 | |||
32 | static int tracer_winch[2]; | ||
33 | |||
34 | int 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 | |||
43 | static 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 | |||
55 | static 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 | |||
67 | void 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 | |||
79 | void 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 | |||
90 | static 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 */ | ||
99 | int debug = 0; | ||
100 | int debug_stop = 1; | ||
101 | int debug_parent = 0; | ||
102 | int honeypot = 0; | ||
103 | |||
104 | static 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 | |||
124 | static 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 */ | ||
161 | int debugger_pid = -1; | ||
162 | int debugger_parent = -1; | ||
163 | int debugger_fd = -1; | ||
164 | int gdb_pid = -1; | ||
165 | |||
166 | struct { | ||
167 | int pid; | ||
168 | int signal; | ||
169 | unsigned long addr; | ||
170 | struct timeval time; | ||
171 | } signal_record[1024][32]; | ||
172 | |||
173 | int signal_index[32]; | ||
174 | int nsignals = 0; | ||
175 | int debug_trace = 0; | ||
176 | extern int io_nsignals, io_count, intr_count; | ||
177 | |||
178 | extern void signal_usr1(int sig); | ||
179 | |||
180 | int tracing_pid = -1; | ||
181 | |||
182 | int 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 | |||
429 | static 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 | |||
458 | static 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 | |||
16 | void 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 | |||
9 | int 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, ¤t->thread.fault_addr, | ||
15 | ¤t->thread.fault_catcher)); | ||
16 | } | ||
17 | |||
18 | int 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, ¤t->thread.fault_addr, | ||
24 | ¤t->thread.fault_catcher)); | ||
25 | } | ||
26 | |||
27 | int 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 | ¤t->thread.fault_addr, | ||
36 | ¤t->thread.fault_catcher); | ||
37 | if(n < 0) return(-EFAULT); | ||
38 | return(n); | ||
39 | } | ||
40 | |||
41 | int __clear_user_tt(void __user *mem, int len) | ||
42 | { | ||
43 | return(__do_clear_user(mem, len, | ||
44 | ¤t->thread.fault_addr, | ||
45 | ¤t->thread.fault_catcher)); | ||
46 | } | ||
47 | |||
48 | int 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, ¤t->thread.fault_addr, | ||
54 | ¤t->thread.fault_catcher)); | ||
55 | } | ||
56 | |||
57 | int strnlen_user_tt(const void __user *str, int len) | ||
58 | { | ||
59 | return(__do_strnlen_user(str, len, | ||
60 | ¤t->thread.fault_addr, | ||
61 | ¤t->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 | |||
14 | int __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 | |||
29 | static void __do_strncpy(void *dst, const void *src, int count) | ||
30 | { | ||
31 | strncpy(dst, src, count); | ||
32 | } | ||
33 | |||
34 | int __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 | |||
49 | static void __do_clear(void *to, const void *from, int n) | ||
50 | { | ||
51 | memset(to, 0, n); | ||
52 | } | ||
53 | |||
54 | int __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 | |||
69 | int __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 | |||
8 | int 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 */ | ||
21 | static char *tty_log_dir = TTY_LOG_DIR; | ||
22 | static 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 | |||
32 | struct 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 | |||
41 | int 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, ¤t_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 | |||
73 | void 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 | |||
92 | static 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 | |||
118 | int 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 | |||
139 | void 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 | |||
174 | extern void register_tty_logger(int (*opener)(void *, void *), | ||
175 | int (*writer)(int, const char *, int, | ||
176 | void *, int), | ||
177 | void (*closer)(int, void *)); | ||
178 | |||
179 | static 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 | |||
187 | static 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 | |||
199 | static 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 | |||
14 | unsigned 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 | |||
37 | void __do_copy(void *to, const void *from, int n) | ||
38 | { | ||
39 | memcpy(to, from, n); | ||
40 | } | ||
41 | |||
42 | |||
43 | int __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 */ | ||
45 | char command_line[COMMAND_LINE_SIZE] = { 0 }; | ||
46 | |||
47 | void 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 | |||
58 | struct cpuinfo_um boot_cpu_data = { | ||
59 | .loops_per_jiffy = 0, | ||
60 | .ipi_pipe = { -1, -1 } | ||
61 | }; | ||
62 | |||
63 | unsigned 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 | |||
69 | static 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 | |||
91 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
92 | { | ||
93 | return *pos < NR_CPUS ? cpu_data + *pos : NULL; | ||
94 | } | ||
95 | |||
96 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
97 | { | ||
98 | ++*pos; | ||
99 | return c_start(m, pos); | ||
100 | } | ||
101 | |||
102 | static void c_stop(struct seq_file *m, void *v) | ||
103 | { | ||
104 | } | ||
105 | |||
106 | struct seq_operations cpuinfo_op = { | ||
107 | .start = c_start, | ||
108 | .next = c_next, | ||
109 | .stop = c_stop, | ||
110 | .show = show_cpuinfo, | ||
111 | }; | ||
112 | |||
113 | pte_t * __bad_pagetable(void) | ||
114 | { | ||
115 | panic("Someone should implement __bad_pagetable"); | ||
116 | return(NULL); | ||
117 | } | ||
118 | |||
119 | /* Set in linux_main */ | ||
120 | unsigned long host_task_size; | ||
121 | unsigned long task_size; | ||
122 | |||
123 | unsigned long uml_start; | ||
124 | |||
125 | /* Set in early boot */ | ||
126 | unsigned long uml_physmem; | ||
127 | unsigned long uml_reserved; | ||
128 | unsigned long start_vm; | ||
129 | unsigned long end_vm; | ||
130 | int 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 | */ | ||
137 | static char *argv1_begin = NULL; | ||
138 | static char *argv1_end = NULL; | ||
139 | #endif | ||
140 | |||
141 | /* Set in early boot */ | ||
142 | static int have_root __initdata = 0; | ||
143 | long physmem_size = 32 * 1024 * 1024; | ||
144 | |||
145 | void 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 | |||
167 | static char *usage_string = | ||
168 | "User Mode Linux v%s\n" | ||
169 | " available at http://user-mode-linux.sourceforge.net/\n\n"; | ||
170 | |||
171 | static 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 | |||
184 | static 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 | ||
200 | static 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 | |||
216 | static int force_tt = 0; | ||
217 | |||
218 | #if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) | ||
219 | #define DEFAULT_TT 0 | ||
220 | |||
221 | static 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 | |||
232 | static 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 | |||
243 | static 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 | |||
264 | int mode_tt = DEFAULT_TT; | ||
265 | |||
266 | static 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 | |||
286 | static 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 | |||
303 | static 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 */ | ||
316 | unsigned long brk_start; | ||
317 | unsigned long end_iomem; | ||
318 | EXPORT_SYMBOL(end_iomem); | ||
319 | |||
320 | #define MIN_VMALLOC (32 * 1024 * 1024) | ||
321 | |||
322 | int 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 | |||
429 | extern int uml_exitcode; | ||
430 | |||
431 | static 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 | |||
442 | static struct notifier_block panic_exit_notifier = { | ||
443 | .notifier_call = panic_exit, | ||
444 | .next = NULL, | ||
445 | .priority = 0 | ||
446 | }; | ||
447 | |||
448 | void __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 | |||
457 | void __init check_bugs(void) | ||
458 | { | ||
459 | arch_check_bugs(); | ||
460 | check_ptrace(); | ||
461 | check_sigio(); | ||
462 | check_devanon(); | ||
463 | } | ||
464 | |||
465 | void 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 */ | ||
26 | static char umid[UMID_LEN] = { 0 }; | ||
27 | |||
28 | /* Changed by set_uml_dir and make_uml_dir, which are run early in boot */ | ||
29 | static char *uml_dir = UML_DIR; | ||
30 | |||
31 | /* Changed by set_umid */ | ||
32 | static int umid_is_random = 1; | ||
33 | static int umid_inited = 0; | ||
34 | |||
35 | static int make_umid(int (*printer)(const char *fmt, ...)); | ||
36 | |||
37 | static 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 | |||
55 | static 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 | |||
67 | int __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 | |||
83 | extern int tracing_pid; | ||
84 | |||
85 | static 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 | |||
109 | static 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 | |||
147 | void 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 | |||
156 | char *get_umid(int only_if_set) | ||
157 | { | ||
158 | if(only_if_set && umid_is_random) return(NULL); | ||
159 | return(umid); | ||
160 | } | ||
161 | |||
162 | int 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 | |||
200 | static 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 | |||
219 | static 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 | |||
257 | static 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 | |||
307 | static 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 | |||
3 | OUTPUT_FORMAT(ELF_FORMAT) | ||
4 | OUTPUT_ARCH(ELF_ARCH) | ||
5 | ENTRY(_start) | ||
6 | jiffies = jiffies_64; | ||
7 | |||
8 | SECTIONS | ||
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 | |||
34 | void stop(void) | ||
35 | { | ||
36 | while(1) sleep(1000000); | ||
37 | } | ||
38 | |||
39 | void 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 | |||
47 | void 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 | |||
63 | int 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 | |||
106 | int 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 | |||
130 | void setup_machinename(char *machine_out) | ||
131 | { | ||
132 | struct utsname host; | ||
133 | |||
134 | uname(&host); | ||
135 | strcpy(machine_out, host.machine); | ||
136 | } | ||
137 | |||
138 | char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1]; | ||
139 | |||
140 | void 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 | |||
149 | int 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 | |||
6 | obj-y = elf_aux.o file.o process.o signal.o time.o tty.o user_syms.o drivers/ \ | ||
7 | sys-$(SUBARCH)/ | ||
8 | |||
9 | USER_OBJS := elf_aux.o file.o process.o signal.o time.o tty.o | ||
10 | |||
11 | CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) | ||
12 | |||
13 | include 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 | |||
6 | ethertap-objs := ethertap_kern.o ethertap_user.o | ||
7 | tuntap-objs := tuntap_kern.o tuntap_user.o | ||
8 | |||
9 | obj-y = | ||
10 | obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o | ||
11 | obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o | ||
12 | |||
13 | include 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 | |||
8 | struct ethertap_data { | ||
9 | char *dev_name; | ||
10 | char *gate_addr; | ||
11 | int data_fd; | ||
12 | int control_fd; | ||
13 | void *dev; | ||
14 | }; | ||
15 | |||
16 | extern 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 | |||
15 | struct ethertap_init { | ||
16 | char *dev_name; | ||
17 | char *gate_addr; | ||
18 | }; | ||
19 | |||
20 | static 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 | |||
40 | static 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 | |||
54 | static 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 | |||
68 | struct net_kern_info ethertap_kern_info = { | ||
69 | .init = etap_init, | ||
70 | .protocol = eth_protocol, | ||
71 | .read = etap_read, | ||
72 | .write = etap_write, | ||
73 | }; | ||
74 | |||
75 | int 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 | |||
93 | static struct transport ethertap_transport = { | ||
94 | .list = LIST_HEAD_INIT(ethertap_transport.list), | ||
95 | .name = "ethertap", | ||
96 | .setup = ethertap_setup, | ||
97 | .user = ðertap_user_info, | ||
98 | .kern = ðertap_kern_info, | ||
99 | .private_size = sizeof(struct ethertap_data), | ||
100 | }; | ||
101 | |||
102 | static int register_ethertap(void) | ||
103 | { | ||
104 | register_transport(ðertap_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 | |||
27 | void etap_user_init(void *data, void *dev) | ||
28 | { | ||
29 | struct ethertap_data *pri = data; | ||
30 | |||
31 | pri->dev = dev; | ||
32 | } | ||
33 | |||
34 | struct addr_change { | ||
35 | enum { ADD_ADDR, DEL_ADDR } what; | ||
36 | unsigned char addr[4]; | ||
37 | unsigned char netmask[4]; | ||
38 | }; | ||
39 | |||
40 | static 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 | |||
63 | static 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 | |||
69 | static 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 | |||
75 | struct etap_pre_exec_data { | ||
76 | int control_remote; | ||
77 | int control_me; | ||
78 | int data_me; | ||
79 | }; | ||
80 | |||
81 | static 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 | |||
90 | static 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 | |||
138 | static 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 | |||
183 | static 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 | |||
196 | static int etap_set_mtu(int mtu, void *data) | ||
197 | { | ||
198 | return(mtu); | ||
199 | } | ||
200 | |||
201 | static 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 | |||
211 | static 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 | |||
220 | struct 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 | |||
11 | struct tuntap_data { | ||
12 | char *dev_name; | ||
13 | int fixed_config; | ||
14 | char *gate_addr; | ||
15 | int fd; | ||
16 | void *dev; | ||
17 | }; | ||
18 | |||
19 | extern 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 | |||
16 | struct tuntap_init { | ||
17 | char *dev_name; | ||
18 | char *gate_addr; | ||
19 | }; | ||
20 | |||
21 | static 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 | |||
41 | static 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 | |||
50 | static 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 | |||
56 | struct net_kern_info tuntap_kern_info = { | ||
57 | .init = tuntap_init, | ||
58 | .protocol = eth_protocol, | ||
59 | .read = tuntap_read, | ||
60 | .write = tuntap_write, | ||
61 | }; | ||
62 | |||
63 | int 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 | |||
77 | static 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 | |||
87 | static 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 | |||
28 | void tuntap_user_init(void *data, void *dev) | ||
29 | { | ||
30 | struct tuntap_data *pri = data; | ||
31 | |||
32 | pri->dev = dev; | ||
33 | } | ||
34 | |||
35 | static 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 | |||
45 | static 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 | |||
54 | struct tuntap_pre_exec_data { | ||
55 | int stdout; | ||
56 | int close_me; | ||
57 | }; | ||
58 | |||
59 | static 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 | |||
67 | static 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 | |||
128 | static 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 | |||
190 | static 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 | |||
200 | static int tuntap_set_mtu(int mtu, void *data) | ||
201 | { | ||
202 | return(mtu); | ||
203 | } | ||
204 | |||
205 | struct 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 | ||
16 | typedef Elf32_auxv_t elf_auxv_t; | ||
17 | #else | ||
18 | typedef Elf64_auxv_t elf_auxv_t; | ||
19 | #endif | ||
20 | |||
21 | char * elf_aux_platform; | ||
22 | long elf_aux_hwcap; | ||
23 | |||
24 | unsigned long vsyscall_ehdr; | ||
25 | unsigned long vsyscall_end; | ||
26 | |||
27 | unsigned 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 | |||
22 | static 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 | |||
40 | int 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 | |||
57 | int 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 | |||
74 | int 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 | |||
88 | void 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) */ | ||
96 | int 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 | |||
107 | int 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 | |||
120 | int 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 */ | ||
136 | int os_get_ifname(int fd, char* namebuf) | ||
137 | { | ||
138 | if(ioctl(fd, SIOCGIFNAME, namebuf) < 0) | ||
139 | return(-errno); | ||
140 | |||
141 | return(0); | ||
142 | } | ||
143 | |||
144 | int 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 | |||
165 | int 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 */ | ||
178 | int 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 | |||
203 | int 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 | |||
217 | int 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 | |||
235 | int 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 | |||
256 | int 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 | |||
282 | int 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 | |||
301 | void os_close_file(int fd) | ||
302 | { | ||
303 | close(fd); | ||
304 | } | ||
305 | |||
306 | int 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 | |||
316 | static 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 | |||
333 | static 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 | |||
354 | int 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 | |||
360 | int 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 | |||
366 | int 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 | |||
400 | int 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 | |||
415 | int 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 | |||
430 | int 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 | |||
446 | int 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 | |||
474 | int 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 | |||
500 | int 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 | |||
510 | int 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 | |||
527 | int 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 | |||
549 | int 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 | |||
566 | int 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 | |||
606 | int 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 | |||
640 | void os_flush_stdout(void) | ||
641 | { | ||
642 | fflush(stdout); | ||
643 | } | ||
644 | |||
645 | int 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 | |||
24 | unsigned 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 | |||
54 | int 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 | |||
85 | void os_stop_process(int pid) | ||
86 | { | ||
87 | kill(pid, SIGSTOP); | ||
88 | } | ||
89 | |||
90 | void 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 | |||
103 | void 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 | |||
112 | void 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.*/ | ||
119 | inline _syscall0(pid_t, getpid) | ||
120 | |||
121 | int os_getpid(void) | ||
122 | { | ||
123 | return(getpid()); | ||
124 | } | ||
125 | |||
126 | int 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 | |||
142 | int 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 | |||
152 | int 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 | |||
11 | void 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 | |||
20 | extern int timer_irq_inited; | ||
21 | |||
22 | void 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 | |||
6 | obj-$(CONFIG_MODE_SKAS) = registers.o | ||
7 | |||
8 | USER_OBJS := $(obj-y) | ||
9 | |||
10 | include 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 | |||
17 | static unsigned long exec_regs[HOST_FRAME_SIZE]; | ||
18 | static unsigned long exec_fp_regs[HOST_FP_SIZE]; | ||
19 | static unsigned long exec_fpx_regs[HOST_XFP_SIZE]; | ||
20 | static int have_fpx_regs = 1; | ||
21 | |||
22 | void 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 | */ | ||
33 | int 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 | |||
40 | int 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 | |||
47 | static 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 | |||
59 | void 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 | |||
79 | void 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 | |||
99 | void 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 | |||
6 | obj-$(CONFIG_MODE_SKAS) = registers.o | ||
7 | |||
8 | USER_OBJS := $(obj-y) | ||
9 | |||
10 | include 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 | |||
16 | static unsigned long exec_regs[HOST_FRAME_SIZE]; | ||
17 | static unsigned long exec_fp_regs[HOST_FP_SIZE]; | ||
18 | |||
19 | void 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 | |||
25 | static 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 | |||
37 | void 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 | |||
47 | void 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 | |||
57 | void 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 | |||
4 | unsigned 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 | |||
12 | struct grantpt_info { | ||
13 | int fd; | ||
14 | int res; | ||
15 | int err; | ||
16 | }; | ||
17 | |||
18 | static 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 | |||
26 | int 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 | |||
15 | extern size_t strlen(const char *); | ||
16 | extern void *memcpy(void *, const void *, size_t); | ||
17 | extern void *memmove(void *, const void *, size_t); | ||
18 | extern void *memset(void *, int, size_t); | ||
19 | extern int printf(const char *, ...); | ||
20 | |||
21 | EXPORT_SYMBOL(strlen); | ||
22 | EXPORT_SYMBOL(memcpy); | ||
23 | EXPORT_SYMBOL(memmove); | ||
24 | EXPORT_SYMBOL(memset); | ||
25 | EXPORT_SYMBOL(printf); | ||
26 | |||
27 | EXPORT_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 | ||
38 | EXPORT_SYMBOL(vsyscall_ehdr); | ||
39 | EXPORT_SYMBOL(vsyscall_end); | ||
40 | #endif | ||
41 | |||
42 | EXPORT_SYMBOL_PROTO(__errno_location); | ||
43 | |||
44 | EXPORT_SYMBOL_PROTO(access); | ||
45 | EXPORT_SYMBOL_PROTO(open); | ||
46 | EXPORT_SYMBOL_PROTO(open64); | ||
47 | EXPORT_SYMBOL_PROTO(close); | ||
48 | EXPORT_SYMBOL_PROTO(read); | ||
49 | EXPORT_SYMBOL_PROTO(write); | ||
50 | EXPORT_SYMBOL_PROTO(dup2); | ||
51 | EXPORT_SYMBOL_PROTO(__xstat); | ||
52 | EXPORT_SYMBOL_PROTO(__lxstat); | ||
53 | EXPORT_SYMBOL_PROTO(__lxstat64); | ||
54 | EXPORT_SYMBOL_PROTO(lseek); | ||
55 | EXPORT_SYMBOL_PROTO(lseek64); | ||
56 | EXPORT_SYMBOL_PROTO(chown); | ||
57 | EXPORT_SYMBOL_PROTO(truncate); | ||
58 | EXPORT_SYMBOL_PROTO(utime); | ||
59 | EXPORT_SYMBOL_PROTO(chmod); | ||
60 | EXPORT_SYMBOL_PROTO(rename); | ||
61 | EXPORT_SYMBOL_PROTO(__xmknod); | ||
62 | |||
63 | EXPORT_SYMBOL_PROTO(symlink); | ||
64 | EXPORT_SYMBOL_PROTO(link); | ||
65 | EXPORT_SYMBOL_PROTO(unlink); | ||
66 | EXPORT_SYMBOL_PROTO(readlink); | ||
67 | |||
68 | EXPORT_SYMBOL_PROTO(mkdir); | ||
69 | EXPORT_SYMBOL_PROTO(rmdir); | ||
70 | EXPORT_SYMBOL_PROTO(opendir); | ||
71 | EXPORT_SYMBOL_PROTO(readdir); | ||
72 | EXPORT_SYMBOL_PROTO(closedir); | ||
73 | EXPORT_SYMBOL_PROTO(seekdir); | ||
74 | EXPORT_SYMBOL_PROTO(telldir); | ||
75 | |||
76 | EXPORT_SYMBOL_PROTO(ioctl); | ||
77 | |||
78 | EXPORT_SYMBOL_PROTO(pread64); | ||
79 | EXPORT_SYMBOL_PROTO(pwrite64); | ||
80 | |||
81 | EXPORT_SYMBOL_PROTO(statfs); | ||
82 | EXPORT_SYMBOL_PROTO(statfs64); | ||
83 | |||
84 | EXPORT_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 @@ | |||
1 | hostprogs-y := mk_user_constants | ||
2 | always := $(hostprogs-y) | ||
3 | |||
4 | mk_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 | */ | ||
6 | typedef __u64 u64; | ||
7 | typedef __u32 u32; | ||
8 | #include <asm/user.h> | ||
9 | |||
10 | int 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 | |||
5 | USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs)) | ||
6 | USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) | ||
7 | |||
8 | USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) | ||
9 | |||
10 | $(USER_OBJS): c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(notdir $@)) | ||
11 | |||
12 | quiet_cmd_make_link = SYMLINK $@ | ||
13 | cmd_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 @@ | |||
1 | obj-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 | |||
4 | obj-$(CONFIG_HIGHMEM) += highmem.o | ||
5 | obj-$(CONFIG_MODULES) += module.o | ||
6 | |||
7 | USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o | ||
8 | |||
9 | include arch/um/scripts/Makefile.rules | ||
10 | |||
11 | SYMLINKS = 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. | ||
15 | clean-files := $(SYMLINKS) | ||
16 | |||
17 | targets += $(SYMLINKS) | ||
18 | |||
19 | SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$f) | ||
20 | |||
21 | bitops.c-dir = lib | ||
22 | semaphore.c-dir = kernel | ||
23 | highmem.c-dir = mm | ||
24 | module.c-dir = kernel | ||
25 | |||
26 | $(SYMLINKS): FORCE | ||
27 | $(call if_changed,make_link) | ||
28 | |||
29 | subdir- := 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 */ | ||
20 | int host_has_cmov = 1; | ||
21 | int host_has_xmm = 0; | ||
22 | |||
23 | static 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 | |||
51 | static 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 | |||
81 | int 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 | |||
104 | static 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 | */ | ||
147 | static 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 | |||
162 | void arch_init_thread(void) | ||
163 | { | ||
164 | #if 0 | ||
165 | disable_lcall(); | ||
166 | #endif | ||
167 | } | ||
168 | |||
169 | void 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 | |||
184 | int 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 | /* | ||
36 | unsigned 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 | */ | ||
52 | arch_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 | ||
64 | 1: movw (%esi), %bx | ||
65 | addl $2, %esi | ||
66 | addw %bx, %ax | ||
67 | adcl $0, %eax | ||
68 | 2: | ||
69 | movl %ecx, %edx | ||
70 | shrl $5, %ecx | ||
71 | jz 2f | ||
72 | testl %esi, %esi | ||
73 | 1: 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 | ||
93 | 2: movl %edx, %ecx | ||
94 | andl $0x1c, %edx | ||
95 | je 4f | ||
96 | shrl $2, %edx # This clears CF | ||
97 | 3: adcl (%esi), %eax | ||
98 | lea 4(%esi), %esi | ||
99 | dec %edx | ||
100 | jne 3b | ||
101 | adcl $0, %eax | ||
102 | 4: 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 | ||
110 | 5: movb (%esi),%cl | ||
111 | 6: addl %ecx,%eax | ||
112 | adcl $0, %eax | ||
113 | 7: | ||
114 | popl %ebx | ||
115 | popl %esi | ||
116 | ret | ||
117 | |||
118 | #else | ||
119 | |||
120 | /* Version for PentiumII/PPro */ | ||
121 | |||
122 | arch_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 | ||
131 | 10: | ||
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 | ||
144 | 20: addw (%esi), %ax | ||
145 | lea 2(%esi), %esi | ||
146 | adcl $0, %eax | ||
147 | jmp 10b | ||
148 | |||
149 | 30: 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 | ||
156 | 32: | ||
157 | addw (%esi), %ax # csumming 2 bytes, 2-aligned | ||
158 | adcl $0, %eax | ||
159 | jmp 80f | ||
160 | |||
161 | 40: | ||
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 | ||
194 | 45: | ||
195 | lea 128(%esi), %esi | ||
196 | adcl $0, %eax | ||
197 | dec %ecx | ||
198 | jge 40b | ||
199 | movl %edx, %ecx | ||
200 | 50: 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 | ||
211 | 80: | ||
212 | popl %ebx | ||
213 | popl %esi | ||
214 | ret | ||
215 | |||
216 | #endif | ||
217 | |||
218 | /* | ||
219 | unsigned 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 | |||
254 | csum_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 | ||
270 | SRC(1: movw (%esi), %bx ) | ||
271 | addl $2, %esi | ||
272 | DST( movw %bx, (%edi) ) | ||
273 | addl $2, %edi | ||
274 | addw %bx, %ax | ||
275 | adcl $0, %eax | ||
276 | 2: | ||
277 | movl %ecx, FP(%esp) | ||
278 | shrl $5, %ecx | ||
279 | jz 2f | ||
280 | testl %esi, %esi | ||
281 | SRC(1: movl (%esi), %ebx ) | ||
282 | SRC( movl 4(%esi), %edx ) | ||
283 | adcl %ebx, %eax | ||
284 | DST( movl %ebx, (%edi) ) | ||
285 | adcl %edx, %eax | ||
286 | DST( movl %edx, 4(%edi) ) | ||
287 | |||
288 | SRC( movl 8(%esi), %ebx ) | ||
289 | SRC( movl 12(%esi), %edx ) | ||
290 | adcl %ebx, %eax | ||
291 | DST( movl %ebx, 8(%edi) ) | ||
292 | adcl %edx, %eax | ||
293 | DST( movl %edx, 12(%edi) ) | ||
294 | |||
295 | SRC( movl 16(%esi), %ebx ) | ||
296 | SRC( movl 20(%esi), %edx ) | ||
297 | adcl %ebx, %eax | ||
298 | DST( movl %ebx, 16(%edi) ) | ||
299 | adcl %edx, %eax | ||
300 | DST( movl %edx, 20(%edi) ) | ||
301 | |||
302 | SRC( movl 24(%esi), %ebx ) | ||
303 | SRC( movl 28(%esi), %edx ) | ||
304 | adcl %ebx, %eax | ||
305 | DST( movl %ebx, 24(%edi) ) | ||
306 | adcl %edx, %eax | ||
307 | DST( 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 | ||
314 | 2: movl FP(%esp), %edx | ||
315 | movl %edx, %ecx | ||
316 | andl $0x1c, %edx | ||
317 | je 4f | ||
318 | shrl $2, %edx # This clears CF | ||
319 | SRC(3: movl (%esi), %ebx ) | ||
320 | adcl %ebx, %eax | ||
321 | DST( movl %ebx, (%edi) ) | ||
322 | lea 4(%esi), %esi | ||
323 | lea 4(%edi), %edi | ||
324 | dec %edx | ||
325 | jne 3b | ||
326 | adcl $0, %eax | ||
327 | 4: andl $3, %ecx | ||
328 | jz 7f | ||
329 | cmpl $2, %ecx | ||
330 | jb 5f | ||
331 | SRC( movw (%esi), %cx ) | ||
332 | leal 2(%esi), %esi | ||
333 | DST( movw %cx, (%edi) ) | ||
334 | leal 2(%edi), %edi | ||
335 | je 6f | ||
336 | shll $16,%ecx | ||
337 | SRC(5: movb (%esi), %cl ) | ||
338 | DST( movb %cl, (%edi) ) | ||
339 | 6: addl %ecx, %eax | ||
340 | adcl $0, %eax | ||
341 | 7: | ||
342 | 5000: | ||
343 | |||
344 | # Exception handler: | ||
345 | .section .fixup, "ax" | ||
346 | |||
347 | 6001: | ||
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 | |||
360 | 6002: | ||
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 | |||
389 | csum_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 | ||
410 | 1: 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) | ||
417 | 3: adcl $0,%eax | ||
418 | addl $64, %edx | ||
419 | dec %ecx | ||
420 | jge 1b | ||
421 | 4: movl ARGBASE+12(%esp),%edx #len | ||
422 | andl $3, %edx | ||
423 | jz 7f | ||
424 | cmpl $2, %edx | ||
425 | jb 5f | ||
426 | SRC( movw (%esi), %dx ) | ||
427 | leal 2(%esi), %esi | ||
428 | DST( movw %dx, (%edi) ) | ||
429 | leal 2(%edi), %edi | ||
430 | je 6f | ||
431 | shll $16,%edx | ||
432 | 5: | ||
433 | SRC( movb (%esi), %dl ) | ||
434 | DST( movb %dl, (%edi) ) | ||
435 | 6: addl %edx, %eax | ||
436 | adcl $0, %eax | ||
437 | 7: | ||
438 | .section .fixup, "ax" | ||
439 | 6001: 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 | ||
447 | 6002: 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 @@ | |||
1 | void __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. */ | ||
11 | struct exception_table_entry | ||
12 | { | ||
13 | unsigned long insn; | ||
14 | unsigned long fixup; | ||
15 | }; | ||
16 | |||
17 | const struct exception_table_entry *search_exception_tables(unsigned long add); | ||
18 | |||
19 | /* Compare this to arch/i386/mm/extable.c:fixup_exception() */ | ||
20 | int 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 | |||
10 | EXPORT_SYMBOL(__down_failed); | ||
11 | EXPORT_SYMBOL(__down_failed_interruptible); | ||
12 | EXPORT_SYMBOL(__down_failed_trylock); | ||
13 | EXPORT_SYMBOL(__up_wakeup); | ||
14 | |||
15 | /* Networking helper routines. */ | ||
16 | EXPORT_SYMBOL(csum_partial_copy_from); | ||
17 | EXPORT_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 | ||
14 | extern int modify_ldt(int func, void *ptr, unsigned long bytecount); | ||
15 | |||
16 | /* XXX this needs copy_to_user and copy_from_user */ | ||
17 | |||
18 | int 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 | ||
28 | extern int userspace_pid; | ||
29 | |||
30 | #include "skas_ptrace.h" | ||
31 | |||
32 | int 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 | |||
81 | int 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 | |||
17 | void arch_switch(void) | ||
18 | { | ||
19 | update_debugregs(current->thread.arch.debugregs_seq); | ||
20 | } | ||
21 | |||
22 | int 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 | |||
41 | int 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 | |||
76 | unsigned 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 | |||
96 | struct 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 | |||
116 | static 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 | |||
130 | static 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 | ||
180 | static 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 | |||
210 | static 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 | ||
217 | static 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 | |||
248 | static 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 | |||
254 | int 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 | |||
264 | int 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 | ||
275 | int 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 | |||
288 | int 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 | ||
294 | int 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 | |||
307 | int 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 | ||
313 | int 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 | ||
330 | static 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 | |||
348 | static 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 | |||
354 | int 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 | |||
18 | int 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 | |||
25 | int 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 | |||
32 | int 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 | |||
39 | int 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 | |||
46 | static 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 | |||
63 | static 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 */ | ||
77 | static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; | ||
78 | static int debugregs_seq = 0; | ||
79 | |||
80 | void arch_enter_kernel(void *task, int pid) | ||
81 | { | ||
82 | read_debugregs(pid, TASK_DEBUGREGS(task)); | ||
83 | write_debugregs(pid, kernel_debugregs); | ||
84 | } | ||
85 | |||
86 | void arch_leave_kernel(void *task, int pid) | ||
87 | { | ||
88 | read_debugregs(pid, kernel_debugregs); | ||
89 | write_debugregs(pid, TASK_DEBUGREGS(task)); | ||
90 | } | ||
91 | |||
92 | void 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 | |||
105 | static void update_debugregs_cb(void *arg) | ||
106 | { | ||
107 | int pid = *((int *) arg); | ||
108 | |||
109 | write_debugregs(pid, kernel_debugregs); | ||
110 | } | ||
111 | |||
112 | void 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 | |||
13 | void 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 | |||
22 | unsigned long *sc_sigmask(void *sc_ptr) | ||
23 | { | ||
24 | struct sigcontext *sc = sc_ptr; | ||
25 | return &sc->oldmask; | ||
26 | } | ||
27 | |||
28 | int 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 | |||
22 | static 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 | |||
64 | int 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 | */ | ||
120 | int 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 | |||
138 | int 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 | |||
155 | static 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 | |||
165 | static 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 | |||
175 | static 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, ¤t->thread.regs); | ||
184 | err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); | ||
185 | return(err); | ||
186 | } | ||
187 | |||
188 | struct 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 | |||
198 | struct 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 | |||
210 | int 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 | |||
260 | int 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 | |||
310 | long sys_sigreturn(struct pt_regs regs) | ||
311 | { | ||
312 | unsigned long sp = PT_REGS_SP(¤t->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(¤t->sighand->siglock); | ||
327 | current->blocked = set; | ||
328 | recalc_sigpending(); | ||
329 | spin_unlock_irq(¤t->sighand->siglock); | ||
330 | |||
331 | if(copy_sc_from_user(¤t->thread.regs, sc)) | ||
332 | goto segfault; | ||
333 | |||
334 | /* Avoid ERESTART handling */ | ||
335 | PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; | ||
336 | return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); | ||
337 | |||
338 | segfault: | ||
339 | force_sig(SIGSEGV, current); | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | long sys_rt_sigreturn(struct pt_regs regs) | ||
344 | { | ||
345 | unsigned long __user sp = PT_REGS_SP(¤t->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(¤t->sighand->siglock); | ||
357 | current->blocked = set; | ||
358 | recalc_sigpending(); | ||
359 | spin_unlock_irq(¤t->sighand->siglock); | ||
360 | |||
361 | if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) | ||
362 | goto segfault; | ||
363 | |||
364 | /* Avoid ERESTART handling */ | ||
365 | PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; | ||
366 | return(PT_REGS_SYSCALL_RET(¤t->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 | |||
20 | struct 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 | |||
29 | extern int old_mmap(unsigned long addr, unsigned long len, | ||
30 | unsigned long prot, unsigned long flags, | ||
31 | unsigned long fd, unsigned long offset); | ||
32 | |||
33 | long 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 | |||
46 | struct 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 | |||
54 | long 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 | */ | ||
67 | long 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 | */ | ||
90 | long 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 | |||
170 | long 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 | |||
12 | void 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 *) ®s); | ||
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 | |||
2 | hostprogs-y := mk_sc mk_thread | ||
3 | always := $(hostprogs-y) | ||
4 | |||
5 | mk_thread-objs := mk_thread_kern.o mk_thread_user.o | ||
6 | |||
7 | HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS) | ||
8 | HOSTCFLAGS_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 | |||
19 | int 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 | |||
5 | extern void print_head(void); | ||
6 | extern void print_constant_ptr(char *name, int value); | ||
7 | extern void print_constant(char *name, char *type, int value); | ||
8 | extern void print_tail(void); | ||
9 | |||
10 | #define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field) | ||
11 | |||
12 | int 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 | |||
3 | void 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 | |||
14 | void print_constant_ptr(char *name, int value) | ||
15 | { | ||
16 | printf("#define %s(task) ((unsigned long *) " | ||
17 | "&(((char *) (task))[%d]))\n", name, value); | ||
18 | } | ||
19 | |||
20 | void 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 | |||
26 | void 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 @@ | |||
1 | OBJ = built-in.o | ||
2 | |||
3 | OBJS = | ||
4 | |||
5 | all: $(OBJ) | ||
6 | |||
7 | $(OBJ): $(OBJS) | ||
8 | rm -f $@ | ||
9 | $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ | ||
10 | |||
11 | clean-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 @@ | |||
1 | OBJ = built-in.o | ||
2 | |||
3 | .S.o: | ||
4 | $(CC) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o | ||
5 | |||
6 | OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \ | ||
7 | ptrace_user.o sysrq.o | ||
8 | |||
9 | EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(TOPDIR)/arch/ppc/kernel | ||
10 | |||
11 | all: $(OBJ) | ||
12 | |||
13 | $(OBJ): $(OBJS) | ||
14 | rm -f $@ | ||
15 | $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ | ||
16 | |||
17 | ptrace_user.o: ptrace_user.c | ||
18 | $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< | ||
19 | |||
20 | sigcontext.o: sigcontext.c | ||
21 | $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< | ||
22 | |||
23 | semaphore.c: | ||
24 | rm -f $@ | ||
25 | ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ | ||
26 | |||
27 | checksum.S: | ||
28 | rm -f $@ | ||
29 | ln -s $(TOPDIR)/arch/ppc/lib/$@ $@ | ||
30 | |||
31 | mk_defs.c: | ||
32 | rm -f $@ | ||
33 | ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ | ||
34 | |||
35 | ppc_defs.head: | ||
36 | rm -f $@ | ||
37 | ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ | ||
38 | |||
39 | ppc_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 | |||
57 | checksum.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 | |||
63 | misc.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 | |||
69 | clean-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 | ||
48 | 1: stw r4, 0(r3) | ||
49 | stw r4, 4(r3) | ||
50 | stw r4, 8(r3) | ||
51 | stw r4, 12(r3) | ||
52 | #else | ||
53 | 1: 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 | ||
85 | 11: 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 | ||
96 | 1: | ||
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 | */ | ||
12 | void 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 | |||
4 | int 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 | |||
11 | unsigned 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 | |||
5 | int 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 | |||
18 | int 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 | |||
11 | void 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(®s->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 | |||
7 | lib-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 | |||
11 | USER_OBJS := ptrace_user.o sigcontext.o | ||
12 | |||
13 | include arch/um/scripts/Makefile.rules | ||
14 | |||
15 | SYMLINKS = 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. | ||
20 | clean-files := $(SYMLINKS) | ||
21 | |||
22 | targets += $(SYMLINKS) | ||
23 | |||
24 | SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$f) | ||
25 | |||
26 | bitops.c-dir = lib | ||
27 | csum-copy.S-dir = lib | ||
28 | csum-partial.c-dir = lib | ||
29 | csum-wrappers.c-dir = lib | ||
30 | memcpy.S-dir = lib | ||
31 | semaphore.c-dir = kernel | ||
32 | thunk.S-dir = lib | ||
33 | |||
34 | $(SYMLINKS): FORCE | ||
35 | $(call if_changed,make_link) | ||
36 | |||
37 | CFLAGS_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 | |||
14 | void arch_init_thread(void) | ||
15 | { | ||
16 | } | ||
17 | |||
18 | void arch_check_bugs(void) | ||
19 | { | ||
20 | } | ||
21 | |||
22 | int 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 */ | ||
30 | int host_has_cmov = 1; | ||
31 | int host_has_xmm = 0; | ||
32 | |||
33 | static 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 | |||
61 | static 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 | |||
91 | int 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 | |||
10 | void __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 | |||
9 | int 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 | |||
11 | unsigned long vm_stack_flags = __VM_STACK_FLAGS; | ||
12 | unsigned long vm_stack_flags32 = __VM_STACK_FLAGS; | ||
13 | unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS; | ||
14 | unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS; | ||
15 | unsigned 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 */ | ||
14 | unsigned long not_ss; | ||
15 | unsigned long not_ds; | ||
16 | unsigned 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 | |||
26 | int 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 | |||
65 | unsigned 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 | |||
87 | void arch_switch(void) | ||
88 | { | ||
89 | /* XXX | ||
90 | printk("arch_switch\n"); | ||
91 | */ | ||
92 | } | ||
93 | |||
94 | int is_syscall(unsigned long addr) | ||
95 | { | ||
96 | panic("is_syscall"); | ||
97 | } | ||
98 | |||
99 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) | ||
100 | { | ||
101 | panic("dump_fpu"); | ||
102 | return(1); | ||
103 | } | ||
104 | |||
105 | int get_fpregs(unsigned long buf, struct task_struct *child) | ||
106 | { | ||
107 | panic("get_fpregs"); | ||
108 | return(0); | ||
109 | } | ||
110 | |||
111 | int set_fpregs(unsigned long buf, struct task_struct *child) | ||
112 | { | ||
113 | panic("set_fpregs"); | ||
114 | return(0); | ||
115 | } | ||
116 | |||
117 | int get_fpxregs(unsigned long buf, struct task_struct *tsk) | ||
118 | { | ||
119 | panic("get_fpxregs"); | ||
120 | return(0); | ||
121 | } | ||
122 | |||
123 | int 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 | |||
13 | int 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 | |||
20 | int 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 | |||
27 | void 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 | |||
36 | void arch_enter_kernel(void *task, int pid) | ||
37 | { | ||
38 | } | ||
39 | |||
40 | void 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 | |||
12 | void 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 | |||
24 | unsigned 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 | |||
23 | static 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 | |||
57 | int 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 | ||
102 | int 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 | |||
117 | int 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 | |||
131 | static 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 | |||
141 | static 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 | |||
149 | struct 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 | |||
158 | int 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 | |||
238 | long sys_rt_sigreturn(struct pt_regs *regs) | ||
239 | { | ||
240 | unsigned long sp = PT_REGS_SP(¤t->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(¤t->sighand->siglock); | ||
252 | current->blocked = set; | ||
253 | recalc_sigpending(); | ||
254 | spin_unlock_irq(¤t->sighand->siglock); | ||
255 | |||
256 | if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) | ||
257 | goto segfault; | ||
258 | |||
259 | /* Avoid ERESTART handling */ | ||
260 | PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; | ||
261 | return(PT_REGS_SYSCALL_RET(¤t->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 | |||
17 | asmlinkage 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 | ||
25 | extern int modify_ldt(int func, void *ptr, unsigned long bytecount); | ||
26 | |||
27 | long 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 | ||
39 | extern int userspace_pid[]; | ||
40 | |||
41 | long 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 | |||
91 | long 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 | ||
98 | extern long arch_prctl(int code, unsigned long addr); | ||
99 | |||
100 | static 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 | |||
127 | static 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 \ | ||
143 | long)], &addr); | ||
144 | break; | ||
145 | default: | ||
146 | ret = -EINVAL; | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | return(ret); | ||
151 | } | ||
152 | #endif | ||
153 | |||
154 | long sys_arch_prctl(int code, unsigned long addr) | ||
155 | { | ||
156 | return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr)); | ||
157 | } | ||
158 | |||
159 | long 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 | |||
14 | void __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 | |||
36 | void show_regs(struct pt_regs *regs) | ||
37 | { | ||
38 | __show_regs(regs); | ||
39 | show_trace((unsigned long *) ®s); | ||
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 | |||
4 | hostprogs-y := mk_sc mk_thread | ||
5 | always := $(hostprogs-y) | ||
6 | |||
7 | mk_thread-objs := mk_thread_kern.o mk_thread_user.o | ||
8 | |||
9 | HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS) | ||
10 | HOSTCFLAGS_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 | |||
24 | int 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 | |||
5 | extern void print_head(void); | ||
6 | extern void print_constant_ptr(char *name, int value); | ||
7 | extern void print_constant(char *name, char *type, int value); | ||
8 | extern void print_tail(void); | ||
9 | |||
10 | #define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field) | ||
11 | |||
12 | int 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 | |||
3 | void 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 | |||
14 | void print_constant_ptr(char *name, int value) | ||
15 | { | ||
16 | printf("#define %s(task) ((unsigned long *) " | ||
17 | "&(((char *) (task))[%d]))\n", name, value); | ||
18 | } | ||
19 | |||
20 | void 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 | |||
26 | void 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 @@ | |||
1 | hostprogs-y := mk_task mk_constants | ||
2 | always := $(hostprogs-y) | ||
3 | |||
4 | mk_task-objs := mk_task_user.o mk_task_kern.o | ||
5 | mk_constants-objs := mk_constants_user.o mk_constants_kern.o | ||
6 | |||
7 | HOSTCFLAGS_mk_task_kern.o := $(CFLAGS) $(CPPFLAGS) | ||
8 | HOSTCFLAGS_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 | |||
6 | extern void print_head(void); | ||
7 | extern void print_constant_str(char *name, char *value); | ||
8 | extern void print_constant_int(char *name, int value); | ||
9 | extern void print_tail(void); | ||
10 | |||
11 | int 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 | |||
3 | void 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 | |||
14 | void print_constant_str(char *name, char *value) | ||
15 | { | ||
16 | printf("#define %s \"%s\"\n", name, value); | ||
17 | } | ||
18 | |||
19 | void print_constant_int(char *name, int value) | ||
20 | { | ||
21 | printf("#define %s %d\n", name, value); | ||
22 | } | ||
23 | |||
24 | void 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 | |||
4 | extern void print(char *name, char *type, int offset); | ||
5 | extern void print_ptr(char *name, char *type, int offset); | ||
6 | extern void print_head(void); | ||
7 | extern void print_tail(void); | ||
8 | |||
9 | int 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 | |||
3 | void print(char *name, char *type, int offset) | ||
4 | { | ||
5 | printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type, | ||
6 | offset); | ||
7 | } | ||
8 | |||
9 | void 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 | |||
15 | void 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 | |||
26 | void print_tail(void) | ||
27 | { | ||
28 | printf("\n"); | ||
29 | printf("#endif\n"); | ||
30 | } | ||