diff options
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 | } | ||
