diff options
Diffstat (limited to 'arch/um')
385 files changed, 16357 insertions, 26338 deletions
diff --git a/arch/um/.gitignore b/arch/um/.gitignore new file mode 100644 index 00000000000..a73d3a1cc74 --- /dev/null +++ b/arch/um/.gitignore @@ -0,0 +1,3 @@ +kernel/config.c +kernel/config.tmp +kernel/vmlinux.lds diff --git a/arch/um/Kconfig b/arch/um/Kconfig deleted file mode 100644 index 3b5f47c4690..00000000000 --- a/arch/um/Kconfig +++ /dev/null @@ -1,333 +0,0 @@ -# UML uses the generic IRQ sugsystem -config GENERIC_HARDIRQS - bool - default y - -config UML - bool - default y - -# XXX: does UM have a mmu/swap? -config MMU - bool - default y - -mainmenu "Linux/Usermode Kernel Configuration" - -config ISA - bool - -config SBUS - bool - -config PCI - bool - -config UID16 - bool - default y - -config GENERIC_CALIBRATE_DELAY - bool - default y - -# Used in kernel/irq/manage.c and include/linux/irq.h -config IRQ_RELEASE_METHOD - bool - default y - -menu "Host processor type and features" - -source "arch/i386/Kconfig.cpu" - -endmenu - -menu "UML-specific options" - -config MODE_TT - bool "Tracing thread support" - default y - help - This option controls whether tracing thread support is compiled - into UML. Normally, this should be set to Y. If you intend to - use only skas mode (and the host has the skas patch applied to it), - then it is OK to say N here. - -config STATIC_LINK - bool "Force a static link" - default n - depends on !MODE_TT - help - If CONFIG_MODE_TT is disabled, then this option gives you the ability - to force a static link of UML. Normally, if only skas mode is built - in to UML, it will be linked as a shared binary. This is inconvenient - for use in a chroot jail. So, if you intend to run UML inside a - chroot, and you disable CONFIG_MODE_TT, you probably want to say Y - here. - -config HOST_2G_2G - bool "2G/2G host address space split" - default n - depends on MODE_TT - help - This is needed when the host on which you run has a 2G/2G memory - split, instead of the customary 3G/1G. - - Note that to enable such a host - configuration, which makes sense only in some cases, you need special - host patches. - - So, if you do not know what to do here, say 'N'. - -config KERNEL_HALF_GIGS - int "Kernel address space size (in .5G units)" - default "1" - depends on MODE_TT - help - This determines the amount of address space that UML will allocate for - its own, measured in half Gigabyte units. The default is 1. - Change this only if you need to boot UML with an unusually large amount - of physical memory. - -config MODE_SKAS - bool "Separate Kernel Address Space support" - default y - help - This option controls whether skas (separate kernel address space) - support is compiled in. If you have applied the skas patch to the - host, then you certainly want to say Y here (and consider saying N - to CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this - option will shrink the UML binary slightly. - -source "arch/um/Kconfig.arch" -source "mm/Kconfig" - -config LD_SCRIPT_STATIC - bool - default y - depends on MODE_TT || STATIC_LINK - -config LD_SCRIPT_DYN - bool - default y - depends on !LD_SCRIPT_STATIC - -config NET - bool "Networking support" - help - Unless you really know what you are doing, you should say Y here. - The reason is that some programs need kernel networking support even - when running on a stand-alone machine that isn't connected to any - other computer. If you are upgrading from an older kernel, you - should consider updating your networking tools too because changes - in the kernel and the tools often go hand in hand. The tools are - contained in the package net-tools, the location and version number - of which are given in <file:Documentation/Changes>. - - For a general introduction to Linux networking, it is highly - recommended to read the NET-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - -source "fs/Kconfig.binfmt" - -config HOSTFS - tristate "Host filesystem" - help - While the User-Mode Linux port uses its own root file system for - booting and normal file access, this module lets the UML user - access files stored on the host. It does not require any - network connection between the Host and UML. An example use of - this might be: - - mount none /tmp/fromhost -t hostfs -o /tmp/umlshare - - where /tmp/fromhost is an empty directory inside UML and - /tmp/umlshare is a directory on the host with files the UML user - wishes to access. - - For more information, see - <http://user-mode-linux.sourceforge.net/hostfs.html>. - - If you'd like to be able to work with files stored on the host, - say Y or M here; otherwise say N. - -config HPPFS - tristate "HoneyPot ProcFS (EXPERIMENTAL)" - help - hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc - entries to be overridden, removed, or fabricated from the host. - Its purpose is to allow a UML to appear to be a physical machine - by removing or changing anything in /proc which gives away the - identity of a UML. - - See <http://user-mode-linux.sf.net/hppfs.html> for more information. - - You only need this if you are setting up a UML honeypot. Otherwise, - it is safe to say 'N' here. - - If you are actively using it, please report any problems, since it's - getting fixed. In this moment, it is experimental on 2.6 (it works on - 2.4). - -config MCONSOLE - bool "Management console" - default y - help - The user mode linux management console is a low-level interface to - the kernel, somewhat like the i386 SysRq interface. Since there is - a full-blown operating system running under every user mode linux - instance, there is much greater flexibility possible than with the - SysRq mechanism. - - If you answer 'Y' to this option, to use this feature, you need the - mconsole client (called uml_mconsole) which is present in CVS in - 2.4.5-9um and later (path /tools/mconsole), and is also in the - distribution RPM package in 2.4.6 and later. - - It is safe to say 'Y' here. - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on MCONSOLE - ---help--- - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). A key for each of the - possible requests is provided. - - This is the feature normally accomplished by pressing a key - while holding SysRq (Alt+PrintScreen). - - On UML, this is accomplished by sending a "sysrq" command with - mconsole, followed by the letter for the requested command. - - The keys are documented in <file:Documentation/sysrq.txt>. Don't say Y - unless you really know what this hack does. - -config SMP - bool "Symmetric multi-processing support (EXPERIMENTAL)" - default n - depends on (MODE_TT && EXPERIMENTAL && !SMP_BROKEN) || (BROKEN && SMP_BROKEN) - help - This option enables UML SMP support. - It is NOT related to having a real SMP box. Not directly, at least. - - UML implements virtual SMP by allowing as many processes to run - simultaneously on the host as there are virtual processors configured. - - Obviously, if the host is a uniprocessor, those processes will - timeshare, but, inside UML, will appear to be running simultaneously. - If the host is a multiprocessor, then UML processes may run - simultaneously, depending on the host scheduler. - - This, however, is supported only in TT mode. So, if you use the SKAS - patch on your host, switching to TT mode and enabling SMP usually gives - you worse performances. - Also, since the support for SMP has been under-developed, there could - be some bugs being exposed by enabling SMP. - - If you don't know what to do, say N. - -config NR_CPUS - int "Maximum number of CPUs (2-32)" - range 2 32 - depends on SMP - default "32" - -config NEST_LEVEL - int "Nesting level" - default "0" - help - This is set to the number of layers of UMLs that this UML will be run - in. Normally, this is zero, meaning that it will run directly on the - host. Setting it to one will build a UML that can run inside a UML - that is running on the host. Generally, if you intend this UML to run - inside another UML, set CONFIG_NEST_LEVEL to one more than the host - UML. - - Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to - greater than one, then the guest UML should have its CONFIG_NEST_LEVEL - set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS. - Only change this if you are running nested UMLs. - -config HIGHMEM - bool "Highmem support" - depends on !64BIT - -config KERNEL_STACK_ORDER - int "Kernel stack size order" - default 2 - help - This option determines the size of UML kernel stacks. They will - be 1 << order pages. The default is OK unless you're running Valgrind - on UML, in which case, set this to 3. - -config UML_REAL_TIME_CLOCK - bool "Real-time Clock" - default y - help - This option makes UML time deltas match wall clock deltas. This should - normally be enabled. The exception would be if you are debugging with - UML and spend long times with UML stopped at a breakpoint. In this - case, when UML is restarted, it will call the timer enough times to make - up for the time spent at the breakpoint. This could result in a - noticable lag. If this is a problem, then disable this option. - -endmenu - -source "init/Kconfig" - -source "net/Kconfig" - -source "drivers/base/Kconfig" - -source "arch/um/Kconfig.char" - -source "drivers/block/Kconfig" - -config NETDEVICES - bool - default NET - -source "arch/um/Kconfig.net" - -source "drivers/net/Kconfig" - -source "fs/Kconfig" - -source "security/Kconfig" - -source "crypto/Kconfig" - -source "lib/Kconfig" - -menu "SCSI support" -depends on BROKEN - -config SCSI - tristate "SCSI support" - -# This gives us free_dma, which scsi.c wants. -config GENERIC_ISA_DMA - bool - depends on SCSI - default y - -source "arch/um/Kconfig.scsi" - -endmenu - -source "drivers/md/Kconfig" - -if BROKEN - source "drivers/mtd/Kconfig" -endif - -#This is just to shut up some Kconfig warnings, so no prompt. -config INPUT - bool - default n - -source "arch/um/Kconfig.debug" diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char index 62d87b71179..f10738d68b2 100644 --- a/arch/um/Kconfig.char +++ b/arch/um/Kconfig.char @@ -1,73 +1,66 @@ - -menu "Character Devices" +menu "UML Character Devices" config STDERR_CONSOLE bool "stderr console" default y help - console driver which dumps all printk messages to stderr. - -config STDIO_CONSOLE - bool - default y + console driver which dumps all printk messages to stderr. config SSL bool "Virtual serial line" help - The User-Mode Linux environment allows you to create virtual serial - lines on the UML that are usually made to show up on the host as - ttys or ptys. + The User-Mode Linux environment allows you to create virtual serial + lines on the UML that are usually made to show up on the host as + ttys or ptys. - See <http://user-mode-linux.sourceforge.net/input.html> for more - information and command line examples of how to use this facility. + See <http://user-mode-linux.sourceforge.net/old/input.html> for more + information and command line examples of how to use this facility. - Unless you have a specific reason for disabling this, say Y. + Unless you have a specific reason for disabling this, say Y. config NULL_CHAN bool "null channel support" help - This option enables support for attaching UML consoles and serial - lines to a device similar to /dev/null. Data written to it disappears - and there is never any data to be read. + This option enables support for attaching UML consoles and serial + lines to a device similar to /dev/null. Data written to it disappears + and there is never any data to be read. config PORT_CHAN bool "port channel support" help - This option enables support for attaching UML consoles and serial - lines to host portals. They may be accessed with 'telnet <host> - <port number>'. Any number of consoles and serial lines may be - attached to a single portal, although what UML device you get when - you telnet to that portal will be unpredictable. - It is safe to say 'Y' here. + This option enables support for attaching UML consoles and serial + lines to host portals. They may be accessed with 'telnet <host> + <port number>'. Any number of consoles and serial lines may be + attached to a single portal, although what UML device you get when + you telnet to that portal will be unpredictable. + It is safe to say 'Y' here. config PTY_CHAN bool "pty channel support" help - This option enables support for attaching UML consoles and serial - lines to host pseudo-terminals. Access to both traditional - pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled - with this option. The assignment of UML devices to host devices - will be announced in the kernel message log. - It is safe to say 'Y' here. + This option enables support for attaching UML consoles and serial + lines to host pseudo-terminals. Access to both traditional + pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled + with this option. The assignment of UML devices to host devices + will be announced in the kernel message log. + It is safe to say 'Y' here. config TTY_CHAN bool "tty channel support" help - This option enables support for attaching UML consoles and serial - lines to host terminals. Access to both virtual consoles - (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and - /dev/pts/*) are controlled by this option. - It is safe to say 'Y' here. + This option enables support for attaching UML consoles and serial + lines to host terminals. Access to both virtual consoles + (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and + /dev/pts/*) are controlled by this option. + It is safe to say 'Y' here. config XTERM_CHAN bool "xterm channel support" help - This option enables support for attaching UML consoles and serial - lines to xterms. Each UML device so assigned will be brought up in - its own xterm. - If you disable this option, then CONFIG_PT_PROXY will be disabled as - well, since UML's gdb currently requires an xterm. - It is safe to say 'Y' here. + This option enables support for attaching UML consoles and serial + lines to xterms. Each UML device so assigned will be brought up in + its own xterm. + It is safe to say 'Y' here. config NOCONFIG_CHAN bool @@ -77,138 +70,54 @@ config CON_ZERO_CHAN string "Default main console channel initialization" default "fd:0,fd:1" help - This is the string describing the channel to which the main console - will be attached by default. This value can be overridden from the - command line. The default value is "fd:0,fd:1", which attaches the - main console to stdin and stdout. - It is safe to leave this unchanged. + This is the string describing the channel to which the main console + will be attached by default. This value can be overridden from the + command line. The default value is "fd:0,fd:1", which attaches the + main console to stdin and stdout. + It is safe to leave this unchanged. config CON_CHAN string "Default console channel initialization" default "xterm" help - This is the string describing the channel to which all consoles - except the main console will be attached by default. This value can - be overridden from the command line. The default value is "xterm", - which brings them up in xterms. - It is safe to leave this unchanged, although you may wish to change - this if you expect the UML that you build to be run in environments - which don't have X or xterm available. + This is the string describing the channel to which all consoles + except the main console will be attached by default. This value can + be overridden from the command line. The default value is "xterm", + which brings them up in xterms. + It is safe to leave this unchanged, although you may wish to change + this if you expect the UML that you build to be run in environments + which don't have X or xterm available. config SSL_CHAN string "Default serial line channel initialization" default "pty" help - This is the string describing the channel to which the serial lines - will be attached by default. This value can be overridden from the - command line. The default value is "pty", which attaches them to - traditional pseudo-terminals. - It is safe to leave this unchanged, although you may wish to change - this if you expect the UML that you build to be run in environments - which don't have a set of /dev/pty* devices. - -config UNIX98_PTYS - bool "Unix98 PTY support" - ---help--- - A pseudo terminal (PTY) is a software device consisting of two - halves: a master and a slave. The slave device behaves identical to - a physical terminal; the master device is used by a process to - read data from and write data to the slave, thereby emulating a - terminal. Typical programs for the master side are telnet servers - and xterms. - - Linux has traditionally used the BSD-like names /dev/ptyxx for - masters and /dev/ttyxx for slaves of pseudo terminals. This scheme - has a number of problems. The GNU C library glibc 2.1 and later, - however, supports the Unix98 naming standard: in order to acquire a - pseudo terminal, a process opens /dev/ptmx; the number of the pseudo - terminal is then made available to the process and the pseudo - terminal slave can be accessed as /dev/pts/<number>. What was - traditionally /dev/ttyp2 will then be /dev/pts/2, for example. - - All modern Linux systems use the Unix98 ptys. Say Y unless - you're on an embedded system and want to conserve memory. - -config LEGACY_PTYS - bool "Legacy (BSD) PTY support" - default y - ---help--- - A pseudo terminal (PTY) is a software device consisting of two - halves: a master and a slave. The slave device behaves identical to - a physical terminal; the master device is used by a process to - read data from and write data to the slave, thereby emulating a - terminal. Typical programs for the master side are telnet servers - and xterms. - - Linux has traditionally used the BSD-like names /dev/ptyxx - for masters and /dev/ttyxx for slaves of pseudo - terminals. This scheme has a number of problems, including - security. This option enables these legacy devices; on most - systems, it is safe to say N. - - -config LEGACY_PTY_COUNT - int "Maximum number of legacy PTY in use" - depends on LEGACY_PTYS - default "256" - ---help--- - The maximum number of legacy PTYs that can be used at any one time. - The default is 256, and should be more than enough. Embedded - systems may want to reduce this to save memory. - - When not in use, each legacy PTY occupies 12 bytes on 32-bit - architectures and 24 bytes on 64-bit architectures. - -config WATCHDOG - bool "Watchdog Timer Support" - -config WATCHDOG_NOWAYOUT - bool "Disable watchdog shutdown on close" - depends on WATCHDOG - -config SOFT_WATCHDOG - tristate "Software Watchdog" - depends on WATCHDOG - -config UML_WATCHDOG - tristate "UML watchdog" - depends on WATCHDOG + This is the string describing the channel to which the serial lines + will be attached by default. This value can be overridden from the + command line. The default value is "pty", which attaches them to + traditional pseudo-terminals. + It is safe to leave this unchanged, although you may wish to change + this if you expect the UML that you build to be run in environments + which don't have a set of /dev/pty* devices. config UML_SOUND tristate "Sound support" help - This option enables UML sound support. If enabled, it will pull in - soundcore and the UML hostaudio relay, which acts as a intermediary - between the host's dsp and mixer devices and the UML sound system. - It is safe to say 'Y' here. + This option enables UML sound support. If enabled, it will pull in + soundcore and the UML hostaudio relay, which acts as a intermediary + between the host's dsp and mixer devices and the UML sound system. + It is safe to say 'Y' here. config SOUND tristate default UML_SOUND +config SOUND_OSS_CORE + bool + default UML_SOUND + config HOSTAUDIO tristate default UML_SOUND -config UML_RANDOM - tristate "Hardware random number generator" - help - This option enables UML's "hardware" random number generator. It - attaches itself to the host's /dev/random, supplying as much entropy - as the host has, rather than the small amount the UML gets from its - own drivers. It registers itself as a standard hardware random number - generator, major 10, minor 183, and the canonical device name is - /dev/hwrng. - The way to make use of this is to install the rng-tools package - (check your distro, or download from - http://sourceforge.net/projects/gkernel/). rngd periodically reads - /dev/hwrng and injects the entropy into /dev/random. - -config MMAPPER - tristate "iomem emulation driver" - help - This driver allows a host file to be used as emulated IO memory inside - UML. - endmenu - diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common new file mode 100644 index 00000000000..6915d28cf11 --- /dev/null +++ b/arch/um/Kconfig.common @@ -0,0 +1,59 @@ +config UML + bool + default y + select HAVE_ARCH_AUDITSYSCALL + select HAVE_UID16 + select GENERIC_IRQ_SHOW + select GENERIC_CPU_DEVICES + select GENERIC_IO + select GENERIC_CLOCKEVENTS + select TTY # Needed for line.c + +config MMU + bool + default y + +config NO_IOMEM + def_bool y + +config ISA + bool + +config SBUS + bool + +config PCI + bool + +config PCMCIA + bool + +# Yet to do! +config TRACE_IRQFLAGS_SUPPORT + bool + default n + +config LOCKDEP_SUPPORT + bool + default y + +config STACKTRACE_SUPPORT + bool + default n + +config GENERIC_CALIBRATE_DELAY + bool + default y + +config GENERIC_BUG + bool + default y + depends on BUG + +config HZ + int + default 100 + +config SUBARCH + string + option env="SUBARCH" diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug index 5681a8bd370..68205fd3b08 100644 --- a/arch/um/Kconfig.debug +++ b/arch/um/Kconfig.debug @@ -2,59 +2,39 @@ menu "Kernel hacking" source "lib/Kconfig.debug" -config CMDLINE_ON_HOST - bool "Show command line arguments on the host in TT mode" - depends on MODE_TT - default !DEBUG_INFO - help - This controls whether arguments in guest processes should be shown on - the host's ps output. - Enabling this option hinders debugging on some recent GDB versions - (because GDB gets "confused" when we do an execvp()). So probably you - should disable it. - -config PT_PROXY - bool "Enable ptrace proxy" - depends on XTERM_CHAN && DEBUG_INFO && MODE_TT - help - This option enables a debugging interface which allows gdb to debug - the kernel without needing to actually attach to kernel threads. - If you want to do kernel debugging, say Y here; otherwise say N. - config GPROF bool "Enable gprof support" - depends on DEBUG_INFO && MODE_SKAS && !MODE_TT + depends on DEBUG_INFO && FRAME_POINTER help - This allows profiling of a User-Mode Linux kernel with the gprof - utility. + This allows profiling of a User-Mode Linux kernel with the gprof + utility. - See <http://user-mode-linux.sourceforge.net/gprof.html> for more - details. + See <http://user-mode-linux.sourceforge.net/old/gprof.html> for more + details. - If you're involved in UML kernel development and want to use gprof, - say Y. If you're unsure, say N. + If you're involved in UML kernel development and want to use gprof, + say Y. If you're unsure, say N. config GCOV bool "Enable gcov support" - depends on DEBUG_INFO && MODE_SKAS + depends on DEBUG_INFO help - This option allows developers to retrieve coverage data from a UML - session. + This option allows developers to retrieve coverage data from a UML + session. - See <http://user-mode-linux.sourceforge.net/gprof.html> for more - details. + See <http://user-mode-linux.sourceforge.net/old/gprof.html> for more + details. - If you're involved in UML kernel development and want to use gcov, - say Y. If you're unsure, say N. + If you're involved in UML kernel development and want to use gcov, + say Y. If you're unsure, say N. -config SYSCALL_DEBUG - bool "Enable system call debugging" - default N - depends on DEBUG_INFO - help - This adds some system debugging to UML, including keeping a ring buffer - with recent system calls and some global and per-task statistics. +config EARLY_PRINTK + bool "Early printk" + default y + ---help--- + Write kernel log output directly to stdout. - If unsure, say N + This is useful for kernel debugging when your machine crashes very + early before the console code is initialized. endmenu diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386 deleted file mode 100644 index 5d92cacd56c..00000000000 --- a/arch/um/Kconfig.i386 +++ /dev/null @@ -1,48 +0,0 @@ -config UML_X86 - bool - default y - -config 64BIT - bool - default n - -config SEMAPHORE_SLEEPERS - bool - default y - -config TOP_ADDR - hex - default 0xc0000000 if !HOST_2G_2G - default 0x80000000 if HOST_2G_2G - -config 3_LEVEL_PGTABLES - bool "Three-level pagetables" - default n - help - Three-level pagetables will let UML have more than 4G of physical - memory. All the memory that can't be mapped directly will be treated - as high memory. - -config STUB_CODE - hex - default 0xbfffe000 - -config STUB_DATA - hex - default 0xbffff000 - -config STUB_START - hex - default STUB_CODE - -config ARCH_HAS_SC_SIGNALS - bool - default y - -config ARCH_REUSE_HOST_VSYSCALL_AREA - bool - default y - -config X86_CMPXCHG - bool - default y diff --git a/arch/um/Kconfig.net b/arch/um/Kconfig.net index 14a04ebdeae..820a56f0033 100644 --- a/arch/um/Kconfig.net +++ b/arch/um/Kconfig.net @@ -14,7 +14,7 @@ config UML_NET For more information, including explanations of the networking and sample configurations, see - <http://user-mode-linux.sourceforge.net/networking.html>. + <http://user-mode-linux.sourceforge.net/old/networking.html>. If you'd like to be able to enable networking in the User-Mode linux environment, say Y; otherwise say N. Note that you must @@ -38,7 +38,7 @@ config UML_NET_ETHERTAP CONFIG_NETLINK_DEV configured as Y or M. For more information, see - <http://user-mode-linux.sourceforge.net/networking.html> That site + <http://user-mode-linux.sourceforge.net/old/networking.html> That site has examples of the UML command line to use to enable Ethertap networking. @@ -72,7 +72,7 @@ config UML_NET_SLIP To use this, your host must support slip devices. For more information, see - <http://user-mode-linux.sourceforge.net/networking.html>. That site + <http://user-mode-linux.sourceforge.net/old/networking.html>. has examples of the UML command line to use to enable slip networking, and details of a few quirks with it. @@ -96,7 +96,7 @@ config UML_NET_DAEMON networking daemon on the host. For more information, see - <http://user-mode-linux.sourceforge.net/networking.html> That site + <http://user-mode-linux.sourceforge.net/old/networking.html> That site has examples of the UML command line to use to enable Daemon networking. @@ -108,6 +108,28 @@ config UML_NET_DAEMON more than one without conflict. If you don't need UML networking, say N. +config UML_NET_VDE + bool "VDE transport" + depends on UML_NET + help + This User-Mode Linux network transport allows one or more running + UMLs on a single host to communicate with each other and also + with the rest of the world using Virtual Distributed Ethernet, + an improved fork of uml_switch. + + You must have libvdeplug installed in order to build the vde + transport into UML. + + To use this form of networking, you will need to run vde_switch + on the host. + + For more information, see <http://wiki.virtualsquare.org/> + That site has a good overview of what VDE is and also examples + of the UML command line to use to enable VDE networking. + + If you need UML networking with VDE, + say Y. + config UML_NET_MCAST bool "Multicast transport" depends on UML_NET @@ -122,7 +144,7 @@ config UML_NET_MCAST To use this, your host kernel(s) must support IP Multicasting. For more information, see - <http://user-mode-linux.sourceforge.net/networking.html> That site + <http://user-mode-linux.sourceforge.net/old/networking.html> That site has examples of the UML command line to use to enable Multicast networking, and notes about the security of this approach. @@ -135,7 +157,7 @@ config UML_NET_MCAST config UML_NET_PCAP bool "pcap transport" - depends on UML_NET && EXPERIMENTAL + depends on UML_NET help The pcap transport makes a pcap packet stream on the host look like an ethernet device inside UML. This is useful for making @@ -143,7 +165,7 @@ config UML_NET_PCAP installed in order to build the pcap transport into UML. For more information, see - <http://user-mode-linux.sourceforge.net/networking.html> That site + <http://user-mode-linux.sourceforge.net/old/networking.html> That site has examples of the UML command line to use to enable this option. If you intend to use UML as a network monitor for the host, say @@ -164,7 +186,7 @@ config UML_NET_SLIRP other transports, SLiRP works without the need of root level privleges, setuid binaries, or SLIP devices on the host. This also means not every type of connection is possible, but most - situations can be accomodated with carefully crafted slirp + situations can be accommodated with carefully crafted slirp commands that can be passed along as part of the network device's setup string. The effect of this transport on the UML is similar that of a host behind a firewall that masquerades all network diff --git a/arch/um/Kconfig.rest b/arch/um/Kconfig.rest new file mode 100644 index 00000000000..567eb5fc21d --- /dev/null +++ b/arch/um/Kconfig.rest @@ -0,0 +1,21 @@ +source "init/Kconfig" + +source "kernel/Kconfig.freezer" + +source "arch/um/Kconfig.char" + +source "drivers/Kconfig" + +source "net/Kconfig" + +source "arch/um/Kconfig.net" + +source "fs/Kconfig" + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + +source "arch/um/Kconfig.debug" diff --git a/arch/um/Kconfig.scsi b/arch/um/Kconfig.scsi deleted file mode 100644 index c291c942b1a..00000000000 --- a/arch/um/Kconfig.scsi +++ /dev/null @@ -1,58 +0,0 @@ -comment "SCSI support type (disk, tape, CD-ROM)" - depends on SCSI - -config BLK_DEV_SD - tristate "SCSI disk support" - depends on SCSI - -config SD_EXTRA_DEVS - int "Maximum number of SCSI disks that can be loaded as modules" - depends on BLK_DEV_SD - default "40" - -config CHR_DEV_ST - tristate "SCSI tape support" - depends on SCSI - -config BLK_DEV_SR - tristate "SCSI CD-ROM support" - depends on SCSI - -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - -config SR_EXTRA_DEVS - int "Maximum number of CDROM devices that can be loaded as modules" - depends on BLK_DEV_SR - default "2" - -config CHR_DEV_SG - tristate "SCSI generic support" - depends on SCSI - -comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" - depends on SCSI - -#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then -config SCSI_DEBUG_QUEUES - bool "Enable extra checks in new queueing code" - depends on SCSI - -#fi -config SCSI_MULTI_LUN - bool "Probe all LUNs on each SCSI device" - depends on SCSI - -config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" - depends on SCSI - -config SCSI_LOGGING - bool "SCSI logging facility" - depends on SCSI - -config SCSI_DEBUG - tristate "SCSI debugging host simulator (EXPERIMENTAL)" - depends on SCSI - diff --git a/arch/um/Kconfig.um b/arch/um/Kconfig.um new file mode 100644 index 00000000000..a7520c90f62 --- /dev/null +++ b/arch/um/Kconfig.um @@ -0,0 +1,157 @@ +config STATIC_LINK + bool "Force a static link" + default n + help + This option gives you the ability to force a static link of UML. + Normally, UML is linked as a shared binary. This is inconvenient for + use in a chroot jail. So, if you intend to run UML inside a chroot, + you probably want to say Y here. + Additionally, this option enables using higher memory spaces (up to + 2.75G) for UML. + +source "mm/Kconfig" + +config LD_SCRIPT_STATIC + bool + default y + depends on STATIC_LINK + +config LD_SCRIPT_DYN + bool + default y + depends on !LD_SCRIPT_STATIC + +source "fs/Kconfig.binfmt" + +config HOSTFS + tristate "Host filesystem" + help + While the User-Mode Linux port uses its own root file system for + booting and normal file access, this module lets the UML user + access files stored on the host. It does not require any + network connection between the Host and UML. An example use of + this might be: + + mount none /tmp/fromhost -t hostfs -o /tmp/umlshare + + where /tmp/fromhost is an empty directory inside UML and + /tmp/umlshare is a directory on the host with files the UML user + wishes to access. + + For more information, see + <http://user-mode-linux.sourceforge.net/hostfs.html>. + + If you'd like to be able to work with files stored on the host, + say Y or M here; otherwise say N. + +config HPPFS + tristate "HoneyPot ProcFS" + depends on PROC_FS + help + hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc + entries to be overridden, removed, or fabricated from the host. + Its purpose is to allow a UML to appear to be a physical machine + by removing or changing anything in /proc which gives away the + identity of a UML. + + See <http://user-mode-linux.sf.net/old/hppfs.html> for more information. + + You only need this if you are setting up a UML honeypot. Otherwise, + it is safe to say 'N' here. + +config MCONSOLE + bool "Management console" + default y + help + The user mode linux management console is a low-level interface to + the kernel, somewhat like the i386 SysRq interface. Since there is + a full-blown operating system running under every user mode linux + instance, there is much greater flexibility possible than with the + SysRq mechanism. + + If you answer 'Y' to this option, to use this feature, you need the + mconsole client (called uml_mconsole) which is present in CVS in + 2.4.5-9um and later (path /tools/mconsole), and is also in the + distribution RPM package in 2.4.6 and later. + + It is safe to say 'Y' here. + +config MAGIC_SYSRQ + bool "Magic SysRq key" + depends on MCONSOLE + help + If you say Y here, you will have some control over the system even + if the system crashes for example during kernel debugging (e.g., you + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). A key for each of the + possible requests is provided. + + This is the feature normally accomplished by pressing a key + while holding SysRq (Alt+PrintScreen). + + On UML, this is accomplished by sending a "sysrq" command with + mconsole, followed by the letter for the requested command. + + The keys are documented in <file:Documentation/sysrq.txt>. Don't say Y + unless you really know what this hack does. + +config SMP + bool "Symmetric multi-processing support" + default n + depends on BROKEN + help + This option enables UML SMP support. + It is NOT related to having a real SMP box. Not directly, at least. + + UML implements virtual SMP by allowing as many processes to run + simultaneously on the host as there are virtual processors configured. + + Obviously, if the host is a uniprocessor, those processes will + timeshare, but, inside UML, will appear to be running simultaneously. + If the host is a multiprocessor, then UML processes may run + simultaneously, depending on the host scheduler. + + This, however, is supported only in TT mode. So, if you use the SKAS + patch on your host, switching to TT mode and enabling SMP usually + gives you worse performances. + Also, since the support for SMP has been under-developed, there could + be some bugs being exposed by enabling SMP. + + If you don't know what to do, say N. + +config NR_CPUS + int "Maximum number of CPUs (2-32)" + range 2 32 + depends on SMP + default "32" + +config HIGHMEM + bool "Highmem support" + depends on !64BIT && BROKEN + default n + help + This was used to allow UML to run with big amounts of memory. + Currently it is unstable, so if unsure say N. + + To use big amounts of memory, it is recommended enable static + linking (i.e. CONFIG_STATIC_LINK) - this should allow the + guest to use up to 2.75G of memory. + +config KERNEL_STACK_ORDER + int "Kernel stack size order" + default 1 if 64BIT + range 1 10 if 64BIT + default 0 if !64BIT + help + This option determines the size of UML kernel stacks. They will + be 1 << order pages. The default is OK unless you're running Valgrind + on UML, in which case, set this to 3. + +config MMAPPER + tristate "iomem emulation driver" + help + This driver allows a host file to be used as emulated IO memory inside + UML. + +config NO_DMA + def_bool y diff --git a/arch/um/Kconfig.x86_64 b/arch/um/Kconfig.x86_64 deleted file mode 100644 index aae19bc4b06..00000000000 --- a/arch/um/Kconfig.x86_64 +++ /dev/null @@ -1,48 +0,0 @@ -config UML_X86 - bool - default y - -config 64BIT - bool - default y - -#XXX: this is so in the underlying arch, but it's wrong!!! -config RWSEM_GENERIC_SPINLOCK - bool - default y - -config SEMAPHORE_SLEEPERS - bool - default y - -config TOP_ADDR - hex - default 0x80000000 - -config 3_LEVEL_PGTABLES - bool - default y - -config STUB_CODE - hex - default 0x7fbfffe000 - -config STUB_DATA - hex - default 0x7fbffff000 - -config STUB_START - hex - default STUB_CODE - -config ARCH_HAS_SC_SIGNALS - bool - default n - -config ARCH_REUSE_HOST_VSYSCALL_AREA - bool - default n - -config SMP_BROKEN - bool - default y diff --git a/arch/um/Makefile b/arch/um/Makefile index e55d32e903b..e4b1a9639c4 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -1,8 +1,22 @@ -# -# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. +# +# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) # Licensed under the GPL # +# select defconfig based on actual architecture +ifeq ($(SUBARCH),x86) + ifeq ($(shell uname -m),x86_64) + KBUILD_DEFCONFIG := x86_64_defconfig + else + KBUILD_DEFCONFIG := i386_defconfig + endif +else + KBUILD_DEFCONFIG := $(SUBARCH)_defconfig +endif + ARCH_DIR := arch/um OS := $(shell uname -s) # We require bash because the vmlinux link and loader script cpp use bash @@ -15,179 +29,124 @@ core-y += $(ARCH_DIR)/kernel/ \ $(ARCH_DIR)/drivers/ \ $(ARCH_DIR)/os-$(OS)/ -# Have to precede the include because the included Makefiles reference them. -SYMLINK_HEADERS := archparam.h system.h sigcontext.h processor.h ptrace.h \ - module.h vm-flags.h elf.h -SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header)) - -# XXX: The "os" symlink is only used by arch/um/include/os.h, which includes -# ../os/include/file.h -# -# These are cleaned up during mrproper. Please DO NOT fix it again, this is -# the Correct Thing(tm) to do! -ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ - $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h - -um-modes-$(CONFIG_MODE_TT) += tt -um-modes-$(CONFIG_MODE_SKAS) += skas - -MODE_INCLUDE += $(foreach mode,$(um-modes-y),\ - -I$(srctree)/$(ARCH_DIR)/kernel/$(mode)/include) +MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/include/shared/skas -MAKEFILES-INCL += $(foreach mode,$(um-modes-y),\ - $(srctree)/$(ARCH_DIR)/Makefile-$(mode)) +HEADER_ARCH := $(SUBARCH) -ifneq ($(MAKEFILES-INCL),) - include $(MAKEFILES-INCL) +ifneq ($(filter $(SUBARCH),x86 x86_64 i386),) + HEADER_ARCH := x86 endif -ARCH_INCLUDE := -I$(ARCH_DIR)/include -ifneq ($(KBUILD_SRC),) -ARCH_INCLUDE += -I$(srctree)/$(ARCH_DIR)/include +ifdef CONFIG_64BIT + KBUILD_CFLAGS += -mcmodel=large endif -SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH) -# -Dvmap=kernel_vmap affects everything, and prevents anything from -# referencing the libpcap.o symbol so named. -# -# Same things for in6addr_loopback - found in libc. +HOST_DIR := arch/$(HEADER_ARCH) -CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ - $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \ - -Din6addr_loopback=kernel_in6addr_loopback +include $(srctree)/$(ARCH_DIR)/Makefile-skas +include $(srctree)/$(HOST_DIR)/Makefile.um -AFLAGS += $(ARCH_INCLUDE) +core-y += $(HOST_DIR)/um/ -USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) -USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ - $(MODE_INCLUDE) -D_FILE_OFFSET_BITS=64 +SHARED_HEADERS := $(ARCH_DIR)/include/shared +ARCH_INCLUDE := -I$(srctree)/$(SHARED_HEADERS) +ARCH_INCLUDE += -I$(srctree)/$(HOST_DIR)/um/shared +KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/um -# -Derrno=kernel_errno - This turns all kernel references to errno into -# kernel_errno to separate them from the libc errno. This allows -fno-common -# in CFLAGS. Otherwise, it would cause ld to complain about the two different -# errnos. +# -Dvmap=kernel_vmap prevents anything from referencing the libpcap.o symbol so +# named - it's a common symbol in libpcap, so we get a binary which crashes. +# +# Same things for in6addr_loopback and mktime - found in libc. For these two we +# only get link-time error, luckily. +# +# These apply to USER_CFLAGS to. -CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask -CFLAGS += $(call cc-option,-fno-unit-at-a-time,) +KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \ + $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \ + -Din6addr_loopback=kernel_in6addr_loopback \ + -Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr -include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH) +KBUILD_AFLAGS += $(ARCH_INCLUDE) + +USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -D__KERNEL__,,\ + $(patsubst -I%,,$(KBUILD_CFLAGS)))) $(ARCH_INCLUDE) $(MODE_INCLUDE) \ + $(filter -I%,$(CFLAGS)) -D_FILE_OFFSET_BITS=64 -idirafter include #This will adjust *FLAGS accordingly to the platform. include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS) -# These are needed for clean and mrproper, since in that case .config is not -# included; the values here are meaningless +KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/include \ + -I$(srctree)/$(HOST_DIR)/include/uapi \ + -I$(HOST_DIR)/include/generated \ + -I$(HOST_DIR)/include/generated/uapi -CONFIG_NEST_LEVEL ?= 0 -CONFIG_KERNEL_HALF_GIGS ?= 0 +# -Derrno=kernel_errno - This turns all kernel references to errno into +# kernel_errno to separate them from the libc errno. This allows -fno-common +# in KBUILD_CFLAGS. Otherwise, it would cause ld to complain about the two different +# errnos. +# These apply to kernelspace only. +# +# strip leading and trailing whitespace to make the USER_CFLAGS removal of these +# defines more robust -SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000) +KERNEL_DEFINES = $(strip -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \ + -Dmktime=kernel_mktime $(ARCH_KERNEL_DEFINES)) +KBUILD_CFLAGS += $(KERNEL_DEFINES) -.PHONY: linux +PHONY += linux all: linux linux: vmlinux - ln -f $< $@ + @echo ' LINK $@' + $(Q)ln -f $< $@ define archhelp echo '* linux - Binary kernel image (./linux) - for backward' echo ' compatibility only, this creates a hard link to the' - echo ' real kernel binary, the the "vmlinux" binary you' + echo ' real kernel binary, the "vmlinux" binary you' echo ' find in the kernel root.' endef -ifneq ($(KBUILD_SRC),) -$(shell mkdir -p $(ARCH_DIR) && ln -fsn $(srctree)/$(ARCH_DIR)/Kconfig.$(SUBARCH) $(ARCH_DIR)/Kconfig.arch) -else -$(shell cd $(ARCH_DIR) && ln -sf Kconfig.$(SUBARCH) Kconfig.arch) -endif +KBUILD_KCONFIG := $(HOST_DIR)/um/Kconfig + +archheaders: + $(Q)$(MAKE) KBUILD_SRC= ARCH=$(HEADER_ARCH) archheaders -archprepare: $(ARCH_SYMLINKS) $(ARCH_DIR)/include/user_constants.h -prepare: $(ARCH_DIR)/include/kern_constants.h +archprepare: include/generated/user_constants.h LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib -CPP_MODE-$(CONFIG_MODE_TT) := -DMODE_TT -CONFIG_KERNEL_STACK_ORDER ?= 2 -STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] ) +CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \ + $(call cc-option, -fno-stack-protector,) \ + $(call cc-option, -fno-stack-protector-all,) -ifndef START - START = $(shell echo $$[ $(TOP_ADDR) - $(SIZE) ] ) -endif +# Options used by linker script +export LDS_START := $(START) +export LDS_ELF_ARCH := $(ELF_ARCH) +export LDS_ELF_FORMAT := $(ELF_FORMAT) -CPPFLAGS_vmlinux.lds = -U$(SUBARCH) \ - -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ - -DELF_FORMAT="$(ELF_FORMAT)" $(CPP_MODE-y) \ - -DKERNEL_STACK_SIZE=$(STACK_SIZE) \ - -DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap_fin.o - -#The wrappers will select whether using "malloc" or the kernel allocator. +# The wrappers will select whether using "malloc" or the kernel allocator. LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc -CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) -define cmd_vmlinux__ - $(CC) $(CFLAGS_vmlinux) -o $@ \ - -Wl,-T,$(vmlinux-lds) $(vmlinux-init) \ - -Wl,--start-group $(vmlinux-main) -Wl,--end-group \ - -lutil \ - $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) \ - FORCE ,$^) ; rm -f linux -endef +LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) -#When cleaning we don't include .config, so we don't include -#TT or skas makefiles and don't clean skas_ptregs.h. -CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \ - $(ARCH_DIR)/include/user_constants.h \ - $(ARCH_DIR)/include/kern_constants.h $(ARCH_DIR)/Kconfig.arch +# Used by link-vmlinux.sh which has special support for um link +export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) -MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ - $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os +# When cleaning we don't include .config, so we don't include +# TT or skas makefiles and don't clean skas_ptregs.h. +CLEAN_FILES += linux x.i gmon.out archclean: @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ -o -name '*.gcov' \) -type f -print | xargs rm -f -$(SYMLINK_HEADERS): - @echo ' SYMLINK $@' -ifneq ($(KBUILD_SRC),) - $(Q)ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@ -else - $(Q)cd $(TOPDIR)/$(dir $@) ; \ - ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@) -endif - -include/asm-um/arch: - @echo ' SYMLINK $@' -ifneq ($(KBUILD_SRC),) - $(Q)mkdir -p include/asm-um - $(Q)ln -fsn $(srctree)/include/asm-$(SUBARCH) include/asm-um/arch -else - $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch -endif - -$(ARCH_DIR)/include/sysdep: - @echo ' SYMLINK $@' -ifneq ($(KBUILD_SRC),) - $(Q)mkdir -p $(ARCH_DIR)/include - $(Q)ln -fsn $(srctree)/$(ARCH_DIR)/include/sysdep-$(SUBARCH) $(ARCH_DIR)/include/sysdep -else - $(Q)cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep -endif - -$(ARCH_DIR)/os: - @echo ' SYMLINK $@' -ifneq ($(KBUILD_SRC),) - $(Q)ln -fsn $(srctree)/$(ARCH_DIR)/os-$(OS) $(ARCH_DIR)/os -else - $(Q)cd $(ARCH_DIR) && ln -sf os-$(OS) os -endif - # Generated files -define filechk_umlconfig - sed 's/ CONFIG/ UML_CONFIG/' -endef + +$(HOST_DIR)/um/user-offsets.s: __headers FORCE + $(Q)$(MAKE) $(build)=$(HOST_DIR)/um $@ define filechk_gen-asm-offsets (set -e; \ @@ -202,24 +161,7 @@ define filechk_gen-asm-offsets echo ""; ) endef -$(ARCH_DIR)/include/uml-config.h : include/linux/autoconf.h - $(call filechk,umlconfig) - -$(ARCH_DIR)/user-offsets.s: $(ARCH_DIR)/sys-$(SUBARCH)/user-offsets.c - $(CC) $(USER_CFLAGS) -S -o $@ $< - -$(ARCH_DIR)/include/user_constants.h: $(ARCH_DIR)/user-offsets.s +include/generated/user_constants.h: $(HOST_DIR)/um/user-offsets.s $(call filechk,gen-asm-offsets) -CLEAN_FILES += $(ARCH_DIR)/user-offsets.s - -$(ARCH_DIR)/kernel-offsets.s: $(ARCH_DIR)/sys-$(SUBARCH)/kernel-offsets.c \ - archprepare - $(CC) $(CFLAGS) $(NOSTDINC_FLAGS) $(CPPFLAGS) -S -o $@ $< - -$(ARCH_DIR)/include/kern_constants.h: $(ARCH_DIR)/kernel-offsets.s - $(call filechk,gen-asm-offsets) - -CLEAN_FILES += $(ARCH_DIR)/kernel-offsets.s - -export SUBARCH USER_CFLAGS OS +export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS DEV_NULL_PATH diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 deleted file mode 100644 index 1f7dcb064ae..00000000000 --- a/arch/um/Makefile-i386 +++ /dev/null @@ -1,38 +0,0 @@ -core-y += arch/um/sys-i386/ arch/i386/crypto/ - -TOP_ADDR := $(CONFIG_TOP_ADDR) - -ifeq ($(CONFIG_MODE_SKAS),y) - ifneq ($(CONFIG_MODE_TT),y) - START := 0x8048000 - endif -endif - -LDFLAGS += -m elf_i386 -ELF_ARCH := $(SUBARCH) -ELF_FORMAT := elf32-$(SUBARCH) -OBJCOPYFLAGS := -O binary -R .note -R .comment -S - -ifeq ("$(origin SUBARCH)", "command line") -ifneq ("$(shell uname -m | sed -e s/i.86/i386/)", "$(SUBARCH)") -CFLAGS += $(call cc-option,-m32) -USER_CFLAGS += $(call cc-option,-m32) -AFLAGS += $(call cc-option,-m32) -LINK-y += $(call cc-option,-m32) -UML_OBJCOPYFLAGS += -F $(ELF_FORMAT) - -export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UML_OBJCOPYFLAGS -endif -endif - -CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) - -# First of all, tune CFLAGS for the specific CPU. This actually sets cflags-y. -include $(srctree)/arch/i386/Makefile.cpu - -# prevent gcc from keeping the stack 16 byte aligned. Taken from i386. -cflags-y += $(call cc-option,-mpreferred-stack-boundary=2) - -CFLAGS += $(cflags-y) -USER_CFLAGS += $(cflags-y) - diff --git a/arch/um/Makefile-os-Linux b/arch/um/Makefile-os-Linux index 0c0f9a1cbba..2c8a598ec14 100644 --- a/arch/um/Makefile-os-Linux +++ b/arch/um/Makefile-os-Linux @@ -5,4 +5,5 @@ # To get a definition of F_SETSIG USER_CFLAGS += -D_GNU_SOURCE -D_LARGEFILE64_SOURCE -CFLAGS += -D_LARGEFILE64_SOURCE +KBUILD_CFLAGS += -D_LARGEFILE64_SOURCE +DEV_NULL_PATH = \"/dev/null\" diff --git a/arch/um/Makefile-tt b/arch/um/Makefile-tt deleted file mode 100644 index 03f7b10cfd0..00000000000 --- a/arch/um/Makefile-tt +++ /dev/null @@ -1,5 +0,0 @@ -# -# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) -# Licensed under the GPL -# - diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 deleted file mode 100644 index 4f118d5cc2e..00000000000 --- a/arch/um/Makefile-x86_64 +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2003 - 2004 Pathscale, Inc -# Released under the GPL - -libs-y += arch/um/sys-x86_64/ -START := 0x60000000 - -#We #undef __x86_64__ for kernelspace, not for userspace where -#it's needed for headers to work! -CFLAGS += -U__$(SUBARCH)__ -fno-builtin -USER_CFLAGS += -fno-builtin -CHECKFLAGS += -m64 - -ELF_ARCH := i386:x86-64 -ELF_FORMAT := elf64-x86-64 diff --git a/arch/um/config.release b/arch/um/config.release deleted file mode 100644 index fc68bcb9294..00000000000 --- a/arch/um/config.release +++ /dev/null @@ -1,333 +0,0 @@ -# -# Automatically generated make config: don't edit -# -CONFIG_USERMODE=y -# CONFIG_ISA is not set -# CONFIG_SBUS is not set -# CONFIG_PCI is not set -CONFIG_UID16=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# General Setup -# -CONFIG_STDIO_CONSOLE=y -CONFIG_NET=y -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_SYSCTL=y -CONFIG_BINFMT_AOUT=y -CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=y -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_SSL=y -CONFIG_HOSTFS=y -CONFIG_MCONSOLE=y -CONFIG_MAGIC_SYSRQ=y -# CONFIG_HOST_2G_2G is not set -# CONFIG_UML_SMP is not set -# CONFIG_SMP is not set -CONFIG_CON_ZERO_CHAN="fd:0,fd:1" -CONFIG_CON_CHAN="xterm" -CONFIG_SSL_CHAN="pty" -CONFIG_NEST_LEVEL=0 -CONFIG_KERNEL_HALF_GIGS=1 - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_KMOD=y - -# -# Devices -# -CONFIG_BLK_DEV_UBD=y -# CONFIG_BLK_DEV_UBD_SYNC is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_NBD=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y -# CONFIG_MMAPPER is not set -CONFIG_UML_SOUND=y -CONFIG_SOUND=y -CONFIG_HOSTAUDIO=y -# CONFIG_UML_WATCHDOG is not set -# CONFIG_TTY_LOG is not set -CONFIG_FD_CHAN=y -# CONFIG_NULL_CHAN is not set -CONFIG_PORT_CHAN=y -CONFIG_PTY_CHAN=y -CONFIG_TTY_CHAN=y -CONFIG_XTERM_CHAN=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK_DEV is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set -# CONFIG_VLAN_8021Q is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network device support -# -CONFIG_UML_NET=y -CONFIG_UML_NET_ETHERTAP=y -CONFIG_UML_NET_TUNTAP=y -CONFIG_UML_NET_SLIP=y -CONFIG_UML_NET_DAEMON=y -CONFIG_UML_NET_MCAST=y -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -CONFIG_DUMMY=y -CONFIG_BONDING=m -CONFIG_EQUALIZER=m -CONFIG_TUN=y -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -# CONFIG_NET_ETHERNET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -CONFIG_PLIP=m -CONFIG_PPP=m -CONFIG_PPP_MULTILINK=y -# CONFIG_PPP_FILTER is not set -# CONFIG_PPP_ASYNC is not set -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -CONFIG_SLIP=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -# CONFIG_SLIP_MODE_SLIP6 is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -CONFIG_SHAPER=m - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# File systems -# -CONFIG_QUOTA=y -CONFIG_AUTOFS_FS=m -CONFIG_AUTOFS4_FS=m -CONFIG_REISERFS_FS=m -# CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set -CONFIG_ADFS_FS=m -# CONFIG_ADFS_FS_RW is not set -CONFIG_AFFS_FS=m -CONFIG_HFS_FS=m -CONFIG_BFS_FS=m -CONFIG_EXT3_FS=y -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -CONFIG_UMSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_EFS_FS=m -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -CONFIG_CRAMFS=m -CONFIG_TMPFS=y -CONFIG_RAMFS=m -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -CONFIG_MINIX_FS=m -CONFIG_VXFS_FS=m -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -CONFIG_HPFS_FS=m -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -CONFIG_QNX4FS_FS=m -# CONFIG_QNX4FS_RW is not set -CONFIG_ROMFS_FS=m -CONFIG_EXT2_FS=y -CONFIG_SYSV_FS=m -CONFIG_UDF_FS=m -CONFIG_UFS_FS=m -# CONFIG_UFS_FS_WRITE is not set - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set -# CONFIG_ZISOFS_FS is not set -CONFIG_ZLIB_FS_INFLATE=m - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Kernel hacking -# -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_INFO is not set -# CONFIG_PT_PROXY is not set -# CONFIG_GPROF is not set -# CONFIG_GCOV is not set diff --git a/arch/um/configs/i386_defconfig b/arch/um/configs/i386_defconfig new file mode 100644 index 00000000000..a12bf68c9f3 --- /dev/null +++ b/arch/um/configs/i386_defconfig @@ -0,0 +1,76 @@ +CONFIG_3_LEVEL_PGTABLES=y +# CONFIG_COMPACTION is not set +CONFIG_BINFMT_MISC=m +CONFIG_HOSTFS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_KERNEL_STACK_ORDER=1 +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CGROUPS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_BLK_CGROUP=y +# CONFIG_PID_NS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_IOSCHED_CFQ=m +CONFIG_SSL=y +CONFIG_NULL_CHAN=y +CONFIG_PORT_CHAN=y +CONFIG_PTY_CHAN=y +CONFIG_TTY_CHAN=y +CONFIG_XTERM_CHAN=y +CONFIG_CON_CHAN="pts" +CONFIG_SSL_CHAN="pts" +CONFIG_UML_SOUND=m +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_BLK_DEV_UBD=y +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_DUMMY=m +CONFIG_TUN=m +CONFIG_PPP=m +CONFIG_SLIP=m +CONFIG_LEGACY_PTY_COUNT=32 +# CONFIG_HW_RANDOM is not set +CONFIG_UML_RANDOM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_UML_NET=y +CONFIG_UML_NET_ETHERTAP=y +CONFIG_UML_NET_TUNTAP=y +CONFIG_UML_NET_SLIP=y +CONFIG_UML_NET_DAEMON=y +CONFIG_UML_NET_MCAST=y +CONFIG_UML_NET_SLIRP=y +CONFIG_EXT4_FS=y +CONFIG_REISERFS_FS=y +CONFIG_QUOTA=y +CONFIG_AUTOFS4_FS=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_NLS=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_KERNEL=y diff --git a/arch/um/configs/x86_64_defconfig b/arch/um/configs/x86_64_defconfig new file mode 100644 index 00000000000..3aab117bd55 --- /dev/null +++ b/arch/um/configs/x86_64_defconfig @@ -0,0 +1,75 @@ +# CONFIG_COMPACTION is not set +CONFIG_BINFMT_MISC=m +CONFIG_HOSTFS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CGROUPS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_BLK_CGROUP=y +# CONFIG_PID_NS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_IOSCHED_CFQ=m +CONFIG_SSL=y +CONFIG_NULL_CHAN=y +CONFIG_PORT_CHAN=y +CONFIG_PTY_CHAN=y +CONFIG_TTY_CHAN=y +CONFIG_XTERM_CHAN=y +CONFIG_CON_CHAN="pts" +CONFIG_SSL_CHAN="pts" +CONFIG_UML_SOUND=m +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_BLK_DEV_UBD=y +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_DUMMY=m +CONFIG_TUN=m +CONFIG_PPP=m +CONFIG_SLIP=m +CONFIG_LEGACY_PTY_COUNT=32 +# CONFIG_HW_RANDOM is not set +CONFIG_UML_RANDOM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_UML_NET=y +CONFIG_UML_NET_ETHERTAP=y +CONFIG_UML_NET_TUNTAP=y +CONFIG_UML_NET_SLIP=y +CONFIG_UML_NET_DAEMON=y +CONFIG_UML_NET_MCAST=y +CONFIG_UML_NET_SLIRP=y +CONFIG_EXT4_FS=y +CONFIG_REISERFS_FS=y +CONFIG_QUOTA=y +CONFIG_AUTOFS4_FS=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_NLS=y +CONFIG_DEBUG_INFO=y +CONFIG_FRAME_WARN=1024 +CONFIG_DEBUG_KERNEL=y diff --git a/arch/um/defconfig b/arch/um/defconfig deleted file mode 100644 index 80d30d19d75..00000000000 --- a/arch/um/defconfig +++ /dev/null @@ -1,459 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc6-mm1 -# Tue Jun 14 18:22:21 2005 -# -CONFIG_GENERIC_HARDIRQS=y -CONFIG_UML=y -CONFIG_MMU=y -CONFIG_UID16=y -CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_GENERIC_CALIBRATE_DELAY=y - -# -# UML-specific options -# -# CONFIG_MODE_TT is not set -# CONFIG_STATIC_LINK is not set -CONFIG_MODE_SKAS=y -CONFIG_UML_X86=y -# CONFIG_64BIT is not set -CONFIG_TOP_ADDR=0xc0000000 -# CONFIG_3_LEVEL_PGTABLES is not set -CONFIG_STUB_CODE=0xbfffe000 -CONFIG_STUB_DATA=0xbffff000 -CONFIG_STUB_START=0xbfffe000 -CONFIG_ARCH_HAS_SC_SIGNALS=y -CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -CONFIG_LD_SCRIPT_DYN=y -CONFIG_NET=y -CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=m -# CONFIG_HOSTFS is not set -CONFIG_MCONSOLE=y -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_HOST_2G_2G is not set -CONFIG_NEST_LEVEL=0 -CONFIG_KERNEL_HALF_GIGS=1 -# CONFIG_HIGHMEM is not set -CONFIG_KERNEL_STACK_ORDER=2 -CONFIG_UML_REAL_TIME_CLOCK=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# -CONFIG_LOCALVERSION="" -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set -# CONFIG_HOTPLUG is not set -CONFIG_KOBJECT_UEVENT=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -# CONFIG_EMBEDDED is not set -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_ALL is not set -CONFIG_KALLSYMS_EXTRA_PASS=y -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_BASE_FULL=y -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y -# CONFIG_MODVERSIONS is not set -# CONFIG_MODULE_SRCVERSION_ALL is not set -CONFIG_KMOD=y - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set -# CONFIG_DEBUG_DRIVER is not set - -# -# Character Devices -# -CONFIG_STDERR_CONSOLE=y -CONFIG_STDIO_CONSOLE=y -CONFIG_SSL=y -CONFIG_NULL_CHAN=y -CONFIG_PORT_CHAN=y -CONFIG_PTY_CHAN=y -CONFIG_TTY_CHAN=y -CONFIG_XTERM_CHAN=y -# CONFIG_NOCONFIG_CHAN is not set -CONFIG_CON_ZERO_CHAN="fd:0,fd:1" -CONFIG_CON_CHAN="xterm" -CONFIG_SSL_CHAN="pty" -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_WATCHDOG is not set -CONFIG_UML_SOUND=m -CONFIG_SOUND=m -CONFIG_HOSTAUDIO=m -CONFIG_UML_RANDOM=y -# CONFIG_MMAPPER is not set - -# -# Block devices -# -CONFIG_BLK_DEV_UBD=y -CONFIG_BLK_DEV_UBD_SYNC=y -CONFIG_BLK_DEV_COW_COMMON=y -CONFIG_BLK_DEV_LOOP=m -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -CONFIG_BLK_DEV_NBD=m -# CONFIG_BLK_DEV_RAM is not set -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_INITRAMFS_SOURCE="" -# CONFIG_LBD is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set -CONFIG_NETDEVICES=y - -# -# UML Network Devices -# -CONFIG_UML_NET=y -CONFIG_UML_NET_ETHERTAP=y -CONFIG_UML_NET_TUNTAP=y -CONFIG_UML_NET_SLIP=y -CONFIG_UML_NET_DAEMON=y -CONFIG_UML_NET_MCAST=y -CONFIG_UML_NET_SLIRP=y - -# -# Networking support -# - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set - -# -# TCP congestion control -# -CONFIG_TCP_CONG_BIC=y -CONFIG_TCP_CONG_WESTWOOD=y -CONFIG_TCP_CONG_HTCP=y -# CONFIG_TCP_CONG_HSTCP is not set -# CONFIG_TCP_CONG_HYBLA is not set -# CONFIG_TCP_CONG_VEGAS is not set -# CONFIG_TCP_CONG_SCALABLE is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_KGDBOE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NETPOLL_RX is not set -# CONFIG_NETPOLL_TRAP is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -# CONFIG_IEEE80211 is not set -CONFIG_DUMMY=m -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -CONFIG_TUN=m - -# -# Wan interfaces -# -# CONFIG_WAN is not set -CONFIG_PPP=m -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_FILTER is not set -# CONFIG_PPP_ASYNC is not set -# CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set -# CONFIG_PPP_BSDCOMP is not set -# CONFIG_PPP_MPPE is not set -# CONFIG_PPPOE is not set -CONFIG_SLIP=m -# CONFIG_SLIP_COMPRESSED is not set -# CONFIG_SLIP_SMART is not set -# CONFIG_SLIP_MODE_SLIP6 is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT2_FS_XIP is not set -CONFIG_EXT3_FS=y -# CONFIG_EXT3_FS_XATTR is not set -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -# CONFIG_REISER4_FS is not set -CONFIG_REISERFS_FS=y -# CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set -# CONFIG_REISERFS_FS_XATTR is not set -# CONFIG_JFS_FS is not set - -# -# XFS support -# -# CONFIG_XFS_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_INOTIFY=y -CONFIG_QUOTA=y -# CONFIG_QFMT_V1 is not set -# CONFIG_QFMT_V2 is not set -CONFIG_QUOTACTL=y -CONFIG_DNOTIFY=y -CONFIG_AUTOFS_FS=m -CONFIG_AUTOFS4_FS=m - -# -# Caches -# -# CONFIG_FSCACHE is not set -# CONFIG_FUSE_FS is not set - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -# CONFIG_ZISOFS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVPTS_FS_XATTR is not set -CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y -# CONFIG_CONFIGFS_FS is not set -# CONFIG_RELAYFS_FS is not set - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -# CONFIG_NFS_FS is not set -# CONFIG_NFSD is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ASCII is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Security options -# -# CONFIG_KEYS is not set -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -# CONFIG_CRYPTO is not set - -# -# Hardware crypto devices -# - -# -# Library routines -# -# CONFIG_CRC_CCITT is not set -CONFIG_CRC32=m -# CONFIG_LIBCRC32C is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_INPUT is not set - -# -# Kernel hacking -# -# CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_DETECT_SOFTLOCKUP=y -# CONFIG_SCHEDSTATS is not set -CONFIG_DEBUG_SLAB=y -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_KOBJECT is not set -CONFIG_DEBUG_INFO=y -# CONFIG_DEBUG_FS is not set -CONFIG_FRAME_POINTER=y -# CONFIG_GPROF is not set -# CONFIG_GCOV is not set -# CONFIG_SYSCALL_DEBUG is not set diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index de17d4c6e02..e7582e1d248 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile @@ -9,7 +9,7 @@ slip-objs := slip_kern.o slip_user.o slirp-objs := slirp_kern.o slirp_user.o daemon-objs := daemon_kern.o daemon_user.o -mcast-objs := mcast_kern.o mcast_user.o +umcast-objs := umcast_kern.o umcast_user.o net-objs := net_kern.o net_user.o mconsole-objs := mconsole_kern.o mconsole_user.o hostaudio-objs := hostaudio_kern.o @@ -17,12 +17,18 @@ ubd-objs := ubd_kern.o ubd_user.o port-objs := port_kern.o port_user.o harddog-objs := harddog_kern.o harddog_user.o -LDFLAGS_pcap.o := -r $(shell $(CC) $(CFLAGS) -print-file-name=libpcap.a) +LDFLAGS_pcap.o := -r $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libpcap.a) -targets := pcap_kern.o pcap_user.o +LDFLAGS_vde.o := -r $(shell $(CC) $(CFLAGS) -print-file-name=libvdeplug.a) + +targets := pcap_kern.o pcap_user.o vde_kern.o vde_user.o $(obj)/pcap.o: $(obj)/pcap_kern.o $(obj)/pcap_user.o $(LD) -r -dp -o $@ $^ $(LDFLAGS) $(LDFLAGS_pcap.o) + +$(obj)/vde.o: $(obj)/vde_kern.o $(obj)/vde_user.o + $(LD) -r -dp -o $@ $^ $(LDFLAGS) $(LDFLAGS_vde.o) + #XXX: The call below does not work because the flags are added before the # object name, so nothing from the library gets linked. #$(call if_changed,ld) @@ -37,7 +43,8 @@ obj-$(CONFIG_STDERR_CONSOLE) += stderr_console.o obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o obj-$(CONFIG_UML_NET_DAEMON) += daemon.o -obj-$(CONFIG_UML_NET_MCAST) += mcast.o +obj-$(CONFIG_UML_NET_VDE) += vde.o +obj-$(CONFIG_UML_NET_MCAST) += umcast.o obj-$(CONFIG_UML_NET_PCAP) += pcap.o obj-$(CONFIG_UML_NET) += net.o obj-$(CONFIG_MCONSOLE) += mconsole.o @@ -54,6 +61,7 @@ obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o obj-$(CONFIG_UML_RANDOM) += random.o # pcap_user.o must be added explicitly. -USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o +USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o +CFLAGS_null.o = -DDEV_NULL=$(DEV_NULL_PATH) include arch/um/scripts/Makefile.rules diff --git a/arch/um/drivers/chan.h b/arch/um/drivers/chan.h new file mode 100644 index 00000000000..c512b0306dd --- /dev/null +++ b/arch/um/drivers/chan.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __CHAN_KERN_H__ +#define __CHAN_KERN_H__ + +#include <linux/tty.h> +#include <linux/list.h> +#include <linux/console.h> +#include "chan_user.h" +#include "line.h" + +struct chan { + struct list_head list; + struct list_head free_list; + struct line *line; + char *dev; + unsigned int primary:1; + unsigned int input:1; + unsigned int output:1; + unsigned int opened:1; + unsigned int enabled:1; + int fd; + const struct chan_ops *ops; + void *data; +}; + +extern void chan_interrupt(struct line *line, int irq); +extern int parse_chan_pair(char *str, struct line *line, int device, + const struct chan_opts *opts, char **error_out); +extern int write_chan(struct chan *chan, const char *buf, int len, + int write_irq); +extern int console_write_chan(struct chan *chan, const char *buf, + int len); +extern int console_open_chan(struct line *line, struct console *co); +extern void deactivate_chan(struct chan *chan, int irq); +extern void reactivate_chan(struct chan *chan, int irq); +extern void chan_enable_winch(struct chan *chan, struct tty_port *port); +extern int enable_chan(struct line *line); +extern void close_chan(struct line *line); +extern int chan_window_size(struct line *line, + unsigned short *rows_out, + unsigned short *cols_out); +extern int chan_config_string(struct line *line, char *str, int size, + char **error_out); + +#endif diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 16e7dc89f61..acbe6c67afb 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -1,117 +1,74 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) * Licensed under the GPL */ -#include <linux/stddef.h> -#include <linux/kernel.h> -#include <linux/list.h> #include <linux/slab.h> #include <linux/tty.h> -#include <linux/string.h> #include <linux/tty_flip.h> -#include <asm/irq.h> -#include "chan_kern.h" -#include "user_util.h" -#include "kern.h" -#include "irq_user.h" -#include "sigio.h" -#include "line.h" -#include "os.h" - -/* XXX: could well be moved to somewhere else, if needed. */ -static int my_printf(const char * fmt, ...) - __attribute__ ((format (printf, 1, 2))); - -static int my_printf(const char * fmt, ...) -{ - /* Yes, can be called on atomic context.*/ - char *buf = kmalloc(4096, GFP_ATOMIC); - va_list args; - int r; - - if (!buf) { - /* We print directly fmt. - * Yes, yes, yes, feel free to complain. */ - r = strlen(fmt); - } else { - va_start(args, fmt); - r = vsprintf(buf, fmt, args); - va_end(args); - fmt = buf; - } - - if (r) - r = os_write_file(1, fmt, r); - return r; - -} +#include "chan.h" +#include <os.h> +#include <irq_kern.h> #ifdef CONFIG_NOCONFIG_CHAN -/* Despite its name, there's no added trailing newline. */ -static int my_puts(const char * buf) -{ - return os_write_file(1, buf, strlen(buf)); -} - -static void *not_configged_init(char *str, int device, struct chan_opts *opts) +static void *not_configged_init(char *str, int device, + const struct chan_opts *opts) { - my_puts("Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); - return(NULL); + return NULL; } static int not_configged_open(int input, int output, int primary, void *data, char **dev_out) { - my_puts("Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); - return(-ENODEV); + return -ENODEV; } static void not_configged_close(int fd, void *data) { - my_puts("Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); } static int not_configged_read(int fd, char *c_out, void *data) { - my_puts("Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); - return(-EIO); + return -EIO; } static int not_configged_write(int fd, const char *buf, int len, void *data) { - my_puts("Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); - return(-EIO); + return -EIO; } -static int not_configged_console_write(int fd, const char *buf, int len, - void *data) +static int not_configged_console_write(int fd, const char *buf, int len) { - my_puts("Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); - return(-EIO); + return -EIO; } static int not_configged_window_size(int fd, void *data, unsigned short *rows, unsigned short *cols) { - my_puts("Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); - return(-ENODEV); + return -ENODEV; } static void not_configged_free(void *data) { - my_puts("Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); } -static struct chan_ops not_configged_ops = { +static const struct chan_ops not_configged_ops = { .init = not_configged_init, .open = not_configged_open, .close = not_configged_close, @@ -124,133 +81,154 @@ static struct chan_ops not_configged_ops = { }; #endif /* CONFIG_NOCONFIG_CHAN */ -void generic_close(int fd, void *unused) +static int open_one_chan(struct chan *chan) { - os_close_file(fd); -} - -int generic_read(int fd, char *c_out, void *unused) -{ - int n; + int fd, err; - n = os_read_file(fd, c_out, sizeof(*c_out)); + if (chan->opened) + return 0; - if(n == -EAGAIN) - return(0); - else if(n == 0) - return(-EIO); - return(n); -} + if (chan->ops->open == NULL) + fd = 0; + else fd = (*chan->ops->open)(chan->input, chan->output, chan->primary, + chan->data, &chan->dev); + if (fd < 0) + return fd; + + err = os_set_fd_block(fd, 0); + if (err) { + (*chan->ops->close)(fd, chan->data); + return err; + } -/* XXX Trivial wrapper around os_write_file */ + chan->fd = fd; -int generic_write(int fd, const char *buf, int n, void *unused) -{ - return(os_write_file(fd, buf, n)); + chan->opened = 1; + return 0; } -int generic_window_size(int fd, void *unused, unsigned short *rows_out, - unsigned short *cols_out) +static int open_chan(struct list_head *chans) { - int rows, cols; - int ret; - - ret = os_window_size(fd, &rows, &cols); - if(ret < 0) - return(ret); - - ret = ((*rows_out != rows) || (*cols_out != cols)); - - *rows_out = rows; - *cols_out = cols; + struct list_head *ele; + struct chan *chan; + int ret, err = 0; - return(ret); + list_for_each(ele, chans) { + chan = list_entry(ele, struct chan, list); + ret = open_one_chan(chan); + if (chan->primary) + err = ret; + } + return err; } -void generic_free(void *data) +void chan_enable_winch(struct chan *chan, struct tty_port *port) { - kfree(data); + if (chan && chan->primary && chan->ops->winch) + register_winch(chan->fd, port); } -static void tty_receive_char(struct tty_struct *tty, char ch) +static void line_timer_cb(struct work_struct *work) { - if(tty == NULL) return; + struct line *line = container_of(work, struct line, task.work); - if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) { - if(ch == STOP_CHAR(tty)){ - stop_tty(tty); - return; - } - else if(ch == START_CHAR(tty)){ - start_tty(tty); - return; - } - } - - if((tty->flip.flag_buf_ptr == NULL) || - (tty->flip.char_buf_ptr == NULL)) - return; - tty_insert_flip_char(tty, ch, TTY_NORMAL); -} - -static int open_one_chan(struct chan *chan, int input, int output, int primary) -{ - int fd; - - if(chan->opened) return(0); - if(chan->ops->open == NULL) fd = 0; - else fd = (*chan->ops->open)(input, output, primary, chan->data, - &chan->dev); - if(fd < 0) return(fd); - chan->fd = fd; - - chan->opened = 1; - return(0); + if (!line->throttled) + chan_interrupt(line, line->driver->read_irq); } -int open_chan(struct list_head *chans) +int enable_chan(struct line *line) { struct list_head *ele; struct chan *chan; - int ret, err = 0; + int err; - list_for_each(ele, chans){ + INIT_DELAYED_WORK(&line->task, line_timer_cb); + + list_for_each(ele, &line->chan_list) { chan = list_entry(ele, struct chan, list); - ret = open_one_chan(chan, chan->input, chan->output, - chan->primary); - if(chan->primary) err = ret; + err = open_one_chan(chan); + if (err) { + if (chan->primary) + goto out_close; + + continue; + } + + if (chan->enabled) + continue; + err = line_setup_irq(chan->fd, chan->input, chan->output, line, + chan); + if (err) + goto out_close; + + chan->enabled = 1; } - return(err); + + return 0; + + out_close: + close_chan(line); + return err; } -void chan_enable_winch(struct list_head *chans, struct tty_struct *tty) +/* Items are added in IRQ context, when free_irq can't be called, and + * removed in process context, when it can. + * This handles interrupt sources which disappear, and which need to + * be permanently disabled. This is discovered in IRQ context, but + * the freeing of the IRQ must be done later. + */ +static DEFINE_SPINLOCK(irqs_to_free_lock); +static LIST_HEAD(irqs_to_free); + +void free_irqs(void) { - struct list_head *ele; struct chan *chan; + LIST_HEAD(list); + struct list_head *ele; + unsigned long flags; - list_for_each(ele, chans){ - chan = list_entry(ele, struct chan, list); - if(chan->primary && chan->output && chan->ops->winch){ - register_winch(chan->fd, tty); - return; - } + spin_lock_irqsave(&irqs_to_free_lock, flags); + list_splice_init(&irqs_to_free, &list); + spin_unlock_irqrestore(&irqs_to_free_lock, flags); + + list_for_each(ele, &list) { + chan = list_entry(ele, struct chan, free_list); + + if (chan->input && chan->enabled) + um_free_irq(chan->line->driver->read_irq, chan); + if (chan->output && chan->enabled) + um_free_irq(chan->line->driver->write_irq, chan); + chan->enabled = 0; } } -void enable_chan(struct list_head *chans, struct tty_struct *tty) +static void close_one_chan(struct chan *chan, int delay_free_irq) { - struct list_head *ele; - struct chan *chan; + unsigned long flags; - list_for_each(ele, chans){ - chan = list_entry(ele, struct chan, list); - if(!chan->opened) continue; + if (!chan->opened) + return; - line_setup_irq(chan->fd, chan->input, chan->output, tty); + if (delay_free_irq) { + spin_lock_irqsave(&irqs_to_free_lock, flags); + list_add(&chan->free_list, &irqs_to_free); + spin_unlock_irqrestore(&irqs_to_free_lock, flags); + } + else { + if (chan->input && chan->enabled) + um_free_irq(chan->line->driver->read_irq, chan); + if (chan->output && chan->enabled) + um_free_irq(chan->line->driver->write_irq, chan); + chan->enabled = 0; } + if (chan->ops->close != NULL) + (*chan->ops->close)(chan->fd, chan->data); + + chan->opened = 0; + chan->fd = -1; } -void close_chan(struct list_head *chans) +void close_chan(struct line *line) { struct chan *chan; @@ -259,99 +237,108 @@ void close_chan(struct list_head *chans) * state. Then, the first one opened will have the original state, * so it must be the last closed. */ - list_for_each_entry_reverse(chan, chans, list) { - if(!chan->opened) continue; - if(chan->ops->close != NULL) - (*chan->ops->close)(chan->fd, chan->data); - chan->opened = 0; - chan->fd = -1; + list_for_each_entry_reverse(chan, &line->chan_list, list) { + close_one_chan(chan, 0); } } -int write_chan(struct list_head *chans, const char *buf, int len, +void deactivate_chan(struct chan *chan, int irq) +{ + if (chan && chan->enabled) + deactivate_fd(chan->fd, irq); +} + +void reactivate_chan(struct chan *chan, int irq) +{ + if (chan && chan->enabled) + reactivate_fd(chan->fd, irq); +} + +int write_chan(struct chan *chan, const char *buf, int len, int write_irq) { - struct list_head *ele; - struct chan *chan = NULL; int n, ret = 0; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->output || (chan->ops->write == NULL)) - continue; - n = chan->ops->write(chan->fd, buf, len, chan->data); - if (chan->primary) { - ret = n; - if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len))) - reactivate_fd(chan->fd, write_irq); - } + if (len == 0 || !chan || !chan->ops->write) + return 0; + + n = chan->ops->write(chan->fd, buf, len, chan->data); + if (chan->primary) { + ret = n; + if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len))) + reactivate_fd(chan->fd, write_irq); } - return(ret); + return ret; } -int console_write_chan(struct list_head *chans, const char *buf, int len) +int console_write_chan(struct chan *chan, const char *buf, int len) { - struct list_head *ele; - struct chan *chan; int n, ret = 0; - list_for_each(ele, chans){ - chan = list_entry(ele, struct chan, list); - if(!chan->output || (chan->ops->console_write == NULL)) - continue; - n = chan->ops->console_write(chan->fd, buf, len, chan->data); - if(chan->primary) ret = n; - } - return(ret); + if (!chan || !chan->ops->console_write) + return 0; + + n = chan->ops->console_write(chan->fd, buf, len); + if (chan->primary) + ret = n; + return ret; } -int console_open_chan(struct line *line, struct console *co, struct chan_opts *opts) +int console_open_chan(struct line *line, struct console *co) { - if (!list_empty(&line->chan_list)) - return 0; + int err; + + err = open_chan(&line->chan_list); + if (err) + return err; - if (0 != parse_chan_pair(line->init_str, &line->chan_list, - line->init_pri, co->index, opts)) - return -1; - if (0 != open_chan(&line->chan_list)) - return -1; - printk("Console initialized on /dev/%s%d\n",co->name,co->index); + printk(KERN_INFO "Console initialized on /dev/%s%d\n", co->name, + co->index); return 0; } -int chan_window_size(struct list_head *chans, unsigned short *rows_out, +int chan_window_size(struct line *line, unsigned short *rows_out, unsigned short *cols_out) { - struct list_head *ele; struct chan *chan; - list_for_each(ele, chans){ - chan = list_entry(ele, struct chan, list); - if(chan->primary){ - if(chan->ops->window_size == NULL) return(0); - return(chan->ops->window_size(chan->fd, chan->data, - rows_out, cols_out)); - } + chan = line->chan_in; + if (chan && chan->primary) { + if (chan->ops->window_size == NULL) + return 0; + return chan->ops->window_size(chan->fd, chan->data, + rows_out, cols_out); + } + chan = line->chan_out; + if (chan && chan->primary) { + if (chan->ops->window_size == NULL) + return 0; + return chan->ops->window_size(chan->fd, chan->data, + rows_out, cols_out); } - return(0); + return 0; } -void free_one_chan(struct chan *chan) +static void free_one_chan(struct chan *chan) { list_del(&chan->list); - if(chan->ops->free != NULL) + + close_one_chan(chan, 0); + + if (chan->ops->free != NULL) (*chan->ops->free)(chan->data); - free_irq_by_fd(chan->fd); - if(chan->primary && chan->output) ignore_sigio_fd(chan->fd); + + if (chan->primary && chan->output) + ignore_sigio_fd(chan->fd); kfree(chan); } -void free_chan(struct list_head *chans) +static void free_chan(struct list_head *chans) { struct list_head *ele, *next; struct chan *chan; - list_for_each_safe(ele, next, chans){ + list_for_each_safe(ele, next, chans) { chan = list_entry(ele, struct chan, list); free_one_chan(chan); } @@ -362,25 +349,25 @@ static int one_chan_config_string(struct chan *chan, char *str, int size, { int n = 0; - if(chan == NULL){ + if (chan == NULL) { CONFIG_CHUNK(str, size, n, "none", 1); - return(n); + return n; } CONFIG_CHUNK(str, size, n, chan->ops->type, 0); - if(chan->dev == NULL){ + if (chan->dev == NULL) { CONFIG_CHUNK(str, size, n, "", 1); - return(n); + return n; } CONFIG_CHUNK(str, size, n, ":", 0); CONFIG_CHUNK(str, size, n, chan->dev, 0); - return(n); + return n; } -static int chan_pair_config_string(struct chan *in, struct chan *out, +static int chan_pair_config_string(struct chan *in, struct chan *out, char *str, int size, char **error_out) { int n; @@ -389,9 +376,9 @@ static int chan_pair_config_string(struct chan *in, struct chan *out, str += n; size -= n; - if(in == out){ + if (in == out) { CONFIG_CHUNK(str, size, n, "", 1); - return(n); + return n; } CONFIG_CHUNK(str, size, n, ",", 1); @@ -400,34 +387,28 @@ static int chan_pair_config_string(struct chan *in, struct chan *out, size -= n; CONFIG_CHUNK(str, size, n, "", 1); - return(n); + return n; } -int chan_config_string(struct list_head *chans, char *str, int size, +int chan_config_string(struct line *line, char *str, int size, char **error_out) { - struct list_head *ele; - struct chan *chan, *in = NULL, *out = NULL; + struct chan *in = line->chan_in, *out = line->chan_out; - list_for_each(ele, chans){ - chan = list_entry(ele, struct chan, list); - if(!chan->primary) - continue; - if(chan->input) - in = chan; - if(chan->output) - out = chan; - } + if (in && !in->primary) + in = NULL; + if (out && !out->primary) + out = NULL; - return(chan_pair_config_string(in, out, str, size, error_out)); + return chan_pair_config_string(in, out, str, size, error_out); } struct chan_type { char *key; - struct chan_ops *ops; + const struct chan_ops *ops; }; -struct chan_type chan_table[] = { +static const struct chan_type chan_table[] = { { "fd", &fd_ops }, #ifdef CONFIG_NULL_CHAN @@ -463,149 +444,138 @@ struct chan_type chan_table[] = { #endif }; -static struct chan *parse_chan(char *str, int pri, int device, - struct chan_opts *opts) +static struct chan *parse_chan(struct line *line, char *str, int device, + const struct chan_opts *opts, char **error_out) { - struct chan_type *entry; - struct chan_ops *ops; + const struct chan_type *entry; + const struct chan_ops *ops; struct chan *chan; void *data; int i; ops = NULL; data = NULL; - for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){ + for(i = 0; i < ARRAY_SIZE(chan_table); i++) { entry = &chan_table[i]; - if(!strncmp(str, entry->key, strlen(entry->key))){ + if (!strncmp(str, entry->key, strlen(entry->key))) { ops = entry->ops; str += strlen(entry->key); break; } } - if(ops == NULL){ - my_printf("parse_chan couldn't parse \"%s\"\n", - str); - return(NULL); + if (ops == NULL) { + *error_out = "No match for configured backends"; + return NULL; } - if(ops->init == NULL) return(NULL); + data = (*ops->init)(str, device, opts); - if(data == NULL) return(NULL); + if (data == NULL) { + *error_out = "Configuration failed"; + return NULL; + } chan = kmalloc(sizeof(*chan), GFP_ATOMIC); - if(chan == NULL) return(NULL); + if (chan == NULL) { + *error_out = "Memory allocation failed"; + return NULL; + } *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), + .free_list = + LIST_HEAD_INIT(chan->free_list), + .line = line, .primary = 1, .input = 0, .output = 0, .opened = 0, + .enabled = 0, .fd = -1, - .pri = pri, .ops = ops, .data = data }); - return(chan); + return chan; } -int parse_chan_pair(char *str, struct list_head *chans, int pri, int device, - struct chan_opts *opts) +int parse_chan_pair(char *str, struct line *line, int device, + const struct chan_opts *opts, char **error_out) { - struct chan *new, *chan; + struct list_head *chans = &line->chan_list; + struct chan *new; char *in, *out; - if(!list_empty(chans)){ - chan = list_entry(chans->next, struct chan, list); - if(chan->pri >= pri) return(0); + if (!list_empty(chans)) { + line->chan_in = line->chan_out = NULL; free_chan(chans); INIT_LIST_HEAD(chans); } + if (!str) + return 0; + out = strchr(str, ','); - if(out != NULL){ + if (out != NULL) { in = str; *out = '\0'; out++; - new = parse_chan(in, pri, device, opts); - if(new == NULL) return(-1); + new = parse_chan(line, in, device, opts, error_out); + if (new == NULL) + return -1; + new->input = 1; list_add(&new->list, chans); + line->chan_in = new; + + new = parse_chan(line, out, device, opts, error_out); + if (new == NULL) + return -1; - new = parse_chan(out, pri, device, opts); - if(new == NULL) return(-1); list_add(&new->list, chans); new->output = 1; + line->chan_out = new; } else { - new = parse_chan(str, pri, device, opts); - if(new == NULL) return(-1); + new = parse_chan(line, str, device, opts, error_out); + if (new == NULL) + return -1; + list_add(&new->list, chans); new->input = 1; new->output = 1; + line->chan_in = line->chan_out = new; } - return(0); -} - -int chan_out_fd(struct list_head *chans) -{ - struct list_head *ele; - struct chan *chan; - - list_for_each(ele, chans){ - chan = list_entry(ele, struct chan, list); - if(chan->primary && chan->output) - return(chan->fd); - } - return(-1); + return 0; } -void chan_interrupt(struct list_head *chans, struct work_struct *task, - struct tty_struct *tty, int irq) +void chan_interrupt(struct line *line, int irq) { - struct list_head *ele, *next; - struct chan *chan; + struct tty_port *port = &line->port; + struct chan *chan = line->chan_in; int err; char c; - list_for_each_safe(ele, next, chans){ - chan = list_entry(ele, struct chan, list); - if(!chan->input || (chan->ops->read == NULL)) continue; - do { - if((tty != NULL) && - (tty->flip.count >= TTY_FLIPBUF_SIZE)){ - schedule_work(task); - goto out; - } - err = chan->ops->read(chan->fd, &c, chan->data); - if(err > 0) - tty_receive_char(tty, c); - } while(err > 0); - - if(err == 0) reactivate_fd(chan->fd, irq); - if(err == -EIO){ - if(chan->primary){ - if(tty != NULL) - tty_hangup(tty); - line_disable(tty, irq); - close_chan(chans); - free_chan(chans); - return; - } - else { - if(chan->ops->close != NULL) - chan->ops->close(chan->fd, chan->data); - free_one_chan(chan); - } + if (!chan || !chan->ops->read) + goto out; + + do { + if (!tty_buffer_request_room(port, 1)) { + schedule_delayed_work(&line->task, 1); + goto out; + } + err = chan->ops->read(chan->fd, &c, chan->data); + if (err > 0) + tty_insert_flip_char(port, c, TTY_NORMAL); + } while (err > 0); + + if (err == 0) + reactivate_fd(chan->fd, irq); + if (err == -EIO) { + if (chan->primary) { + tty_port_tty_hangup(&line->port, false); + if (line->chan_out != chan) + close_one_chan(line->chan_out, 1); } + close_one_chan(chan, 1); + if (chan->primary) + return; } out: - if(tty) tty_flip_buffer_push(tty); + tty_flip_buffer_push(port); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 1c55d580248..3fd7c3efdb1 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -1,69 +1,135 @@ -/* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) * Licensed under the GPL */ -#include <unistd.h> #include <stdlib.h> +#include <unistd.h> #include <errno.h> -#include <termios.h> -#include <string.h> +#include <sched.h> #include <signal.h> -#include <sys/stat.h> +#include <termios.h> #include <sys/ioctl.h> -#include <sys/socket.h> -#include "kern_util.h" -#include "user_util.h" #include "chan_user.h" -#include "user.h" -#include "os.h" -#include "choose-mode.h" -#include "mode.h" +#include <os.h> +#include <um_malloc.h> + +void generic_close(int fd, void *unused) +{ + close(fd); +} -int generic_console_write(int fd, const char *buf, int n, void *unused) +int generic_read(int fd, char *c_out, void *unused) { + int n; + + n = read(fd, c_out, sizeof(*c_out)); + if (n > 0) + return n; + else if (errno == EAGAIN) + return 0; + else if (n == 0) + return -EIO; + return -errno; +} + +/* XXX Trivial wrapper around write */ + +int generic_write(int fd, const char *buf, int n, void *unused) +{ + int err; + + err = write(fd, buf, n); + if (err > 0) + return err; + else if (errno == EAGAIN) + return 0; + else if (err == 0) + return -EIO; + return -errno; +} + +int generic_window_size(int fd, void *unused, unsigned short *rows_out, + unsigned short *cols_out) +{ + struct winsize size; + int ret; + + if (ioctl(fd, TIOCGWINSZ, &size) < 0) + return -errno; + + ret = ((*rows_out != size.ws_row) || (*cols_out != size.ws_col)); + + *rows_out = size.ws_row; + *cols_out = size.ws_col; + + return ret; +} + +void generic_free(void *data) +{ + kfree(data); +} + +int generic_console_write(int fd, const char *buf, int n) +{ + sigset_t old, no_sigio; struct termios save, new; int err; - if(isatty(fd)){ + if (isatty(fd)) { + sigemptyset(&no_sigio); + sigaddset(&no_sigio, SIGIO); + if (sigprocmask(SIG_BLOCK, &no_sigio, &old)) + goto error; + CATCH_EINTR(err = tcgetattr(fd, &save)); if (err) goto error; new = save; - /* The terminal becomes a bit less raw, to handle \n also as + /* + * The terminal becomes a bit less raw, to handle \n also as * "Carriage Return", not only as "New Line". Otherwise, the new - * line won't start at the first column.*/ + * line won't start at the first column. + */ new.c_oflag |= OPOST; CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new)); if (err) goto error; } err = generic_write(fd, buf, n, NULL); - /* Restore raw mode, in any case; we *must* ignore any error apart - * EINTR, except for debug.*/ - if(isatty(fd)) + /* + * Restore raw mode, in any case; we *must* ignore any error apart + * EINTR, except for debug. + */ + if (isatty(fd)) { CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save)); - return(err); + sigprocmask(SIG_SETMASK, &old, NULL); + } + + return err; error: - return(-errno); + return -errno; } /* * UML SIGWINCH handling * - * The point of this is to handle SIGWINCH on consoles which have host ttys and - * relay them inside UML to whatever might be running on the console and cares - * about the window size (since SIGWINCH notifies about terminal size changes). + * The point of this is to handle SIGWINCH on consoles which have host + * ttys and relay them inside UML to whatever might be running on the + * console and cares about the window size (since SIGWINCH notifies + * about terminal size changes). * - * So, we have a separate thread for each host tty attached to a UML device - * (side-issue - I'm annoyed that one thread can't have multiple controlling - * ttys for purposed of handling SIGWINCH, but I imagine there are other reasons - * that doesn't make any sense). + * So, we have a separate thread for each host tty attached to a UML + * device (side-issue - I'm annoyed that one thread can't have + * multiple controlling ttys for the purpose of handling SIGWINCH, but + * I imagine there are other reasons that doesn't make any sense). * - * SIGWINCH can't be received synchronously, so you have to set up to receive it - * as a signal. That being the case, if you are going to wait for it, it is - * convenient to sit in sigsuspend() and wait for the signal to bounce you out of - * it (see below for how we make sure to exit only on SIGWINCH). + * SIGWINCH can't be received synchronously, so you have to set up to + * receive it as a signal. That being the case, if you are going to + * wait for it, it is convenient to sit in sigsuspend() and wait for + * the signal to bounce you out of it (see below for how we make sure + * to exit only on SIGWINCH). */ static void winch_handler(int sig) @@ -73,7 +139,6 @@ static void winch_handler(int sig) struct winch_data { int pty_fd; int pipe_fd; - int close_me; }; static int winch_thread(void *arg) @@ -81,138 +146,156 @@ static int winch_thread(void *arg) struct winch_data *data = arg; sigset_t sigs; int pty_fd, pipe_fd; - int count, err; + int count; char c = 1; - os_close_file(data->close_me); pty_fd = data->pty_fd; pipe_fd = data->pipe_fd; - count = os_write_file(pipe_fd, &c, sizeof(c)); - if(count != sizeof(c)) - printk("winch_thread : failed to write synchronization " - "byte, err = %d\n", -count); + count = write(pipe_fd, &c, sizeof(c)); + if (count != sizeof(c)) + printk(UM_KERN_ERR "winch_thread : failed to write " + "synchronization byte, err = %d\n", -count); - /* We are not using SIG_IGN on purpose, so don't fix it as I thought to + /* + * We are not using SIG_IGN on purpose, so don't fix it as I thought to * do! If using SIG_IGN, the sigsuspend() call below would not stop on - * SIGWINCH. */ + * SIGWINCH. + */ signal(SIGWINCH, winch_handler); sigfillset(&sigs); /* Block all signals possible. */ - if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){ - printk("winch_thread : sigprocmask failed, errno = %d\n", - errno); + if (sigprocmask(SIG_SETMASK, &sigs, NULL) < 0) { + printk(UM_KERN_ERR "winch_thread : sigprocmask failed, " + "errno = %d\n", errno); exit(1); } /* In sigsuspend(), block anything else than SIGWINCH. */ sigdelset(&sigs, SIGWINCH); - if(setsid() < 0){ - printk("winch_thread : setsid failed, errno = %d\n", errno); + if (setsid() < 0) { + printk(UM_KERN_ERR "winch_thread : setsid failed, errno = %d\n", + errno); + exit(1); + } + + if (ioctl(pty_fd, TIOCSCTTY, 0) < 0) { + printk(UM_KERN_ERR "winch_thread : TIOCSCTTY failed on " + "fd %d err = %d\n", pty_fd, errno); exit(1); } - err = os_new_tty_pgrp(pty_fd, os_getpid()); - if(err < 0){ - printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err); + if (tcsetpgrp(pty_fd, os_getpid()) < 0) { + printk(UM_KERN_ERR "winch_thread : tcsetpgrp failed on " + "fd %d err = %d\n", pty_fd, errno); exit(1); } - /* These are synchronization calls between various UML threads on the + /* + * These are synchronization calls between various UML threads on the * host - since they are not different kernel threads, we cannot use * kernel semaphores. We don't use SysV semaphores because they are - * persistant. */ - count = os_read_file(pipe_fd, &c, sizeof(c)); - if(count != sizeof(c)) - printk("winch_thread : failed to read synchronization byte, " - "err = %d\n", -count); - - while(1){ - /* This will be interrupted by SIGWINCH only, since other signals - * are blocked.*/ + * persistent. + */ + count = read(pipe_fd, &c, sizeof(c)); + if (count != sizeof(c)) + printk(UM_KERN_ERR "winch_thread : failed to read " + "synchronization byte, err = %d\n", errno); + + while(1) { + /* + * This will be interrupted by SIGWINCH only, since + * other signals are blocked. + */ sigsuspend(&sigs); - count = os_write_file(pipe_fd, &c, sizeof(c)); - if(count != sizeof(c)) - printk("winch_thread : write failed, err = %d\n", - -count); + count = write(pipe_fd, &c, sizeof(c)); + if (count != sizeof(c)) + printk(UM_KERN_ERR "winch_thread : write failed, " + "err = %d\n", errno); } } -static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out) +static int winch_tramp(int fd, struct tty_port *port, int *fd_out, + unsigned long *stack_out) { struct winch_data data; - unsigned long stack; int fds[2], n, err; char c; err = os_pipe(fds, 1, 1); - if(err < 0){ - printk("winch_tramp : os_pipe failed, err = %d\n", -err); + if (err < 0) { + printk(UM_KERN_ERR "winch_tramp : os_pipe failed, err = %d\n", + -err); goto out; } data = ((struct winch_data) { .pty_fd = fd, - .pipe_fd = fds[1], - .close_me = fds[0] } ); - err = run_helper_thread(winch_thread, &data, 0, &stack, 0); - if(err < 0){ - printk("fork of winch_thread failed - errno = %d\n", errno); + .pipe_fd = fds[1] } ); + /* + * CLONE_FILES so this thread doesn't hold open files which are open + * now, but later closed in a different thread. This is a + * problem with /dev/net/tun, which if held open by this + * thread, prevents the TUN/TAP device from being reused. + */ + err = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out); + if (err < 0) { + printk(UM_KERN_ERR "fork of winch_thread failed - errno = %d\n", + -err); goto out_close; } - os_close_file(fds[1]); *fd_out = fds[0]; - n = os_read_file(fds[0], &c, sizeof(c)); - if(n != sizeof(c)){ - printk("winch_tramp : failed to read synchronization byte\n"); - printk("read failed, err = %d\n", -n); - printk("fd %d will not support SIGWINCH\n", fd); - err = -EINVAL; - goto out_close1; + n = read(fds[0], &c, sizeof(c)); + if (n != sizeof(c)) { + printk(UM_KERN_ERR "winch_tramp : failed to read " + "synchronization byte\n"); + printk(UM_KERN_ERR "read failed, err = %d\n", errno); + printk(UM_KERN_ERR "fd %d will not support SIGWINCH\n", fd); + err = -EINVAL; + goto out_close; + } + + if (os_set_fd_block(*fd_out, 0)) { + printk(UM_KERN_ERR "winch_tramp: failed to set thread_fd " + "non-blocking.\n"); + goto out_close; } - return err ; + + return err; out_close: - os_close_file(fds[1]); - out_close1: - os_close_file(fds[0]); + close(fds[1]); + close(fds[0]); out: return err; } -void register_winch(int fd, struct tty_struct *tty) +void register_winch(int fd, struct tty_port *port) { - int pid, thread, thread_fd = -1; - int count; + unsigned long stack; + int pid, thread, count, thread_fd = -1; char c = 1; - if(!isatty(fd)) + if (!isatty(fd)) return; pid = tcgetpgrp(fd); - if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, - tty) && (pid == -1)){ - thread = winch_tramp(fd, tty, &thread_fd); - if(thread > 0){ - register_winch_irq(thread_fd, fd, thread, tty); - - count = os_write_file(thread_fd, &c, sizeof(c)); - if(count != sizeof(c)) - printk("register_winch : failed to write " - "synchronization byte, err = %d\n", - -count); - } + if (is_skas_winch(pid, fd, port)) { + register_winch_irq(-1, fd, -1, port, 0); + return; } -} -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ + if (pid == -1) { + thread = winch_tramp(fd, port, &thread_fd, &stack); + if (thread < 0) + return; + + register_winch_irq(thread_fd, fd, thread, port, stack); + + count = write(thread_fd, &c, sizeof(c)); + if (count != sizeof(c)) + printk(UM_KERN_ERR "register_winch : failed to write " + "synchronization byte, err = %d\n", errno); + } +} diff --git a/arch/um/drivers/chan_user.h b/arch/um/drivers/chan_user.h new file mode 100644 index 00000000000..03f1b565c5f --- /dev/null +++ b/arch/um/drivers/chan_user.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __CHAN_USER_H__ +#define __CHAN_USER_H__ + +#include <init.h> + +struct chan_opts { + void (*const announce)(char *dev_name, int dev); + char *xterm_title; + const int raw; +}; + +struct chan_ops { + char *type; + void *(*init)(char *, int, const struct chan_opts *); + int (*open)(int, int, int, void *, char **); + void (*close)(int, void *); + int (*read)(int, char *, void *); + int (*write)(int, const char *, int, void *); + int (*console_write)(int, const char *, int); + int (*window_size)(int, void *, unsigned short *, unsigned short *); + void (*free)(void *); + int winch; +}; + +extern const struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, + tty_ops, xterm_ops; + +extern void generic_close(int fd, void *unused); +extern int generic_read(int fd, char *c_out, void *unused); +extern int generic_write(int fd, const char *buf, int n, void *unused); +extern int generic_console_write(int fd, const char *buf, int n); +extern int generic_window_size(int fd, void *unused, unsigned short *rows_out, + unsigned short *cols_out); +extern void generic_free(void *data); + +struct tty_port; +extern void register_winch(int fd, struct tty_port *port); +extern void register_winch_irq(int fd, int tty_fd, int pid, + struct tty_port *port, unsigned long stack); + +#define __channel_help(fn, prefix) \ +__uml_help(fn, prefix "[0-9]*=<channel description>\n" \ +" Attach a console or serial line to a host channel. See\n" \ +" http://user-mode-linux.sourceforge.net/old/input.html for a complete\n" \ +" description of this switch.\n\n" \ +); + +#endif diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h index dc36b222100..6673508f342 100644 --- a/arch/um/drivers/cow.h +++ b/arch/um/drivers/cow.h @@ -3,41 +3,6 @@ #include <asm/types.h> -#if defined(__KERNEL__) - -# include <asm/byteorder.h> - -# if defined(__BIG_ENDIAN) -# define ntohll(x) (x) -# define htonll(x) (x) -# elif defined(__LITTLE_ENDIAN) -# define ntohll(x) be64_to_cpu(x) -# define htonll(x) cpu_to_be64(x) -# else -# error "Could not determine byte order" -# endif - -#else -/* For the definition of ntohl, htonl and __BYTE_ORDER */ -#include <endian.h> -#include <netinet/in.h> -#if defined(__BYTE_ORDER) - -# if __BYTE_ORDER == __BIG_ENDIAN -# define ntohll(x) (x) -# define htonll(x) (x) -# elif __BYTE_ORDER == __LITTLE_ENDIAN -# define ntohll(x) bswap_64(x) -# define htonll(x) bswap_64(x) -# else -# error "Could not determine byte order: __BYTE_ORDER uncorrectly defined" -# endif - -#else /* ! defined(__BYTE_ORDER) */ -# error "Could not determine byte order: __BYTE_ORDER not defined" -#endif -#endif /* ! defined(__KERNEL__) */ - extern int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out); diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h index c83fc5d6893..67cbee63e70 100644 --- a/arch/um/drivers/cow_sys.h +++ b/arch/um/drivers/cow_sys.h @@ -1,14 +1,13 @@ #ifndef __COW_SYS_H__ #define __COW_SYS_H__ -#include "kern_util.h" -#include "user_util.h" -#include "os.h" -#include "user.h" +#include <kern_util.h> +#include <os.h> +#include <um_malloc.h> static inline void *cow_malloc(int size) { - return(um_kmalloc(size)); + return uml_kmalloc(size, UM_GFP_KERNEL); } static inline void cow_free(void *ptr) @@ -20,29 +19,22 @@ static inline void cow_free(void *ptr) static inline char *cow_strdup(char *str) { - return(uml_strdup(str)); + return uml_strdup(str); } -static inline int cow_seek_file(int fd, unsigned long long offset) +static inline int cow_seek_file(int fd, __u64 offset) { - return(os_seek_file(fd, offset)); + return os_seek_file(fd, offset); } static inline int cow_file_size(char *file, unsigned long long *size_out) { - return(os_file_size(file, size_out)); + return os_file_size(file, size_out); } -static inline int cow_write_file(int fd, char *buf, int size) +static inline int cow_write_file(int fd, void *buf, int size) { - return(os_write_file(fd, buf, size)); + return os_write_file(fd, buf, size); } #endif - -/* - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index fbe2217db5d..0ee9cc6cc4c 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c @@ -1,48 +1,54 @@ -#include <stddef.h> -#include <string.h> -#include <errno.h> -/* _XOPEN_SOURCE is needed for pread, but we define _GNU_SOURCE, which defines +/* + * Copyright (C) 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) + * Licensed under the GPL + */ + +/* + * _XOPEN_SOURCE is needed for pread, but we define _GNU_SOURCE, which defines * that. */ #include <unistd.h> -#include <byteswap.h> -#include <sys/time.h> -#include <sys/param.h> -#include <sys/user.h> - -#include "os.h" - +#include <errno.h> +#include <string.h> +#include <arpa/inet.h> +#include <endian.h> #include "cow.h" #include "cow_sys.h" #define PATH_LEN_V1 256 +typedef __u32 time32_t; + struct cow_header_v1 { - int magic; - int version; + __s32 magic; + __s32 version; char backing_file[PATH_LEN_V1]; - time_t mtime; + time32_t mtime; __u64 size; - int sectorsize; -}; + __s32 sectorsize; +} __attribute__((packed)); -#define PATH_LEN_V2 MAXPATHLEN +/* + * Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in + * case other systems have different values for MAXPATHLEN. + * + * The same must hold for V2 - we want file format compatibility, not anything + * else. + */ +#define PATH_LEN_V3 4096 +#define PATH_LEN_V2 PATH_LEN_V3 struct cow_header_v2 { __u32 magic; __u32 version; char backing_file[PATH_LEN_V2]; - time_t mtime; + time32_t mtime; __u64 size; - int sectorsize; -}; - -/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in - * case other systems have different values for MAXPATHLEN - */ -#define PATH_LEN_V3 4096 + __s32 sectorsize; +} __attribute__((packed)); -/* Changes from V2 - +/* + * Changes from V2 - * PATH_LEN_V3 as described above * Explicitly specify field bit lengths for systems with different * lengths for the usual C types. Not sure whether char or @@ -66,6 +72,16 @@ struct cow_header_v2 { * Fixed (finally!) the rounding bug */ +/* + * Until Dec2005, __attribute__((packed)) was left out from the below + * definition, leading on 64-bit systems to 4 bytes of padding after mtime, to + * align size to 8-byte alignment. This shifted all fields above (no padding + * was present on 32-bit, no other padding was added). + * + * However, this _can be detected_: it means that cow_format (always 0 until + * now) is shifted onto the first 4 bytes of backing_file, where it is otherwise + * impossible to find 4 zeros. -bb */ + struct cow_header_v3 { __u32 magic; __u32 version; @@ -75,6 +91,18 @@ struct cow_header_v3 { __u32 alignment; __u32 cow_format; char backing_file[PATH_LEN_V3]; +} __attribute__((packed)); + +/* This is the broken layout used by some 64-bit binaries. */ +struct cow_header_v3_broken { + __u32 magic; + __u32 version; + __s64 mtime; + __u64 size; + __u32 sectorsize; + __u32 alignment; + __u32 cow_format; + char backing_file[PATH_LEN_V3]; }; /* COW format definitions - for now, we have only the usual COW bitmap */ @@ -84,6 +112,7 @@ union cow_header { struct cow_header_v1 v1; struct cow_header_v2 v2; struct cow_header_v3 v3; + struct cow_header_v3_broken v3_b; }; #define COW_MAGIC 0x4f4f4f4d /* MOOO */ @@ -96,7 +125,7 @@ void cow_sizes(int version, __u64 size, int sectorsize, int align, int bitmap_offset, unsigned long *bitmap_len_out, int *data_offset_out) { - if(version < 3){ + if (version < 3) { *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); *data_offset_out = bitmap_offset + *bitmap_len_out; @@ -118,46 +147,50 @@ static int absolutize(char *to, int size, char *from) char save_cwd[256], *slash; int remaining; - if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) { + if (getcwd(save_cwd, sizeof(save_cwd)) == NULL) { cow_printf("absolutize : unable to get cwd - errno = %d\n", errno); - return(-1); + return -1; } slash = strrchr(from, '/'); - if(slash != NULL){ + if (slash != NULL) { *slash = '\0'; - if(chdir(from)){ + if (chdir(from)) { *slash = '/'; cow_printf("absolutize : Can't cd to '%s' - " "errno = %d\n", from, errno); - return(-1); + return -1; } *slash = '/'; - if(getcwd(to, size) == NULL){ + if (getcwd(to, size) == NULL) { cow_printf("absolutize : unable to get cwd of '%s' - " "errno = %d\n", from, errno); - return(-1); + return -1; } remaining = size - strlen(to); - if(strlen(slash) + 1 > remaining){ + if (strlen(slash) + 1 > remaining) { cow_printf("absolutize : unable to fit '%s' into %d " "chars\n", from, size); - return(-1); + return -1; } strcat(to, slash); } else { - if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){ + if (strlen(save_cwd) + 1 + strlen(from) + 1 > size) { cow_printf("absolutize : unable to fit '%s' into %d " "chars\n", from, size); - return(-1); + return -1; } strcpy(to, save_cwd); strcat(to, "/"); strcat(to, from); } - chdir(save_cwd); - return(0); + if (chdir(save_cwd)) { + cow_printf("absolutize : Can't cd to '%s' - " + "errno = %d\n", save_cwd, errno); + return -1; + } + return 0; } int write_cow_header(char *cow_file, int fd, char *backing_file, @@ -168,70 +201,75 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, int err; err = cow_seek_file(fd, 0); - if(err < 0){ + if (err < 0) { cow_printf("write_cow_header - lseek failed, err = %d\n", -err); goto out; } err = -ENOMEM; header = cow_malloc(sizeof(*header)); - if(header == NULL){ - cow_printf("Failed to allocate COW V3 header\n"); + if (header == NULL) { + cow_printf("write_cow_header - failed to allocate COW V3 " + "header\n"); goto out; } - header->magic = htonl(COW_MAGIC); - header->version = htonl(COW_VERSION); + header->magic = htobe32(COW_MAGIC); + header->version = htobe32(COW_VERSION); err = -EINVAL; - if(strlen(backing_file) > sizeof(header->backing_file) - 1){ + if (strlen(backing_file) > sizeof(header->backing_file) - 1) { + /* Below, %zd is for a size_t value */ cow_printf("Backing file name \"%s\" is too long - names are " - "limited to %d characters\n", backing_file, + "limited to %zd characters\n", backing_file, sizeof(header->backing_file) - 1); goto out_free; } - if(absolutize(header->backing_file, sizeof(header->backing_file), + if (absolutize(header->backing_file, sizeof(header->backing_file), backing_file)) goto out_free; err = os_file_modtime(header->backing_file, &modtime); - if(err < 0){ - cow_printf("Backing file '%s' mtime request failed, " - "err = %d\n", header->backing_file, -err); + if (err < 0) { + cow_printf("write_cow_header - backing file '%s' mtime " + "request failed, err = %d\n", header->backing_file, + -err); goto out_free; } err = cow_file_size(header->backing_file, size); - if(err < 0){ - cow_printf("Couldn't get size of backing file '%s', " - "err = %d\n", header->backing_file, -err); + if (err < 0) { + cow_printf("write_cow_header - couldn't get size of " + "backing file '%s', err = %d\n", + header->backing_file, -err); goto out_free; } - header->mtime = htonl(modtime); - header->size = htonll(*size); - header->sectorsize = htonl(sectorsize); - header->alignment = htonl(alignment); + header->mtime = htobe32(modtime); + header->size = htobe64(*size); + header->sectorsize = htobe32(sectorsize); + header->alignment = htobe32(alignment); header->cow_format = COW_BITMAP; - err = os_write_file(fd, header, sizeof(*header)); - if(err != sizeof(*header)){ - cow_printf("Write of header to new COW file '%s' failed, " - "err = %d\n", cow_file, -err); + err = cow_write_file(fd, header, sizeof(*header)); + if (err != sizeof(*header)) { + cow_printf("write_cow_header - write of header to " + "new COW file '%s' failed, err = %d\n", cow_file, + -err); goto out_free; } err = 0; out_free: cow_free(header); out: - return(err); + return err; } int file_reader(__u64 offset, char *buf, int len, void *arg) { int fd = *((int *) arg); - return(pread(fd, buf, len, offset)); + return pread(fd, buf, len, offset); } /* XXX Need to sanity-check the values read from the header */ @@ -248,31 +286,29 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, unsigned long version, magic; header = cow_malloc(sizeof(*header)); - if(header == NULL){ + if (header == NULL) { cow_printf("read_cow_header - Failed to allocate header\n"); - return(-ENOMEM); + return -ENOMEM; } err = -EINVAL; n = (*reader)(0, (char *) header, sizeof(*header), arg); - if(n < offsetof(typeof(header->v1), backing_file)){ + if (n < offsetof(typeof(header->v1), backing_file)) { cow_printf("read_cow_header - short header\n"); goto out; } magic = header->v1.magic; - if(magic == COW_MAGIC) { + if (magic == COW_MAGIC) version = header->v1.version; - } - else if(magic == ntohl(COW_MAGIC)){ - version = ntohl(header->v1.version); - } + else if (magic == be32toh(COW_MAGIC)) + version = be32toh(header->v1.version); /* No error printed because the non-COW case comes through here */ else goto out; *version_out = version; - if(version == 1){ - if(n < sizeof(header->v1)){ + if (version == 1) { + if (n < sizeof(header->v1)) { cow_printf("read_cow_header - failed to read V1 " "header\n"); goto out; @@ -284,39 +320,75 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, *align_out = *sectorsize_out; file = header->v1.backing_file; } - else if(version == 2){ - if(n < sizeof(header->v2)){ + else if (version == 2) { + if (n < sizeof(header->v2)) { cow_printf("read_cow_header - failed to read V2 " "header\n"); goto out; } - *mtime_out = ntohl(header->v2.mtime); - *size_out = ntohll(header->v2.size); - *sectorsize_out = ntohl(header->v2.sectorsize); + *mtime_out = be32toh(header->v2.mtime); + *size_out = be64toh(header->v2.size); + *sectorsize_out = be32toh(header->v2.sectorsize); *bitmap_offset_out = sizeof(header->v2); *align_out = *sectorsize_out; file = header->v2.backing_file; } - else if(version == 3){ - if(n < sizeof(header->v3)){ - cow_printf("read_cow_header - failed to read V2 " + /* This is very subtle - see above at union cow_header definition */ + else if (version == 3 && (*((int*)header->v3.backing_file) != 0)) { + if (n < sizeof(header->v3)) { + cow_printf("read_cow_header - failed to read V3 " "header\n"); goto out; } - *mtime_out = ntohl(header->v3.mtime); - *size_out = ntohll(header->v3.size); - *sectorsize_out = ntohl(header->v3.sectorsize); - *align_out = ntohl(header->v3.alignment); + *mtime_out = be32toh(header->v3.mtime); + *size_out = be64toh(header->v3.size); + *sectorsize_out = be32toh(header->v3.sectorsize); + *align_out = be32toh(header->v3.alignment); + if (*align_out == 0) { + cow_printf("read_cow_header - invalid COW header, " + "align == 0\n"); + } *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); file = header->v3.backing_file; } + else if (version == 3) { + cow_printf("read_cow_header - broken V3 file with" + " 64-bit layout - recovering content.\n"); + + if (n < sizeof(header->v3_b)) { + cow_printf("read_cow_header - failed to read V3 " + "header\n"); + goto out; + } + + /* + * this was used until Dec2005 - 64bits are needed to represent + * 2038+. I.e. we can safely do this truncating cast. + * + * Additionally, we must use be32toh() instead of be64toh(), since + * the program used to use the former (tested - I got mtime + * mismatch "0 vs whatever"). + * + * Ever heard about bug-to-bug-compatibility ? ;-) */ + *mtime_out = (time32_t) be32toh(header->v3_b.mtime); + + *size_out = be64toh(header->v3_b.size); + *sectorsize_out = be32toh(header->v3_b.sectorsize); + *align_out = be32toh(header->v3_b.alignment); + if (*align_out == 0) { + cow_printf("read_cow_header - invalid COW header, " + "align == 0\n"); + } + *bitmap_offset_out = ROUND_UP(sizeof(header->v3_b), *align_out); + file = header->v3_b.backing_file; + } else { cow_printf("read_cow_header - invalid COW version\n"); goto out; } err = -ENOMEM; *backing_file_out = cow_strdup(file); - if(*backing_file_out == NULL){ + if (*backing_file_out == NULL) { cow_printf("read_cow_header - failed to allocate backing " "file\n"); goto out; @@ -324,7 +396,7 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, err = 0; out: cow_free(header); - return(err); + return err; } int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, @@ -337,7 +409,7 @@ int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, err = write_cow_header(cow_file, fd, backing_file, sectorsize, alignment, &size); - if(err) + if (err) goto out; *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment); @@ -346,32 +418,26 @@ int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, offset = *data_offset_out + size - sizeof(zero); err = cow_seek_file(fd, offset); - if(err < 0){ + if (err < 0) { cow_printf("cow bitmap lseek failed : err = %d\n", -err); goto out; } - /* does not really matter how much we write it is just to set EOF + /* + * does not really matter how much we write it is just to set EOF * this also sets the entire COW bitmap * to zero without having to allocate it */ err = cow_write_file(fd, &zero, sizeof(zero)); - if(err != sizeof(zero)){ + if (err != sizeof(zero)) { cow_printf("Write of bitmap to new COW file '%s' failed, " "err = %d\n", cow_file, -err); - err = -EINVAL; + if (err >= 0) + err = -EINVAL; goto out; } - return(0); - + return 0; out: - return(err); + return err; } - -/* - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/daemon.h b/arch/um/drivers/daemon.h index 7326c42f7ef..c2dd1951559 100644 --- a/arch/um/drivers/daemon.h +++ b/arch/um/drivers/daemon.h @@ -1,9 +1,12 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "net_user.h" +#ifndef __DAEMON_H__ +#define __DAEMON_H__ + +#include <net_user.h> #define SWITCH_VERSION 3 @@ -18,18 +21,9 @@ struct daemon_data { void *dev; }; -extern struct net_user_info daemon_user_info; +extern const struct net_user_info daemon_user_info; -extern int daemon_user_write(int fd, void *buf, int len, +extern int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +#endif diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c index 30d285b266a..7568cc2f3cd 100644 --- a/arch/um/drivers/daemon_kern.c +++ b/arch/um/drivers/daemon_kern.c @@ -1,16 +1,14 @@ /* - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Copyright (C) 2001 by various other people who didn't put their name here. * Licensed under the GPL. */ -#include "linux/kernel.h" -#include "linux/init.h" -#include "linux/netdevice.h" -#include "linux/etherdevice.h" -#include "net_kern.h" -#include "net_user.h" +#include <linux/init.h> +#include <linux/netdevice.h> +#include <net_kern.h> #include "daemon.h" struct daemon_init { @@ -18,49 +16,49 @@ struct daemon_init { char *ctl_sock; }; -void daemon_init(struct net_device *dev, void *data) +static void daemon_init(struct net_device *dev, void *data) { struct uml_net_private *pri; struct daemon_data *dpri; struct daemon_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); dpri = (struct daemon_data *) pri->user; dpri->sock_type = init->sock_type; dpri->ctl_sock = init->ctl_sock; dpri->fd = -1; dpri->control = -1; dpri->dev = dev; + /* We will free this pointer. If it contains crap we're burned. */ + dpri->ctl_addr = NULL; + dpri->data_addr = NULL; + dpri->local_addr = NULL; - printk("daemon backend (uml_switch version %d) - %s:%s", + printk("daemon backend (uml_switch version %d) - %s:%s", SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock); printk("\n"); } -static int daemon_read(int fd, struct sk_buff **skb, - struct uml_net_private *lp) +static int daemon_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); - if(*skb == NULL) return(-ENOMEM); - return(net_recvfrom(fd, (*skb)->mac.raw, - (*skb)->dev->mtu + ETH_HEADER_OTHER)); + return net_recvfrom(fd, skb_mac_header(skb), + skb->dev->mtu + ETH_HEADER_OTHER); } -static int daemon_write(int fd, struct sk_buff **skb, - struct uml_net_private *lp) +static int daemon_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - return(daemon_user_write(fd, (*skb)->data, (*skb)->len, - (struct daemon_data *) &lp->user)); + return daemon_user_write(fd, skb->data, skb->len, + (struct daemon_data *) &lp->user); } -static struct net_kern_info daemon_kern_info = { +static const struct net_kern_info daemon_kern_info = { .init = daemon_init, .protocol = eth_protocol, .read = daemon_read, .write = daemon_write, }; -int daemon_setup(char *str, char **mac_out, void *data) +static int daemon_setup(char *str, char **mac_out, void *data) { struct daemon_init *init = data; char *remain; @@ -68,14 +66,14 @@ int daemon_setup(char *str, char **mac_out, void *data) *init = ((struct daemon_init) { .sock_type = "unix", .ctl_sock = "/tmp/uml.ctl" }); - + remain = split_if_spec(str, mac_out, &init->sock_type, &init->ctl_sock, NULL); - if(remain != NULL) + if (remain != NULL) printk(KERN_WARNING "daemon_setup : Ignoring data socket " "specification\n"); - - return(1); + + return 1; } static struct transport daemon_transport = { @@ -91,18 +89,7 @@ static struct transport daemon_transport = { static int register_daemon(void) { register_transport(&daemon_transport); - return(1); + return 0; } -__initcall(register_daemon); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +late_initcall(register_daemon); diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c index c1b03f7c1da..8813c10d017 100644 --- a/arch/um/drivers/daemon_user.c +++ b/arch/um/drivers/daemon_user.c @@ -1,24 +1,22 @@ /* - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and * James Leu (jleu@mindspring.net). * Copyright (C) 2001 by various other people who didn't put their name here. * Licensed under the GPL. */ -#include <errno.h> -#include <unistd.h> #include <stdint.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> #include <sys/socket.h> -#include <sys/un.h> #include <sys/time.h> -#include "net_user.h" +#include <sys/un.h> #include "daemon.h" -#include "kern_util.h" -#include "user_util.h" -#include "user.h" -#include "os.h" - -#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) +#include <net_user.h> +#include <os.h> +#include <um_malloc.h> enum request_type { REQ_NEW_CONTROL }; @@ -35,14 +33,15 @@ static struct sockaddr_un *new_addr(void *name, int len) { struct sockaddr_un *sun; - sun = um_kmalloc(sizeof(struct sockaddr_un)); - if(sun == NULL){ - printk("new_addr: allocation of sockaddr_un failed\n"); - return(NULL); + sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); + if (sun == NULL) { + printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un " + "failed\n"); + return NULL; } sun->sun_family = AF_UNIX; memcpy(sun->sun_path, name, len); - return(sun); + return sun; } static int connect_to_switch(struct daemon_data *pri) @@ -54,37 +53,39 @@ static int connect_to_switch(struct daemon_data *pri) int fd, n, err; pri->control = socket(AF_UNIX, SOCK_STREAM, 0); - if(pri->control < 0){ - printk("daemon_open : control socket failed, errno = %d\n", - errno); - return(-errno); + if (pri->control < 0) { + err = -errno; + printk(UM_KERN_ERR "daemon_open : control socket failed, " + "errno = %d\n", -err); + return err; } - if(connect(pri->control, (struct sockaddr *) ctl_addr, - sizeof(*ctl_addr)) < 0){ - printk("daemon_open : control connect failed, errno = %d\n", - errno); + if (connect(pri->control, (struct sockaddr *) ctl_addr, + sizeof(*ctl_addr)) < 0) { err = -errno; + printk(UM_KERN_ERR "daemon_open : control connect failed, " + "errno = %d\n", -err); goto out; } fd = socket(AF_UNIX, SOCK_DGRAM, 0); - if(fd < 0){ - printk("daemon_open : data socket failed, errno = %d\n", - errno); + if (fd < 0) { err = -errno; + printk(UM_KERN_ERR "daemon_open : data socket failed, " + "errno = %d\n", -err); goto out; } - if(bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0){ - printk("daemon_open : data bind failed, errno = %d\n", - errno); + if (bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0) { err = -errno; + printk(UM_KERN_ERR "daemon_open : data bind failed, " + "errno = %d\n", -err); goto out_close; } - sun = um_kmalloc(sizeof(struct sockaddr_un)); - if(sun == NULL){ - printk("new_addr: allocation of sockaddr_un failed\n"); + sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); + if (sun == NULL) { + printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un " + "failed\n"); err = -ENOMEM; goto out_close; } @@ -93,33 +94,35 @@ static int connect_to_switch(struct daemon_data *pri) req.version = SWITCH_VERSION; req.type = REQ_NEW_CONTROL; req.sock = *local_addr; - n = os_write_file(pri->control, &req, sizeof(req)); - if(n != sizeof(req)){ - printk("daemon_open : control setup request failed, err = %d\n", - -n); + n = write(pri->control, &req, sizeof(req)); + if (n != sizeof(req)) { + printk(UM_KERN_ERR "daemon_open : control setup request " + "failed, err = %d\n", -errno); err = -ENOTCONN; - goto out; + goto out_free; } - n = os_read_file(pri->control, sun, sizeof(*sun)); - if(n != sizeof(*sun)){ - printk("daemon_open : read of data socket failed, err = %d\n", - -n); + n = read(pri->control, sun, sizeof(*sun)); + if (n != sizeof(*sun)) { + printk(UM_KERN_ERR "daemon_open : read of data socket failed, " + "err = %d\n", -errno); err = -ENOTCONN; - goto out_close; + goto out_free; } pri->data_addr = sun; - return(fd); + return fd; + out_free: + kfree(sun); out_close: - os_close_file(fd); + close(fd); out: - os_close_file(pri->control); - return(err); + close(pri->control); + return err; } -static void daemon_user_init(void *data, void *dev) +static int daemon_user_init(void *data, void *dev) { struct daemon_data *pri = data; struct timeval tv; @@ -129,8 +132,8 @@ static void daemon_user_init(void *data, void *dev) int usecs; } name; - if(!strcmp(pri->sock_type, "unix")) - pri->ctl_addr = new_addr(pri->ctl_sock, + if (!strcmp(pri->sock_type, "unix")) + pri->ctl_addr = new_addr(pri->ctl_sock, strlen(pri->ctl_sock) + 1); name.zero = 0; name.pid = os_getpid(); @@ -139,59 +142,52 @@ static void daemon_user_init(void *data, void *dev) pri->local_addr = new_addr(&name, sizeof(name)); pri->dev = dev; pri->fd = connect_to_switch(pri); - if(pri->fd < 0){ + if (pri->fd < 0) { kfree(pri->local_addr); pri->local_addr = NULL; + return pri->fd; } + + return 0; } static int daemon_open(void *data) { struct daemon_data *pri = data; - return(pri->fd); + return pri->fd; } static void daemon_remove(void *data) { struct daemon_data *pri = data; - os_close_file(pri->fd); - os_close_file(pri->control); + close(pri->fd); + pri->fd = -1; + close(pri->control); + pri->control = -1; + kfree(pri->data_addr); + pri->data_addr = NULL; kfree(pri->ctl_addr); + pri->ctl_addr = NULL; kfree(pri->local_addr); + pri->local_addr = NULL; } int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri) { struct sockaddr_un *data_addr = pri->data_addr; - return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr))); -} - -static int daemon_set_mtu(int mtu, void *data) -{ - return(mtu); + return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)); } -struct net_user_info daemon_user_info = { +const struct net_user_info daemon_user_info = { .init = daemon_user_init, .open = daemon_open, .close = NULL, .remove = daemon_remove, - .set_mtu = daemon_set_mtu, .add_address = NULL, .delete_address = NULL, - .max_packet = MAX_PACKET - ETH_HEADER_OTHER + .mtu = ETH_MAX_PACKET, + .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index f0b888f66e0..a13a427b996 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -1,16 +1,16 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) * Licensed under the GPL */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> -#include <termios.h> #include <errno.h> -#include "user.h" -#include "user_util.h" +#include <termios.h> #include "chan_user.h" +#include <os.h> +#include <um_malloc.h> struct fd_chan { int fd; @@ -19,28 +19,32 @@ struct fd_chan { char str[sizeof("1234567890\0")]; }; -static void *fd_init(char *str, int device, struct chan_opts *opts) +static void *fd_init(char *str, int device, const struct chan_opts *opts) { struct fd_chan *data; char *end; int n; - if(*str != ':'){ - printk("fd_init : channel type 'fd' must specify a file " - "descriptor\n"); - return(NULL); + if (*str != ':') { + printk(UM_KERN_ERR "fd_init : channel type 'fd' must specify a " + "file descriptor\n"); + return NULL; } str++; n = strtoul(str, &end, 0); - if((*end != '\0') || (end == str)){ - printk("fd_init : couldn't parse file descriptor '%s'\n", str); - return(NULL); + if ((*end != '\0') || (end == str)) { + printk(UM_KERN_ERR "fd_init : couldn't parse file descriptor " + "'%s'\n", str); + return NULL; } - data = um_kmalloc(sizeof(*data)); - if(data == NULL) return(NULL); + + data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); + if (data == NULL) + return NULL; + *data = ((struct fd_chan) { .fd = n, .raw = opts->raw }); - return(data); + return data; } static int fd_open(int input, int output, int primary, void *d, char **dev_out) @@ -48,18 +52,18 @@ static int fd_open(int input, int output, int primary, void *d, char **dev_out) struct fd_chan *data = d; int err; - if(data->raw && isatty(data->fd)){ + if (data->raw && isatty(data->fd)) { CATCH_EINTR(err = tcgetattr(data->fd, &data->tt)); - if(err) - return(err); + if (err) + return err; err = raw(data->fd); - if(err) - return(err); + if (err) + return err; } sprintf(data->str, "%d", data->fd); *dev_out = data->str; - return(data->fd); + return data->fd; } static void fd_close(int fd, void *d) @@ -67,42 +71,25 @@ static void fd_close(int fd, void *d) struct fd_chan *data = d; int err; - if(data->raw && isatty(fd)){ - CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt)); - if(err) - printk("Failed to restore terminal state - " - "errno = %d\n", -err); - data->raw = 0; - } -} + if (!data->raw || !isatty(fd)) + return; -static int fd_console_write(int fd, const char *buf, int n, void *d) -{ - struct fd_chan *data = d; - - return(generic_console_write(fd, buf, n, &data->tt)); + CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt)); + if (err) + printk(UM_KERN_ERR "Failed to restore terminal state - " + "errno = %d\n", -err); + data->raw = 0; } -struct chan_ops fd_ops = { +const struct chan_ops fd_ops = { .type = "fd", .init = fd_init, .open = fd_open, .close = fd_close, .read = generic_read, .write = generic_write, - .console_write = fd_console_write, + .console_write = generic_console_write, .window_size = generic_window_size, .free = generic_free, .winch = 1, }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index 49acb2badf3..2d0266d0254 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c @@ -9,10 +9,10 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. * * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> * @@ -29,13 +29,12 @@ * Made SMP safe for 2.3.x * * 20011127 Joel Becker (jlbec@evilplan.org> - * Added soft_noboot; Allows testing the softdog trigger without + * Added soft_noboot; Allows testing the softdog trigger without * requiring a recompile. * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT. */ - + #include <linux/module.h> -#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/fs.h> @@ -43,14 +42,16 @@ #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/reboot.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/init.h> +#include <linux/spinlock.h> #include <asm/uaccess.h> #include "mconsole.h" MODULE_LICENSE("GPL"); -/* Locked by the BKL in harddog_open and harddog_release */ +static DEFINE_MUTEX(harddog_mutex); +static DEFINE_SPINLOCK(lock); static int timer_alive; static int harddog_in_fd = -1; static int harddog_out_fd = -1; @@ -58,18 +59,19 @@ static int harddog_out_fd = -1; /* * Allow only one person to hold it open */ - + extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock); static int harddog_open(struct inode *inode, struct file *file) { - int err; + int err = -EBUSY; char *sock = NULL; - lock_kernel(); + mutex_lock(&harddog_mutex); + spin_lock(&lock); if(timer_alive) - return -EBUSY; -#ifdef CONFIG_HARDDOG_NOWAYOUT + goto err; +#ifdef CONFIG_WATCHDOG_NOWAYOUT __module_get(THIS_MODULE); #endif @@ -77,11 +79,17 @@ static int harddog_open(struct inode *inode, struct file *file) sock = mconsole_notify_socket(); #endif err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock); - if(err) return(err); + if(err) + goto err; timer_alive = 1; - unlock_kernel(); + spin_unlock(&lock); + mutex_unlock(&harddog_mutex); return nonseekable_open(inode, file); +err: + spin_unlock(&lock); + mutex_unlock(&harddog_mutex); + return err; } extern void stop_watchdog(int in_fd, int out_fd); @@ -91,33 +99,36 @@ static int harddog_release(struct inode *inode, struct file *file) /* * Shut off the timer. */ - lock_kernel(); + + spin_lock(&lock); stop_watchdog(harddog_in_fd, harddog_out_fd); harddog_in_fd = -1; harddog_out_fd = -1; timer_alive=0; - unlock_kernel(); + spin_unlock(&lock); + return 0; } extern int ping_watchdog(int fd); -static ssize_t harddog_write(struct file *file, const char *data, size_t len, +static ssize_t harddog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { /* * Refresh the timer. */ if(len) - return(ping_watchdog(harddog_out_fd)); + return ping_watchdog(harddog_out_fd); return 0; } -static int harddog_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int harddog_ioctl_unlocked(struct file *file, + unsigned int cmd, unsigned long arg) { + void __user *argp= (void __user *)arg; static struct watchdog_info ident = { WDIOC_SETTIMEOUT, 0, @@ -127,24 +138,36 @@ static int harddog_ioctl(struct inode *inode, struct file *file, default: return -ENOTTY; case WDIOC_GETSUPPORT: - if(copy_to_user((struct harddog_info *)arg, &ident, - sizeof(ident))) + if(copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; return 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: - return put_user(0,(int *)arg); + return put_user(0,(int __user *)argp); case WDIOC_KEEPALIVE: - return(ping_watchdog(harddog_out_fd)); + return ping_watchdog(harddog_out_fd); } } -static struct file_operations harddog_fops = { +static long harddog_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + + mutex_lock(&harddog_mutex); + ret = harddog_ioctl_unlocked(file, cmd, arg); + mutex_unlock(&harddog_mutex); + + return ret; +} + +static const struct file_operations harddog_fops = { .owner = THIS_MODULE, .write = harddog_write, - .ioctl = harddog_ioctl, + .unlocked_ioctl = harddog_ioctl, .open = harddog_open, .release = harddog_release, + .llseek = no_llseek, }; static struct miscdevice harddog_miscdev = { @@ -166,7 +189,7 @@ static int __init harddog_init(void) printk(banner); - return(0); + return 0; } static void __exit harddog_exit(void) @@ -176,14 +199,3 @@ static void __exit harddog_exit(void) module_init(harddog_init); module_exit(harddog_exit); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index def013b5a3c..f99b32a4dbf 100644 --- a/arch/um/drivers/harddog_user.c +++ b/arch/um/drivers/harddog_user.c @@ -1,17 +1,12 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #include <stdio.h> #include <unistd.h> #include <errno.h> -#include "user_util.h" -#include "user.h" -#include "mconsole.h" -#include "os.h" -#include "choose-mode.h" -#include "mode.h" +#include <os.h> struct dog_data { int stdin; @@ -26,30 +21,30 @@ static void pre_exec(void *d) dup2(data->stdin, 0); dup2(data->stdout, 1); dup2(data->stdout, 2); - os_close_file(data->stdin); - os_close_file(data->stdout); - os_close_file(data->close_me[0]); - os_close_file(data->close_me[1]); + close(data->stdin); + close(data->stdout); + close(data->close_me[0]); + close(data->close_me[1]); } int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) { struct dog_data data; int in_fds[2], out_fds[2], pid, n, err; - char pid_buf[sizeof("nnnnn\0")], c; + char pid_buf[sizeof("nnnnnnn\0")], c; char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL }; - char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, + char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, NULL }; char **args = NULL; err = os_pipe(in_fds, 1, 0); - if(err < 0){ + if (err < 0) { printk("harddog_open - os_pipe failed, err = %d\n", -err); goto out; } err = os_pipe(out_fds, 1, 0); - if(err < 0){ + if (err < 0) { printk("harddog_open - os_pipe failed, err = %d\n", -err); goto out_close_in; } @@ -59,59 +54,59 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) data.close_me[0] = out_fds[1]; data.close_me[1] = in_fds[0]; - if(sock != NULL){ + if (sock != NULL) { mconsole_args[2] = sock; args = mconsole_args; } else { /* XXX The os_getpid() is not SMP correct */ - sprintf(pid_buf, "%d", CHOOSE_MODE(tracing_pid, os_getpid())); + sprintf(pid_buf, "%d", os_getpid()); args = pid_args; } - pid = run_helper(pre_exec, &data, args, NULL); + pid = run_helper(pre_exec, &data, args); - os_close_file(out_fds[0]); - os_close_file(in_fds[1]); + close(out_fds[0]); + close(in_fds[1]); - if(pid < 0){ + if (pid < 0) { err = -pid; printk("harddog_open - run_helper failed, errno = %d\n", -err); goto out_close_out; } - n = os_read_file(in_fds[0], &c, sizeof(c)); - if(n == 0){ + n = read(in_fds[0], &c, sizeof(c)); + if (n == 0) { printk("harddog_open - EOF on watchdog pipe\n"); helper_wait(pid); err = -EIO; goto out_close_out; } - else if(n < 0){ + else if (n < 0) { printk("harddog_open - read of watchdog pipe failed, " - "err = %d\n", -n); + "err = %d\n", errno); helper_wait(pid); err = n; goto out_close_out; } *in_fd_ret = in_fds[0]; *out_fd_ret = out_fds[1]; - return(0); + return 0; out_close_in: - os_close_file(in_fds[0]); - os_close_file(in_fds[1]); + close(in_fds[0]); + close(in_fds[1]); out_close_out: - os_close_file(out_fds[0]); - os_close_file(out_fds[1]); + close(out_fds[0]); + close(out_fds[1]); out: - return(err); + return err; } void stop_watchdog(int in_fd, int out_fd) { - os_close_file(in_fd); - os_close_file(out_fd); + close(in_fd); + close(out_fd); } int ping_watchdog(int fd) @@ -119,24 +114,14 @@ int ping_watchdog(int fd) int n; char c = '\n'; - n = os_write_file(fd, &c, sizeof(c)); - if(n != sizeof(c)){ - printk("ping_watchdog - write failed, err = %d\n", -n); - if(n < 0) - return(n); - return(-EIO); + n = write(fd, &c, sizeof(c)); + if (n != sizeof(c)) { + printk("ping_watchdog - write failed, ret = %d, err = %d\n", + n, errno); + if (n < 0) + return n; + return -EIO; } return 1; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index 59602b81b24..9b90fdc4b15 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -1,34 +1,36 @@ -/* - * Copyright (C) 2002 Steve Schmidtke +/* + * Copyright (C) 2002 Steve Schmidtke * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/module.h" -#include "linux/init.h" -#include "linux/slab.h" -#include "linux/fs.h" -#include "linux/sound.h" -#include "linux/soundcard.h" -#include "asm/uaccess.h" -#include "kern_util.h" -#include "init.h" -#include "os.h" +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/sound.h> +#include <linux/soundcard.h> +#include <linux/mutex.h> +#include <asm/uaccess.h> +#include <init.h> +#include <os.h> struct hostaudio_state { - int fd; + int fd; }; struct hostmixer_state { - int fd; + int fd; }; #define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" #define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" -/* Only changed from linux_main at boot time */ -char *dsp = HOSTAUDIO_DEV_DSP; -char *mixer = HOSTAUDIO_DEV_MIXER; +/* + * Changed either at boot time or module load time. At boot, this is + * single-threaded; at module load, multiple modules would each have + * their own copy of these variables. + */ +static char *dsp = HOSTAUDIO_DEV_DSP; +static char *mixer = HOSTAUDIO_DEV_MIXER; #define DSP_HELP \ " This is used to specify the host dsp device to the hostaudio driver.\n" \ @@ -38,11 +40,16 @@ char *mixer = HOSTAUDIO_DEV_MIXER; " This is used to specify the host mixer device to the hostaudio driver.\n"\ " The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n" +module_param(dsp, charp, 0644); +MODULE_PARM_DESC(dsp, DSP_HELP); +module_param(mixer, charp, 0644); +MODULE_PARM_DESC(mixer, MIXER_HELP); + #ifndef MODULE static int set_dsp(char *name, int *add) { dsp = name; - return(0); + return 0; } __uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP); @@ -50,100 +57,93 @@ __uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP); static int set_mixer(char *name, int *add) { mixer = name; - return(0); + return 0; } __uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP); - -#else /*MODULE*/ - -module_param(dsp, charp, 0644); -MODULE_PARM_DESC(dsp, DSP_HELP); - -module_param(mixer, charp, 0644); -MODULE_PARM_DESC(mixer, MIXER_HELP); - #endif +static DEFINE_MUTEX(hostaudio_mutex); + /* /dev/dsp file operations */ -static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, - loff_t *ppos) +static ssize_t hostaudio_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) { - struct hostaudio_state *state = file->private_data; + struct hostaudio_state *state = file->private_data; void *kbuf; int err; #ifdef DEBUG - printk("hostaudio: read called, count = %d\n", count); + printk(KERN_DEBUG "hostaudio: read called, count = %d\n", count); #endif kbuf = kmalloc(count, GFP_KERNEL); - if(kbuf == NULL) - return(-ENOMEM); + if (kbuf == NULL) + return -ENOMEM; err = os_read_file(state->fd, kbuf, count); - if(err < 0) + if (err < 0) goto out; - if(copy_to_user(buffer, kbuf, err)) + if (copy_to_user(buffer, kbuf, err)) err = -EFAULT; - out: +out: kfree(kbuf); - return(err); + return err; } -static ssize_t hostaudio_write(struct file *file, const char *buffer, +static ssize_t hostaudio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { - struct hostaudio_state *state = file->private_data; + struct hostaudio_state *state = file->private_data; void *kbuf; int err; #ifdef DEBUG - printk("hostaudio: write called, count = %d\n", count); + printk(KERN_DEBUG "hostaudio: write called, count = %d\n", count); #endif kbuf = kmalloc(count, GFP_KERNEL); - if(kbuf == NULL) - return(-ENOMEM); + if (kbuf == NULL) + return -ENOMEM; err = -EFAULT; - if(copy_from_user(kbuf, buffer, count)) + if (copy_from_user(kbuf, buffer, count)) goto out; err = os_write_file(state->fd, kbuf, count); - if(err < 0) + if (err < 0) goto out; *ppos += err; out: kfree(kbuf); - return(err); + return err; } -static unsigned int hostaudio_poll(struct file *file, +static unsigned int hostaudio_poll(struct file *file, struct poll_table_struct *wait) { - unsigned int mask = 0; + unsigned int mask = 0; #ifdef DEBUG - printk("hostaudio: poll called (unimplemented)\n"); + printk(KERN_DEBUG "hostaudio: poll called (unimplemented)\n"); #endif - return(mask); + return mask; } -static int hostaudio_ioctl(struct inode *inode, struct file *file, +static long hostaudio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct hostaudio_state *state = file->private_data; + struct hostaudio_state *state = file->private_data; unsigned long data = 0; int err; #ifdef DEBUG - printk("hostaudio: ioctl called, cmd = %u\n", cmd); + printk(KERN_DEBUG "hostaudio: ioctl called, cmd = %u\n", cmd); #endif switch(cmd){ case SNDCTL_DSP_SPEED: @@ -152,8 +152,8 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_CHANNELS: case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_SETFRAGMENT: - if(get_user(data, (int *) arg)) - return(-EFAULT); + if (get_user(data, (int __user *) arg)) + return -EFAULT; break; default: break; @@ -168,136 +168,151 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_CHANNELS: case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_SETFRAGMENT: - if(put_user(data, (int *) arg)) - return(-EFAULT); + if (put_user(data, (int __user *) arg)) + return -EFAULT; break; default: break; } - return(err); + return err; } static int hostaudio_open(struct inode *inode, struct file *file) { - struct hostaudio_state *state; - int r = 0, w = 0; - int ret; + struct hostaudio_state *state; + int r = 0, w = 0; + int ret; #ifdef DEBUG - printk("hostaudio: open called (host: %s)\n", dsp); + kparam_block_sysfs_write(dsp); + printk(KERN_DEBUG "hostaudio: open called (host: %s)\n", dsp); + kparam_unblock_sysfs_write(dsp); #endif - state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); - if(state == NULL) - return(-ENOMEM); + state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; - if(file->f_mode & FMODE_READ) r = 1; - if(file->f_mode & FMODE_WRITE) w = 1; + if (file->f_mode & FMODE_READ) + r = 1; + if (file->f_mode & FMODE_WRITE) + w = 1; + kparam_block_sysfs_write(dsp); + mutex_lock(&hostaudio_mutex); ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); - if(ret < 0){ - kfree(state); - return(ret); - } + mutex_unlock(&hostaudio_mutex); + kparam_unblock_sysfs_write(dsp); + if (ret < 0) { + kfree(state); + return ret; + } state->fd = ret; - file->private_data = state; - return(0); + file->private_data = state; + return 0; } static int hostaudio_release(struct inode *inode, struct file *file) { - struct hostaudio_state *state = file->private_data; + struct hostaudio_state *state = file->private_data; #ifdef DEBUG - printk("hostaudio: release called\n"); + printk(KERN_DEBUG "hostaudio: release called\n"); #endif + os_close_file(state->fd); + kfree(state); - os_close_file(state->fd); - kfree(state); - - return(0); + return 0; } /* /dev/mixer file operations */ -static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, +static long hostmixer_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) { - struct hostmixer_state *state = file->private_data; + struct hostmixer_state *state = file->private_data; #ifdef DEBUG - printk("hostmixer: ioctl called\n"); + printk(KERN_DEBUG "hostmixer: ioctl called\n"); #endif - return(os_ioctl_generic(state->fd, cmd, arg)); + return os_ioctl_generic(state->fd, cmd, arg); } static int hostmixer_open_mixdev(struct inode *inode, struct file *file) { - struct hostmixer_state *state; - int r = 0, w = 0; - int ret; + struct hostmixer_state *state; + int r = 0, w = 0; + int ret; #ifdef DEBUG - printk("hostmixer: open called (host: %s)\n", mixer); + printk(KERN_DEBUG "hostmixer: open called (host: %s)\n", mixer); #endif - state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL); - if(state == NULL) return(-ENOMEM); + state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; - if(file->f_mode & FMODE_READ) r = 1; - if(file->f_mode & FMODE_WRITE) w = 1; + if (file->f_mode & FMODE_READ) + r = 1; + if (file->f_mode & FMODE_WRITE) + w = 1; + kparam_block_sysfs_write(mixer); + mutex_lock(&hostaudio_mutex); ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); - - if(ret < 0){ - printk("hostaudio_open_mixdev failed to open '%s', err = %d\n", - dsp, -ret); + mutex_unlock(&hostaudio_mutex); + kparam_unblock_sysfs_write(mixer); + + if (ret < 0) { + kparam_block_sysfs_write(dsp); + printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', " + "err = %d\n", dsp, -ret); + kparam_unblock_sysfs_write(dsp); kfree(state); - return(ret); - } + return ret; + } - file->private_data = state; - return(0); + file->private_data = state; + return 0; } static int hostmixer_release(struct inode *inode, struct file *file) { - struct hostmixer_state *state = file->private_data; + struct hostmixer_state *state = file->private_data; #ifdef DEBUG - printk("hostmixer: release called\n"); + printk(KERN_DEBUG "hostmixer: release called\n"); #endif - os_close_file(state->fd); - kfree(state); + os_close_file(state->fd); + kfree(state); - return(0); + return 0; } - /* kernel module operations */ -static struct file_operations hostaudio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = hostaudio_read, - .write = hostaudio_write, - .poll = hostaudio_poll, - .ioctl = hostaudio_ioctl, - .mmap = NULL, - .open = hostaudio_open, - .release = hostaudio_release, +static const struct file_operations hostaudio_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = hostaudio_read, + .write = hostaudio_write, + .poll = hostaudio_poll, + .unlocked_ioctl = hostaudio_ioctl, + .mmap = NULL, + .open = hostaudio_open, + .release = hostaudio_release, }; -static struct file_operations hostmixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = hostmixer_ioctl_mixdev, - .open = hostmixer_open_mixdev, - .release = hostmixer_release, +static const struct file_operations hostmixer_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .unlocked_ioctl = hostmixer_ioctl_mixdev, + .open = hostmixer_open_mixdev, + .release = hostmixer_release, }; struct { @@ -311,42 +326,33 @@ MODULE_LICENSE("GPL"); static int __init hostaudio_init_module(void) { - printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", + __kernel_param_lock(); + printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", dsp, mixer); + __kernel_param_unlock(); module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); - if(module_data.dev_audio < 0){ - printk(KERN_ERR "hostaudio: couldn't register DSP device!\n"); - return -ENODEV; - } + if (module_data.dev_audio < 0) { + printk(KERN_ERR "hostaudio: couldn't register DSP device!\n"); + return -ENODEV; + } module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1); - if(module_data.dev_mixer < 0){ - printk(KERN_ERR "hostmixer: couldn't register mixer " + if (module_data.dev_mixer < 0) { + printk(KERN_ERR "hostmixer: couldn't register mixer " "device!\n"); - unregister_sound_dsp(module_data.dev_audio); - return -ENODEV; - } + unregister_sound_dsp(module_data.dev_audio); + return -ENODEV; + } - return 0; + return 0; } static void __exit hostaudio_cleanup_module (void) { - unregister_sound_mixer(module_data.dev_mixer); - unregister_sound_dsp(module_data.dev_audio); + unregister_sound_mixer(module_data.dev_mixer); + unregister_sound_dsp(module_data.dev_audio); } module_init(hostaudio_init_module); module_exit(hostaudio_cleanup_module); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index e0fdffa2d54..8035145f043 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -1,47 +1,35 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/sched.h" -#include "linux/slab.h" -#include "linux/list.h" -#include "linux/kd.h" -#include "linux/interrupt.h" -#include "linux/devfs_fs_kernel.h" -#include "asm/uaccess.h" -#include "chan_kern.h" -#include "irq_user.h" -#include "line.h" -#include "kern.h" -#include "user_util.h" -#include "kern_util.h" -#include "os.h" -#include "irq_kern.h" +#include <linux/irqreturn.h> +#include <linux/kd.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include "chan.h" +#include <irq_kern.h> +#include <irq_user.h> +#include <kern_util.h> +#include <os.h> #define LINE_BUFSIZE 4096 -static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) +static irqreturn_t line_interrupt(int irq, void *data) { - struct tty_struct *tty = data; - struct line *line = tty->driver_data; + struct chan *chan = data; + struct line *line = chan->line; if (line) - chan_interrupt(&line->chan_list, &line->task, tty, irq); - return IRQ_HANDLED; -} - -static void line_timer_cb(void *arg) -{ - struct tty_struct *tty = arg; - struct line *line = tty->driver_data; + chan_interrupt(line, irq); - line_interrupt(line->driver->read_irq, arg, NULL); + return IRQ_HANDLED; } -/* Returns the free space inside the ring buffer of this line. +/* + * Returns the free space inside the ring buffer of this line. * - * Should be called while holding line->lock (this does not modify datas). + * Should be called while holding line->lock (this does not modify data). */ static int write_room(struct line *line) { @@ -54,7 +42,7 @@ static int write_room(struct line *line) n = line->head - line->tail; if (n <= 0) - n = LINE_BUFSIZE + n; /* The other case */ + n += LINE_BUFSIZE; /* The other case */ return n - 1; } @@ -64,17 +52,10 @@ int line_write_room(struct tty_struct *tty) unsigned long flags; int room; - if (tty->stopped) - return 0; - spin_lock_irqsave(&line->lock, flags); room = write_room(line); spin_unlock_irqrestore(&line->lock, flags); - /*XXX: Warning to remove */ - if (0 == room) - printk(KERN_DEBUG "%s: %s: no room left in buffer\n", - __FUNCTION__,tty->name); return room; } @@ -85,8 +66,7 @@ int line_chars_in_buffer(struct tty_struct *tty) int ret; spin_lock_irqsave(&line->lock, flags); - - /*write_room subtracts 1 for the needed NULL, so we readd it.*/ + /* write_room subtracts 1 for the needed NULL, so we readd it.*/ ret = LINE_BUFSIZE - (write_room(line) + 1); spin_unlock_irqrestore(&line->lock, flags); @@ -106,11 +86,12 @@ static int buffer_data(struct line *line, const char *buf, int len) { int end, room; - if(line->buffer == NULL){ + if (line->buffer == NULL) { line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC); if (line->buffer == NULL) { - printk("buffer_data - atomic allocation failed\n"); - return(0); + printk(KERN_ERR "buffer_data - atomic allocation " + "failed\n"); + return 0; } line->head = line->buffer; line->tail = line->buffer; @@ -121,10 +102,11 @@ static int buffer_data(struct line *line, const char *buf, int len) end = line->buffer + LINE_BUFSIZE - line->tail; - if (len < end){ + if (len < end) { memcpy(line->tail, buf, len); line->tail += len; - } else { + } + else { /* The circular buffer is wrapping */ memcpy(line->tail, buf, end); buf += end; @@ -155,13 +137,15 @@ static int flush_buffer(struct line *line) /* line->buffer + LINE_BUFSIZE is the end of the buffer! */ count = line->buffer + LINE_BUFSIZE - line->head; - n = write_chan(&line->chan_list, line->head, count, + n = write_chan(line->chan_out, line->head, count, line->driver->write_irq); if (n < 0) return n; if (n == count) { - /* We have flushed from ->head to buffer end, now we - * must flush only from the beginning to ->tail.*/ + /* + * We have flushed from ->head to buffer end, now we + * must flush only from the beginning to ->tail. + */ line->head = line->buffer; } else { line->head += n; @@ -170,10 +154,10 @@ static int flush_buffer(struct line *line) } count = line->tail - line->head; - n = write_chan(&line->chan_list, line->head, count, + n = write_chan(line->chan_out, line->head, count, line->driver->write_irq); - if(n < 0) + if (n < 0) return n; line->head += n; @@ -184,50 +168,37 @@ void line_flush_buffer(struct tty_struct *tty) { struct line *line = tty->driver_data; unsigned long flags; - int err; - - /*XXX: copied from line_write, verify if it is correct!*/ - if(tty->stopped) - return; - //return 0; spin_lock_irqsave(&line->lock, flags); - err = flush_buffer(line); - /*if (err == 1) - err = 0;*/ + flush_buffer(line); spin_unlock_irqrestore(&line->lock, flags); - //return err; } -/* We map both ->flush_chars and ->put_char (which go in pair) onto ->flush_buffer - * and ->write. Hope it's not that bad.*/ +/* + * We map both ->flush_chars and ->put_char (which go in pair) onto + * ->flush_buffer and ->write. Hope it's not that bad. + */ void line_flush_chars(struct tty_struct *tty) { line_flush_buffer(tty); } -void line_put_char(struct tty_struct *tty, unsigned char ch) +int line_put_char(struct tty_struct *tty, unsigned char ch) { - line_write(tty, &ch, sizeof(ch)); + return line_write(tty, &ch, sizeof(ch)); } int line_write(struct tty_struct *tty, const unsigned char *buf, int len) { struct line *line = tty->driver_data; unsigned long flags; - int n, err, ret = 0; - - if(tty->stopped) - return 0; + int n, ret = 0; spin_lock_irqsave(&line->lock, flags); - if (line->head != line->tail) { + if (line->head != line->tail) ret = buffer_data(line, buf, len); - err = flush_buffer(line); - if (err <= 0 && (err != -EAGAIN || !ret)) - ret = err; - } else { - n = write_chan(&line->chan_list, buf, len, + else { + n = write_chan(line->chan_out, buf, len, line->driver->write_irq); if (n < 0) { ret = n; @@ -244,248 +215,151 @@ out_up: return ret; } -void line_set_termios(struct tty_struct *tty, struct termios * old) +void line_set_termios(struct tty_struct *tty, struct ktermios * old) { /* nothing */ } -static struct { - int cmd; - char *level; - char *name; -} tty_ioctls[] = { - /* don't print these, they flood the log ... */ - { TCGETS, NULL, "TCGETS" }, - { TCSETS, NULL, "TCSETS" }, - { TCSETSW, NULL, "TCSETSW" }, - { TCFLSH, NULL, "TCFLSH" }, - { TCSBRK, NULL, "TCSBRK" }, - - /* general tty stuff */ - { TCSETSF, KERN_DEBUG, "TCSETSF" }, - { TCGETA, KERN_DEBUG, "TCGETA" }, - { TIOCMGET, KERN_DEBUG, "TIOCMGET" }, - { TCSBRKP, KERN_DEBUG, "TCSBRKP" }, - { TIOCMSET, KERN_DEBUG, "TIOCMSET" }, - - /* linux-specific ones */ - { TIOCLINUX, KERN_INFO, "TIOCLINUX" }, - { KDGKBMODE, KERN_INFO, "KDGKBMODE" }, - { KDGKBTYPE, KERN_INFO, "KDGKBTYPE" }, - { KDSIGACCEPT, KERN_INFO, "KDSIGACCEPT" }, -}; - -int line_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +void line_throttle(struct tty_struct *tty) { - int ret; - int i; + struct line *line = tty->driver_data; - ret = 0; - switch(cmd) { -#ifdef TIOCGETP - case TIOCGETP: - case TIOCSETP: - case TIOCSETN: -#endif -#ifdef TIOCGETC - case TIOCGETC: - case TIOCSETC: -#endif -#ifdef TIOCGLTC - case TIOCGLTC: - case TIOCSLTC: -#endif - case TCGETS: - case TCSETSF: - case TCSETSW: - case TCSETS: - case TCGETA: - case TCSETAF: - case TCSETAW: - case TCSETA: - case TCXONC: - case TCFLSH: - case TIOCOUTQ: - case TIOCINQ: - case TIOCGLCKTRMIOS: - case TIOCSLCKTRMIOS: - case TIOCPKT: - case TIOCGSOFTCAR: - case TIOCSSOFTCAR: - return -ENOIOCTLCMD; -#if 0 - case TCwhatever: - /* do something */ - break; -#endif - default: - for (i = 0; i < ARRAY_SIZE(tty_ioctls); i++) - if (cmd == tty_ioctls[i].cmd) - break; - if (i < ARRAY_SIZE(tty_ioctls)) { - if (NULL != tty_ioctls[i].level) - printk("%s%s: %s: ioctl %s called\n", - tty_ioctls[i].level, __FUNCTION__, - tty->name, tty_ioctls[i].name); - } else { - printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n", - __FUNCTION__, tty->name, cmd); - } - ret = -ENOIOCTLCMD; - break; - } - return ret; + deactivate_chan(line->chan_in, line->driver->read_irq); + line->throttled = 1; } -static irqreturn_t line_write_interrupt(int irq, void *data, - struct pt_regs *unused) +void line_unthrottle(struct tty_struct *tty) { - struct tty_struct *tty = data; struct line *line = tty->driver_data; + + line->throttled = 0; + chan_interrupt(line, line->driver->read_irq); + + /* + * Maybe there is enough stuff pending that calling the interrupt + * throttles us again. In this case, line->throttled will be 1 + * again and we shouldn't turn the interrupt back on. + */ + if (!line->throttled) + reactivate_chan(line->chan_in, line->driver->read_irq); +} + +static irqreturn_t line_write_interrupt(int irq, void *data) +{ + struct chan *chan = data; + struct line *line = chan->line; int err; - /* Interrupts are enabled here because we registered the interrupt with - * SA_INTERRUPT (see line_setup_irq).*/ + /* + * Interrupts are disabled here because genirq keep irqs disabled when + * calling the action handler. + */ - spin_lock_irq(&line->lock); + spin_lock(&line->lock); err = flush_buffer(line); if (err == 0) { + spin_unlock(&line->lock); return IRQ_NONE; - } else if(err < 0) { + } else if (err < 0) { line->head = line->buffer; line->tail = line->buffer; } - spin_unlock_irq(&line->lock); + spin_unlock(&line->lock); - if(tty == NULL) - return IRQ_NONE; + tty_port_tty_wakeup(&line->port); - if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && - (tty->ldisc.write_wakeup != NULL)) - (tty->ldisc.write_wakeup)(tty); - - /* BLOCKING mode - * In blocking mode, everything sleeps on tty->write_wait. - * Sleeping in the console driver would break non-blocking - * writes. - */ - - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); return IRQ_HANDLED; } -int line_setup_irq(int fd, int input, int output, struct tty_struct *tty) +int line_setup_irq(int fd, int input, int output, struct line *line, void *data) { - struct line *line = tty->driver_data; - struct line_driver *driver = line->driver; - int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM; + const struct line_driver *driver = line->driver; + int err = 0; if (input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, - line_interrupt, flags, - driver->read_irq_name, tty); + line_interrupt, IRQF_SHARED, + driver->read_irq_name, data); if (err) return err; if (output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, - line_write_interrupt, flags, - driver->write_irq_name, tty); - line->have_irq = 1; + line_write_interrupt, IRQF_SHARED, + driver->write_irq_name, data); return err; } -void line_disable(struct tty_struct *tty, int current_irq) +static int line_activate(struct tty_port *port, struct tty_struct *tty) { + int ret; struct line *line = tty->driver_data; - if(!line->have_irq) - return; + ret = enable_chan(line); + if (ret) + return ret; - if(line->driver->read_irq == current_irq) - free_irq_later(line->driver->read_irq, tty); - else { - free_irq(line->driver->read_irq, tty); + if (!line->sigio) { + chan_enable_winch(line->chan_out, port); + line->sigio = 1; } - if(line->driver->write_irq == current_irq) - free_irq_later(line->driver->write_irq, tty); - else { - free_irq(line->driver->write_irq, tty); - } + chan_window_size(line, &tty->winsize.ws_row, + &tty->winsize.ws_col); - line->have_irq = 0; + return 0; } -int line_open(struct line *lines, struct tty_struct *tty, - struct chan_opts *opts) -{ - struct line *line; - int err = 0; +static void unregister_winch(struct tty_struct *tty); - line = &lines[tty->index]; - tty->driver_data = line; +static void line_destruct(struct tty_port *port) +{ + struct tty_struct *tty = tty_port_tty_get(port); + struct line *line = tty->driver_data; - /* The IRQ which takes this lock is not yet enabled and won't be run - * before the end, so we don't need to use spin_lock_irq.*/ - spin_lock(&line->lock); - if (tty->count == 1) { - if (!line->valid) { - err = -ENODEV; - goto out; - } - if (list_empty(&line->chan_list)) { - err = parse_chan_pair(line->init_str, &line->chan_list, - line->init_pri, tty->index, opts); - if(err) goto out; - err = open_chan(&line->chan_list); - if(err) goto out; - } - /* Here the interrupt is registered.*/ - enable_chan(&line->chan_list, tty); - INIT_WORK(&line->task, line_timer_cb, tty); + if (line->sigio) { + unregister_winch(tty); + line->sigio = 0; } +} - if(!line->sigio){ - chan_enable_winch(&line->chan_list, tty); - line->sigio = 1; - } - chan_window_size(&line->chan_list, &tty->winsize.ws_row, - &tty->winsize.ws_col); - line->count++; +static const struct tty_port_operations line_port_ops = { + .activate = line_activate, + .destruct = line_destruct, +}; -out: - spin_unlock(&line->lock); - return err; +int line_open(struct tty_struct *tty, struct file *filp) +{ + struct line *line = tty->driver_data; + + return tty_port_open(&line->port, tty, filp); } -static void unregister_winch(struct tty_struct *tty); +int line_install(struct tty_driver *driver, struct tty_struct *tty, + struct line *line) +{ + int ret; + + ret = tty_standard_install(driver, tty); + if (ret) + return ret; + + tty->driver_data = line; + + return 0; +} void line_close(struct tty_struct *tty, struct file * filp) { struct line *line = tty->driver_data; - /* XXX: I assume this should be called in process context, not with - * interrupts disabled! - */ - spin_lock_irq(&line->lock); - - /* We ignore the error anyway! */ - flush_buffer(line); - - line->count--; - if (tty->count == 1) { - line_disable(tty, -1); - tty->driver_data = NULL; - } + tty_port_close(&line->port, tty, filp); +} - if((line->count == 0) && line->sigio){ - unregister_winch(tty); - line->sigio = 0; - } +void line_hangup(struct tty_struct *tty) +{ + struct line *line = tty->driver_data; - spin_unlock_irq(&line->lock); + tty_port_hangup(&line->port); } void close_lines(struct line *lines, int nlines) @@ -493,82 +367,123 @@ void close_lines(struct line *lines, int nlines) int i; for(i = 0; i < nlines; i++) - close_chan(&lines[i].chan_list); + close_chan(&lines[i]); } -/* Common setup code for both startup command line and mconsole initialization. - * @lines contains the the array (of size @num) to modify; - * @init is the setup string; - * @all_allowed is a boolean saying if we can setup the whole @lines - * at once. For instance, it will be usually true for startup init. (where we - * can use con=xterm) and false for mconsole.*/ - -int line_setup(struct line *lines, unsigned int num, char *init, int all_allowed) +int setup_one_line(struct line *lines, int n, char *init, + const struct chan_opts *opts, char **error_out) { - int i, n; - char *end; + struct line *line = &lines[n]; + struct tty_driver *driver = line->driver->driver; + int err = -EINVAL; - if(*init == '=') { - /* We said con=/ssl= instead of con#=, so we are configuring all - * consoles at once.*/ - n = -1; - } else { - n = simple_strtoul(init, &end, 0); - if(*end != '='){ - printk(KERN_ERR "line_setup failed to parse \"%s\"\n", - init); - return 0; - } - init = end; + if (line->port.count) { + *error_out = "Device is already open"; + goto out; } - init++; - if (n >= (signed int) num) { - printk("line_setup - %d out of range ((0 ... %d) allowed)\n", - n, num - 1); - return 0; - } else if (n >= 0){ - if (lines[n].count > 0) { - printk("line_setup - device %d is open\n", n); - return 0; + if (!strcmp(init, "none")) { + if (line->valid) { + line->valid = 0; + kfree(line->init_str); + tty_unregister_device(driver, n); + parse_chan_pair(NULL, line, n, opts, error_out); + err = 0; } - if (lines[n].init_pri <= INIT_ONE){ - lines[n].init_pri = INIT_ONE; - if (!strcmp(init, "none")) - lines[n].valid = 0; - else { - lines[n].init_str = init; - lines[n].valid = 1; - } - } - } else if(!all_allowed){ - printk("line_setup - can't configure all devices from " - "mconsole\n"); - return 0; } else { - for(i = 0; i < num; i++){ - if(lines[i].init_pri <= INIT_ALL){ - lines[i].init_pri = INIT_ALL; - if(!strcmp(init, "none")) lines[i].valid = 0; - else { - lines[i].init_str = init; - lines[i].valid = 1; - } + char *new = kstrdup(init, GFP_KERNEL); + if (!new) { + *error_out = "Failed to allocate memory"; + return -ENOMEM; + } + if (line->valid) { + tty_unregister_device(driver, n); + kfree(line->init_str); + } + line->init_str = new; + line->valid = 1; + err = parse_chan_pair(new, line, n, opts, error_out); + if (!err) { + struct device *d = tty_port_register_device(&line->port, + driver, n, NULL); + if (IS_ERR(d)) { + *error_out = "Failed to register device"; + err = PTR_ERR(d); + parse_chan_pair(NULL, line, n, opts, error_out); } } + if (err) { + line->init_str = NULL; + line->valid = 0; + kfree(new); + } } - return 1; +out: + return err; } -int line_config(struct line *lines, unsigned int num, char *str) +/* + * Common setup code for both startup command line and mconsole initialization. + * @lines contains the array (of size @num) to modify; + * @init is the setup string; + * @error_out is an error string in the case of failure; + */ + +int line_setup(char **conf, unsigned int num, char **def, + char *init, char *name) { - char *new = uml_strdup(str); + char *error; + + if (*init == '=') { + /* + * We said con=/ssl= instead of con#=, so we are configuring all + * consoles at once. + */ + *def = init + 1; + } else { + char *end; + unsigned n = simple_strtoul(init, &end, 0); - if(new == NULL){ - printk("line_config - uml_strdup failed\n"); - return -ENOMEM; + if (*end != '=') { + error = "Couldn't parse device number"; + goto out; + } + if (n >= num) { + error = "Device number out of range"; + goto out; + } + conf[n] = end + 1; } - return !line_setup(lines, num, new, 0); + return 0; + +out: + printk(KERN_ERR "Failed to set up %s with " + "configuration string \"%s\" : %s\n", name, init, error); + return -EINVAL; +} + +int line_config(struct line *lines, unsigned int num, char *str, + const struct chan_opts *opts, char **error_out) +{ + char *end; + int n; + + if (*str == '=') { + *error_out = "Can't configure all devices from mconsole"; + return -EINVAL; + } + + n = simple_strtoul(str, &end, 0); + if (*end++ != '=') { + *error_out = "Couldn't parse device number"; + return -EINVAL; + } + if (n >= num) { + *error_out = "Device number out of range"; + return -EINVAL; + } + + return setup_one_line(lines, n, end, opts, error_out); } int line_get_config(char *name, struct line *lines, unsigned int num, char *str, @@ -579,25 +494,29 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, int dev, n = 0; dev = simple_strtoul(name, &end, 0); - if((*end != '\0') || (end == name)){ + if ((*end != '\0') || (end == name)) { *error_out = "line_get_config failed to parse device number"; return 0; } - if((dev < 0) || (dev >= num)){ + if ((dev < 0) || (dev >= num)) { *error_out = "device number out of range"; return 0; } line = &lines[dev]; - spin_lock(&line->lock); - if(!line->valid) + if (!line->valid) CONFIG_CHUNK(str, size, n, "none", 1); - else if(line->count == 0) - CONFIG_CHUNK(str, size, n, line->init_str, 1); - else n = chan_config_string(&line->chan_list, str, size, error_out); - spin_unlock(&line->lock); + else { + struct tty_struct *tty = tty_port_tty_get(&line->port); + if (tty == NULL) { + CONFIG_CHUNK(str, size, n, line->init_str, 1); + } else { + n = chan_config_string(line, str, size, error_out); + tty_kref_put(tty); + } + } return n; } @@ -605,204 +524,222 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, int line_id(char **str, int *start_out, int *end_out) { char *end; - int n; + int n; n = simple_strtoul(*str, &end, 0); - if((*end != '\0') || (end == *str)) - return -1; + if ((*end != '\0') || (end == *str)) + return -1; - *str = end; - *start_out = n; - *end_out = n; - return n; + *str = end; + *start_out = n; + *end_out = n; + return n; } -int line_remove(struct line *lines, unsigned int num, int n) +int line_remove(struct line *lines, unsigned int num, int n, char **error_out) { - char config[sizeof("conxxxx=none\0")]; - - sprintf(config, "%d=none", n); - return !line_setup(lines, num, config, 0); + if (n >= num) { + *error_out = "Device number out of range"; + return -EINVAL; + } + return setup_one_line(lines, n, "none", NULL, error_out); } -struct tty_driver *line_register_devfs(struct lines *set, - struct line_driver *line_driver, - struct tty_operations *ops, struct line *lines, - int nlines) +int register_lines(struct line_driver *line_driver, + const struct tty_operations *ops, + struct line *lines, int nlines) { - int i; struct tty_driver *driver = alloc_tty_driver(nlines); + int err; + int i; if (!driver) - return NULL; + return -ENOMEM; driver->driver_name = line_driver->name; driver->name = line_driver->device_name; - driver->devfs_name = line_driver->devfs_name; driver->major = line_driver->major; driver->minor_start = line_driver->minor_start; driver->type = line_driver->type; driver->subtype = line_driver->subtype; - driver->flags = TTY_DRIVER_REAL_RAW; + driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; driver->init_termios = tty_std_termios; + + for (i = 0; i < nlines; i++) { + tty_port_init(&lines[i].port); + lines[i].port.ops = &line_port_ops; + spin_lock_init(&lines[i].lock); + lines[i].driver = line_driver; + INIT_LIST_HEAD(&lines[i].chan_list); + } tty_set_operations(driver, ops); - if (tty_register_driver(driver)) { - printk("%s: can't register %s driver\n", - __FUNCTION__,line_driver->name); + err = tty_register_driver(driver); + if (err) { + printk(KERN_ERR "register_lines : can't register %s driver\n", + line_driver->name); put_tty_driver(driver); - return NULL; - } - - for(i = 0; i < nlines; i++){ - if(!lines[i].valid) - tty_unregister_device(driver, i); + for (i = 0; i < nlines; i++) + tty_port_destroy(&lines[i].port); + return err; } + line_driver->driver = driver; mconsole_register_dev(&line_driver->mc); - return driver; + return 0; } -static spinlock_t winch_handler_lock; -LIST_HEAD(winch_handlers); - -void lines_init(struct line *lines, int nlines) -{ - struct line *line; - int i; - - spin_lock_init(&winch_handler_lock); - for(i = 0; i < nlines; i++){ - line = &lines[i]; - INIT_LIST_HEAD(&line->chan_list); - spin_lock_init(&line->lock); - if(line->init_str != NULL){ - line->init_str = uml_strdup(line->init_str); - if(line->init_str == NULL) - printk("lines_init - uml_strdup returned " - "NULL\n"); - } - } -} +static DEFINE_SPINLOCK(winch_handler_lock); +static LIST_HEAD(winch_handlers); struct winch { struct list_head list; int fd; int tty_fd; int pid; - struct tty_struct *tty; + struct tty_port *port; + unsigned long stack; + struct work_struct work; }; -irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) +static void __free_winch(struct work_struct *work) +{ + struct winch *winch = container_of(work, struct winch, work); + um_free_irq(WINCH_IRQ, winch); + + if (winch->pid != -1) + os_kill_process(winch->pid, 1); + if (winch->stack != 0) + free_stack(winch->stack, 0); + kfree(winch); +} + +static void free_winch(struct winch *winch) +{ + int fd = winch->fd; + winch->fd = -1; + if (fd != -1) + os_close_file(fd); + list_del(&winch->list); + __free_winch(&winch->work); +} + +static irqreturn_t winch_interrupt(int irq, void *data) { struct winch *winch = data; struct tty_struct *tty; struct line *line; + int fd = winch->fd; int err; char c; - if(winch->fd != -1){ - err = generic_read(winch->fd, &c, NULL); - if(err < 0){ - if(err != -EAGAIN){ - printk("winch_interrupt : read failed, " - "errno = %d\n", -err); - printk("fd %d is losing SIGWINCH support\n", - winch->tty_fd); + if (fd != -1) { + err = generic_read(fd, &c, NULL); + if (err < 0) { + if (err != -EAGAIN) { + winch->fd = -1; + list_del(&winch->list); + os_close_file(fd); + printk(KERN_ERR "winch_interrupt : " + "read failed, errno = %d\n", -err); + printk(KERN_ERR "fd %d is losing SIGWINCH " + "support\n", winch->tty_fd); + INIT_WORK(&winch->work, __free_winch); + schedule_work(&winch->work); return IRQ_HANDLED; } goto out; } } - tty = winch->tty; + tty = tty_port_tty_get(winch->port); if (tty != NULL) { line = tty->driver_data; - chan_window_size(&line->chan_list, - &tty->winsize.ws_row, - &tty->winsize.ws_col); - kill_pg(tty->pgrp, SIGWINCH, 1); + if (line != NULL) { + chan_window_size(line, &tty->winsize.ws_row, + &tty->winsize.ws_col); + kill_pgrp(tty->pgrp, SIGWINCH, 1); + } + tty_kref_put(tty); } out: - if(winch->fd != -1) + if (winch->fd != -1) reactivate_fd(winch->fd, WINCH_IRQ); return IRQ_HANDLED; } -void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) +void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port, + unsigned long stack) { struct winch *winch; winch = kmalloc(sizeof(*winch), GFP_KERNEL); if (winch == NULL) { - printk("register_winch_irq - kmalloc failed\n"); - return; + printk(KERN_ERR "register_winch_irq - kmalloc failed\n"); + goto cleanup; } *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), .fd = fd, .tty_fd = tty_fd, .pid = pid, - .tty = tty }); + .port = port, + .stack = stack }); + + if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, + IRQF_SHARED, "winch", winch) < 0) { + printk(KERN_ERR "register_winch_irq - failed to register " + "IRQ\n"); + goto out_free; + } spin_lock(&winch_handler_lock); list_add(&winch->list, &winch_handlers); spin_unlock(&winch_handler_lock); - if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, - SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, - "winch", winch) < 0) - printk("register_winch_irq - failed to register IRQ\n"); + return; + + out_free: + kfree(winch); + cleanup: + os_kill_process(pid, 1); + os_close_file(fd); + if (stack != 0) + free_stack(stack, 0); } static void unregister_winch(struct tty_struct *tty) { - struct list_head *ele; - struct winch *winch, *found = NULL; + struct list_head *ele, *next; + struct winch *winch; + struct tty_struct *wtty; spin_lock(&winch_handler_lock); - list_for_each(ele, &winch_handlers){ - winch = list_entry(ele, struct winch, list); - if(winch->tty == tty){ - found = winch; - break; - } - } - if(found == NULL) - goto err; - - list_del(&winch->list); - spin_unlock(&winch_handler_lock); - - if(winch->pid != -1) - os_kill_process(winch->pid, 1); - - free_irq(WINCH_IRQ, winch); - kfree(winch); - return; -err: + list_for_each_safe(ele, next, &winch_handlers) { + winch = list_entry(ele, struct winch, list); + wtty = tty_port_tty_get(winch->port); + if (wtty == tty) { + free_winch(winch); + break; + } + tty_kref_put(wtty); + } spin_unlock(&winch_handler_lock); } -/* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup - * order... are we sure that nothing else is done on the list? */ static void winch_cleanup(void) { - struct list_head *ele; + struct list_head *ele, *next; struct winch *winch; - list_for_each(ele, &winch_handlers){ + spin_lock(&winch_handler_lock); + + list_for_each_safe(ele, next, &winch_handlers) { winch = list_entry(ele, struct winch, list); - if(winch->fd != -1){ - /* Why is this different from the above free_irq(), - * which deactivates SIGIO? This searches the FD - * somewhere else and removes it from the list... */ - deactivate_fd(winch->fd, WINCH_IRQ); - os_close_file(winch->fd); - } - if(winch->pid != -1) - os_kill_process(winch->pid, 1); + free_winch(winch); } + + spin_unlock(&winch_handler_lock); } __uml_exitcall(winch_cleanup); @@ -811,14 +748,14 @@ char *add_xterm_umid(char *base) char *umid, *title; int len; - umid = get_umid(1); - if(umid == NULL) + umid = get_umid(); + if (*umid == '\0') return base; - + len = strlen(base) + strlen(" ()") + strlen(umid) + 1; title = kmalloc(len, GFP_KERNEL); - if(title == NULL){ - printk("Failed to allocate buffer for xterm title\n"); + if (title == NULL) { + printk(KERN_ERR "Failed to allocate buffer for xterm title\n"); return base; } diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h new file mode 100644 index 00000000000..138a14526d9 --- /dev/null +++ b/arch/um/drivers/line.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __LINE_H__ +#define __LINE_H__ + +#include <linux/list.h> +#include <linux/workqueue.h> +#include <linux/tty.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/mutex.h> +#include "chan_user.h" +#include "mconsole_kern.h" + +/* There's only two modifiable fields in this - .mc.list and .driver */ +struct line_driver { + const char *name; + const char *device_name; + const short major; + const short minor_start; + const short type; + const short subtype; + const int read_irq; + const char *read_irq_name; + const int write_irq; + const char *write_irq_name; + struct mc_device mc; + struct tty_driver *driver; +}; + +struct line { + struct tty_port port; + int valid; + + char *init_str; + struct list_head chan_list; + struct chan *chan_in, *chan_out; + + /*This lock is actually, mostly, local to*/ + spinlock_t lock; + int throttled; + /* Yes, this is a real circular buffer. + * XXX: And this should become a struct kfifo! + * + * buffer points to a buffer allocated on demand, of length + * LINE_BUFSIZE, head to the start of the ring, tail to the end.*/ + char *buffer; + char *head; + char *tail; + + int sigio; + struct delayed_work task; + const struct line_driver *driver; +}; + +extern void line_close(struct tty_struct *tty, struct file * filp); +extern int line_open(struct tty_struct *tty, struct file *filp); +extern int line_install(struct tty_driver *driver, struct tty_struct *tty, + struct line *line); +extern void line_cleanup(struct tty_struct *tty); +extern void line_hangup(struct tty_struct *tty); +extern int line_setup(char **conf, unsigned nlines, char **def, + char *init, char *name); +extern int line_write(struct tty_struct *tty, const unsigned char *buf, + int len); +extern int line_put_char(struct tty_struct *tty, unsigned char ch); +extern void line_set_termios(struct tty_struct *tty, struct ktermios * old); +extern int line_chars_in_buffer(struct tty_struct *tty); +extern void line_flush_buffer(struct tty_struct *tty); +extern void line_flush_chars(struct tty_struct *tty); +extern int line_write_room(struct tty_struct *tty); +extern void line_throttle(struct tty_struct *tty); +extern void line_unthrottle(struct tty_struct *tty); + +extern char *add_xterm_umid(char *base); +extern int line_setup_irq(int fd, int input, int output, struct line *line, + void *data); +extern void line_close_chan(struct line *line); +extern int register_lines(struct line_driver *line_driver, + const struct tty_operations *driver, + struct line *lines, int nlines); +extern int setup_one_line(struct line *lines, int n, char *init, + const struct chan_opts *opts, char **error_out); +extern void close_lines(struct line *lines, int nlines); + +extern int line_config(struct line *lines, unsigned int sizeof_lines, + char *str, const struct chan_opts *opts, + char **error_out); +extern int line_id(char **str, int *start_out, int *end_out); +extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n, + char **error_out); +extern int line_get_config(char *dev, struct line *lines, + unsigned int sizeof_lines, char *str, + int size, char **error_out); + +#endif diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h deleted file mode 100644 index a2c6db24345..00000000000 --- a/arch/um/drivers/mcast.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "net_user.h" - -struct mcast_data { - char *addr; - unsigned short port; - void *mcast_addr; - int ttl; - void *dev; -}; - -extern struct net_user_info mcast_user_info; - -extern int mcast_user_write(int fd, void *buf, int len, - struct mcast_data *pri); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c deleted file mode 100644 index 217438cdef3..00000000000 --- a/arch/um/drivers/mcast_kern.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * user-mode-linux networking multicast transport - * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> - * - * based on the existing uml-networking code, which is - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and - * James Leu (jleu@mindspring.net). - * Copyright (C) 2001 by various other people who didn't put their name here. - * - * Licensed under the GPL. - */ - -#include "linux/kernel.h" -#include "linux/init.h" -#include "linux/netdevice.h" -#include "linux/etherdevice.h" -#include "linux/in.h" -#include "linux/inet.h" -#include "net_kern.h" -#include "net_user.h" -#include "mcast.h" - -struct mcast_init { - char *addr; - int port; - int ttl; -}; - -void mcast_init(struct net_device *dev, void *data) -{ - struct uml_net_private *pri; - struct mcast_data *dpri; - struct mcast_init *init = data; - - pri = dev->priv; - dpri = (struct mcast_data *) pri->user; - dpri->addr = init->addr; - dpri->port = init->port; - dpri->ttl = init->ttl; - dpri->dev = dev; - - printk("mcast backend "); - printk("multicast adddress: %s:%u, TTL:%u ", - dpri->addr, dpri->port, dpri->ttl); - - printk("\n"); -} - -static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) -{ - *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); - if(*skb == NULL) return(-ENOMEM); - return(net_recvfrom(fd, (*skb)->mac.raw, - (*skb)->dev->mtu + ETH_HEADER_OTHER)); -} - -static int mcast_write(int fd, struct sk_buff **skb, - struct uml_net_private *lp) -{ - return mcast_user_write(fd, (*skb)->data, (*skb)->len, - (struct mcast_data *) &lp->user); -} - -static struct net_kern_info mcast_kern_info = { - .init = mcast_init, - .protocol = eth_protocol, - .read = mcast_read, - .write = mcast_write, -}; - -int mcast_setup(char *str, char **mac_out, void *data) -{ - struct mcast_init *init = data; - char *port_str = NULL, *ttl_str = NULL, *remain; - char *last; - - *init = ((struct mcast_init) - { .addr = "239.192.168.1", - .port = 1102, - .ttl = 1 }); - - remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str, - NULL); - if(remain != NULL){ - printk(KERN_ERR "mcast_setup - Extra garbage on " - "specification : '%s'\n", remain); - return(0); - } - - if(port_str != NULL){ - init->port = simple_strtoul(port_str, &last, 10); - if((*last != '\0') || (last == port_str)){ - printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", - port_str); - return(0); - } - } - - if(ttl_str != NULL){ - init->ttl = simple_strtoul(ttl_str, &last, 10); - if((*last != '\0') || (last == ttl_str)){ - printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", - ttl_str); - return(0); - } - } - - printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr, - init->port, init->ttl); - - return(1); -} - -static struct transport mcast_transport = { - .list = LIST_HEAD_INIT(mcast_transport.list), - .name = "mcast", - .setup = mcast_setup, - .user = &mcast_user_info, - .kern = &mcast_kern_info, - .private_size = sizeof(struct mcast_data), - .setup_size = sizeof(struct mcast_init), -}; - -static int register_mcast(void) -{ - register_transport(&mcast_transport); - return(1); -} - -__initcall(register_mcast); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c deleted file mode 100644 index 5db136e2651..00000000000 --- a/arch/um/drivers/mcast_user.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * user-mode-linux networking multicast transport - * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> - * - * based on the existing uml-networking code, which is - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and - * James Leu (jleu@mindspring.net). - * Copyright (C) 2001 by various other people who didn't put their name here. - * - * Licensed under the GPL. - * - */ - -#include <errno.h> -#include <unistd.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/time.h> -#include <netinet/in.h> -#include "net_user.h" -#include "mcast.h" -#include "kern_util.h" -#include "user_util.h" -#include "user.h" -#include "os.h" - -#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) - -static struct sockaddr_in *new_addr(char *addr, unsigned short port) -{ - struct sockaddr_in *sin; - - sin = um_kmalloc(sizeof(struct sockaddr_in)); - if(sin == NULL){ - printk("new_addr: allocation of sockaddr_in failed\n"); - return(NULL); - } - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = in_aton(addr); - sin->sin_port = htons(port); - return(sin); -} - -static void mcast_user_init(void *data, void *dev) -{ - struct mcast_data *pri = data; - - pri->mcast_addr = new_addr(pri->addr, pri->port); - pri->dev = dev; -} - -static int mcast_open(void *data) -{ - struct mcast_data *pri = data; - struct sockaddr_in *sin = pri->mcast_addr; - struct ip_mreq mreq; - int fd, yes = 1, err = 0; - - - if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) - goto out; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - - if (fd < 0){ - printk("mcast_open : data socket failed, errno = %d\n", - errno); - err = -errno; - goto out; - } - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { - printk("mcast_open: SO_REUSEADDR failed, errno = %d\n", - errno); - err = -errno; - goto out_close; - } - - /* set ttl according to config */ - if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl, - sizeof(pri->ttl)) < 0) { - printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n", - errno); - err = -errno; - goto out_close; - } - - /* set LOOP, so data does get fed back to local sockets */ - if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) { - printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n", - errno); - err = -errno; - goto out_close; - } - - /* bind socket to mcast address */ - if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) { - printk("mcast_open : data bind failed, errno = %d\n", errno); - err = -errno; - goto out_close; - } - - /* subscribe to the multicast group */ - mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr; - mreq.imr_interface.s_addr = 0; - if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, - &mreq, sizeof(mreq)) < 0) { - printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n", - errno); - printk("There appears not to be a multicast-capable network " - "interface on the host.\n"); - printk("eth0 should be configured in order to use the " - "multicast transport.\n"); - err = -errno; - goto out_close; - } - - return fd; - - out_close: - os_close_file(fd); - out: - return err; -} - -static void mcast_close(int fd, void *data) -{ - struct ip_mreq mreq; - struct mcast_data *pri = data; - struct sockaddr_in *sin = pri->mcast_addr; - - mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr; - mreq.imr_interface.s_addr = 0; - if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, - &mreq, sizeof(mreq)) < 0) { - printk("mcast_open: IP_DROP_MEMBERSHIP failed, error = %d\n", - errno); - } - - os_close_file(fd); -} - -int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri) -{ - struct sockaddr_in *data_addr = pri->mcast_addr; - - return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr))); -} - -static int mcast_set_mtu(int mtu, void *data) -{ - return(mtu); -} - -struct net_user_info mcast_user_info = { - .init = mcast_user_init, - .open = mcast_open, - .close = mcast_close, - .remove = NULL, - .set_mtu = mcast_set_mtu, - .add_address = NULL, - .delete_address = NULL, - .max_packet = MAX_PACKET - ETH_HEADER_OTHER -}; diff --git a/arch/um/include/mconsole.h b/arch/um/drivers/mconsole.h index b1b512f4703..8b22535c62c 100644 --- a/arch/um/include/mconsole.h +++ b/arch/um/drivers/mconsole.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -12,6 +12,8 @@ #define u32 uint32_t #endif +#include <sysdep/ptrace.h> + #define MCONSOLE_MAGIC (0xcafebabe) #define MCONSOLE_MAX_DATA (512) #define MCONSOLE_VERSION 2 @@ -32,7 +34,7 @@ struct mconsole_reply { struct mconsole_notify { u32 magic; - u32 version; + u32 version; enum { MCONSOLE_SOCKET, MCONSOLE_PANIC, MCONSOLE_HANG, MCONSOLE_USER_NOTIFY } type; u32 len; @@ -61,12 +63,15 @@ struct mc_request struct mconsole_request request; struct mconsole_command *cmd; + struct uml_pt_regs regs; }; extern char mconsole_socket_name[]; extern int mconsole_unlink_socket(void); -extern int mconsole_reply(struct mc_request *req, char *reply, int err, +extern int mconsole_reply_len(struct mc_request *req, const char *reply, + int len, int err, int more); +extern int mconsole_reply(struct mc_request *req, const char *str, int err, int more); extern void mconsole_version(struct mc_request *req); @@ -84,21 +89,10 @@ extern void mconsole_proc(struct mc_request *req); extern void mconsole_stack(struct mc_request *req); extern int mconsole_get_request(int fd, struct mc_request *req); -extern int mconsole_notify(char *sock_name, int type, const void *data, +extern int mconsole_notify(char *sock_name, int type, const void *data, int len); extern char *mconsole_notify_socket(void); extern void lock_notify(void); extern void unlock_notify(void); #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 12c95368124..29880c9b324 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -1,43 +1,44 @@ /* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) - * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2001 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/kernel.h" -#include "linux/slab.h" -#include "linux/init.h" -#include "linux/notifier.h" -#include "linux/reboot.h" -#include "linux/utsname.h" -#include "linux/ctype.h" -#include "linux/interrupt.h" -#include "linux/sysrq.h" -#include "linux/workqueue.h" -#include "linux/module.h" -#include "linux/file.h" -#include "linux/fs.h" -#include "linux/namei.h" -#include "linux/proc_fs.h" -#include "linux/syscalls.h" -#include "asm/irq.h" -#include "asm/uaccess.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" +#include <linux/console.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/proc_fs.h> +#include <linux/slab.h> +#include <linux/syscalls.h> +#include <linux/utsname.h> +#include <linux/socket.h> +#include <linux/un.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> +#include <linux/fs.h> +#include <linux/mount.h> +#include <linux/file.h> +#include <asm/uaccess.h> +#include <asm/switch_to.h> + +#include <init.h> +#include <irq_kern.h> +#include <irq_user.h> +#include <kern_util.h> #include "mconsole.h" #include "mconsole_kern.h" -#include "irq_user.h" -#include "init.h" -#include "os.h" -#include "umid.h" -#include "irq_kern.h" -#include "choose-mode.h" - -static int do_unlink_socket(struct notifier_block *notifier, +#include <os.h> + +static int do_unlink_socket(struct notifier_block *notifier, unsigned long what, void *data) { - return(mconsole_unlink_socket()); + return mconsole_unlink_socket(); } @@ -46,22 +47,21 @@ static struct notifier_block reboot_notifier = { .priority = 0, }; -/* Safe without explicit locking for now. Tasklets provide their own +/* Safe without explicit locking for now. Tasklets provide their own * locking, and the interrupt handler is safe because it can't interrupt * itself and it can only happen on CPU 0. */ -LIST_HEAD(mc_requests); +static LIST_HEAD(mc_requests); -static void mc_work_proc(void *unused) +static void mc_work_proc(struct work_struct *unused) { struct mconsole_entry *req; unsigned long flags; - while(!list_empty(&mc_requests)){ - local_save_flags(flags); - req = list_entry(mc_requests.next, struct mconsole_entry, - list); + while (!list_empty(&mc_requests)) { + local_irq_save(flags); + req = list_entry(mc_requests.next, struct mconsole_entry, list); list_del(&req->list); local_irq_restore(flags); req->request.cmd->handler(&req->request); @@ -69,43 +69,43 @@ static void mc_work_proc(void *unused) } } -DECLARE_WORK(mconsole_work, mc_work_proc, NULL); +static DECLARE_WORK(mconsole_work, mc_work_proc); -static irqreturn_t mconsole_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t mconsole_interrupt(int irq, void *dev_id) { /* long to avoid size mismatch warnings from gcc */ long fd; struct mconsole_entry *new; - struct mc_request req; + static struct mc_request req; /* that's OK */ fd = (long) dev_id; - while (mconsole_get_request(fd, &req)){ - if(req.cmd->context == MCONSOLE_INTR) + while (mconsole_get_request(fd, &req)) { + if (req.cmd->context == MCONSOLE_INTR) (*req.cmd->handler)(&req); else { - new = kmalloc(sizeof(*new), GFP_ATOMIC); - if(new == NULL) + new = kmalloc(sizeof(*new), GFP_NOWAIT); + if (new == NULL) mconsole_reply(&req, "Out of memory", 1, 0); else { new->request = req; + new->request.regs = get_irq_regs()->regs; list_add(&new->list, &mc_requests); } } } - if(!list_empty(&mc_requests)) + if (!list_empty(&mc_requests)) schedule_work(&mconsole_work); reactivate_fd(fd, MCONSOLE_IRQ); - return(IRQ_HANDLED); + return IRQ_HANDLED; } void mconsole_version(struct mc_request *req) { char version[256]; - sprintf(version, "%s %s %s %s %s", system_utsname.sysname, - system_utsname.nodename, system_utsname.release, - system_utsname.version, system_utsname.machine); + sprintf(version, "%s %s %s %s %s", utsname()->sysname, + utsname()->nodename, utsname()->release, utsname()->version, + utsname()->machine); mconsole_reply(req, version, 0, 0); } @@ -117,148 +117,59 @@ void mconsole_log(struct mc_request *req) ptr += strlen("log "); len = req->len - (ptr - req->request.data); - printk("%.*s", len, ptr); + printk(KERN_WARNING "%.*s", len, ptr); mconsole_reply(req, "", 0, 0); } -/* This is a more convoluted version of mconsole_proc, which has some stability - * problems; however, we need it fixed, because it is expected that UML users - * mount HPPFS instead of procfs on /proc. And we want mconsole_proc to still - * show the real procfs content, not the ones from hppfs.*/ -#if 0 -void mconsole_proc(struct mc_request *req) -{ - struct nameidata nd; - struct file_system_type *proc; - struct super_block *super; - struct file *file; - int n, err; - char *ptr = req->request.data, *buf; - - ptr += strlen("proc"); - while(isspace(*ptr)) ptr++; - - proc = get_fs_type("proc"); - if(proc == NULL){ - mconsole_reply(req, "procfs not registered", 1, 0); - goto out; - } - - super = (*proc->get_sb)(proc, 0, NULL, NULL); - put_filesystem(proc); - if(super == NULL){ - mconsole_reply(req, "Failed to get procfs superblock", 1, 0); - goto out; - } - up_write(&super->s_umount); - - nd.dentry = super->s_root; - nd.mnt = NULL; - nd.flags = O_RDONLY + 1; - nd.last_type = LAST_ROOT; - - /* START: it was experienced that the stability problems are closed - * if commenting out these two calls + the below read cycle. To - * make UML crash again, it was enough to readd either one.*/ - err = link_path_walk(ptr, &nd); - if(err){ - mconsole_reply(req, "Failed to look up file", 1, 0); - goto out_kill; - } - - file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); - if(IS_ERR(file)){ - mconsole_reply(req, "Failed to open file", 1, 0); - goto out_kill; - } - /*END*/ - - buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if(buf == NULL){ - mconsole_reply(req, "Failed to allocate buffer", 1, 0); - goto out_fput; - } - - if((file->f_op != NULL) && (file->f_op->read != NULL)){ - do { - n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1, - &file->f_pos); - if(n >= 0){ - buf[n] = '\0'; - mconsole_reply(req, buf, 0, (n > 0)); - } - else { - mconsole_reply(req, "Read of file failed", - 1, 0); - goto out_free; - } - } while(n > 0); - } - else mconsole_reply(req, "", 0, 0); - - out_free: - kfree(buf); - out_fput: - fput(file); - out_kill: - deactivate_super(super); - out: ; -} -#endif - void mconsole_proc(struct mc_request *req) { - char path[64]; + struct vfsmount *mnt = task_active_pid_ns(current)->proc_mnt; char *buf; int len; - int fd; + struct file *file; int first_chunk = 1; char *ptr = req->request.data; ptr += strlen("proc"); - while(isspace(*ptr)) ptr++; - snprintf(path, sizeof(path), "/proc/%s", ptr); + ptr = skip_spaces(ptr); - fd = sys_open(path, 0, 0); - if (fd < 0) { + file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY); + if (IS_ERR(file)) { mconsole_reply(req, "Failed to open file", 1, 0); - printk("open %s: %d\n",path,fd); + printk(KERN_ERR "open /proc/%s: %ld\n", ptr, PTR_ERR(file)); goto out; } buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if(buf == NULL){ + if (buf == NULL) { mconsole_reply(req, "Failed to allocate buffer", 1, 0); - goto out_close; + goto out_fput; } - for (;;) { - len = sys_read(fd, buf, PAGE_SIZE-1); + do { + loff_t pos = file->f_pos; + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + len = vfs_read(file, buf, PAGE_SIZE - 1, &pos); + set_fs(old_fs); + file->f_pos = pos; if (len < 0) { mconsole_reply(req, "Read of file failed", 1, 0); goto out_free; } - /*Begin the file content on his own line.*/ + /* Begin the file content on his own line. */ if (first_chunk) { mconsole_reply(req, "\n", 0, 1); first_chunk = 0; } - if (len == PAGE_SIZE-1) { - buf[len] = '\0'; - mconsole_reply(req, buf, 0, 1); - } else { - buf[len] = '\0'; - mconsole_reply(req, buf, 0, 0); - break; - } - } - + buf[len] = '\0'; + mconsole_reply(req, buf, 0, (len > 0)); + } while (len > 0); out_free: kfree(buf); - out_close: - sys_close(fd); - out: - /* nothing */; + out_fput: + fput(file); + out: ; } #define UML_MCONSOLE_HELPTEXT \ @@ -272,7 +183,7 @@ void mconsole_proc(struct mc_request *req) config <dev> - Query the configuration of a device \n\ remove <dev> - Remove a device from UML \n\ sysrq <letter> - Performs the SysRq action controlled by the letter \n\ - cad - invoke the Ctl-Alt-Del handler \n\ + cad - invoke the Ctrl-Alt-Del handler \n\ stop - pause the UML; it will do nothing until it receives a 'go' \n\ go - continue the UML after a 'stop' \n\ log <string> - make UML enter <string> into the kernel log\n\ @@ -297,8 +208,6 @@ void mconsole_reboot(struct mc_request *req) machine_restart(NULL); } -extern void ctrl_alt_del(void); - void mconsole_cad(struct mc_request *req) { mconsole_reply(req, "", 0, 0); @@ -314,9 +223,23 @@ void mconsole_stop(struct mc_request *req) { deactivate_fd(req->originating_fd, MCONSOLE_IRQ); os_set_fd_block(req->originating_fd, 1); - mconsole_reply(req, "", 0, 0); - while(mconsole_get_request(req->originating_fd, req)){ - if(req->cmd->handler == mconsole_go) break; + mconsole_reply(req, "stopped", 0, 0); + for (;;) { + if (!mconsole_get_request(req->originating_fd, req)) + continue; + if (req->cmd->handler == mconsole_go) + break; + if (req->cmd->handler == mconsole_stop) { + mconsole_reply(req, "Already stopped", 1, 0); + continue; + } + if (req->cmd->handler == mconsole_sysrq) { + struct pt_regs *old_regs; + old_regs = set_irq_regs((struct pt_regs *)&req->regs); + mconsole_sysrq(req); + set_irq_regs(old_regs); + continue; + } (*req->cmd->handler)(req); } os_set_fd_block(req->originating_fd, 0); @@ -324,13 +247,15 @@ void mconsole_stop(struct mc_request *req) mconsole_reply(req, "", 0, 0); } -/* This list is populated by __initcall routines. */ - -LIST_HEAD(mconsole_devices); +static DEFINE_SPINLOCK(mc_devices_lock); +static LIST_HEAD(mconsole_devices); void mconsole_register_dev(struct mc_device *new) { + spin_lock(&mc_devices_lock); + BUG_ON(!list_empty(&new->list)); list_add(&new->list, &mconsole_devices); + spin_unlock(&mc_devices_lock); } static struct mc_device *mconsole_find_dev(char *name) @@ -338,141 +263,378 @@ static struct mc_device *mconsole_find_dev(char *name) struct list_head *ele; struct mc_device *dev; - list_for_each(ele, &mconsole_devices){ + list_for_each(ele, &mconsole_devices) { dev = list_entry(ele, struct mc_device, list); - if(!strncmp(name, dev->name, strlen(dev->name))) - return(dev); + if (!strncmp(name, dev->name, strlen(dev->name))) + return dev; } - return(NULL); + return NULL; } +#define UNPLUGGED_PER_PAGE \ + ((PAGE_SIZE - sizeof(struct list_head)) / sizeof(unsigned long)) + +struct unplugged_pages { + struct list_head list; + void *pages[UNPLUGGED_PER_PAGE]; +}; + +static DEFINE_MUTEX(plug_mem_mutex); +static unsigned long long unplugged_pages_count = 0; +static LIST_HEAD(unplugged_pages); +static int unplug_index = UNPLUGGED_PER_PAGE; + +static int mem_config(char *str, char **error_out) +{ + unsigned long long diff; + int err = -EINVAL, i, add; + char *ret; + + if (str[0] != '=') { + *error_out = "Expected '=' after 'mem'"; + goto out; + } + + str++; + if (str[0] == '-') + add = 0; + else if (str[0] == '+') { + add = 1; + } + else { + *error_out = "Expected increment to start with '-' or '+'"; + goto out; + } + + str++; + diff = memparse(str, &ret); + if (*ret != '\0') { + *error_out = "Failed to parse memory increment"; + goto out; + } + + diff /= PAGE_SIZE; + + mutex_lock(&plug_mem_mutex); + for (i = 0; i < diff; i++) { + struct unplugged_pages *unplugged; + void *addr; + + if (add) { + if (list_empty(&unplugged_pages)) + break; + + unplugged = list_entry(unplugged_pages.next, + struct unplugged_pages, list); + if (unplug_index > 0) + addr = unplugged->pages[--unplug_index]; + else { + list_del(&unplugged->list); + addr = unplugged; + unplug_index = UNPLUGGED_PER_PAGE; + } + + free_page((unsigned long) addr); + unplugged_pages_count--; + } + else { + struct page *page; + + page = alloc_page(GFP_ATOMIC); + if (page == NULL) + break; + + unplugged = page_address(page); + if (unplug_index == UNPLUGGED_PER_PAGE) { + list_add(&unplugged->list, &unplugged_pages); + unplug_index = 0; + } + else { + struct list_head *entry = unplugged_pages.next; + addr = unplugged; + + unplugged = list_entry(entry, + struct unplugged_pages, + list); + err = os_drop_memory(addr, PAGE_SIZE); + if (err) { + printk(KERN_ERR "Failed to release " + "memory - errno = %d\n", err); + *error_out = "Failed to release memory"; + goto out_unlock; + } + unplugged->pages[unplug_index++] = addr; + } + + unplugged_pages_count++; + } + } + + err = 0; +out_unlock: + mutex_unlock(&plug_mem_mutex); +out: + return err; +} + +static int mem_get_config(char *name, char *str, int size, char **error_out) +{ + char buf[sizeof("18446744073709551615")]; + int len = 0; + + sprintf(buf, "%ld", uml_physmem); + CONFIG_CHUNK(str, size, len, buf, 1); + + return len; +} + +static int mem_id(char **str, int *start_out, int *end_out) +{ + *start_out = 0; + *end_out = 0; + + return 0; +} + +static int mem_remove(int n, char **error_out) +{ + *error_out = "Memory doesn't support the remove operation"; + return -EBUSY; +} + +static struct mc_device mem_mc = { + .list = LIST_HEAD_INIT(mem_mc.list), + .name = "mem", + .config = mem_config, + .get_config = mem_get_config, + .id = mem_id, + .remove = mem_remove, +}; + +static int __init mem_mc_init(void) +{ + if (can_drop_memory()) + mconsole_register_dev(&mem_mc); + else printk(KERN_ERR "Can't release memory to the host - memory " + "hotplug won't be supported\n"); + return 0; +} + +__initcall(mem_mc_init); + #define CONFIG_BUF_SIZE 64 -static void mconsole_get_config(int (*get_config)(char *, char *, int, +static void mconsole_get_config(int (*get_config)(char *, char *, int, char **), struct mc_request *req, char *name) { char default_buf[CONFIG_BUF_SIZE], *error, *buf; int n, size; - if(get_config == NULL){ + if (get_config == NULL) { mconsole_reply(req, "No get_config routine defined", 1, 0); return; } error = NULL; - size = sizeof(default_buf)/sizeof(default_buf[0]); + size = ARRAY_SIZE(default_buf); buf = default_buf; - while(1){ + while (1) { n = (*get_config)(name, buf, size, &error); - if(error != NULL){ + if (error != NULL) { mconsole_reply(req, error, 1, 0); goto out; } - if(n <= size){ + if (n <= size) { mconsole_reply(req, buf, 0, 0); goto out; } - if(buf != default_buf) + if (buf != default_buf) kfree(buf); size = n; buf = kmalloc(size, GFP_KERNEL); - if(buf == NULL){ + if (buf == NULL) { mconsole_reply(req, "Failed to allocate buffer", 1, 0); return; } } out: - if(buf != default_buf) + if (buf != default_buf) kfree(buf); - } void mconsole_config(struct mc_request *req) { struct mc_device *dev; - char *ptr = req->request.data, *name; + char *ptr = req->request.data, *name, *error_string = ""; int err; ptr += strlen("config"); - while(isspace(*ptr)) ptr++; + ptr = skip_spaces(ptr); dev = mconsole_find_dev(ptr); - if(dev == NULL){ + if (dev == NULL) { mconsole_reply(req, "Bad configuration option", 1, 0); return; } name = &ptr[strlen(dev->name)]; ptr = name; - while((*ptr != '=') && (*ptr != '\0')) + while ((*ptr != '=') && (*ptr != '\0')) ptr++; - if(*ptr == '='){ - err = (*dev->config)(name); - mconsole_reply(req, "", err, 0); + if (*ptr == '=') { + err = (*dev->config)(name, &error_string); + mconsole_reply(req, error_string, err, 0); } else mconsole_get_config(dev->get_config, req, name); } void mconsole_remove(struct mc_request *req) { - struct mc_device *dev; + struct mc_device *dev; char *ptr = req->request.data, *err_msg = ""; - char error[256]; + char error[256]; int err, start, end, n; ptr += strlen("remove"); - while(isspace(*ptr)) ptr++; + ptr = skip_spaces(ptr); dev = mconsole_find_dev(ptr); - if(dev == NULL){ + if (dev == NULL) { mconsole_reply(req, "Bad remove option", 1, 0); return; } - ptr = &ptr[strlen(dev->name)]; - - err = 1; - n = (*dev->id)(&ptr, &start, &end); - if(n < 0){ - err_msg = "Couldn't parse device number"; - goto out; - } - else if((n < start) || (n > end)){ - sprintf(error, "Invalid device number - must be between " - "%d and %d", start, end); - err_msg = error; - goto out; - } - - err = (*dev->remove)(n); - switch(err){ - case -ENODEV: - err_msg = "Device doesn't exist"; - break; - case -EBUSY: - err_msg = "Device is currently open"; - break; - default: - break; - } - out: + ptr = &ptr[strlen(dev->name)]; + + err = 1; + n = (*dev->id)(&ptr, &start, &end); + if (n < 0) { + err_msg = "Couldn't parse device number"; + goto out; + } + else if ((n < start) || (n > end)) { + sprintf(error, "Invalid device number - must be between " + "%d and %d", start, end); + err_msg = error; + goto out; + } + + err_msg = NULL; + err = (*dev->remove)(n, &err_msg); + switch(err) { + case 0: + err_msg = ""; + break; + case -ENODEV: + if (err_msg == NULL) + err_msg = "Device doesn't exist"; + break; + case -EBUSY: + if (err_msg == NULL) + err_msg = "Device is currently open"; + break; + default: + break; + } +out: mconsole_reply(req, err_msg, err, 0); } +struct mconsole_output { + struct list_head list; + struct mc_request *req; +}; + +static DEFINE_SPINLOCK(client_lock); +static LIST_HEAD(clients); +static char console_buf[MCONSOLE_MAX_DATA]; + +static void console_write(struct console *console, const char *string, + unsigned int len) +{ + struct list_head *ele; + int n; + + if (list_empty(&clients)) + return; + + while (len > 0) { + n = min((size_t) len, ARRAY_SIZE(console_buf)); + strncpy(console_buf, string, n); + string += n; + len -= n; + + list_for_each(ele, &clients) { + struct mconsole_output *entry; + + entry = list_entry(ele, struct mconsole_output, list); + mconsole_reply_len(entry->req, console_buf, n, 0, 1); + } + } +} + +static struct console mc_console = { .name = "mc", + .write = console_write, + .flags = CON_ENABLED, + .index = -1 }; + +static int mc_add_console(void) +{ + register_console(&mc_console); + return 0; +} + +late_initcall(mc_add_console); + +static void with_console(struct mc_request *req, void (*proc)(void *), + void *arg) +{ + struct mconsole_output entry; + unsigned long flags; + + entry.req = req; + spin_lock_irqsave(&client_lock, flags); + list_add(&entry.list, &clients); + spin_unlock_irqrestore(&client_lock, flags); + + (*proc)(arg); + + mconsole_reply_len(req, "", 0, 0, 0); + + spin_lock_irqsave(&client_lock, flags); + list_del(&entry.list); + spin_unlock_irqrestore(&client_lock, flags); +} + #ifdef CONFIG_MAGIC_SYSRQ + +#include <linux/sysrq.h> + +static void sysrq_proc(void *arg) +{ + char *op = arg; + handle_sysrq(*op); +} + void mconsole_sysrq(struct mc_request *req) { char *ptr = req->request.data; ptr += strlen("sysrq"); - while(isspace(*ptr)) ptr++; + ptr = skip_spaces(ptr); - mconsole_reply(req, "", 0, 0); - handle_sysrq(*ptr, ¤t->thread.regs, NULL); + /* + * With 'b', the system will shut down without a chance to reply, + * so in this case, we reply first. + */ + if (*ptr == 'b') + mconsole_reply(req, "", 0, 0); + + with_console(req, sysrq_proc, ptr); } #else void mconsole_sysrq(struct mc_request *req) @@ -481,114 +643,116 @@ void mconsole_sysrq(struct mc_request *req) } #endif -/* Mconsole stack trace +static void stack_proc(void *arg) +{ + struct task_struct *task = arg; + + show_stack(task, NULL); +} + +/* + * Mconsole stack trace * Added by Allan Graves, Jeff Dike * Dumps a stacks registers to the linux console. * Usage stack <pid>. */ -void do_stack(struct mc_request *req) +void mconsole_stack(struct mc_request *req) { - char *ptr = req->request.data; - int pid_requested= -1; - struct task_struct *from = NULL; + char *ptr = req->request.data; + int pid_requested= -1; struct task_struct *to = NULL; - /* Would be nice: - * 1) Send showregs output to mconsole. + /* + * Would be nice: + * 1) Send showregs output to mconsole. * 2) Add a way to stack dump all pids. */ - ptr += strlen("stack"); - while(isspace(*ptr)) ptr++; - - /* Should really check for multiple pids or reject bad args here */ - /* What do the arguments in mconsole_reply mean? */ - if(sscanf(ptr, "%d", &pid_requested) == 0){ - mconsole_reply(req, "Please specify a pid", 1, 0); - return; - } + ptr += strlen("stack"); + ptr = skip_spaces(ptr); - from = current; - to = find_task_by_pid(pid_requested); - - if((to == NULL) || (pid_requested == 0)) { - mconsole_reply(req, "Couldn't find that pid", 1, 0); - return; - } - to->thread.saved_task = current; - - switch_to(from, to, from); - mconsole_reply(req, "Stack Dumped to console and message log", 0, 0); -} - -void mconsole_stack(struct mc_request *req) -{ - /* This command doesn't work in TT mode, so let's check and then - * get out of here + /* + * Should really check for multiple pids or reject bad args here */ - CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode", - 1, 0), - do_stack(req)); + /* What do the arguments in mconsole_reply mean? */ + if (sscanf(ptr, "%d", &pid_requested) == 0) { + mconsole_reply(req, "Please specify a pid", 1, 0); + return; + } + + to = find_task_by_pid_ns(pid_requested, &init_pid_ns); + if ((to == NULL) || (pid_requested == 0)) { + mconsole_reply(req, "Couldn't find that pid", 1, 0); + return; + } + with_console(req, stack_proc, to); } -/* Changed by mconsole_setup, which is __setup, and called before SMP is +/* + * Changed by mconsole_setup, which is __setup, and called before SMP is * active. */ -static char *notify_socket = NULL; +static char *notify_socket = NULL; -int mconsole_init(void) +static int __init mconsole_init(void) { /* long to avoid size mismatch warnings from gcc */ long sock; int err; - char file[256]; + char file[UNIX_PATH_MAX]; - if(umid_file_name("mconsole", file, sizeof(file))) return(-1); + if (umid_file_name("mconsole", file, sizeof(file))) + return -1; snprintf(mconsole_socket_name, sizeof(file), "%s", file); sock = os_create_unix_socket(file, sizeof(file), 1); - if (sock < 0){ - printk("Failed to initialize management console\n"); - return(1); + if (sock < 0) { + printk(KERN_ERR "Failed to initialize management console\n"); + return 1; } + if (os_set_fd_block(sock, 0)) + goto out; register_reboot_notifier(&reboot_notifier); err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt, - SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, - "mconsole", (void *)sock); - if (err){ - printk("Failed to get IRQ for management console\n"); - return(1); + IRQF_SHARED, "mconsole", (void *)sock); + if (err) { + printk(KERN_ERR "Failed to get IRQ for management console\n"); + goto out; } - if(notify_socket != NULL){ - notify_socket = uml_strdup(notify_socket); - if(notify_socket != NULL) + if (notify_socket != NULL) { + notify_socket = kstrdup(notify_socket, GFP_KERNEL); + if (notify_socket != NULL) mconsole_notify(notify_socket, MCONSOLE_SOCKET, - mconsole_socket_name, + mconsole_socket_name, strlen(mconsole_socket_name) + 1); else printk(KERN_ERR "mconsole_setup failed to strdup " "string\n"); } - printk("mconsole (version %d) initialized on %s\n", + printk(KERN_INFO "mconsole (version %d) initialized on %s\n", MCONSOLE_VERSION, mconsole_socket_name); - return(0); + return 0; + + out: + os_close_file(sock); + return 1; } __initcall(mconsole_init); -static int write_proc_mconsole(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static ssize_t mconsole_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) { char *buf; buf = kmalloc(count + 1, GFP_KERNEL); - if(buf == NULL) - return(-ENOMEM); + if (buf == NULL) + return -ENOMEM; - if(copy_from_user(buf, buffer, count)){ + if (copy_from_user(buf, buffer, count)) { count = -EFAULT; goto out; } @@ -598,24 +762,28 @@ static int write_proc_mconsole(struct file *file, const char __user *buffer, mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count); out: kfree(buf); - return(count); + return count; } +static const struct file_operations mconsole_proc_fops = { + .owner = THIS_MODULE, + .write = mconsole_proc_write, + .llseek = noop_llseek, +}; + static int create_proc_mconsole(void) { struct proc_dir_entry *ent; - if(notify_socket == NULL) return(0); + if (notify_socket == NULL) + return 0; - ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL); - if(ent == NULL){ - printk(KERN_INFO "create_proc_mconsole : create_proc_entry failed\n"); - return(0); + ent = proc_create("mconsole", 0200, NULL, &mconsole_proc_fops); + if (ent == NULL) { + printk(KERN_INFO "create_proc_mconsole : proc_create failed\n"); + return 0; } - - ent->read_proc = NULL; - ent->write_proc = write_proc_mconsole; - return(0); + return 0; } static DEFINE_SPINLOCK(notify_spinlock); @@ -632,19 +800,19 @@ void unlock_notify(void) __initcall(create_proc_mconsole); -#define NOTIFY "=notify:" +#define NOTIFY "notify:" static int mconsole_setup(char *str) { - if(!strncmp(str, NOTIFY, strlen(NOTIFY))){ + if (!strncmp(str, NOTIFY, strlen(NOTIFY))) { str += strlen(NOTIFY); notify_socket = str; } else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str); - return(1); + return 1; } -__setup("mconsole", mconsole_setup); +__setup("mconsole=", mconsole_setup); __uml_help(mconsole_setup, "mconsole=notify:<socket>\n" @@ -659,11 +827,12 @@ static int notify_panic(struct notifier_block *self, unsigned long unused1, { char *message = ptr; - if(notify_socket == NULL) return(0); + if (notify_socket == NULL) + return 0; - mconsole_notify(notify_socket, MCONSOLE_PANIC, message, + mconsole_notify(notify_socket, MCONSOLE_PANIC, message, strlen(message) + 1); - return(0); + return 0; } static struct notifier_block panic_exit_notifier = { @@ -674,26 +843,16 @@ static struct notifier_block panic_exit_notifier = { static int add_notifier(void) { - notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); - return(0); + atomic_notifier_chain_register(&panic_notifier_list, + &panic_exit_notifier); + return 0; } __initcall(add_notifier); char *mconsole_notify_socket(void) { - return(notify_socket); + return notify_socket; } EXPORT_SYMBOL(mconsole_notify_socket); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/mconsole_kern.h b/arch/um/drivers/mconsole_kern.h index d86ee14260c..7a0c6a1ad1d 100644 --- a/arch/um/include/mconsole_kern.h +++ b/arch/um/drivers/mconsole_kern.h @@ -6,8 +6,7 @@ #ifndef __MCONSOLE_KERN_H__ #define __MCONSOLE_KERN_H__ -#include "linux/config.h" -#include "linux/list.h" +#include <linux/list.h> #include "mconsole.h" struct mconsole_entry { @@ -15,13 +14,14 @@ struct mconsole_entry { struct mc_request request; }; +/* All these methods are called in process context. */ struct mc_device { struct list_head list; char *name; - int (*config)(char *); + int (*config)(char *, char **); int (*get_config)(char *, char *, int, char **); - int (*id)(char **, int *, int *); - int (*remove)(int); + int (*id)(char **, int *, int *); + int (*remove)(int, char **); }; #define CONFIG_CHUNK(str, size, current, chunk, end) \ @@ -50,14 +50,3 @@ static inline void mconsole_register_dev(struct mc_device *new) #endif #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c index 310c1f823f2..99209826adb 100644 --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c @@ -1,24 +1,25 @@ /* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) - * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stdio.h> -#include <stdlib.h> #include <errno.h> -#include <signal.h> +#include <string.h> +#include <unistd.h> #include <sys/socket.h> -#include <sys/types.h> #include <sys/uio.h> #include <sys/un.h> -#include <unistd.h> -#include "user.h" #include "mconsole.h" -#include "umid.h" static struct mconsole_command commands[] = { - { "version", mconsole_version, MCONSOLE_INTR }, + /* + * With uts namespaces, uts information becomes process-specific, so + * we need a process context. If we try handling this in interrupt + * context, we may hit an exiting process without a valid uts + * namespace. + */ + { "version", mconsole_version, MCONSOLE_PROC }, { "halt", mconsole_halt, MCONSOLE_PROC }, { "reboot", mconsole_reboot, MCONSOLE_PROC }, { "config", mconsole_config, MCONSOLE_PROC }, @@ -30,29 +31,29 @@ static struct mconsole_command commands[] = { { "go", mconsole_go, MCONSOLE_INTR }, { "log", mconsole_log, MCONSOLE_INTR }, { "proc", mconsole_proc, MCONSOLE_PROC }, - { "stack", mconsole_stack, MCONSOLE_INTR }, + { "stack", mconsole_stack, MCONSOLE_INTR }, }; /* Initialized in mconsole_init, which is an initcall */ char mconsole_socket_name[256]; -int mconsole_reply_v0(struct mc_request *req, char *reply) +static int mconsole_reply_v0(struct mc_request *req, char *reply) { - struct iovec iov; - struct msghdr msg; + struct iovec iov; + struct msghdr msg; - iov.iov_base = reply; - iov.iov_len = strlen(reply); + iov.iov_base = reply; + iov.iov_len = strlen(reply); - msg.msg_name = &(req->origin); - msg.msg_namelen = req->originlen; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; + msg.msg_name = &(req->origin); + msg.msg_namelen = req->originlen; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; - return sendmsg(req->originating_fd, &msg, 0); + return sendmsg(req->originating_fd, &msg, 0); } static struct mconsole_command *mconsole_parse(struct mc_request *req) @@ -60,14 +61,14 @@ static struct mconsole_command *mconsole_parse(struct mc_request *req) struct mconsole_command *cmd; int i; - for(i=0;i<sizeof(commands)/sizeof(commands[0]);i++){ + for (i = 0; i < ARRAY_SIZE(commands); i++) { cmd = &commands[i]; - if(!strncmp(req->request.data, cmd->command, - strlen(cmd->command))){ - return(cmd); + if (!strncmp(req->request.data, cmd->command, + strlen(cmd->command))) { + return cmd; } } - return(NULL); + return NULL; } #define MIN(a,b) ((a)<(b) ? (a):(b)) @@ -87,9 +88,9 @@ int mconsole_get_request(int fd, struct mc_request *req) req->originating_fd = fd; - if(req->request.magic != MCONSOLE_MAGIC){ + if (req->request.magic != MCONSOLE_MAGIC) { /* Unversioned request */ - len = MIN(sizeof(req->request.data) - 1, + len = MIN(sizeof(req->request.data) - 1, strlen((char *) &req->request)); memmove(req->request.data, &req->request, len); req->request.data[len] = '\0'; @@ -100,34 +101,39 @@ int mconsole_get_request(int fd, struct mc_request *req) mconsole_reply_v0(req, "ERR Version 0 mconsole clients are " "not supported by this driver"); - return(0); + return 0; } - if(req->request.len >= MCONSOLE_MAX_DATA){ + if (req->request.len >= MCONSOLE_MAX_DATA) { mconsole_reply(req, "Request too large", 1, 0); - return(0); + return 0; } - if(req->request.version != MCONSOLE_VERSION){ - mconsole_reply(req, "This driver only supports version " - STRING(MCONSOLE_VERSION) " clients", 1, 0); + if (req->request.version != MCONSOLE_VERSION) { + mconsole_reply(req, "This driver only supports version " + STRING(MCONSOLE_VERSION) " clients", 1, 0); } - + req->request.data[req->request.len] = '\0'; req->cmd = mconsole_parse(req); - if(req->cmd == NULL){ + if (req->cmd == NULL) { mconsole_reply(req, "Unknown command", 1, 0); - return(0); + return 0; } - return(1); + return 1; } -int mconsole_reply(struct mc_request *req, char *str, int err, int more) +int mconsole_reply_len(struct mc_request *req, const char *str, int total, + int err, int more) { + /* + * XXX This is a stack consumption problem. It'd be nice to + * make it global and serialize access to it, but there are a + * ton of callers to this function. + */ struct mconsole_reply reply; - int total, len, n; + int len, n; - total = strlen(str); do { reply.err = err; @@ -136,7 +142,7 @@ int mconsole_reply(struct mc_request *req, char *str, int err, int more) len = MIN(total, MCONSOLE_MAX_DATA - 1); - if(len == total) reply.more = more; + if (len == total) reply.more = more; else reply.more = 1; memcpy(reply.data, str, len); @@ -150,11 +156,18 @@ int mconsole_reply(struct mc_request *req, char *str, int err, int more) n = sendto(req->originating_fd, &reply, len, 0, (struct sockaddr *) req->origin, req->originlen); - if(n < 0) return(-errno); - } while(total > 0); - return(0); + if (n < 0) + return -errno; + } while (total > 0); + return 0; } +int mconsole_reply(struct mc_request *req, const char *str, int err, int more) +{ + return mconsole_reply_len(req, str, strlen(str), err, more); +} + + int mconsole_unlink_socket(void) { unlink(mconsole_socket_name); @@ -170,18 +183,18 @@ int mconsole_notify(char *sock_name, int type, const void *data, int len) int n, err = 0; lock_notify(); - if(notify_sock < 0){ + if (notify_sock < 0) { notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0); - if(notify_sock < 0){ + if (notify_sock < 0) { err = -errno; - printk("mconsole_notify - socket failed, errno = %d\n", - err); + printk(UM_KERN_ERR "mconsole_notify - socket failed, " + "errno = %d\n", errno); } } unlock_notify(); - - if(err) - return(err); + + if (err) + return err; target.sun_family = AF_UNIX; strcpy(target.sun_path, sock_name); @@ -195,22 +208,12 @@ int mconsole_notify(char *sock_name, int type, const void *data, int len) err = 0; len = sizeof(packet) + packet.len - sizeof(packet.data); - n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target, + n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target, sizeof(target)); - if(n < 0){ + if (n < 0) { err = -errno; - printk("mconsole_notify - sendto failed, errno = %d\n", errno); + printk(UM_KERN_ERR "mconsole_notify - sendto failed, " + "errno = %d\n", errno); } - return(err); + return err; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c index 022f67bb687..62145c27616 100644 --- a/arch/um/drivers/mmapper_kern.c +++ b/arch/um/drivers/mmapper_kern.c @@ -9,92 +9,90 @@ * */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/mm.h> +#include <linux/stddef.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/init.h> #include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/mm.h> + #include <asm/uaccess.h> -#include "mem_user.h" -#include "user_util.h" - +#include <mem_user.h> + /* These are set in mmapper_init, which is called at boot time */ static unsigned long mmapper_size; -static unsigned long p_buf = 0; -static char *v_buf = NULL; +static unsigned long p_buf; +static char *v_buf; -static ssize_t -mmapper_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +static ssize_t mmapper_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) { return simple_read_from_buffer(buf, count, ppos, v_buf, mmapper_size); } -static ssize_t -mmapper_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +static ssize_t mmapper_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { if (*ppos > mmapper_size) return -EINVAL; - if (count > mmapper_size - *ppos) - count = mmapper_size - *ppos; - - if (copy_from_user(&v_buf[*ppos], buf, count)) - return -EFAULT; - - return count; + return simple_write_to_buffer(v_buf, mmapper_size, ppos, buf, count); } -static int -mmapper_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static long mmapper_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return(-ENOIOCTLCMD); + return -ENOIOCTLCMD; } -static int -mmapper_mmap(struct file *file, struct vm_area_struct * vma) +static int mmapper_mmap(struct file *file, struct vm_area_struct *vma) { int ret = -EINVAL; int size; if (vma->vm_pgoff != 0) goto out; - + size = vma->vm_end - vma->vm_start; - if(size > mmapper_size) return(-EFAULT); + if (size > mmapper_size) + return -EFAULT; - /* XXX A comment above remap_pfn_range says it should only be + /* + * XXX A comment above remap_pfn_range says it should only be * called when the mm semaphore is held */ if (remap_pfn_range(vma, vma->vm_start, p_buf >> PAGE_SHIFT, size, - vma->vm_page_prot)) + vma->vm_page_prot)) goto out; ret = 0; out: return ret; } -static int -mmapper_open(struct inode *inode, struct file *file) +static int mmapper_open(struct inode *inode, struct file *file) { return 0; } -static int -mmapper_release(struct inode *inode, struct file *file) +static int mmapper_release(struct inode *inode, struct file *file) { return 0; } -static struct file_operations mmapper_fops = { +static const struct file_operations mmapper_fops = { .owner = THIS_MODULE, .read = mmapper_read, .write = mmapper_write, - .ioctl = mmapper_ioctl, + .unlocked_ioctl = mmapper_ioctl, .mmap = mmapper_mmap, .open = mmapper_open, .release = mmapper_release, + .llseek = default_llseek, }; +/* + * No locking needed - only used (and modified) by below initcall and exitcall. + */ static struct miscdevice mmapper_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "mmapper", @@ -108,20 +106,18 @@ static int __init mmapper_init(void) printk(KERN_INFO "Mapper v0.1\n"); v_buf = (char *) find_iomem("mmapper", &mmapper_size); - if(mmapper_size == 0){ + if (mmapper_size == 0) { printk(KERN_ERR "mmapper_init - find_iomem failed\n"); - goto out; + return -ENODEV; } + p_buf = __pa(v_buf); err = misc_register(&mmapper_dev); - if(err){ + if (err) { printk(KERN_ERR "mmapper - misc_register failed, err = %d\n", err); - goto out; + return err; } - - p_buf = __pa(v_buf); -out: return 0; } @@ -135,9 +131,4 @@ module_exit(mmapper_exit); MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>"); MODULE_DESCRIPTION("DSPLinux simulator mmapper driver"); -/* - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +MODULE_LICENSE("GPL"); diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index fe865d9a372..7d26d9c0b2f 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -1,66 +1,103 @@ /* - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and * James Leu (jleu@mindspring.net). * Copyright (C) 2001 by various other people who didn't put their name here. * Licensed under the GPL. */ -#include "linux/config.h" -#include "linux/kernel.h" -#include "linux/netdevice.h" -#include "linux/rtnetlink.h" -#include "linux/skbuff.h" -#include "linux/socket.h" -#include "linux/spinlock.h" -#include "linux/module.h" -#include "linux/init.h" -#include "linux/etherdevice.h" -#include "linux/list.h" -#include "linux/inetdevice.h" -#include "linux/ctype.h" -#include "linux/bootmem.h" -#include "linux/ethtool.h" -#include "linux/platform_device.h" -#include "asm/uaccess.h" -#include "user_util.h" -#include "kern_util.h" -#include "net_kern.h" -#include "net_user.h" +#include <linux/bootmem.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/inetdevice.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> +#include <linux/rtnetlink.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <init.h> +#include <irq_kern.h> +#include <irq_user.h> #include "mconsole_kern.h" -#include "init.h" -#include "irq_user.h" -#include "irq_kern.h" +#include <net_kern.h> +#include <net_user.h> #define DRIVER_NAME "uml-netdev" static DEFINE_SPINLOCK(opened_lock); -LIST_HEAD(opened); +static LIST_HEAD(opened); + +/* + * The drop_skb is used when we can't allocate an skb. The + * packet is read into drop_skb in order to get the data off the + * connection to the host. + * It is reallocated whenever a maximum packet size is seen which is + * larger than any seen before. update_drop_skb is called from + * eth_configure when a new interface is added. + */ +static DEFINE_SPINLOCK(drop_lock); +static struct sk_buff *drop_skb; +static int drop_max; + +static int update_drop_skb(int max) +{ + struct sk_buff *new; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&drop_lock, flags); + + if (max <= drop_max) + goto out; + + err = -ENOMEM; + new = dev_alloc_skb(max); + if (new == NULL) + goto out; + + skb_put(new, max); + + kfree_skb(drop_skb); + drop_skb = new; + drop_max = max; + err = 0; +out: + spin_unlock_irqrestore(&drop_lock, flags); + + return err; +} static int uml_net_rx(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int pkt_len; struct sk_buff *skb; /* If we can't allocate memory, try again next round. */ - skb = dev_alloc_skb(dev->mtu); + skb = dev_alloc_skb(lp->max_packet); if (skb == NULL) { - lp->stats.rx_dropped++; + drop_skb->dev = dev; + /* Read a packet into drop_skb and don't do anything with it. */ + (*lp->read)(lp->fd, drop_skb, lp); + dev->stats.rx_dropped++; return 0; } skb->dev = dev; - skb_put(skb, dev->mtu); - skb->mac.raw = skb->data; - pkt_len = (*lp->read)(lp->fd, &skb, lp); + skb_put(skb, lp->max_packet); + skb_reset_mac_header(skb); + pkt_len = (*lp->read)(lp->fd, skb, lp); if (pkt_len > 0) { skb_trim(skb, pkt_len); skb->protocol = (*lp->protocol)(skb); - netif_rx(skb); - lp->stats.rx_bytes += skb->len; - lp->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + netif_rx(skb); return pkt_len; } @@ -68,61 +105,67 @@ static int uml_net_rx(struct net_device *dev) return pkt_len; } -irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void uml_dev_close(struct work_struct *work) +{ + struct uml_net_private *lp = + container_of(work, struct uml_net_private, work); + dev_close(lp->dev); +} + +static irqreturn_t uml_net_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int err; - if(!netif_running(dev)) - return(IRQ_NONE); + if (!netif_running(dev)) + return IRQ_NONE; spin_lock(&lp->lock); - while((err = uml_net_rx(dev)) > 0) ; - if(err < 0) { - printk(KERN_ERR - "Device '%s' read returned %d, shutting it down\n", + while ((err = uml_net_rx(dev)) > 0) ; + if (err < 0) { + printk(KERN_ERR + "Device '%s' read returned %d, shutting it down\n", dev->name, err); - dev_close(dev); + /* dev_close can't be called in interrupt context, and takes + * again lp->lock. + * And dev_close() can be safely called multiple times on the + * same device, since it tests for (dev->flags & IFF_UP). So + * there's no harm in delaying the device shutdown. + * Furthermore, the workqueue will not re-enqueue an already + * enqueued work item. */ + schedule_work(&lp->work); goto out; } reactivate_fd(lp->fd, UM_ETH_IRQ); - out: +out: spin_unlock(&lp->lock); - return(IRQ_HANDLED); + return IRQ_HANDLED; } static int uml_net_open(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int err; - spin_lock(&lp->lock); - - if(lp->fd >= 0){ + if (lp->fd >= 0) { err = -ENXIO; goto out; } - if(!lp->have_mac){ - dev_ip_addr(dev, &lp->mac[2]); - set_ether_mac(dev, lp->mac); - } - lp->fd = (*lp->open)(&lp->user); - if(lp->fd < 0){ + if (lp->fd < 0) { err = lp->fd; goto out; } err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt, - SA_INTERRUPT | SA_SHIRQ, dev->name, dev); - if(err != 0){ + IRQF_SHARED, dev->name, dev); + if (err != 0) { printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err); - if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); - lp->fd = -1; err = -ENETUNREACH; + goto out_close; } lp->tl.data = (unsigned long) &lp->user; @@ -132,32 +175,41 @@ static int uml_net_open(struct net_device *dev) * is full when we get here. In this case, new data is never queued, * SIGIOs never arrive, and the net never works. */ - while((err = uml_net_rx(dev)) > 0) ; + while ((err = uml_net_rx(dev)) > 0) ; - out: - spin_unlock(&lp->lock); - return(err); + spin_lock(&opened_lock); + list_add(&lp->list, &opened); + spin_unlock(&opened_lock); + + return 0; +out_close: + if (lp->close != NULL) (*lp->close)(lp->fd, &lp->user); + lp->fd = -1; +out: + return err; } static int uml_net_close(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; - + struct uml_net_private *lp = netdev_priv(dev); + netif_stop_queue(dev); - spin_lock(&lp->lock); - free_irq(dev->irq, dev); - if(lp->close != NULL) + um_free_irq(dev->irq, dev); + if (lp->close != NULL) (*lp->close)(lp->fd, &lp->user); lp->fd = -1; - spin_unlock(&lp->lock); + spin_lock(&opened_lock); + list_del(&lp->list); + spin_unlock(&opened_lock); + return 0; } static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); unsigned long flags; int len; @@ -165,20 +217,21 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); - len = (*lp->write)(lp->fd, &skb, lp); + len = (*lp->write)(lp->fd, skb, lp); + skb_tx_timestamp(skb); - if(len == skb->len) { - lp->stats.tx_packets++; - lp->stats.tx_bytes += skb->len; + if (len == skb->len) { + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; dev->trans_start = jiffies; netif_start_queue(dev); /* this is normally done in the interrupt when tx finishes */ netif_wake_queue(dev); - } - else if(len == 0){ + } + else if (len == 0) { netif_start_queue(dev); - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; } else { netif_start_queue(dev); @@ -187,22 +240,14 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); - dev_kfree_skb(skb); - - return 0; -} + dev_consume_skb_any(skb); -static struct net_device_stats *uml_net_get_stats(struct net_device *dev) -{ - struct uml_net_private *lp = dev->priv; - return &lp->stats; + return NETDEV_TX_OK; } static void uml_net_set_multicast_list(struct net_device *dev) { - if (dev->flags & IFF_PROMISC) return; - else if (dev->mc_count) dev->flags |= IFF_ALLMULTI; - else dev->flags &= ~IFF_ALLMULTI; + return; } static void uml_net_tx_timeout(struct net_device *dev) @@ -211,67 +256,36 @@ static void uml_net_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int uml_net_set_mac(struct net_device *dev, void *addr) +static int uml_net_change_mtu(struct net_device *dev, int new_mtu) { - struct uml_net_private *lp = dev->priv; - struct sockaddr *hwaddr = addr; - - spin_lock(&lp->lock); - memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); - spin_unlock(&lp->lock); + dev->mtu = new_mtu; - return(0); + return 0; } -static int uml_net_change_mtu(struct net_device *dev, int new_mtu) +#ifdef CONFIG_NET_POLL_CONTROLLER +static void uml_net_poll_controller(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; - int err = 0; - - spin_lock(&lp->lock); - - new_mtu = (*lp->set_mtu)(new_mtu, &lp->user); - if(new_mtu < 0){ - err = new_mtu; - goto out; - } - - dev->mtu = new_mtu; - - out: - spin_unlock(&lp->lock); - return err; + disable_irq(dev->irq); + uml_net_interrupt(dev->irq, dev); + enable_irq(dev->irq); } +#endif -static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - static const struct ethtool_drvinfo info = { - .cmd = ETHTOOL_GDRVINFO, - .driver = DRIVER_NAME, - .version = "42", - }; - void *useraddr; - u32 ethcmd; - - switch (cmd) { - case SIOCETHTOOL: - useraddr = ifr->ifr_data; - if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) - return -EFAULT; - switch (ethcmd) { - case ETHTOOL_GDRVINFO: - if (copy_to_user(useraddr, &info, sizeof(info))) - return -EFAULT; - return 0; - default: - return -EOPNOTSUPP; - } - default: - return -EINVAL; - } +static void uml_net_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); + strlcpy(info->version, "42", sizeof(info->version)); } -void uml_net_user_timer_expire(unsigned long _conn) +static const struct ethtool_ops uml_net_ethtool_ops = { + .get_drvinfo = uml_net_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, +}; + +static void uml_net_user_timer_expire(unsigned long _conn) { #ifdef undef struct connection *conn = (struct connection *)_conn; @@ -281,111 +295,168 @@ void uml_net_user_timer_expire(unsigned long _conn) #endif } +static void setup_etheraddr(struct net_device *dev, char *str) +{ + unsigned char *addr = dev->dev_addr; + char *end; + int i; + + if (str == NULL) + goto random; + + for (i = 0; i < 6; i++) { + addr[i] = simple_strtoul(str, &end, 16); + if ((end == str) || + ((*end != ':') && (*end != ',') && (*end != '\0'))) { + printk(KERN_ERR + "setup_etheraddr: failed to parse '%s' " + "as an ethernet address\n", str); + goto random; + } + str = end + 1; + } + if (is_multicast_ether_addr(addr)) { + printk(KERN_ERR + "Attempt to assign a multicast ethernet address to a " + "device disallowed\n"); + goto random; + } + if (!is_valid_ether_addr(addr)) { + printk(KERN_ERR + "Attempt to assign an invalid ethernet address to a " + "device disallowed\n"); + goto random; + } + if (!is_local_ether_addr(addr)) { + printk(KERN_WARNING + "Warning: Assigning a globally valid ethernet " + "address to a device\n"); + printk(KERN_WARNING "You should set the 2nd rightmost bit in " + "the first byte of the MAC,\n"); + printk(KERN_WARNING "i.e. %02x:%02x:%02x:%02x:%02x:%02x\n", + addr[0] | 0x02, addr[1], addr[2], addr[3], addr[4], + addr[5]); + } + return; + +random: + printk(KERN_INFO + "Choosing a random ethernet address for device %s\n", dev->name); + eth_hw_addr_random(dev); +} + static DEFINE_SPINLOCK(devices_lock); -static struct list_head devices = LIST_HEAD_INIT(devices); +static LIST_HEAD(devices); -static struct device_driver uml_net_driver = { - .name = DRIVER_NAME, - .bus = &platform_bus_type, +static struct platform_driver uml_net_driver = { + .driver = { + .name = DRIVER_NAME, + }, }; + +static void net_device_release(struct device *dev) +{ + struct uml_net *device = dev_get_drvdata(dev); + struct net_device *netdev = device->dev; + struct uml_net_private *lp = netdev_priv(netdev); + + if (lp->remove != NULL) + (*lp->remove)(&lp->user); + list_del(&device->list); + kfree(device); + free_netdev(netdev); +} + +static const struct net_device_ops uml_netdev_ops = { + .ndo_open = uml_net_open, + .ndo_stop = uml_net_close, + .ndo_start_xmit = uml_net_start_xmit, + .ndo_set_rx_mode = uml_net_set_multicast_list, + .ndo_tx_timeout = uml_net_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = uml_net_change_mtu, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = uml_net_poll_controller, +#endif +}; + +/* + * Ensures that platform_driver_register is called only once by + * eth_configure. Will be set in an initcall. + */ static int driver_registered; -static int eth_configure(int n, void *init, char *mac, - struct transport *transport) +static void eth_configure(int n, void *init, char *mac, + struct transport *transport) { struct uml_net *device; struct net_device *dev; struct uml_net_private *lp; - int save, err, size; + int err, size; - size = transport->private_size + sizeof(struct uml_net_private) + - sizeof(((struct uml_net_private *) 0)->user); + size = transport->private_size + sizeof(struct uml_net_private); - device = kmalloc(sizeof(*device), GFP_KERNEL); + device = kzalloc(sizeof(*device), GFP_KERNEL); if (device == NULL) { - printk(KERN_ERR "eth_configure failed to allocate uml_net\n"); - return(1); + printk(KERN_ERR "eth_configure failed to allocate struct " + "uml_net\n"); + return; + } + + dev = alloc_etherdev(size); + if (dev == NULL) { + printk(KERN_ERR "eth_configure: failed to allocate struct " + "net_device for eth%d\n", n); + goto out_free_device; } - memset(device, 0, sizeof(*device)); INIT_LIST_HEAD(&device->list); device->index = n; - spin_lock(&devices_lock); - list_add(&device->list, &devices); - spin_unlock(&devices_lock); + /* If this name ends up conflicting with an existing registered + * netdevice, that is OK, register_netdev{,ice}() will notice this + * and fail. + */ + snprintf(dev->name, sizeof(dev->name), "eth%d", n); - if (setup_etheraddr(mac, device->mac)) - device->have_mac = 1; + setup_etheraddr(dev, mac); - printk(KERN_INFO "Netdevice %d ", n); - if (device->have_mac) - printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", - device->mac[0], device->mac[1], - device->mac[2], device->mac[3], - device->mac[4], device->mac[5]); - printk(": "); - dev = alloc_etherdev(size); - if (dev == NULL) { - printk(KERN_ERR "eth_configure: failed to allocate device\n"); - return 1; - } + printk(KERN_INFO "Netdevice %d (%pM) : ", n, dev->dev_addr); + + lp = netdev_priv(dev); + /* This points to the transport private data. It's still clear, but we + * must memset it to 0 *now*. Let's help the drivers. */ + memset(lp, 0, size); + INIT_WORK(&lp->work, uml_dev_close); /* sysfs register */ if (!driver_registered) { - driver_register(¨_net_driver); + platform_driver_register(¨_net_driver); driver_registered = 1; } device->pdev.id = n; device->pdev.name = DRIVER_NAME; - platform_device_register(&device->pdev); + device->pdev.dev.release = net_device_release; + dev_set_drvdata(&device->pdev.dev, device); + if (platform_device_register(&device->pdev)) + goto out_free_netdev; SET_NETDEV_DEV(dev,&device->pdev.dev); - /* If this name ends up conflicting with an existing registered - * netdevice, that is OK, register_netdev{,ice}() will notice this - * and fail. - */ - snprintf(dev->name, sizeof(dev->name), "eth%d", n); device->dev = dev; + /* + * These just fill in a data structure, so there's no failure + * to be worried about. + */ (*transport->kern->init)(dev, init); - dev->mtu = transport->user->max_packet; - dev->open = uml_net_open; - dev->hard_start_xmit = uml_net_start_xmit; - dev->stop = uml_net_close; - dev->get_stats = uml_net_get_stats; - dev->set_multicast_list = uml_net_set_multicast_list; - dev->tx_timeout = uml_net_tx_timeout; - dev->set_mac_address = uml_net_set_mac; - dev->change_mtu = uml_net_change_mtu; - dev->do_ioctl = uml_net_ioctl; - dev->watchdog_timeo = (HZ >> 1); - dev->irq = UM_ETH_IRQ; - - rtnl_lock(); - err = register_netdevice(dev); - rtnl_unlock(); - if (err) { - device->dev = NULL; - /* XXX: should we call ->remove() here? */ - free_netdev(dev); - return 1; - } - lp = dev->priv; - - /* lp.user is the first four bytes of the transport data, which - * has already been initialized. This structure assignment will - * overwrite that, so we make sure that .user gets overwritten with - * what it already has. - */ - save = lp->user[0]; *lp = ((struct uml_net_private) { .list = LIST_HEAD_INIT(lp->list), .dev = dev, .fd = -1, .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0}, - .have_mac = device->have_mac, + .max_packet = transport->user->max_packet, .protocol = transport->kern->protocol, .open = transport->user->open, .close = transport->user->close, @@ -393,27 +464,49 @@ static int eth_configure(int n, void *init, char *mac, .read = transport->kern->read, .write = transport->kern->write, .add_address = transport->user->add_address, - .delete_address = transport->user->delete_address, - .set_mtu = transport->user->set_mtu, - .user = { save } }); + .delete_address = transport->user->delete_address }); init_timer(&lp->tl); spin_lock_init(&lp->lock); lp->tl.function = uml_net_user_timer_expire; - if (lp->have_mac) - memcpy(lp->mac, device->mac, sizeof(lp->mac)); + memcpy(lp->mac, dev->dev_addr, sizeof(lp->mac)); - if (transport->user->init) - (*transport->user->init)(&lp->user, dev); + if ((transport->user->init != NULL) && + ((*transport->user->init)(&lp->user, dev) != 0)) + goto out_unregister; - if (device->have_mac) - set_ether_mac(dev, device->mac); + dev->mtu = transport->user->mtu; + dev->netdev_ops = ¨_netdev_ops; + dev->ethtool_ops = ¨_net_ethtool_ops; + dev->watchdog_timeo = (HZ >> 1); + dev->irq = UM_ETH_IRQ; - spin_lock(&opened_lock); - list_add(&lp->list, &opened); - spin_unlock(&opened_lock); + err = update_drop_skb(lp->max_packet); + if (err) + goto out_undo_user_init; + + rtnl_lock(); + err = register_netdevice(dev); + rtnl_unlock(); + if (err) + goto out_undo_user_init; - return(0); + spin_lock(&devices_lock); + list_add(&device->list, &devices); + spin_unlock(&devices_lock); + + return; + +out_undo_user_init: + if (transport->user->remove != NULL) + (*transport->user->remove)(&lp->user); +out_unregister: + platform_device_unregister(&device->pdev); + return; /* platform_device_unregister frees dev and device */ +out_free_netdev: + free_netdev(dev); +out_free_device: + kfree(device); } static struct uml_net *find_device(int n) @@ -422,46 +515,44 @@ static struct uml_net *find_device(int n) struct list_head *ele; spin_lock(&devices_lock); - list_for_each(ele, &devices){ + list_for_each(ele, &devices) { device = list_entry(ele, struct uml_net, list); - if(device->index == n) + if (device->index == n) goto out; } device = NULL; out: spin_unlock(&devices_lock); - return(device); + return device; } -static int eth_parse(char *str, int *index_out, char **str_out) +static int eth_parse(char *str, int *index_out, char **str_out, + char **error_out) { char *end; - int n; + int n, err = -EINVAL; n = simple_strtoul(str, &end, 0); - if(end == str){ - printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str); - return(1); - } - if(n < 0){ - printk(KERN_ERR "eth_setup: device %d is negative\n", n); - return(1); + if (end == str) { + *error_out = "Bad device number"; + return err; } + str = end; - if(*str != '='){ - printk(KERN_ERR - "eth_setup: expected '=' after device number\n"); - return(1); + if (*str != '=') { + *error_out = "Expected '=' after device number"; + return err; } + str++; - if(find_device(n)){ - printk(KERN_ERR "eth_setup: Device %d already configured\n", - n); - return(1); + if (find_device(n)) { + *error_out = "Device already configured"; + return err; } - if(index_out) *index_out = n; + + *index_out = n; *str_out = str; - return(0); + return 0; } struct eth_init { @@ -470,13 +561,11 @@ struct eth_init { int index; }; -/* Filled in at boot time. Will need locking if the transports become - * modular. - */ -struct list_head transports = LIST_HEAD_INIT(transports); +static DEFINE_SPINLOCK(transports_lock); +static LIST_HEAD(transports); /* Filled in during early boot */ -struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line); +static LIST_HEAD(eth_cmd_line); static int check_transport(struct transport *transport, char *eth, int n, void **init_out, char **mac_out) @@ -484,24 +573,24 @@ static int check_transport(struct transport *transport, char *eth, int n, int len; len = strlen(transport->name); - if(strncmp(eth, transport->name, len)) - return(0); + if (strncmp(eth, transport->name, len)) + return 0; eth += len; - if(*eth == ',') + if (*eth == ',') eth++; - else if(*eth != '\0') - return(0); + else if (*eth != '\0') + return 0; *init_out = kmalloc(transport->setup_size, GFP_KERNEL); - if(*init_out == NULL) - return(1); + if (*init_out == NULL) + return 1; - if(!transport->setup(eth, mac_out, *init_out)){ + if (!transport->setup(eth, mac_out, *init_out)) { kfree(*init_out); *init_out = NULL; } - return(1); + return 1; } void register_transport(struct transport *new) @@ -512,15 +601,18 @@ void register_transport(struct transport *new) char *mac = NULL; int match; + spin_lock(&transports_lock); + BUG_ON(!list_empty(&new->list)); list_add(&new->list, &transports); + spin_unlock(&transports_lock); - list_for_each_safe(ele, next, ð_cmd_line){ + list_for_each_safe(ele, next, ð_cmd_line) { eth = list_entry(ele, struct eth_init, list); match = check_transport(new, eth->init, eth->index, &init, &mac); - if(!match) + if (!match) continue; - else if(init != NULL){ + else if (init != NULL) { eth_configure(eth->index, init, mac, new); kfree(init); } @@ -534,32 +626,42 @@ static int eth_setup_common(char *str, int index) struct transport *transport; void *init; char *mac = NULL; + int found = 0; - list_for_each(ele, &transports){ + spin_lock(&transports_lock); + list_for_each(ele, &transports) { transport = list_entry(ele, struct transport, list); - if(!check_transport(transport, str, index, &init, &mac)) + if (!check_transport(transport, str, index, &init, &mac)) continue; - if(init != NULL){ + if (init != NULL) { eth_configure(index, init, mac, transport); kfree(init); } - return(1); + found = 1; + break; } - return(0); + + spin_unlock(&transports_lock); + return found; } -static int eth_setup(char *str) +static int __init eth_setup(char *str) { struct eth_init *new; + char *error; int n, err; - err = eth_parse(str, &n, &str); - if(err) return(1); + err = eth_parse(str, &n, &str, &error); + if (err) { + printk(KERN_ERR "eth_setup - Couldn't parse '%s' : %s\n", + str, error); + return 1; + } - new = alloc_bootmem(sizeof(new)); - if (new == NULL){ - printk("eth_init : alloc_bootmem failed\n"); - return(1); + new = alloc_bootmem(sizeof(*new)); + if (new == NULL) { + printk(KERN_ERR "eth_init : alloc_bootmem failed\n"); + return 1; } INIT_LIST_HEAD(&new->list); @@ -567,7 +669,7 @@ static int eth_setup(char *str) new->init = str; list_add_tail(&new->list, ð_cmd_line); - return(1); + return 1; } __setup("eth", eth_setup); @@ -576,89 +678,73 @@ __uml_help(eth_setup, " Configure a network device.\n\n" ); -#if 0 -static int eth_init(void) -{ - struct list_head *ele, *next; - struct eth_init *eth; - - list_for_each_safe(ele, next, ð_cmd_line){ - eth = list_entry(ele, struct eth_init, list); - - if(eth_setup_common(eth->init, eth->index)) - list_del(ð->list); - } - - return(1); -} -__initcall(eth_init); -#endif - -static int net_config(char *str) +static int net_config(char *str, char **error_out) { int n, err; - err = eth_parse(str, &n, &str); - if(err) return(err); + err = eth_parse(str, &n, &str, error_out); + if (err) + return err; - str = uml_strdup(str); - if(str == NULL){ - printk(KERN_ERR "net_config failed to strdup string\n"); - return(-1); + /* This string is broken up and the pieces used by the underlying + * driver. So, it is freed only if eth_setup_common fails. + */ + str = kstrdup(str, GFP_KERNEL); + if (str == NULL) { + *error_out = "net_config failed to strdup string"; + return -ENOMEM; } err = !eth_setup_common(str, n); - if(err) + if (err) kfree(str); - return(err); + return err; } static int net_id(char **str, int *start_out, int *end_out) { - char *end; - int n; + char *end; + int n; n = simple_strtoul(*str, &end, 0); - if((*end != '\0') || (end == *str)) + if ((*end != '\0') || (end == *str)) return -1; - *start_out = n; - *end_out = n; - *str = end; - return n; + *start_out = n; + *end_out = n; + *str = end; + return n; } -static int net_remove(int n) +static int net_remove(int n, char **error_out) { struct uml_net *device; struct net_device *dev; struct uml_net_private *lp; device = find_device(n); - if(device == NULL) + if (device == NULL) return -ENODEV; dev = device->dev; - lp = dev->priv; - if(lp->fd > 0) - return -EBUSY; - if(lp->remove != NULL) (*lp->remove)(&lp->user); + lp = netdev_priv(dev); + if (lp->fd > 0) + return -EBUSY; unregister_netdev(dev); platform_device_unregister(&device->pdev); - list_del(&device->list); - kfree(device); - free_netdev(dev); return 0; } static struct mc_device net_mc = { + .list = LIST_HEAD_INIT(net_mc.list), .name = "eth", .config = net_config, .get_config = NULL, - .id = net_id, + .id = net_id, .remove = net_remove, }; +#ifdef CONFIG_INET static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) { @@ -668,12 +754,13 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, void (*proc)(unsigned char *, unsigned char *, void *); unsigned char addr_buf[4], netmask_buf[4]; - if(dev->open != uml_net_open) return(NOTIFY_DONE); + if (dev->netdev_ops->ndo_open != uml_net_open) + return NOTIFY_DONE; - lp = dev->priv; + lp = netdev_priv(dev); proc = NULL; - switch (event){ + switch (event) { case NETDEV_UP: proc = lp->add_address; break; @@ -681,44 +768,57 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, proc = lp->delete_address; break; } - if(proc != NULL){ + if (proc != NULL) { memcpy(addr_buf, &ifa->ifa_address, sizeof(addr_buf)); memcpy(netmask_buf, &ifa->ifa_mask, sizeof(netmask_buf)); (*proc)(addr_buf, netmask_buf, &lp->user); } - return(NOTIFY_DONE); + return NOTIFY_DONE; } -struct notifier_block uml_inetaddr_notifier = { +/* uml_net_init shouldn't be called twice on two CPUs at the same time */ +static struct notifier_block uml_inetaddr_notifier = { .notifier_call = uml_inetaddr_event, }; -static int uml_net_init(void) +static void inet_register(void) { struct list_head *ele; - struct uml_net_private *lp; + struct uml_net_private *lp; struct in_device *ip; struct in_ifaddr *in; - mconsole_register_dev(&net_mc); register_inetaddr_notifier(¨_inetaddr_notifier); /* Devices may have been opened already, so the uml_inetaddr_notifier * didn't get a chance to run for them. This fakes it so that * addresses which have already been set up get handled properly. */ - list_for_each(ele, &opened){ + spin_lock(&opened_lock); + list_for_each(ele, &opened) { lp = list_entry(ele, struct uml_net_private, list); ip = lp->dev->ip_ptr; - if(ip == NULL) continue; + if (ip == NULL) + continue; in = ip->ifa_list; - while(in != NULL){ + while (in != NULL) { uml_inetaddr_event(NULL, NETDEV_UP, in); in = in->ifa_next; } - } + } + spin_unlock(&opened_lock); +} +#else +static inline void inet_register(void) +{ +} +#endif - return(0); +static int uml_net_init(void) +{ + mconsole_register_dev(&net_mc); + inet_register(); + return 0; } __initcall(uml_net_init); @@ -728,79 +828,22 @@ static void close_devices(void) struct list_head *ele; struct uml_net_private *lp; - list_for_each(ele, &opened){ + spin_lock(&opened_lock); + list_for_each(ele, &opened) { lp = list_entry(ele, struct uml_net_private, list); - if((lp->close != NULL) && (lp->fd >= 0)) + um_free_irq(lp->dev->irq, lp->dev); + if ((lp->close != NULL) && (lp->fd >= 0)) (*lp->close)(lp->fd, &lp->user); - if(lp->remove != NULL) (*lp->remove)(&lp->user); + if (lp->remove != NULL) + (*lp->remove)(&lp->user); } + spin_unlock(&opened_lock); } __uml_exitcall(close_devices); -int setup_etheraddr(char *str, unsigned char *addr) -{ - char *end; - int i; - - if(str == NULL) - return(0); - for(i=0;i<6;i++){ - addr[i] = simple_strtoul(str, &end, 16); - if((end == str) || - ((*end != ':') && (*end != ',') && (*end != '\0'))){ - printk(KERN_ERR - "setup_etheraddr: failed to parse '%s' " - "as an ethernet address\n", str); - return(0); - } - str = end + 1; - } - if(addr[0] & 1){ - printk(KERN_ERR - "Attempt to assign a broadcast ethernet address to a " - "device disallowed\n"); - return(0); - } - return(1); -} - -void dev_ip_addr(void *d, unsigned char *bin_buf) -{ - struct net_device *dev = d; - struct in_device *ip = dev->ip_ptr; - struct in_ifaddr *in; - - if((ip == NULL) || ((in = ip->ifa_list) == NULL)){ - printk(KERN_WARNING "dev_ip_addr - device not assigned an " - "IP address\n"); - return; - } - memcpy(bin_buf, &in->ifa_address, sizeof(in->ifa_address)); -} - -void set_ether_mac(void *d, unsigned char *addr) -{ - struct net_device *dev = d; - - memcpy(dev->dev_addr, addr, ETH_ALEN); -} - -struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra) -{ - if((skb != NULL) && (skb_tailroom(skb) < extra)){ - struct sk_buff *skb2; - - skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC); - dev_kfree_skb(skb); - skb = skb2; - } - if(skb != NULL) skb_put(skb, extra); - return(skb); -} - -void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, - void *), +void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, + void *), void *arg) { struct net_device *dev = d; @@ -808,9 +851,9 @@ void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, struct in_ifaddr *in; unsigned char address[4], netmask[4]; - if(ip == NULL) return; + if (ip == NULL) return; in = ip->ifa_list; - while(in != NULL){ + while (in != NULL) { memcpy(address, &in->ifa_address, sizeof(address)); memcpy(netmask, &in->ifa_mask, sizeof(netmask)); (*cb)(address, netmask, arg); @@ -823,17 +866,17 @@ int dev_netmask(void *d, void *m) struct net_device *dev = d; struct in_device *ip = dev->ip_ptr; struct in_ifaddr *in; - __u32 *mask_out = m; + __be32 *mask_out = m; - if(ip == NULL) - return(1); + if (ip == NULL) + return 1; in = ip->ifa_list; - if(in == NULL) - return(1); + if (in == NULL) + return 1; *mask_out = in->ifa_mask; - return(0); + return 0; } void *get_output_buffer(int *len_out) @@ -841,9 +884,9 @@ void *get_output_buffer(int *len_out) void *ret; ret = (void *) __get_free_pages(GFP_KERNEL, 0); - if(ret) *len_out = PAGE_SIZE; + if (ret) *len_out = PAGE_SIZE; else *len_out = 0; - return(ret); + return ret; } void free_output_buffer(void *buffer) @@ -851,33 +894,22 @@ void free_output_buffer(void *buffer) free_pages((unsigned long) buffer, 0); } -int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, +int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, char **gate_addr) { char *remain; remain = split_if_spec(str, dev_name, mac_out, gate_addr, NULL); - if(remain != NULL){ - printk("tap_setup_common - Extra garbage on specification : " - "'%s'\n", remain); - return(1); + if (remain != NULL) { + printk(KERN_ERR "tap_setup_common - Extra garbage on " + "specification : '%s'\n", remain); + return 1; } - return(0); + return 0; } unsigned short eth_protocol(struct sk_buff *skb) { - return(eth_type_trans(skb, skb->dev)); + return eth_type_trans(skb, skb->dev); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 098fa65981a..cd14157b556 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -1,148 +1,167 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stddef.h> -#include <stdarg.h> -#include <unistd.h> #include <stdio.h> +#include <unistd.h> +#include <stdarg.h> #include <errno.h> -#include <stdlib.h> +#include <stddef.h> #include <string.h> #include <sys/socket.h> #include <sys/wait.h> -#include "user.h" -#include "user_util.h" -#include "kern_util.h" -#include "net_user.h" -#include "os.h" +#include <net_user.h> +#include <os.h> +#include <um_malloc.h> int tap_open_common(void *dev, char *gate_addr) { int tap_addr[4]; - if(gate_addr == NULL) return(0); - if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], - &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){ - printk("Invalid tap IP address - '%s'\n", gate_addr); - return(-EINVAL); + if (gate_addr == NULL) + return 0; + if (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], + &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4) { + printk(UM_KERN_ERR "Invalid tap IP address - '%s'\n", + gate_addr); + return -EINVAL; } - return(0); + return 0; } void tap_check_ips(char *gate_addr, unsigned char *eth_addr) { int tap_addr[4]; - if((gate_addr != NULL) && - (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], - &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) && - (eth_addr[0] == tap_addr[0]) && - (eth_addr[1] == tap_addr[1]) && - (eth_addr[2] == tap_addr[2]) && - (eth_addr[3] == tap_addr[3])){ - printk("The tap IP address and the UML eth IP address" - " must be different\n"); + if ((gate_addr != NULL) && + (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], + &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) && + (eth_addr[0] == tap_addr[0]) && + (eth_addr[1] == tap_addr[1]) && + (eth_addr[2] == tap_addr[2]) && + (eth_addr[3] == tap_addr[3])) { + printk(UM_KERN_ERR "The tap IP address and the UML eth IP " + "address must be different\n"); } } +/* Do reliable error handling as this fails frequently enough. */ void read_output(int fd, char *output, int len) { - int remain, n, actual; + int remain, ret, expected; char c; + char *str; - if(output == NULL){ + if (output == NULL) { output = &c; len = sizeof(c); } - + *output = '\0'; - n = os_read_file(fd, &remain, sizeof(remain)); - if(n != sizeof(remain)){ - printk("read_output - read of length failed, err = %d\n", -n); - return; + ret = read(fd, &remain, sizeof(remain)); + + if (ret != sizeof(remain)) { + if (ret < 0) + ret = -errno; + expected = sizeof(remain); + str = "length"; + goto err; } - while(remain != 0){ - n = (remain < len) ? remain : len; - actual = os_read_file(fd, output, n); - if(actual != n){ - printk("read_output - read of data failed, " - "err = %d\n", -actual); - return; + while (remain != 0) { + expected = (remain < len) ? remain : len; + ret = read(fd, output, expected); + if (ret != expected) { + if (ret < 0) + ret = -errno; + str = "data"; + goto err; } - remain -= actual; + remain -= ret; } + return; + +err: + if (ret < 0) + printk(UM_KERN_ERR "read_output - read of %s failed, " + "errno = %d\n", str, -ret); + else + printk(UM_KERN_ERR "read_output - read of %s failed, read only " + "%d of %d bytes\n", str, ret, expected); } int net_read(int fd, void *buf, int len) { int n; - n = os_read_file(fd, buf, len); + n = read(fd, buf, len); - if(n == -EAGAIN) - return(0); - else if(n == 0) - return(-ENOTCONN); - return(n); + if ((n < 0) && (errno == EAGAIN)) + return 0; + else if (n == 0) + return -ENOTCONN; + return n; } int net_recvfrom(int fd, void *buf, int len) { int n; - while(((n = recvfrom(fd, buf, len, 0, NULL, NULL)) < 0) && - (errno == EINTR)) ; - - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); + CATCH_EINTR(n = recvfrom(fd, buf, len, 0, NULL, NULL)); + if (n < 0) { + if (errno == EAGAIN) + return 0; + return -errno; } - else if(n == 0) return(-ENOTCONN); - return(n); + else if (n == 0) + return -ENOTCONN; + return n; } int net_write(int fd, void *buf, int len) { int n; - n = os_write_file(fd, buf, len); + n = write(fd, buf, len); - if(n == -EAGAIN) - return(0); - else if(n == 0) - return(-ENOTCONN); - return(n); + if ((n < 0) && (errno == EAGAIN)) + return 0; + else if (n == 0) + return -ENOTCONN; + return n; } int net_send(int fd, void *buf, int len) { int n; - while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ; - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); + CATCH_EINTR(n = send(fd, buf, len, 0)); + if (n < 0) { + if (errno == EAGAIN) + return 0; + return -errno; } - else if(n == 0) return(-ENOTCONN); - return(n); + else if (n == 0) + return -ENOTCONN; + return n; } int net_sendto(int fd, void *buf, int len, void *to, int sock_len) { int n; - while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to, - sock_len)) < 0) && (errno == EINTR)) ; - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); + CATCH_EINTR(n = sendto(fd, buf, len, 0, (struct sockaddr *) to, + sock_len)); + if (n < 0) { + if (errno == EAGAIN) + return 0; + return -errno; } - else if(n == 0) return(-ENOTCONN); - return(n); + else if (n == 0) + return -ENOTCONN; + return n; } struct change_pre_exec_data { @@ -154,7 +173,7 @@ static void change_pre_exec(void *arg) { struct change_pre_exec_data *data = arg; - os_close_file(data->close_me); + close(data->close_me); dup2(data->stdout, 1); } @@ -164,21 +183,24 @@ static int change_tramp(char **argv, char *output, int output_len) struct change_pre_exec_data pe_data; err = os_pipe(fds, 1, 0); - if(err < 0){ - printk("change_tramp - pipe failed, err = %d\n", -err); - return(err); + if (err < 0) { + printk(UM_KERN_ERR "change_tramp - pipe failed, err = %d\n", + -err); + return err; } pe_data.close_me = fds[0]; pe_data.stdout = fds[1]; - pid = run_helper(change_pre_exec, &pe_data, argv, NULL); + pid = run_helper(change_pre_exec, &pe_data, argv); + + if (pid > 0) /* Avoid hang as we won't get data in failure case. */ + read_output(fds[0], output, output_len); - read_output(fds[0], output, output_len); - os_close_file(fds[0]); - os_close_file(fds[1]); + close(fds[0]); + close(fds[1]); if (pid > 0) - CATCH_EINTR(err = waitpid(pid, NULL, 0)); - return(pid); + helper_wait(pid); + return pid; } static void change(char *dev, char *what, unsigned char *addr, @@ -187,25 +209,29 @@ static void change(char *dev, char *what, unsigned char *addr, char addr_buf[sizeof("255.255.255.255\0")]; char netmask_buf[sizeof("255.255.255.255\0")]; char version[sizeof("nnnnn\0")]; - char *argv[] = { "uml_net", version, what, dev, addr_buf, + char *argv[] = { "uml_net", version, what, dev, addr_buf, netmask_buf, NULL }; char *output; int output_len, pid; sprintf(version, "%d", UML_NET_VERSION); sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); - sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], + sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], netmask[2], netmask[3]); - output_len = page_size(); - output = um_kmalloc(output_len); - if(output == NULL) - printk("change : failed to allocate output buffer\n"); + output_len = UM_KERN_PAGE_SIZE; + output = uml_kmalloc(output_len, UM_GFP_KERNEL); + if (output == NULL) + printk(UM_KERN_ERR "change : failed to allocate output " + "buffer\n"); pid = change_tramp(argv, output, output_len); - if(pid < 0) return; + if (pid < 0) { + kfree(output); + return; + } - if(output != NULL){ + if (output != NULL) { printk("%s", output); kfree(output); } @@ -227,28 +253,17 @@ char *split_if_spec(char *str, ...) va_list ap; va_start(ap, str); - while((arg = va_arg(ap, char **)) != NULL){ - if(*str == '\0') - return(NULL); + while ((arg = va_arg(ap, char **)) != NULL) { + if (*str == '\0') + return NULL; end = strchr(str, ','); - if(end != str) + if (end != str) *arg = str; - if(end == NULL) - return(NULL); + if (end == NULL) + return NULL; *end++ = '\0'; str = end; } va_end(ap); - return(str); + return str; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c index 14cc5f78398..10495747ce8 100644 --- a/arch/um/drivers/null.c +++ b/arch/um/drivers/null.c @@ -1,37 +1,43 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) * Licensed under the GPL */ -#include <stdlib.h> +#include <stddef.h> #include <errno.h> +#include <fcntl.h> #include "chan_user.h" -#include "os.h" +#include <os.h> +/* This address is used only as a unique identifier */ static int null_chan; -static void *null_init(char *str, int device, struct chan_opts *opts) +static void *null_init(char *str, int device, const struct chan_opts *opts) { - return(&null_chan); + return &null_chan; } static int null_open(int input, int output, int primary, void *d, char **dev_out) { + int fd; + *dev_out = NULL; - return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0)); + + fd = open(DEV_NULL, O_RDWR); + return (fd < 0) ? -errno : fd; } static int null_read(int fd, char *c_out, void *unused) { - return(-ENODEV); + return -ENODEV; } static void null_free(void *data) { } -struct chan_ops null_ops = { +const struct chan_ops null_ops = { .type = "null", .init = null_init, .open = null_open, @@ -43,14 +49,3 @@ struct chan_ops null_ops = { .free = null_free, .winch = 0, }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c index 07c80f2156e..be0fb57bd1d 100644 --- a/arch/um/drivers/pcap_kern.c +++ b/arch/um/drivers/pcap_kern.c @@ -1,13 +1,11 @@ /* - * Copyright (C) 2002 Jeff Dike <jdike@karaya.com> + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL. */ -#include "linux/init.h" -#include "linux/netdevice.h" -#include "linux/etherdevice.h" -#include "net_kern.h" -#include "net_user.h" +#include <linux/init.h> +#include <linux/netdevice.h> +#include <net_kern.h> #include "pcap_user.h" struct pcap_init { @@ -23,30 +21,29 @@ void pcap_init(struct net_device *dev, void *data) struct pcap_data *ppri; struct pcap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); ppri = (struct pcap_data *) pri->user; ppri->host_if = init->host_if; ppri->promisc = init->promisc; ppri->optimize = init->optimize; ppri->filter = init->filter; + + printk("pcap backend, host interface %s\n", ppri->host_if); } -static int pcap_read(int fd, struct sk_buff **skb, - struct uml_net_private *lp) +static int pcap_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); - if(*skb == NULL) return(-ENOMEM); - return(pcap_user_read(fd, (*skb)->mac.raw, - (*skb)->dev->mtu + ETH_HEADER_OTHER, - (struct pcap_data *) &lp->user)); + return pcap_user_read(fd, skb_mac_header(skb), + skb->dev->mtu + ETH_HEADER_OTHER, + (struct pcap_data *) &lp->user); } -static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp) +static int pcap_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - return(-EPERM); + return -EPERM; } -static struct net_kern_info pcap_kern_info = { +static const struct net_kern_info pcap_kern_info = { .init = pcap_init, .protocol = eth_protocol, .read = pcap_read, @@ -65,32 +62,36 @@ int pcap_setup(char *str, char **mac_out, void *data) .optimize = 0, .filter = NULL }); - remain = split_if_spec(str, &host_if, &init->filter, - &options[0], &options[1], NULL); - if(remain != NULL){ + remain = split_if_spec(str, &host_if, &init->filter, + &options[0], &options[1], mac_out, NULL); + if (remain != NULL) { printk(KERN_ERR "pcap_setup - Extra garbage on " "specification : '%s'\n", remain); - return(0); + return 0; } - if(host_if != NULL) + if (host_if != NULL) init->host_if = host_if; - for(i = 0; i < sizeof(options)/sizeof(options[0]); i++){ - if(options[i] == NULL) + for (i = 0; i < ARRAY_SIZE(options); i++) { + if (options[i] == NULL) continue; - if(!strcmp(options[i], "promisc")) + if (!strcmp(options[i], "promisc")) init->promisc = 1; - else if(!strcmp(options[i], "nopromisc")) + else if (!strcmp(options[i], "nopromisc")) init->promisc = 0; - else if(!strcmp(options[i], "optimize")) + else if (!strcmp(options[i], "optimize")) init->optimize = 1; - else if(!strcmp(options[i], "nooptimize")) + else if (!strcmp(options[i], "nooptimize")) init->optimize = 0; - else printk("pcap_setup : bad option - '%s'\n", options[i]); + else { + printk(KERN_ERR "pcap_setup : bad option - '%s'\n", + options[i]); + return 0; + } } - return(1); + return 1; } static struct transport pcap_transport = { @@ -106,18 +107,7 @@ static struct transport pcap_transport = { static int register_pcap(void) { register_transport(&pcap_transport); - return(1); + return 0; } -__initcall(register_pcap); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +late_initcall(register_pcap); diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c index edfcb29273e..c07b9c752c8 100644 --- a/arch/um/drivers/pcap_user.c +++ b/arch/um/drivers/pcap_user.c @@ -1,37 +1,35 @@ /* - * Copyright (C) 2002 Jeff Dike <jdike@karaya.com> + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL. */ -#include <unistd.h> -#include <stdlib.h> -#include <string.h> #include <errno.h> #include <pcap.h> +#include <string.h> #include <asm/types.h> -#include "net_user.h" +#include <net_user.h> #include "pcap_user.h" -#include "user.h" - -#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) +#include <um_malloc.h> #define PCAP_FD(p) (*(int *)(p)) -static void pcap_user_init(void *data, void *dev) +static int pcap_user_init(void *data, void *dev) { struct pcap_data *pri = data; pcap_t *p; char errors[PCAP_ERRBUF_SIZE]; - p = pcap_open_live(pri->host_if, MAX_PACKET, pri->promisc, 0, errors); - if(p == NULL){ - printk("pcap_user_init : pcap_open_live failed - '%s'\n", - errors); - return; + p = pcap_open_live(pri->host_if, ETH_MAX_PACKET + ETH_HEADER_OTHER, + pri->promisc, 0, errors); + if (p == NULL) { + printk(UM_KERN_ERR "pcap_user_init : pcap_open_live failed - " + "'%s'\n", errors); + return -EINVAL; } pri->dev = dev; pri->pcap = p; + return 0; } static int pcap_open(void *data) @@ -40,50 +38,56 @@ static int pcap_open(void *data) __u32 netmask; int err; - if(pri->pcap == NULL) - return(-ENODEV); + if (pri->pcap == NULL) + return -ENODEV; - if(pri->filter != NULL){ + if (pri->filter != NULL) { err = dev_netmask(pri->dev, &netmask); - if(err < 0){ - printk("pcap_open : dev_netmask failed\n"); - return(-EIO); + if (err < 0) { + printk(UM_KERN_ERR "pcap_open : dev_netmask failed\n"); + return -EIO; } - pri->compiled = um_kmalloc(sizeof(struct bpf_program)); - if(pri->compiled == NULL){ - printk("pcap_open : kmalloc failed\n"); - return(-ENOMEM); + pri->compiled = uml_kmalloc(sizeof(struct bpf_program), + UM_GFP_KERNEL); + if (pri->compiled == NULL) { + printk(UM_KERN_ERR "pcap_open : kmalloc failed\n"); + return -ENOMEM; } - - err = pcap_compile(pri->pcap, - (struct bpf_program *) pri->compiled, + + err = pcap_compile(pri->pcap, + (struct bpf_program *) pri->compiled, pri->filter, pri->optimize, netmask); - if(err < 0){ - printk("pcap_open : pcap_compile failed - '%s'\n", - pcap_geterr(pri->pcap)); - return(-EIO); + if (err < 0) { + printk(UM_KERN_ERR "pcap_open : pcap_compile failed - " + "'%s'\n", pcap_geterr(pri->pcap)); + goto out; } err = pcap_setfilter(pri->pcap, pri->compiled); - if(err < 0){ - printk("pcap_open : pcap_setfilter failed - '%s'\n", - pcap_geterr(pri->pcap)); - return(-EIO); + if (err < 0) { + printk(UM_KERN_ERR "pcap_open : pcap_setfilter " + "failed - '%s'\n", pcap_geterr(pri->pcap)); + goto out; } } - - return(PCAP_FD(pri->pcap)); + + return PCAP_FD(pri->pcap); + + out: + kfree(pri->compiled); + return -EIO; } static void pcap_remove(void *data) { struct pcap_data *pri = data; - if(pri->compiled != NULL) + if (pri->compiled != NULL) pcap_freecode(pri->compiled); - pcap_close(pri->pcap); + if (pri->pcap != NULL) + pcap_close(pri->pcap); } struct pcap_handler_data { @@ -91,7 +95,7 @@ struct pcap_handler_data { int len; }; -static void handler(u_char *data, const struct pcap_pkthdr *header, +static void handler(u_char *data, const struct pcap_pkthdr *header, const u_char *packet) { int len; @@ -111,33 +115,23 @@ int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri) int n; n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata); - if(n < 0){ - printk("pcap_dispatch failed - %s\n", pcap_geterr(pri->pcap)); - return(-EIO); + if (n < 0) { + printk(UM_KERN_ERR "pcap_dispatch failed - %s\n", + pcap_geterr(pri->pcap)); + return -EIO; } - else if(n == 0) - return(0); - return(hdata.len); + else if (n == 0) + return 0; + return hdata.len; } -struct net_user_info pcap_user_info = { +const struct net_user_info pcap_user_info = { .init = pcap_user_init, .open = pcap_open, .close = NULL, .remove = pcap_remove, - .set_mtu = NULL, .add_address = NULL, .delete_address = NULL, - .max_packet = MAX_PACKET - ETH_HEADER_OTHER + .mtu = ETH_MAX_PACKET, + .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/pcap_user.h b/arch/um/drivers/pcap_user.h index 58f9f6a1420..1ca7c764cc6 100644 --- a/arch/um/drivers/pcap_user.h +++ b/arch/um/drivers/pcap_user.h @@ -3,7 +3,7 @@ * Licensed under the GPL */ -#include "net_user.h" +#include <net_user.h> struct pcap_data { char *host_if; @@ -15,17 +15,7 @@ struct pcap_data { void *dev; }; -extern struct net_user_info pcap_user_info; +extern const struct net_user_info pcap_user_info; extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/port.h b/arch/um/drivers/port.h index 9117609a575..372a80c0556 100644 --- a/arch/um/drivers/port.h +++ b/arch/um/drivers/port.h @@ -18,13 +18,3 @@ extern void port_remove_dev(void *d); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 189839e4f1d..40ca5cc275e 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -1,24 +1,19 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) * Licensed under the GPL */ -#include "linux/list.h" -#include "linux/sched.h" -#include "linux/slab.h" -#include "linux/interrupt.h" -#include "linux/spinlock.h" -#include "linux/errno.h" -#include "asm/atomic.h" -#include "asm/semaphore.h" -#include "asm/errno.h" -#include "kern_util.h" -#include "kern.h" -#include "irq_user.h" -#include "irq_kern.h" +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <asm/atomic.h> +#include <init.h> +#include <irq_kern.h> +#include <os.h> #include "port.h" -#include "init.h" -#include "os.h" struct port_list { struct list_head list; @@ -47,17 +42,17 @@ struct connection { struct port_list *port; }; -static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t pipe_interrupt(int irq, void *data) { struct connection *conn = data; int fd; fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); - if(fd < 0){ - if(fd == -EAGAIN) - return(IRQ_NONE); + if (fd < 0) { + if (fd == -EAGAIN) + return IRQ_NONE; - printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", + printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", -fd); os_close_file(conn->fd); } @@ -68,7 +63,7 @@ static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs) list_add(&conn->list, &conn->port->connections); complete(&conn->port->done); - return(IRQ_HANDLED); + return IRQ_HANDLED; } #define NO_WAITER_MSG \ @@ -81,85 +76,85 @@ static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs) static int port_accept(struct port_list *port) { struct connection *conn; - int fd, socket[2], pid, ret = 0; + int fd, socket[2], pid; fd = port_connection(port->fd, socket, &pid); - if(fd < 0){ - if(fd != -EAGAIN) + if (fd < 0) { + if (fd != -EAGAIN) printk(KERN_ERR "port_accept : port_connection " "returned %d\n", -fd); goto out; } conn = kmalloc(sizeof(*conn), GFP_ATOMIC); - if(conn == NULL){ + if (conn == NULL) { printk(KERN_ERR "port_accept : failed to allocate " "connection\n"); goto out_close; } - *conn = ((struct connection) + *conn = ((struct connection) { .list = LIST_HEAD_INIT(conn->list), .fd = fd, .socket = { socket[0], socket[1] }, .telnetd_pid = pid, .port = port }); - if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, - SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, - "telnetd", conn)){ + if (um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, + IRQF_SHARED, "telnetd", conn)) { printk(KERN_ERR "port_accept : failed to get IRQ for " "telnetd\n"); goto out_free; } - if(atomic_read(&port->wait_count) == 0){ + if (atomic_read(&port->wait_count) == 0) { os_write_file(fd, NO_WAITER_MSG, sizeof(NO_WAITER_MSG)); - printk("No one waiting for port\n"); + printk(KERN_ERR "No one waiting for port\n"); } list_add(&conn->list, &port->pending); - return(1); + return 1; out_free: kfree(conn); out_close: os_close_file(fd); - if(pid != -1) - os_kill_process(pid, 1); + os_kill_process(pid, 1); out: - return(ret); -} + return 0; +} -DECLARE_MUTEX(ports_sem); -struct list_head ports = LIST_HEAD_INIT(ports); +static DEFINE_MUTEX(ports_mutex); +static LIST_HEAD(ports); -void port_work_proc(void *unused) +static void port_work_proc(struct work_struct *unused) { struct port_list *port; struct list_head *ele; unsigned long flags; local_irq_save(flags); - list_for_each(ele, &ports){ + list_for_each(ele, &ports) { port = list_entry(ele, struct port_list, list); - if(!port->has_connection) + if (!port->has_connection) continue; + reactivate_fd(port->fd, ACCEPT_IRQ); - while(port_accept(port)) ; + while (port_accept(port)) + ; port->has_connection = 0; } local_irq_restore(flags); } -DECLARE_WORK(port_work, port_work_proc, NULL); +DECLARE_WORK(port_work, port_work_proc); -static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t port_interrupt(int irq, void *data) { struct port_list *port = data; port->has_connection = 1; schedule_work(&port_work); - return(IRQ_HANDLED); -} + return IRQ_HANDLED; +} void *port_data(int port_num) { @@ -168,31 +163,32 @@ void *port_data(int port_num) struct port_dev *dev = NULL; int fd; - down(&ports_sem); - list_for_each(ele, &ports){ + mutex_lock(&ports_mutex); + list_for_each(ele, &ports) { port = list_entry(ele, struct port_list, list); - if(port->port == port_num) goto found; + if (port->port == port_num) + goto found; } port = kmalloc(sizeof(struct port_list), GFP_KERNEL); - if(port == NULL){ + if (port == NULL) { printk(KERN_ERR "Allocation of port list failed\n"); goto out; } fd = port_listen_fd(port_num); - if(fd < 0){ + if (fd < 0) { printk(KERN_ERR "binding to port %d failed, errno = %d\n", port_num, -fd); goto out_free; } - if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, - SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port", - port)){ + + if (um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, + IRQF_SHARED, "port", port)) { printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num); goto out_close; } - *port = ((struct port_list) + *port = ((struct port_list) { .list = LIST_HEAD_INIT(port->list), .wait_count = ATOMIC_INIT(0), .has_connection = 0, @@ -206,7 +202,7 @@ void *port_data(int port_num) found: dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL); - if(dev == NULL){ + if (dev == NULL) { printk(KERN_ERR "Allocation of port device entry failed\n"); goto out; } @@ -216,13 +212,13 @@ void *port_data(int port_num) .telnetd_pid = -1 }); goto out; - out_free: - kfree(port); out_close: os_close_file(fd); + out_free: + kfree(port); out: - up(&ports_sem); - return(dev); + mutex_unlock(&ports_mutex); + return dev; } int port_wait(void *data) @@ -232,15 +228,15 @@ int port_wait(void *data) struct port_list *port = dev->port; int fd; - atomic_inc(&port->wait_count); - while(1){ + atomic_inc(&port->wait_count); + while (1) { fd = -ERESTARTSYS; - if(wait_for_completion_interruptible(&port->done)) - goto out; + if (wait_for_completion_interruptible(&port->done)) + goto out; spin_lock(&port->lock); - conn = list_entry(port->connections.next, struct connection, + conn = list_entry(port->connections.next, struct connection, list); list_del(&conn->list); spin_unlock(&port->lock); @@ -248,17 +244,18 @@ int port_wait(void *data) os_shutdown_socket(conn->socket[0], 1, 1); os_close_file(conn->socket[0]); os_shutdown_socket(conn->socket[1], 1, 1); - os_close_file(conn->socket[1]); + os_close_file(conn->socket[1]); /* This is done here because freeing an IRQ can't be done * within the IRQ handler. So, pipe_interrupt always ups * the semaphore regardless of whether it got a successful - * connection. Then we loop here throwing out failed + * connection. Then we loop here throwing out failed * connections until a good one is found. */ - free_irq(TELNETD_IRQ, conn); + um_free_irq(TELNETD_IRQ, conn); - if(conn->fd >= 0) break; + if (conn->fd >= 0) + break; os_close_file(conn->fd); kfree(conn); } @@ -276,9 +273,9 @@ void port_remove_dev(void *d) { struct port_dev *dev = d; - if(dev->helper_pid != -1) + if (dev->helper_pid != -1) os_kill_process(dev->helper_pid, 0); - if(dev->telnetd_pid != -1) + if (dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid, 1); dev->helper_pid = -1; dev->telnetd_pid = -1; @@ -297,7 +294,7 @@ static void free_port(void) struct list_head *ele; struct port_list *port; - list_for_each(ele, &ports){ + list_for_each(ele, &ports) { port = list_entry(ele, struct port_list, list); free_irq_by_fd(port->fd); os_close_file(port->fd); diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index ed4a1a6c5d8..9a8e1b64c22 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -1,24 +1,18 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) * Licensed under the GPL */ #include <stdio.h> -#include <stddef.h> #include <stdlib.h> -#include <string.h> #include <errno.h> -#include <unistd.h> #include <termios.h> -#include <sys/socket.h> -#include <sys/un.h> +#include <unistd.h> #include <netinet/in.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" #include "chan_user.h" +#include <os.h> #include "port.h" -#include "os.h" +#include <um_malloc.h> struct port_chan { int raw; @@ -27,41 +21,42 @@ struct port_chan { char dev[sizeof("32768\0")]; }; -static void *port_init(char *str, int device, struct chan_opts *opts) +static void *port_init(char *str, int device, const struct chan_opts *opts) { struct port_chan *data; void *kern_data; char *end; int port; - if(*str != ':'){ - printk("port_init : channel type 'port' must specify a " - "port number\n"); - return(NULL); + if (*str != ':') { + printk(UM_KERN_ERR "port_init : channel type 'port' must " + "specify a port number\n"); + return NULL; } str++; port = strtoul(str, &end, 0); - if((*end != '\0') || (end == str)){ - printk("port_init : couldn't parse port '%s'\n", str); - return(NULL); + if ((*end != '\0') || (end == str)) { + printk(UM_KERN_ERR "port_init : couldn't parse port '%s'\n", + str); + return NULL; } kern_data = port_data(port); - if(kern_data == NULL) - return(NULL); + if (kern_data == NULL) + return NULL; - data = um_kmalloc(sizeof(*data)); - if(data == NULL) + data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); + if (data == NULL) goto err; *data = ((struct port_chan) { .raw = opts->raw, .kernel_data = kern_data }); sprintf(data->dev, "%d", port); - return(data); + return data; err: port_kern_free(kern_data); - return(NULL); + return NULL; } static void port_free(void *d) @@ -79,17 +74,17 @@ static int port_open(int input, int output, int primary, void *d, int fd, err; fd = port_wait(data->kernel_data); - if((fd >= 0) && data->raw){ + if ((fd >= 0) && data->raw) { CATCH_EINTR(err = tcgetattr(fd, &data->tt)); - if(err) - return(err); + if (err) + return err; err = raw(fd); - if(err) - return(err); + if (err) + return err; } *dev_out = data->dev; - return(fd); + return fd; } static void port_close(int fd, void *d) @@ -100,21 +95,14 @@ static void port_close(int fd, void *d) os_close_file(fd); } -static int port_console_write(int fd, const char *buf, int n, void *d) -{ - struct port_chan *data = d; - - return(generic_console_write(fd, buf, n, &data->tt)); -} - -struct chan_ops port_ops = { +const struct chan_ops port_ops = { .type = "port", .init = port_init, .open = port_open, .close = port_close, .read = generic_read, .write = generic_write, - .console_write = port_console_write, + .console_write = generic_console_write, .window_size = generic_window_size, .free = port_free, .winch = 1, @@ -126,11 +114,11 @@ int port_listen_fd(int port) int fd, err, arg; fd = socket(PF_INET, SOCK_STREAM, 0); - if(fd == -1) - return(-errno); + if (fd == -1) + return -errno; arg = 1; - if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){ + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0) { err = -errno; goto out; } @@ -138,24 +126,24 @@ int port_listen_fd(int port) addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); - if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0){ + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { err = -errno; goto out; } - - if(listen(fd, 1) < 0){ + + if (listen(fd, 1) < 0) { err = -errno; goto out; } err = os_set_fd_block(fd, 0); - if(err < 0) + if (err < 0) goto out; - return(fd); + return fd; out: - os_close_file(fd); - return(err); + close(fd); + return err; } struct port_pre_exec_data { @@ -163,62 +151,51 @@ struct port_pre_exec_data { int pipe_fd; }; -void port_pre_exec(void *arg) +static void port_pre_exec(void *arg) { struct port_pre_exec_data *data = arg; dup2(data->sock_fd, 0); dup2(data->sock_fd, 1); dup2(data->sock_fd, 2); - os_close_file(data->sock_fd); + close(data->sock_fd); dup2(data->pipe_fd, 3); - os_shutdown_socket(3, 1, 0); - os_close_file(data->pipe_fd); + shutdown(3, SHUT_RD); + close(data->pipe_fd); } int port_connection(int fd, int *socket, int *pid_out) { int new, err; - char *argv[] = { "/usr/sbin/in.telnetd", "-L", + char *argv[] = { "/usr/sbin/in.telnetd", "-L", "/usr/lib/uml/port-helper", NULL }; struct port_pre_exec_data data; - new = os_accept_connection(fd); - if(new < 0) - return(new); + new = accept(fd, NULL, 0); + if (new < 0) + return -errno; err = os_pipe(socket, 0, 0); - if(err < 0) + if (err < 0) goto out_close; data = ((struct port_pre_exec_data) { .sock_fd = new, .pipe_fd = socket[1] }); - err = run_helper(port_pre_exec, &data, argv, NULL); - if(err < 0) + err = run_helper(port_pre_exec, &data, argv); + if (err < 0) goto out_shutdown; *pid_out = err; - return(new); + return new; out_shutdown: - os_shutdown_socket(socket[0], 1, 1); - os_close_file(socket[0]); - os_shutdown_socket(socket[1], 1, 1); - os_close_file(socket[1]); + shutdown(socket[0], SHUT_RDWR); + close(socket[0]); + shutdown(socket[1], SHUT_RDWR); + close(socket[1]); out_close: - os_close_file(new); - return(err); + close(new); + return err; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index 0306a1b215b..f1fcc2cedb5 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -1,18 +1,19 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #include <stdio.h> +#include <stdlib.h> #include <unistd.h> -#include <string.h> #include <errno.h> +#include <fcntl.h> +#include <string.h> #include <termios.h> +#include <sys/stat.h> #include "chan_user.h" -#include "user.h" -#include "user_util.h" -#include "kern_util.h" -#include "os.h" +#include <os.h> +#include <um_malloc.h> struct pty_chan { void (*announce)(char *dev_name, int dev); @@ -22,16 +23,18 @@ struct pty_chan { char dev_name[sizeof("/dev/pts/0123456\0")]; }; -static void *pty_chan_init(char *str, int device, struct chan_opts *opts) +static void *pty_chan_init(char *str, int device, const struct chan_opts *opts) { struct pty_chan *data; - data = um_kmalloc(sizeof(*data)); - if(data == NULL) return(NULL); - *data = ((struct pty_chan) { .announce = opts->announce, + data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); + if (data == NULL) + return NULL; + + *data = ((struct pty_chan) { .announce = opts->announce, .dev = device, .raw = opts->raw }); - return(data); + return data; } static int pts_open(int input, int output, int primary, void *d, @@ -42,31 +45,39 @@ static int pts_open(int input, int output, int primary, void *d, int fd, err; fd = get_pty(); - if(fd < 0){ + if (fd < 0) { err = -errno; - printk("open_pts : Failed to open pts\n"); + printk(UM_KERN_ERR "open_pts : Failed to open pts\n"); return err; } - if(data->raw){ + + if (data->raw) { CATCH_EINTR(err = tcgetattr(fd, &data->tt)); - if(err) - return(err); + if (err) + goto out_close; err = raw(fd); - if(err) - return(err); + if (err) + goto out_close; } dev = ptsname(fd); sprintf(data->dev_name, "%s", dev); *dev_out = data->dev_name; + if (data->announce) (*data->announce)(dev, data->dev); - return(fd); + + return fd; + +out_close: + close(fd); + return err; } static int getmaster(char *line) { + struct stat buf; char *pty, *bank, *cp; int master, err; @@ -74,24 +85,29 @@ static int getmaster(char *line) for (bank = "pqrs"; *bank; bank++) { line[strlen("/dev/pty")] = *bank; *pty = '0'; - if (os_stat_file(line, NULL) < 0) + /* Did we hit the end ? */ + if ((stat(line, &buf) < 0) && (errno == ENOENT)) break; + for (cp = "0123456789abcdef"; *cp; cp++) { *pty = *cp; - master = os_open_file(line, of_rdwr(OPENFLAGS()), 0); + master = open(line, O_RDWR); if (master >= 0) { char *tp = &line[strlen("/dev/")]; /* verify slave side is usable */ *tp = 't'; - err = os_access(line, OS_ACC_RW_OK); + err = access(line, R_OK | W_OK); *tp = 'p'; - if(err == 0) return(master); - (void) os_close_file(master); + if (!err) + return master; + close(master); } } } - return(-1); + + printk(UM_KERN_ERR "getmaster - no usable host pty devices\n"); + return -ENOENT; } static int pty_open(int input, int output, int primary, void *d, @@ -102,62 +118,48 @@ static int pty_open(int input, int output, int primary, void *d, char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx"; fd = getmaster(dev); - if(fd < 0) - return(-errno); + if (fd < 0) + return fd; - if(data->raw){ + if (data->raw) { err = raw(fd); - if(err) - return(err); + if (err) { + close(fd); + return err; + } } - - if(data->announce) (*data->announce)(dev, data->dev); + + if (data->announce) + (*data->announce)(dev, data->dev); sprintf(data->dev_name, "%s", dev); *dev_out = data->dev_name; - return(fd); -} - -static int pty_console_write(int fd, const char *buf, int n, void *d) -{ - struct pty_chan *data = d; - return(generic_console_write(fd, buf, n, &data->tt)); + return fd; } -struct chan_ops pty_ops = { +const struct chan_ops pty_ops = { .type = "pty", .init = pty_chan_init, .open = pty_open, .close = generic_close, .read = generic_read, .write = generic_write, - .console_write = pty_console_write, + .console_write = generic_console_write, .window_size = generic_window_size, .free = generic_free, .winch = 0, }; -struct chan_ops pts_ops = { +const struct chan_ops pts_ops = { .type = "pts", .init = pty_chan_init, .open = pts_open, .close = generic_close, .read = generic_read, .write = generic_write, - .console_write = pty_console_write, + .console_write = generic_console_write, .window_size = generic_window_size, .free = generic_free, .winch = 0, }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index f9e22198e01..9e3a7220582 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c @@ -1,87 +1,122 @@ -/* Copyright (C) 2005 Jeff Dike <jdike@addtoit.com> */ +/* Copyright (C) 2005 - 2008 Jeff Dike <jdike@{linux.intel,addtoit}.com> */ + /* Much of this ripped from drivers/char/hw_random.c, see there for other * copyright. * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. */ +#include <linux/sched.h> #include <linux/module.h> #include <linux/fs.h> +#include <linux/interrupt.h> #include <linux/miscdevice.h> #include <linux/delay.h> #include <asm/uaccess.h> -#include "os.h" +#include <irq_kern.h> +#include <os.h> /* * core module and version information */ #define RNG_VERSION "1.0.0" -#define RNG_MODULE_NAME "random" +#define RNG_MODULE_NAME "hw_random" #define RNG_MISCDEV_MINOR 183 /* official */ +/* Changed at init time, in the non-modular case, and at module load + * time, in the module case. Presumably, the module subsystem + * protects against a module being loaded twice at the same time. + */ static int random_fd = -1; +static DECLARE_WAIT_QUEUE_HEAD(host_read_wait); static int rng_dev_open (struct inode *inode, struct file *filp) { /* enforce read-only access to this chrdev */ if ((filp->f_mode & FMODE_READ) == 0) return -EINVAL; - if (filp->f_mode & FMODE_WRITE) + if ((filp->f_mode & FMODE_WRITE) != 0) return -EINVAL; return 0; } +static atomic_t host_sleep_count = ATOMIC_INIT(0); + static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, - loff_t * offp) + loff_t *offp) { - u32 data; - int n, ret = 0, have_data; - - while(size){ - n = os_read_file(random_fd, &data, sizeof(data)); - if(n > 0){ - have_data = n; - while (have_data && size) { - if (put_user((u8)data, buf++)) { - ret = ret ? : -EFAULT; - break; - } - size--; - ret++; - have_data--; - data>>=8; - } - } - else if(n == -EAGAIN){ - if (filp->f_flags & O_NONBLOCK) - return ret ? : -EAGAIN; - - if(need_resched()){ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - } - else return n; + u32 data; + int n, ret = 0, have_data; + + while (size) { + n = os_read_file(random_fd, &data, sizeof(data)); + if (n > 0) { + have_data = n; + while (have_data && size) { + if (put_user((u8) data, buf++)) { + ret = ret ? : -EFAULT; + break; + } + size--; + ret++; + have_data--; + data >>= 8; + } + } + else if (n == -EAGAIN) { + DECLARE_WAITQUEUE(wait, current); + + if (filp->f_flags & O_NONBLOCK) + return ret ? : -EAGAIN; + + atomic_inc(&host_sleep_count); + reactivate_fd(random_fd, RANDOM_IRQ); + add_sigio_fd(random_fd); + + add_wait_queue(&host_read_wait, &wait); + set_task_state(current, TASK_INTERRUPTIBLE); + + schedule(); + set_task_state(current, TASK_RUNNING); + remove_wait_queue(&host_read_wait, &wait); + + if (atomic_dec_and_test(&host_sleep_count)) { + ignore_sigio_fd(random_fd); + deactivate_fd(random_fd, RANDOM_IRQ); + } + } + else + return n; + if (signal_pending (current)) return ret ? : -ERESTARTSYS; } return ret; } -static struct file_operations rng_chrdev_ops = { +static const struct file_operations rng_chrdev_ops = { .owner = THIS_MODULE, .open = rng_dev_open, .read = rng_dev_read, + .llseek = noop_llseek, }; +/* rng_init shouldn't be called more than once at boot time */ static struct miscdevice rng_miscdev = { RNG_MISCDEV_MINOR, RNG_MODULE_NAME, &rng_chrdev_ops, }; +static irqreturn_t random_interrupt(int irq, void *data) +{ + wake_up(&host_read_wait); + + return IRQ_HANDLED; +} + /* * rng_init - initialize RNG module */ @@ -89,28 +124,32 @@ static int __init rng_init (void) { int err; - err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0); - if(err < 0) - goto out; + err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0); + if (err < 0) + goto out; - random_fd = err; + random_fd = err; - err = os_set_fd_block(random_fd, 0); - if(err) + err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt, + 0, "random", NULL); + if (err) goto err_out_cleanup_hw; + sigio_broken(random_fd, 1); + err = misc_register (&rng_miscdev); if (err) { - printk (KERN_ERR RNG_MODULE_NAME ": misc device register failed\n"); + printk (KERN_ERR RNG_MODULE_NAME ": misc device register " + "failed\n"); goto err_out_cleanup_hw; } +out: + return err; - out: - return err; - - err_out_cleanup_hw: - random_fd = -1; - goto out; +err_out_cleanup_hw: + os_close_file(random_fd); + random_fd = -1; + goto out; } /* @@ -118,6 +157,7 @@ static int __init rng_init (void) */ static void __exit rng_cleanup (void) { + os_close_file(random_fd); misc_deregister (&rng_miscdev); } diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h index bb0dab41c2e..c64f8c61d27 100644 --- a/arch/um/drivers/slip.h +++ b/arch/um/drivers/slip.h @@ -12,7 +12,7 @@ struct slip_data { struct slip_proto slip; }; -extern struct net_user_info slip_user_info; +extern const struct net_user_info slip_user_info; extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri); extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri); diff --git a/arch/um/drivers/slip_common.c b/arch/um/drivers/slip_common.c index e89cfc68fc3..f597fa7c91d 100644 --- a/arch/um/drivers/slip_common.c +++ b/arch/um/drivers/slip_common.c @@ -1,6 +1,6 @@ #include <string.h> #include "slip_common.h" -#include "net_user.h" +#include <net_user.h> int slip_proto_read(int fd, void *buf, int len, struct slip_proto *slip) { diff --git a/arch/um/drivers/slip_common.h b/arch/um/drivers/slip_common.h index 2ae76d8f1be..d574e0a9dc1 100644 --- a/arch/um/drivers/slip_common.h +++ b/arch/um/drivers/slip_common.h @@ -88,12 +88,13 @@ struct slip_proto { int esc; }; -#define SLIP_PROTO_INIT { \ - .ibuf = { '\0' }, \ - .obuf = { '\0' }, \ - .more = 0, \ - .pos = 0, \ - .esc = 0 \ +static inline void slip_proto_init(struct slip_proto * slip) +{ + memset(slip->ibuf, 0, sizeof(slip->ibuf)); + memset(slip->obuf, 0, sizeof(slip->obuf)); + slip->more = 0; + slip->pos = 0; + slip->esc = 0; } extern int slip_proto_read(int fd, void *buf, int len, diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index 9a6f5c85f90..ed5249fc057 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c @@ -1,39 +1,37 @@ -#include "linux/config.h" -#include "linux/kernel.h" -#include "linux/stddef.h" -#include "linux/init.h" -#include "linux/netdevice.h" -#include "linux/if_arp.h" -#include "net_kern.h" -#include "net_user.h" -#include "kern.h" +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL. + */ + +#include <linux/if_arp.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <net_kern.h> #include "slip.h" struct slip_init { char *gate_addr; }; -void slip_init(struct net_device *dev, void *data) +static void slip_init(struct net_device *dev, void *data) { struct uml_net_private *private; struct slip_data *spri; struct slip_init *init = data; - private = dev->priv; + private = netdev_priv(dev); spri = (struct slip_data *) private->user; - *spri = ((struct slip_data) - { .name = { '\0' }, - .addr = NULL, - .gate_addr = init->gate_addr, - .slave = -1, - .slip = SLIP_PROTO_INIT, - .dev = dev }); - - dev->init = NULL; - dev->header_cache_update = NULL; - dev->hard_header_cache = NULL; - dev->hard_header = NULL; + + memset(spri->name, 0, sizeof(spri->name)); + spri->addr = NULL; + spri->gate_addr = init->gate_addr; + spri->slave = -1; + spri->dev = dev; + + slip_proto_init(&spri->slip); + dev->hard_header_len = 0; + dev->header_ops = NULL; dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = 256; @@ -43,24 +41,22 @@ void slip_init(struct net_device *dev, void *data) static unsigned short slip_protocol(struct sk_buff *skbuff) { - return(htons(ETH_P_IP)); + return htons(ETH_P_IP); } -static int slip_read(int fd, struct sk_buff **skb, - struct uml_net_private *lp) +static int slip_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - return(slip_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, - (struct slip_data *) &lp->user)); + return slip_user_read(fd, skb_mac_header(skb), skb->dev->mtu, + (struct slip_data *) &lp->user); } -static int slip_write(int fd, struct sk_buff **skb, - struct uml_net_private *lp) +static int slip_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - return(slip_user_write(fd, (*skb)->data, (*skb)->len, - (struct slip_data *) &lp->user)); + return slip_user_write(fd, skb->data, skb->len, + (struct slip_data *) &lp->user); } -struct net_kern_info slip_kern_info = { +static const struct net_kern_info slip_kern_info = { .init = slip_init, .protocol = slip_protocol, .read = slip_read, @@ -71,12 +67,11 @@ static int slip_setup(char *str, char **mac_out, void *data) { struct slip_init *init = data; - *init = ((struct slip_init) - { .gate_addr = NULL }); + *init = ((struct slip_init) { .gate_addr = NULL }); - if(str[0] != '\0') + if (str[0] != '\0') init->gate_addr = str; - return(1); + return 1; } static struct transport slip_transport = { @@ -92,18 +87,7 @@ static struct transport slip_transport = { static int register_slip(void) { register_transport(&slip_transport); - return(1); + return 0; } -__initcall(register_slip); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +late_initcall(register_slip); diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index 89fbec185cc..55c290d925f 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -1,26 +1,27 @@ +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL. + */ + #include <stdio.h> #include <stdlib.h> #include <unistd.h> -#include <stddef.h> -#include <sched.h> -#include <string.h> #include <errno.h> +#include <fcntl.h> +#include <string.h> #include <sys/termios.h> #include <sys/wait.h> -#include <sys/signal.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "net_user.h" +#include <net_user.h> +#include <os.h> #include "slip.h" -#include "slip_common.h" -#include "os.h" +#include <um_malloc.h> -void slip_user_init(void *data, void *dev) +static int slip_user_init(void *data, void *dev) { struct slip_data *pri = data; pri->dev = dev; + return 0; } static int set_up_tty(int fd) @@ -29,8 +30,9 @@ static int set_up_tty(int fd) struct termios tios; if (tcgetattr(fd, &tios) < 0) { - printk("could not get initial terminal attributes\n"); - return(-1); + printk(UM_KERN_ERR "could not get initial terminal " + "attributes\n"); + return -1; } tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL; @@ -46,10 +48,10 @@ static int set_up_tty(int fd) cfsetispeed(&tios, B38400); if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { - printk("failed to set terminal attributes\n"); - return(-1); + printk(UM_KERN_ERR "failed to set terminal attributes\n"); + return -1; } - return(0); + return 0; } struct slip_pre_exec_data { @@ -62,20 +64,23 @@ static void slip_pre_exec(void *arg) { struct slip_pre_exec_data *data = arg; - if(data->stdin >= 0) dup2(data->stdin, 0); + if (data->stdin >= 0) + dup2(data->stdin, 0); dup2(data->stdout, 1); - if(data->close_me >= 0) os_close_file(data->close_me); + if (data->close_me >= 0) + close(data->close_me); } static int slip_tramp(char **argv, int fd) { struct slip_pre_exec_data pe_data; char *output; - int status, pid, fds[2], err, output_len; + int pid, fds[2], err, output_len; err = os_pipe(fds, 1, 0); - if(err < 0){ - printk("slip_tramp : pipe failed, err = %d\n", -err); + if (err < 0) { + printk(UM_KERN_ERR "slip_tramp : pipe failed, err = %d\n", + -err); goto out; } @@ -83,42 +88,34 @@ static int slip_tramp(char **argv, int fd) pe_data.stdin = fd; pe_data.stdout = fds[1]; pe_data.close_me = fds[0]; - err = run_helper(slip_pre_exec, &pe_data, argv, NULL); - if(err < 0) + err = run_helper(slip_pre_exec, &pe_data, argv); + if (err < 0) goto out_close; pid = err; - output_len = page_size(); - output = um_kmalloc(output_len); - if(output == NULL){ - printk("slip_tramp : failed to allocate output buffer\n"); + output_len = UM_KERN_PAGE_SIZE; + output = uml_kmalloc(output_len, UM_GFP_KERNEL); + if (output == NULL) { + printk(UM_KERN_ERR "slip_tramp : failed to allocate output " + "buffer\n"); os_kill_process(pid, 1); err = -ENOMEM; - goto out_free; + goto out_close; } - os_close_file(fds[1]); + close(fds[1]); read_output(fds[0], output, output_len); printk("%s", output); - CATCH_EINTR(err = waitpid(pid, &status, 0)); - if(err < 0) - err = errno; - else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ - printk("'%s' didn't exit with status 0\n", argv[0]); - err = -EINVAL; - } - else err = 0; + err = helper_wait(pid); + close(fds[0]); - os_close_file(fds[0]); - -out_free: kfree(output); return err; out_close: - os_close_file(fds[0]); - os_close_file(fds[1]); + close(fds[0]); + close(fds[1]); out: return err; } @@ -128,60 +125,64 @@ static int slip_open(void *data) struct slip_data *pri = data; char version_buf[sizeof("nnnnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; - char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, + char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, NULL }; int sfd, mfd, err; err = get_pty(); - if(err < 0){ - printk("slip-open : Failed to open pty, err = %d\n", -err); + if (err < 0) { + printk(UM_KERN_ERR "slip-open : Failed to open pty, err = %d\n", + -err); goto out; } mfd = err; - err = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0); - if(err < 0){ - printk("Couldn't open tty for slip line, err = %d\n", -err); + err = open(ptsname(mfd), O_RDWR, 0); + if (err < 0) { + printk(UM_KERN_ERR "Couldn't open tty for slip line, " + "err = %d\n", -err); goto out_close; } sfd = err; - if(set_up_tty(sfd)) + if (set_up_tty(sfd)) goto out_close2; pri->slave = sfd; pri->slip.pos = 0; pri->slip.esc = 0; - if(pri->gate_addr != NULL){ + if (pri->gate_addr != NULL) { sprintf(version_buf, "%d", UML_NET_VERSION); strcpy(gate_buf, pri->gate_addr); err = slip_tramp(argv, sfd); - if(err < 0){ - printk("slip_tramp failed - err = %d\n", -err); + if (err < 0) { + printk(UM_KERN_ERR "slip_tramp failed - err = %d\n", + -err); goto out_close2; } err = os_get_ifname(pri->slave, pri->name); - if(err < 0){ - printk("get_ifname failed, err = %d\n", -err); + if (err < 0) { + printk(UM_KERN_ERR "get_ifname failed, err = %d\n", + -err); goto out_close2; } iter_addresses(pri->dev, open_addr, pri->name); } else { err = os_set_slip(sfd); - if(err < 0){ - printk("Failed to set slip discipline encapsulation - " - "err = %d\n", -err); + if (err < 0) { + printk(UM_KERN_ERR "Failed to set slip discipline " + "encapsulation - err = %d\n", -err); goto out_close2; } } - return(mfd); + return mfd; out_close2: - os_close_file(sfd); + close(sfd); out_close: - os_close_file(mfd); + close(mfd); out: return err; } @@ -190,21 +191,21 @@ static void slip_close(int fd, void *data) { struct slip_data *pri = data; char version_buf[sizeof("nnnnn\0")]; - char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, + char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, NULL }; int err; - if(pri->gate_addr != NULL) + if (pri->gate_addr != NULL) iter_addresses(pri->dev, close_addr, pri->name); sprintf(version_buf, "%d", UML_NET_VERSION); err = slip_tramp(argv, pri->slave); - if(err != 0) - printk("slip_tramp failed - errno = %d\n", -err); - os_close_file(fd); - os_close_file(pri->slave); + if (err != 0) + printk(UM_KERN_ERR "slip_tramp failed - errno = %d\n", -err); + close(fd); + close(pri->slave); pri->slave = -1; } @@ -218,17 +219,13 @@ int slip_user_write(int fd, void *buf, int len, struct slip_data *pri) return slip_proto_write(fd, buf, len, &pri->slip); } -static int slip_set_mtu(int mtu, void *data) -{ - return(mtu); -} - static void slip_add_addr(unsigned char *addr, unsigned char *netmask, void *data) { struct slip_data *pri = data; - if(pri->slave < 0) return; + if (pri->slave < 0) + return; open_addr(addr, netmask, pri->name); } @@ -237,17 +234,18 @@ static void slip_del_addr(unsigned char *addr, unsigned char *netmask, { struct slip_data *pri = data; - if(pri->slave < 0) return; + if (pri->slave < 0) + return; close_addr(addr, netmask, pri->name); } -struct net_user_info slip_user_info = { +const struct net_user_info slip_user_info = { .init = slip_user_init, .open = slip_open, .close = slip_close, .remove = NULL, - .set_mtu = slip_set_mtu, .add_address = slip_add_addr, .delete_address = slip_del_addr, - .max_packet = BUF_SIZE + .mtu = BUF_SIZE, + .max_packet = BUF_SIZE, }; diff --git a/arch/um/drivers/slirp.h b/arch/um/drivers/slirp.h index 6cf88ab580c..89ccf83b757 100644 --- a/arch/um/drivers/slirp.h +++ b/arch/um/drivers/slirp.h @@ -24,7 +24,7 @@ struct slirp_data { struct slip_proto slip; }; -extern struct net_user_info slirp_user_info; +extern const struct net_user_info slirp_user_info; extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri); extern int slirp_user_write(int fd, void *buf, int len, diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c index 9864d27afdb..4ef11ca7cac 100644 --- a/arch/um/drivers/slirp_kern.c +++ b/arch/um/drivers/slirp_kern.c @@ -1,11 +1,14 @@ -#include "linux/kernel.h" -#include "linux/stddef.h" -#include "linux/init.h" -#include "linux/netdevice.h" -#include "linux/if_arp.h" -#include "net_kern.h" -#include "net_user.h" -#include "kern.h" +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL. + */ + +#include <linux/if_arp.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/string.h> +#include <net_kern.h> +#include <net_user.h> #include "slirp.h" struct slirp_init { @@ -19,51 +22,46 @@ void slirp_init(struct net_device *dev, void *data) struct slirp_init *init = data; int i; - private = dev->priv; + private = netdev_priv(dev); spri = (struct slirp_data *) private->user; - *spri = ((struct slirp_data) - { .argw = init->argw, - .pid = -1, - .slave = -1, - .slip = SLIP_PROTO_INIT, - .dev = dev }); - - dev->init = NULL; + + spri->argw = init->argw; + spri->pid = -1; + spri->slave = -1; + spri->dev = dev; + + slip_proto_init(&spri->slip); + dev->hard_header_len = 0; - dev->header_cache_update = NULL; - dev->hard_header_cache = NULL; - dev->hard_header = NULL; + dev->header_ops = NULL; dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = 256; dev->flags = IFF_NOARP; printk("SLIRP backend - command line:"); - for(i=0;spri->argw.argv[i]!=NULL;i++) { + for (i = 0; spri->argw.argv[i] != NULL; i++) printk(" '%s'",spri->argw.argv[i]); - } printk("\n"); } static unsigned short slirp_protocol(struct sk_buff *skbuff) { - return(htons(ETH_P_IP)); + return htons(ETH_P_IP); } -static int slirp_read(int fd, struct sk_buff **skb, - struct uml_net_private *lp) +static int slirp_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, - (struct slirp_data *) &lp->user)); + return slirp_user_read(fd, skb_mac_header(skb), skb->dev->mtu, + (struct slirp_data *) &lp->user); } -static int slirp_write(int fd, struct sk_buff **skb, - struct uml_net_private *lp) +static int slirp_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - return(slirp_user_write(fd, (*skb)->data, (*skb)->len, - (struct slirp_data *) &lp->user)); + return slirp_user_write(fd, skb->data, skb->len, + (struct slirp_data *) &lp->user); } -struct net_kern_info slirp_kern_info = { +const struct net_kern_info slirp_kern_info = { .init = slirp_init, .protocol = slirp_protocol, .read = slirp_read, @@ -75,31 +73,32 @@ static int slirp_setup(char *str, char **mac_out, void *data) struct slirp_init *init = data; int i=0; - *init = ((struct slirp_init) - { argw : { { "slirp", NULL } } }); + *init = ((struct slirp_init) { .argw = { { "slirp", NULL } } }); str = split_if_spec(str, mac_out, NULL); - if(str == NULL) { /* no command line given after MAC addr */ - return(1); - } + if (str == NULL) /* no command line given after MAC addr */ + return 1; do { - if(i>=SLIRP_MAX_ARGS-1) { - printk("slirp_setup: truncating slirp arguments\n"); + if (i >= SLIRP_MAX_ARGS - 1) { + printk(KERN_WARNING "slirp_setup: truncating slirp " + "arguments\n"); break; } init->argw.argv[i++] = str; while(*str && *str!=',') { - if(*str=='_') *str=' '; + if (*str == '_') + *str=' '; str++; } - if(*str!=',') + if (*str != ',') break; - *str++='\0'; - } while(1); - init->argw.argv[i]=NULL; - return(1); + *str++ = '\0'; + } while (1); + + init->argw.argv[i] = NULL; + return 1; } static struct transport slirp_transport = { @@ -115,18 +114,7 @@ static struct transport slirp_transport = { static int register_slirp(void) { register_transport(&slirp_transport); - return(1); + return 0; } -__initcall(register_slirp); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +late_initcall(register_slirp); diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index b94c66114bc..c999d187abb 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -1,25 +1,22 @@ -#include <stdio.h> -#include <stdlib.h> +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL. + */ + #include <unistd.h> -#include <stddef.h> -#include <sched.h> -#include <string.h> #include <errno.h> +#include <string.h> #include <sys/wait.h> -#include <sys/signal.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "net_user.h" +#include <net_user.h> +#include <os.h> #include "slirp.h" -#include "slip_common.h" -#include "os.h" -void slirp_user_init(void *data, void *dev) +static int slirp_user_init(void *data, void *dev) { struct slirp_data *pri = data; pri->dev = dev; + return 0; } struct slirp_pre_exec_data { @@ -31,8 +28,10 @@ static void slirp_pre_exec(void *arg) { struct slirp_pre_exec_data *data = arg; - if(data->stdin != -1) dup2(data->stdin, 0); - if(data->stdout != -1) dup2(data->stdout, 1); + if (data->stdin != -1) + dup2(data->stdin, 0); + if (data->stdout != -1) + dup2(data->stdout, 1); } static int slirp_tramp(char **argv, int fd) @@ -42,9 +41,9 @@ static int slirp_tramp(char **argv, int fd) pe_data.stdin = fd; pe_data.stdout = fd; - pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL); + pid = run_helper(slirp_pre_exec, &pe_data, argv); - return(pid); + return pid; } static int slirp_open(void *data) @@ -53,12 +52,12 @@ static int slirp_open(void *data) int fds[2], pid, err; err = os_pipe(fds, 1, 1); - if(err) - return(err); + if (err) + return err; err = slirp_tramp(pri->argw.argv, fds[1]); - if(err < 0){ - printk("slirp_tramp failed - errno = %d\n", -err); + if (err < 0) { + printk(UM_KERN_ERR "slirp_tramp failed - errno = %d\n", -err); goto out; } pid = err; @@ -68,45 +67,38 @@ static int slirp_open(void *data) pri->slip.esc = 0; pri->pid = err; - return(fds[0]); + return fds[0]; out: - os_close_file(fds[0]); - os_close_file(fds[1]); + close(fds[0]); + close(fds[1]); return err; } static void slirp_close(int fd, void *data) { struct slirp_data *pri = data; - int status,err; + int err; - os_close_file(fd); - os_close_file(pri->slave); + close(fd); + close(pri->slave); pri->slave = -1; - if(pri->pid<1) { - printk("slirp_close: no child process to shut down\n"); + if (pri->pid<1) { + printk(UM_KERN_ERR "slirp_close: no child process to shut " + "down\n"); return; } #if 0 - if(kill(pri->pid, SIGHUP)<0) { - printk("slirp_close: sending hangup to %d failed (%d)\n", - pri->pid, errno); + if (kill(pri->pid, SIGHUP)<0) { + printk(UM_KERN_ERR "slirp_close: sending hangup to %d failed " + "(%d)\n", pri->pid, errno); } #endif - - CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG)); - if(err < 0) { - printk("slirp_close: waitpid returned %d\n", errno); + err = helper_wait(pri->pid); + if (err < 0) return; - } - - if(err == 0) { - printk("slirp_close: process %d has not exited\n"); - return; - } pri->pid = -1; } @@ -121,18 +113,13 @@ int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri) return slip_proto_write(fd, buf, len, &pri->slip); } -static int slirp_set_mtu(int mtu, void *data) -{ - return(mtu); -} - -struct net_user_info slirp_user_info = { +const struct net_user_info slirp_user_info = { .init = slirp_user_init, .open = slirp_open, .close = slirp_close, .remove = NULL, - .set_mtu = slirp_set_mtu, .add_address = NULL, .delete_address = NULL, - .max_packet = BUF_SIZE + .mtu = BUF_SIZE, + .max_packet = BUF_SIZE, }; diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 62e04ecfada..b8d14fa5205 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -3,58 +3,47 @@ * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/fs.h" -#include "linux/tty.h" -#include "linux/tty_driver.h" -#include "linux/major.h" -#include "linux/mm.h" -#include "linux/init.h" -#include "linux/console.h" -#include "asm/termbits.h" -#include "asm/irq.h" -#include "line.h" +#include <linux/fs.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/major.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/console.h> +#include <asm/termbits.h> +#include <asm/irq.h> #include "ssl.h" -#include "chan_kern.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" -#include "init.h" -#include "irq_user.h" +#include "chan.h" +#include <init.h> +#include <irq_user.h> #include "mconsole_kern.h" -static int ssl_version = 1; - -/* Referenced only by tty_driver below - presumably it's locked correctly - * by the tty driver. - */ - -static struct tty_driver *ssl_driver; +static const int ssl_version = 1; #define NR_PORTS 64 -void ssl_announce(char *dev_name, int dev) +static void ssl_announce(char *dev_name, int dev) { printk(KERN_INFO "Serial line %d assigned device '%s'\n", dev, dev_name); } +/* Almost const, except that xterm_title may be changed in an initcall */ static struct chan_opts opts = { .announce = ssl_announce, .xterm_title = "Serial Line #%d", .raw = 1, - .tramp_stack = 0, - .in_kernel = 1, }; -static int ssl_config(char *str); +static int ssl_config(char *str, char **error_out); static int ssl_get_config(char *dev, char *str, int size, char **error_out); -static int ssl_remove(int n); +static int ssl_remove(int n, char **error_out); + +/* Const, except for .mc.list */ static struct line_driver driver = { .name = "UML serial line", .device_name = "ttyS", - .devfs_name = "tts/", .major = TTY_MAJOR, .minor_start = 64, .type = TTY_DRIVER_TYPE_SERIAL, @@ -63,82 +52,48 @@ static struct line_driver driver = { .read_irq_name = "ssl", .write_irq = SSL_WRITE_IRQ, .write_irq_name = "ssl-write", - .symlink_from = "serial", - .symlink_to = "tts", .mc = { + .list = LIST_HEAD_INIT(driver.mc.list), .name = "ssl", .config = ssl_config, .get_config = ssl_get_config, - .id = line_id, + .id = line_id, .remove = ssl_remove, }, }; -/* The array is initialized by line_init, which is an initcall. The - * individual elements are protected by individual semaphores. +/* The array is initialized by line_init, at initcall time. The + * elements are locked individually as needed. */ -static struct line serial_lines[NR_PORTS] = - { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) }; - -static struct lines lines = LINES_INIT(NR_PORTS); +static char *conf[NR_PORTS]; +static char *def_conf = CONFIG_SSL_CHAN; +static struct line serial_lines[NR_PORTS]; -static int ssl_config(char *str) +static int ssl_config(char *str, char **error_out) { - return(line_config(serial_lines, - sizeof(serial_lines)/sizeof(serial_lines[0]), str)); + return line_config(serial_lines, ARRAY_SIZE(serial_lines), str, &opts, + error_out); } static int ssl_get_config(char *dev, char *str, int size, char **error_out) { - return(line_get_config(dev, serial_lines, - sizeof(serial_lines)/sizeof(serial_lines[0]), - str, size, error_out)); -} - -static int ssl_remove(int n) -{ - return line_remove(serial_lines, - sizeof(serial_lines)/sizeof(serial_lines[0]), n); -} - -int ssl_open(struct tty_struct *tty, struct file *filp) -{ - return line_open(serial_lines, tty, &opts); -} - -#if 0 -static void ssl_flush_buffer(struct tty_struct *tty) -{ - return; -} - -static void ssl_throttle(struct tty_struct * tty) -{ - printk(KERN_ERR "Someone should implement ssl_throttle\n"); -} - -static void ssl_unthrottle(struct tty_struct * tty) -{ - printk(KERN_ERR "Someone should implement ssl_unthrottle\n"); -} - -static void ssl_stop(struct tty_struct *tty) -{ - printk(KERN_ERR "Someone should implement ssl_stop\n"); + return line_get_config(dev, serial_lines, ARRAY_SIZE(serial_lines), str, + size, error_out); } -static void ssl_start(struct tty_struct *tty) +static int ssl_remove(int n, char **error_out) { - printk(KERN_ERR "Someone should implement ssl_start\n"); + return line_remove(serial_lines, ARRAY_SIZE(serial_lines), n, + error_out); } -void ssl_hangup(struct tty_struct *tty) +static int ssl_install(struct tty_driver *driver, struct tty_struct *tty) { + return line_install(driver, tty, &serial_lines[tty->index]); } -#endif -static struct tty_operations ssl_ops = { - .open = ssl_open, +static const struct tty_operations ssl_ops = { + .open = line_open, .close = line_close, .write = line_write, .put_char = line_put_char, @@ -147,14 +102,10 @@ static struct tty_operations ssl_ops = { .flush_buffer = line_flush_buffer, .flush_chars = line_flush_chars, .set_termios = line_set_termios, - .ioctl = line_ioctl, -#if 0 - .throttle = ssl_throttle, - .unthrottle = ssl_unthrottle, - .stop = ssl_stop, - .start = ssl_start, - .hangup = ssl_hangup, -#endif + .throttle = line_throttle, + .unthrottle = line_unthrottle, + .install = ssl_install, + .hangup = line_hangup, }; /* Changed by ssl_init and referenced by ssl_exit, which are both serialized @@ -169,50 +120,64 @@ static void ssl_console_write(struct console *c, const char *string, unsigned long flags; spin_lock_irqsave(&line->lock, flags); - console_write_chan(&line->chan_list, string, len); + console_write_chan(line->chan_out, string, len); spin_unlock_irqrestore(&line->lock, flags); } static struct tty_driver *ssl_console_device(struct console *c, int *index) { *index = c->index; - return ssl_driver; + return driver.driver; } static int ssl_console_setup(struct console *co, char *options) { struct line *line = &serial_lines[co->index]; - return console_open_chan(line,co,&opts); + return console_open_chan(line, co); } +/* No locking for register_console call - relies on single-threaded initcalls */ static struct console ssl_cons = { .name = "ttyS", .write = ssl_console_write, .device = ssl_console_device, .setup = ssl_console_setup, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER|CON_ANYTIME, .index = -1, }; -int ssl_init(void) +static int ssl_init(void) { char *new_title; + int err; + int i; - printk(KERN_INFO "Initializing software serial port version %d\n", + printk(KERN_INFO "Initializing software serial port version %d\n", ssl_version); - ssl_driver = line_register_devfs(&lines, &driver, &ssl_ops, - serial_lines, ARRAY_SIZE(serial_lines)); - lines_init(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0])); + err = register_lines(&driver, &ssl_ops, serial_lines, + ARRAY_SIZE(serial_lines)); + if (err) + return err; new_title = add_xterm_umid(opts.xterm_title); if (new_title != NULL) opts.xterm_title = new_title; + for (i = 0; i < NR_PORTS; i++) { + char *error; + char *s = conf[i]; + if (!s) + s = def_conf; + if (setup_one_line(serial_lines, i, s, &opts, &error)) + printk(KERN_ERR "setup_one_line failed for " + "device %d : %s\n", i, error); + } + ssl_init_done = 1; register_console(&ssl_cons); - return(0); + return 0; } late_initcall(ssl_init); @@ -220,16 +185,14 @@ static void ssl_exit(void) { if (!ssl_init_done) return; - close_lines(serial_lines, - sizeof(serial_lines)/sizeof(serial_lines[0])); + close_lines(serial_lines, ARRAY_SIZE(serial_lines)); } __uml_exitcall(ssl_exit); static int ssl_chan_setup(char *str) { - return(line_setup(serial_lines, - sizeof(serial_lines)/sizeof(serial_lines[0]), - str, 1)); + line_setup(conf, NR_PORTS, &def_conf, str, "serial line"); + return 1; } __setup("ssl", ssl_chan_setup); diff --git a/arch/um/drivers/ssl.h b/arch/um/drivers/ssl.h index 98412aa6660..314d17725ce 100644 --- a/arch/um/drivers/ssl.h +++ b/arch/um/drivers/ssl.h @@ -11,13 +11,3 @@ extern void ssl_receive_char(int line, char ch); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/stderr_console.c b/arch/um/drivers/stderr_console.c index 429ae8e6c7e..d07a97f8b99 100644 --- a/arch/um/drivers/stderr_console.c +++ b/arch/um/drivers/stderr_console.c @@ -1,3 +1,4 @@ +#include <linux/kernel.h> #include <linux/init.h> #include <linux/console.h> @@ -7,11 +8,10 @@ /* trivial console driver -- simply dump everything to stderr */ /* - * Don't register by default -- as this registeres very early in the - * boot process it becomes the default console. And as this isn't a - * real tty driver init isn't able to open /dev/console then. + * Don't register by default -- as this registers very early in the + * boot process it becomes the default console. * - * In most cases this isn't what you want ... + * Initialized at init time. */ static int use_stderr_console = 0; @@ -43,3 +43,20 @@ static int stderr_setup(char *str) return 1; } __setup("stderr=", stderr_setup); + +/* The previous behavior of not unregistering led to /dev/console being + * impossible to open. My FC5 filesystem started having init die, and the + * system panicing because of this. Unregistering causes the real + * console to become the default console, and /dev/console can then be + * opened. Making this an initcall makes this happen late enough that + * there is no added value in dumping everything to stderr, and the + * normal console is good enough to show you all available output. + */ +static int __init unregister_stderr(void) +{ + unregister_console(&stderr_console); + + return 0; +} + +__initcall(unregister_stderr); diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 005aa6333b6..7b361f36ca9 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -3,64 +3,52 @@ * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/posix_types.h" -#include "linux/tty.h" -#include "linux/tty_flip.h" -#include "linux/types.h" -#include "linux/major.h" -#include "linux/kdev_t.h" -#include "linux/console.h" -#include "linux/string.h" -#include "linux/sched.h" -#include "linux/list.h" -#include "linux/init.h" -#include "linux/interrupt.h" -#include "linux/slab.h" -#include "linux/hardirq.h" -#include "asm/current.h" -#include "asm/irq.h" +#include <linux/posix_types.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/kdev_t.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/list.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/hardirq.h> +#include <asm/current.h> +#include <asm/irq.h> #include "stdio_console.h" -#include "line.h" -#include "chan_kern.h" -#include "user_util.h" -#include "kern_util.h" -#include "irq_user.h" +#include "chan.h" +#include <irq_user.h> #include "mconsole_kern.h" -#include "init.h" +#include <init.h> #define MAX_TTYS (16) -/* ----------------------------------------------------------------------------- */ - -/* Referenced only by tty_driver below - presumably it's locked correctly - * by the tty driver. - */ - -static struct tty_driver *console_driver; - -void stdio_announce(char *dev_name, int dev) +static void stdio_announce(char *dev_name, int dev) { printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev, dev_name); } +/* Almost const, except that xterm_title may be changed in an initcall */ static struct chan_opts opts = { .announce = stdio_announce, .xterm_title = "Virtual Console #%d", .raw = 1, - .tramp_stack = 0, - .in_kernel = 1, }; -static int con_config(char *str); +static int con_config(char *str, char **error_out); static int con_get_config(char *dev, char *str, int size, char **error_out); -static int con_remove(int n); +static int con_remove(int n, char **con_remove); + +/* Const, except for .mc.list */ static struct line_driver driver = { .name = "UML console", .device_name = "tty", - .devfs_name = "vc/", .major = TTY_MAJOR, .minor_start = 0, .type = TTY_DRIVER_TYPE_CONSOLE, @@ -69,116 +57,128 @@ static struct line_driver driver = { .read_irq_name = "console", .write_irq = CONSOLE_WRITE_IRQ, .write_irq_name = "console-write", - .symlink_from = "ttys", - .symlink_to = "vc", .mc = { + .list = LIST_HEAD_INIT(driver.mc.list), .name = "con", .config = con_config, .get_config = con_get_config, - .id = line_id, + .id = line_id, .remove = con_remove, }, }; -static struct lines console_lines = LINES_INIT(MAX_TTYS); - -/* The array is initialized by line_init, which is an initcall. The - * individual elements are protected by individual semaphores. +/* The array is initialized by line_init, at initcall time. The + * elements are locked individually as needed. */ -struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), - [ 1 ... MAX_TTYS - 1 ] = - LINE_INIT(CONFIG_CON_CHAN, &driver) }; +static char *vt_conf[MAX_TTYS]; +static char *def_conf; +static struct line vts[MAX_TTYS]; -static int con_config(char *str) +static int con_config(char *str, char **error_out) { - return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str)); + return line_config(vts, ARRAY_SIZE(vts), str, &opts, error_out); } static int con_get_config(char *dev, char *str, int size, char **error_out) { - return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str, - size, error_out)); + return line_get_config(dev, vts, ARRAY_SIZE(vts), str, size, error_out); } -static int con_remove(int n) +static int con_remove(int n, char **error_out) { - return line_remove(vts, sizeof(vts)/sizeof(vts[0]), n); + return line_remove(vts, ARRAY_SIZE(vts), n, error_out); } -static int con_open(struct tty_struct *tty, struct file *filp) +/* Set in an initcall, checked in an exitcall */ +static int con_init_done = 0; + +static int con_install(struct tty_driver *driver, struct tty_struct *tty) { - return line_open(vts, tty, &opts); + return line_install(driver, tty, &vts[tty->index]); } -static int con_init_done = 0; - -static struct tty_operations console_ops = { - .open = con_open, +static const struct tty_operations console_ops = { + .open = line_open, + .install = con_install, .close = line_close, .write = line_write, .put_char = line_put_char, - .write_room = line_write_room, + .write_room = line_write_room, .chars_in_buffer = line_chars_in_buffer, .flush_buffer = line_flush_buffer, .flush_chars = line_flush_chars, .set_termios = line_set_termios, - .ioctl = line_ioctl, + .throttle = line_throttle, + .unthrottle = line_unthrottle, + .hangup = line_hangup, }; static void uml_console_write(struct console *console, const char *string, - unsigned len) + unsigned len) { struct line *line = &vts[console->index]; unsigned long flags; spin_lock_irqsave(&line->lock, flags); - console_write_chan(&line->chan_list, string, len); + console_write_chan(line->chan_out, string, len); spin_unlock_irqrestore(&line->lock, flags); } static struct tty_driver *uml_console_device(struct console *c, int *index) { *index = c->index; - return console_driver; + return driver.driver; } static int uml_console_setup(struct console *co, char *options) { struct line *line = &vts[co->index]; - return console_open_chan(line,co,&opts); + return console_open_chan(line, co); } +/* No locking for register_console call - relies on single-threaded initcalls */ static struct console stdiocons = { .name = "tty", .write = uml_console_write, .device = uml_console_device, .setup = uml_console_setup, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER|CON_ANYTIME, .index = -1, - .data = &vts, }; -int stdio_init(void) +static int stdio_init(void) { char *new_title; + int err; + int i; - console_driver = line_register_devfs(&console_lines, &driver, - &console_ops, vts, - ARRAY_SIZE(vts)); - if (NULL == console_driver) - return -1; - printk(KERN_INFO "Initialized stdio console driver\n"); + err = register_lines(&driver, &console_ops, vts, + ARRAY_SIZE(vts)); + if (err) + return err; - lines_init(vts, sizeof(vts)/sizeof(vts[0])); + printk(KERN_INFO "Initialized stdio console driver\n"); new_title = add_xterm_umid(opts.xterm_title); if(new_title != NULL) opts.xterm_title = new_title; + for (i = 0; i < MAX_TTYS; i++) { + char *error; + char *s = vt_conf[i]; + if (!s) + s = def_conf; + if (!s) + s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN; + if (setup_one_line(vts, i, s, &opts, &error)) + printk(KERN_ERR "setup_one_line failed for " + "device %d : %s\n", i, error); + } + con_init_done = 1; register_console(&stdiocons); - return(0); + return 0; } late_initcall(stdio_init); @@ -186,13 +186,14 @@ static void console_exit(void) { if (!con_init_done) return; - close_lines(vts, sizeof(vts)/sizeof(vts[0])); + close_lines(vts, ARRAY_SIZE(vts)); } __uml_exitcall(console_exit); static int console_chan_setup(char *str) { - return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1)); + line_setup(vt_conf, MAX_TTYS, &def_conf, str, "console"); + return 1; } __setup("con", console_chan_setup); __channel_help(console_chan_setup, "con"); diff --git a/arch/um/drivers/stdio_console.h b/arch/um/drivers/stdio_console.h index 505a3d5bea5..6d8275f71fd 100644 --- a/arch/um/drivers/stdio_console.h +++ b/arch/um/drivers/stdio_console.h @@ -9,13 +9,3 @@ extern void save_console_flags(void); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c index 6fbb670ee27..eaa201bca5e 100644 --- a/arch/um/drivers/tty.c +++ b/arch/um/drivers/tty.c @@ -1,16 +1,14 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) * Licensed under the GPL */ -#include <stdio.h> -#include <termios.h> #include <errno.h> -#include <unistd.h> +#include <fcntl.h> +#include <termios.h> #include "chan_user.h" -#include "user_util.h" -#include "user.h" -#include "os.h" +#include <os.h> +#include <um_malloc.h> struct tty_chan { char *dev; @@ -18,75 +16,66 @@ struct tty_chan { struct termios tt; }; -static void *tty_chan_init(char *str, int device, struct chan_opts *opts) +static void *tty_chan_init(char *str, int device, const struct chan_opts *opts) { struct tty_chan *data; - if(*str != ':'){ - printk("tty_init : channel type 'tty' must specify " + if (*str != ':') { + printk(UM_KERN_ERR "tty_init : channel type 'tty' must specify " "a device\n"); - return(NULL); + return NULL; } str++; - data = um_kmalloc(sizeof(*data)); - if(data == NULL) - return(NULL); + data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); + if (data == NULL) + return NULL; *data = ((struct tty_chan) { .dev = str, .raw = opts->raw }); - - return(data); + + return data; } static int tty_open(int input, int output, int primary, void *d, char **dev_out) { struct tty_chan *data = d; - int fd, err; + int fd, err, mode = 0; - fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0); - if(fd < 0) return(fd); - if(data->raw){ + if (input && output) + mode = O_RDWR; + else if (input) + mode = O_RDONLY; + else if (output) + mode = O_WRONLY; + + fd = open(data->dev, mode); + if (fd < 0) + return -errno; + + if (data->raw) { CATCH_EINTR(err = tcgetattr(fd, &data->tt)); - if(err) - return(err); + if (err) + return err; err = raw(fd); - if(err) - return(err); + if (err) + return err; } *dev_out = data->dev; - return(fd); -} - -static int tty_console_write(int fd, const char *buf, int n, void *d) -{ - struct tty_chan *data = d; - - return(generic_console_write(fd, buf, n, &data->tt)); + return fd; } -struct chan_ops tty_ops = { +const struct chan_ops tty_ops = { .type = "tty", .init = tty_chan_init, .open = tty_open, .close = generic_close, .read = generic_read, .write = generic_write, - .console_write = tty_console_write, + .console_write = generic_console_write, .window_size = generic_window_size, .free = generic_free, .winch = 0, }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/ubd.h b/arch/um/drivers/ubd.h new file mode 100644 index 00000000000..3b48cd2081e --- /dev/null +++ b/arch/um/drivers/ubd.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com) + * Licensed under the GPL + */ + +#ifndef __UM_UBD_USER_H +#define __UM_UBD_USER_H + +extern int start_io_thread(unsigned long sp, int *fds_out); +extern int io_thread(void *arg); +extern int kernel_fd; + +#endif + diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index b2c86257b0f..3716e695255 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -17,47 +17,34 @@ * James McMechan */ -#define MAJOR_NR UBD_MAJOR #define UBD_SHIFT 4 -#include "linux/config.h" -#include "linux/module.h" -#include "linux/blkdev.h" -#include "linux/hdreg.h" -#include "linux/init.h" -#include "linux/devfs_fs_kernel.h" -#include "linux/cdrom.h" -#include "linux/proc_fs.h" -#include "linux/ctype.h" -#include "linux/capability.h" -#include "linux/mm.h" -#include "linux/vmalloc.h" -#include "linux/blkpg.h" -#include "linux/genhd.h" -#include "linux/spinlock.h" -#include "linux/platform_device.h" -#include "asm/segment.h" -#include "asm/uaccess.h" -#include "asm/irq.h" -#include "asm/types.h" -#include "asm/tlbflush.h" -#include "user_util.h" -#include "mem_user.h" -#include "kern_util.h" -#include "kern.h" +#include <linux/module.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <linux/ata.h> +#include <linux/hdreg.h> +#include <linux/cdrom.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/ctype.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/platform_device.h> +#include <linux/scatterlist.h> +#include <asm/tlbflush.h> +#include <kern_util.h> #include "mconsole_kern.h" -#include "init.h" -#include "irq_user.h" -#include "irq_kern.h" -#include "ubd_user.h" -#include "os.h" -#include "mem.h" -#include "mem_kern.h" +#include <init.h> +#include <irq_kern.h> +#include "ubd.h" +#include <os.h> #include "cow.h" -enum ubd_req { UBD_READ, UBD_WRITE }; +enum ubd_req { UBD_READ, UBD_WRITE, UBD_FLUSH }; struct io_thread_req { + struct request *req; enum ubd_req op; int fds[2]; unsigned long offsets[2]; @@ -71,18 +58,6 @@ struct io_thread_req { int error; }; -extern int open_ubd_file(char *file, struct openflags *openflags, - char **backing_file_out, int *bitmap_offset_out, - unsigned long *bitmap_len_out, int *data_offset_out, - int *create_cow_out); -extern int create_cow_file(char *cow_file, char *backing_file, - struct openflags flags, int sectorsize, - int alignment, int *bitmap_offset_out, - unsigned long *bitmap_len_out, - int *data_offset_out); -extern int read_cow_bitmap(int fd, void *buf, int offset, int len); -extern void do_io(struct io_thread_req *req); - static inline int ubd_test_bit(__u64 bit, unsigned char *data) { __u64 n; @@ -91,7 +66,7 @@ static inline int ubd_test_bit(__u64 bit, unsigned char *data) bits = sizeof(data[0]) * 8; n = bit / bits; off = bit % bits; - return((data[n] & (1 << off)) != 0); + return (data[n] & (1 << off)) != 0; } static inline void ubd_set_bit(__u64 bit, unsigned char *data) @@ -108,34 +83,30 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data) #define DRIVER_NAME "uml-blkdev" -static DEFINE_SPINLOCK(ubd_io_lock); -static DEFINE_SPINLOCK(ubd_lock); - -static void (*do_ubd)(void); +static DEFINE_MUTEX(ubd_lock); +static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */ -static int ubd_open(struct inode * inode, struct file * filp); -static int ubd_release(struct inode * inode, struct file * file); -static int ubd_ioctl(struct inode * inode, struct file * file, +static int ubd_open(struct block_device *bdev, fmode_t mode); +static void ubd_release(struct gendisk *disk, fmode_t mode); +static int ubd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg); +static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo); -#define MAX_DEV (8) +#define MAX_DEV (16) -static struct block_device_operations ubd_blops = { +static const struct block_device_operations ubd_blops = { .owner = THIS_MODULE, .open = ubd_open, .release = ubd_release, .ioctl = ubd_ioctl, + .getgeo = ubd_getgeo, }; -/* Protected by the queue_lock */ -static request_queue_t *ubd_queue; - /* Protected by ubd_lock */ -static int fake_major = MAJOR_NR; - +static int fake_major = UBD_MAJOR; static struct gendisk *ubd_gendisk[MAX_DEV]; static struct gendisk *fake_gendisk[MAX_DEV]; - + #ifdef CONFIG_BLK_DEV_UBD_SYNC #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \ .cl = 1 }) @@ -143,40 +114,49 @@ static struct gendisk *fake_gendisk[MAX_DEV]; #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \ .cl = 1 }) #endif - -/* Not protected - changed only in ubd_setup_common and then only to - * to enable O_SYNC. - */ static struct openflags global_openflags = OPEN_FLAGS; struct cow { - /* This is the backing file, actually */ + /* backing file name */ char *file; + /* backing file fd */ int fd; unsigned long *bitmap; unsigned long bitmap_len; int bitmap_offset; - int data_offset; + int data_offset; }; +#define MAX_SG 64 + struct ubd { + struct list_head restart; + /* name (and fd, below) of the file opened for writing, either the + * backing or the cow file. */ char *file; int count; int fd; __u64 size; struct openflags boot_openflags; struct openflags openflags; - int no_cow; + unsigned shared:1; + unsigned no_cow:1; struct cow cow; struct platform_device pdev; + struct request_queue *queue; + spinlock_t lock; + struct scatterlist sg[MAX_SG]; + struct request *request; + int start_sg, end_sg; + sector_t rq_pos; }; #define DEFAULT_COW { \ .file = NULL, \ - .fd = -1, \ - .bitmap = NULL, \ + .fd = -1, \ + .bitmap = NULL, \ .bitmap_offset = 0, \ - .data_offset = 0, \ + .data_offset = 0, \ } #define DEFAULT_UBD { \ @@ -186,22 +166,18 @@ struct ubd { .size = -1, \ .boot_openflags = OPEN_FLAGS, \ .openflags = OPEN_FLAGS, \ - .no_cow = 0, \ - .cow = DEFAULT_COW, \ + .no_cow = 0, \ + .shared = 0, \ + .cow = DEFAULT_COW, \ + .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \ + .request = NULL, \ + .start_sg = 0, \ + .end_sg = 0, \ + .rq_pos = 0, \ } -struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; - -static int ubd0_init(void) -{ - struct ubd *dev = &ubd_dev[0]; - - if(dev->file == NULL) - dev->file = "root_fs"; - return(0); -} - -__initcall(ubd0_init); +/* Protected by ubd_lock */ +static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD }; /* Only changed by fake_ide_setup which is a setup */ static int fake_ide = 0; @@ -214,24 +190,26 @@ static void make_proc_ide(void) proc_ide = proc_mkdir("ide0", proc_ide_root); } -static int proc_ide_read_media(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int fake_ide_media_proc_show(struct seq_file *m, void *v) { - int len; - - strcpy(page, "disk\n"); - len = strlen("disk\n"); - len -= off; - if (len < count){ - *eof = 1; - if (len <= 0) return 0; - } - else len = count; - *start = page + off; - return len; + seq_puts(m, "disk\n"); + return 0; +} + +static int fake_ide_media_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, fake_ide_media_proc_show, NULL); } -static void make_ide_entries(char *dev_name) +static const struct file_operations fake_ide_media_proc_fops = { + .owner = THIS_MODULE, + .open = fake_ide_media_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void make_ide_entries(const char *dev_name) { struct proc_dir_entry *dir, *ent; char name[64]; @@ -241,20 +219,16 @@ static void make_ide_entries(char *dev_name) dir = proc_mkdir(dev_name, proc_ide); if(!dir) return; - ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir); + ent = proc_create("media", S_IRUGO, dir, &fake_ide_media_proc_fops); if(!ent) return; - ent->nlink = 1; - ent->data = NULL; - ent->read_proc = proc_ide_read_media; - ent->write_proc = NULL; - sprintf(name,"ide0/%s", dev_name); + snprintf(name, sizeof(name), "ide0/%s", dev_name); proc_symlink(dev_name, proc_ide_root, name); } static int fake_ide_setup(char *str) { fake_ide = 1; - return(1); + return 1; } __setup("fake_ide", fake_ide_setup); @@ -272,23 +246,27 @@ static int parse_unit(char **ptr) if(isdigit(*str)) { n = simple_strtoul(str, &end, 0); if(end == str) - return(-1); + return -1; *ptr = end; } - else if (('a' <= *str) && (*str <= 'h')) { + else if (('a' <= *str) && (*str <= 'z')) { n = *str - 'a'; str++; *ptr = str; } - return(n); + return n; } -static int ubd_setup_common(char *str, int *index_out) +/* If *index_out == -1 at exit, the passed option was a general one; + * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it + * should not be freed on exit. + */ +static int ubd_setup_common(char *str, int *index_out, char **error_out) { - struct ubd *dev; + struct ubd *ubd_dev; struct openflags flags = global_openflags; char *backing_file; - int n, err, i; + int n, err = 0, i; if(index_out) *index_out = -1; n = *str; @@ -299,57 +277,56 @@ static int ubd_setup_common(char *str, int *index_out) str++; if(!strcmp(str, "sync")){ global_openflags = of_sync(global_openflags); - return(0); + goto out1; } + + err = -EINVAL; major = simple_strtoul(str, &end, 0); if((*end != '\0') || (end == str)){ - printk(KERN_ERR - "ubd_setup : didn't parse major number\n"); - return(1); + *error_out = "Didn't parse major number"; + goto out1; } - err = 1; - spin_lock(&ubd_lock); - if(fake_major != MAJOR_NR){ - printk(KERN_ERR "Can't assign a fake major twice\n"); - goto out1; - } - - fake_major = major; + mutex_lock(&ubd_lock); + if (fake_major != UBD_MAJOR) { + *error_out = "Can't assign a fake major twice"; + goto out1; + } + + fake_major = major; printk(KERN_INFO "Setting extra ubd major number to %d\n", major); - err = 0; - out1: - spin_unlock(&ubd_lock); - return(err); + err = 0; + out1: + mutex_unlock(&ubd_lock); + return err; } n = parse_unit(&str); if(n < 0){ - printk(KERN_ERR "ubd_setup : couldn't parse unit number " - "'%s'\n", str); - return(1); + *error_out = "Couldn't parse device number"; + return -EINVAL; } if(n >= MAX_DEV){ - printk(KERN_ERR "ubd_setup : index %d out of range " - "(%d devices, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1); - return(1); + *error_out = "Device number out of range"; + return 1; } - err = 1; - spin_lock(&ubd_lock); + err = -EBUSY; + mutex_lock(&ubd_lock); - dev = &ubd_dev[n]; - if(dev->file != NULL){ - printk(KERN_ERR "ubd_setup : device already configured\n"); + ubd_dev = &ubd_devs[n]; + if(ubd_dev->file != NULL){ + *error_out = "Device is already configured"; goto out; } if (index_out) *index_out = n; - for (i = 0; i < 4; i++) { + err = -EINVAL; + for (i = 0; i < sizeof("rscd="); i++) { switch (*str) { case 'r': flags.w = 0; @@ -358,53 +335,63 @@ static int ubd_setup_common(char *str, int *index_out) flags.s = 1; break; case 'd': - dev->no_cow = 1; + ubd_dev->no_cow = 1; + break; + case 'c': + ubd_dev->shared = 1; break; case '=': str++; goto break_loop; default: - printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r,s or d)\n"); + *error_out = "Expected '=' or flag letter " + "(r, s, c, or d)"; goto out; } str++; } - if (*str == '=') - printk(KERN_ERR "ubd_setup : Too many flags specified\n"); - else - printk(KERN_ERR "ubd_setup : Expected '='\n"); + if (*str == '=') + *error_out = "Too many flags specified"; + else + *error_out = "Missing '='"; goto out; break_loop: - err = 0; backing_file = strchr(str, ','); - if (!backing_file) { + if (backing_file == NULL) backing_file = strchr(str, ':'); - } - if(backing_file){ - if(dev->no_cow) - printk(KERN_ERR "Can't specify both 'd' and a " - "cow file\n"); + if(backing_file != NULL){ + if(ubd_dev->no_cow){ + *error_out = "Can't specify both 'd' and a cow file"; + goto out; + } else { *backing_file = '\0'; backing_file++; } } - dev->file = str; - dev->cow.file = backing_file; - dev->boot_openflags = flags; + err = 0; + ubd_dev->file = str; + ubd_dev->cow.file = backing_file; + ubd_dev->boot_openflags = flags; out: - spin_unlock(&ubd_lock); - return(err); + mutex_unlock(&ubd_lock); + return err; } static int ubd_setup(char *str) { - ubd_setup_common(str, NULL); - return(1); + char *error; + int err; + + err = ubd_setup_common(str, NULL, &error); + if(err) + printk(KERN_ERR "Failed to initialize device with \"%s\" : " + "%s\n", str, error); + return 1; } __setup("ubd", ubd_setup); @@ -416,7 +403,7 @@ __uml_help(ubd_setup, " use either a ':' or a ',': the first one allows writing things like;\n" " ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n" " while with a ',' the shell would not expand the 2nd '~'.\n" -" When using only one filename, UML will detect whether to thread it like\n" +" When using only one filename, UML will detect whether to treat it like\n" " a COW file or a backing file. To override this detection, add the 'd'\n" " flag:\n" " ubd0d=BackingFile\n" @@ -427,14 +414,17 @@ __uml_help(ubd_setup, " machine by running 'dd' on the device. <n> must be in the range\n" " 0 to 7. Appending an 'r' to the number will cause that device\n" " to be mounted read-only. For example ubd1r=./ext_fs. Appending\n" -" an 's' will cause data to be written to disk on the host immediately.\n\n" +" an 's' will cause data to be written to disk on the host immediately.\n" +" 'c' will cause the device to be treated as being shared between multiple\n" +" UMLs and file locking will be turned off - this is appropriate for a\n" +" cluster filesystem and inappropriate at almost all other times.\n\n" ); static int udb_setup(char *str) { printk("udb%s specified on command line is almost certainly a ubd -> " "udb TYPO\n", str); - return(1); + return 1; } __setup("udb", udb_setup); @@ -446,216 +436,402 @@ __uml_help(udb_setup, " in the boot output.\n\n" ); -static int fakehd_set = 0; -static int fakehd(char *str) +static void do_ubd_request(struct request_queue * q); + +/* Only changed by ubd_init, which is an initcall. */ +static int thread_fd = -1; +static LIST_HEAD(restart); + +/* XXX - move this inside ubd_intr. */ +/* Called without dev->lock held, and only in interrupt context. */ +static void ubd_handler(void) { - printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n"); - fakehd_set = 1; - return 1; -} + struct io_thread_req *req; + struct ubd *ubd; + struct list_head *list, *next_ele; + unsigned long flags; + int n; -__setup("fakehd", fakehd); -__uml_help(fakehd, -"fakehd\n" -" Change the ubd device name to \"hd\".\n\n" -); + while(1){ + n = os_read_file(thread_fd, &req, + sizeof(struct io_thread_req *)); + if(n != sizeof(req)){ + if(n == -EAGAIN) + break; + printk(KERN_ERR "spurious interrupt in ubd_handler, " + "err = %d\n", -n); + return; + } -static void do_ubd_request(request_queue_t * q); + blk_end_request(req->req, 0, req->length); + kfree(req); + } + reactivate_fd(thread_fd, UBD_IRQ); + + list_for_each_safe(list, next_ele, &restart){ + ubd = container_of(list, struct ubd, restart); + list_del_init(&ubd->restart); + spin_lock_irqsave(&ubd->lock, flags); + do_ubd_request(ubd->queue); + spin_unlock_irqrestore(&ubd->lock, flags); + } +} + +static irqreturn_t ubd_intr(int irq, void *dev) +{ + ubd_handler(); + return IRQ_HANDLED; +} /* Only changed by ubd_init, which is an initcall. */ -int thread_fd = -1; +static int io_pid = -1; -/* Changed by ubd_handler, which is serialized because interrupts only - * happen on CPU 0. - */ -int intr_count = 0; +static void kill_io_thread(void) +{ + if(io_pid != -1) + os_kill_process(io_pid, 1); +} + +__uml_exitcall(kill_io_thread); -/* call ubd_finish if you need to serialize */ -static void __ubd_finish(struct request *req, int error) +static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out) { - int nsect; + char *file; + int fd; + int err; - if(error){ - end_request(req, 0); - return; + __u32 version; + __u32 align; + char *backing_file; + time_t mtime; + unsigned long long size; + int sector_size; + int bitmap_offset; + + if (ubd_dev->file && ubd_dev->cow.file) { + file = ubd_dev->cow.file; + + goto out; } - nsect = req->current_nr_sectors; - req->sector += nsect; - req->buffer += nsect << 9; - req->errors = 0; - req->nr_sectors -= nsect; - req->current_nr_sectors = 0; - end_request(req, 1); + + fd = os_open_file(ubd_dev->file, of_read(OPENFLAGS()), 0); + if (fd < 0) + return fd; + + err = read_cow_header(file_reader, &fd, &version, &backing_file, \ + &mtime, &size, §or_size, &align, &bitmap_offset); + os_close_file(fd); + + if(err == -EINVAL) + file = ubd_dev->file; + else + file = backing_file; + +out: + return os_file_size(file, size_out); } -static inline void ubd_finish(struct request *req, int error) +static int read_cow_bitmap(int fd, void *buf, int offset, int len) { - spin_lock(&ubd_io_lock); - __ubd_finish(req, error); - spin_unlock(&ubd_io_lock); + int err; + + err = os_seek_file(fd, offset); + if (err < 0) + return err; + + err = os_read_file(fd, buf, len); + if (err < 0) + return err; + + return 0; } -/* Called without ubd_io_lock held */ -static void ubd_handler(void) +static int backing_file_mismatch(char *file, __u64 size, time_t mtime) { - struct io_thread_req req; - struct request *rq = elv_next_request(ubd_queue); - int n; + unsigned long modtime; + unsigned long long actual; + int err; - do_ubd = NULL; - intr_count++; - n = os_read_file(thread_fd, &req, sizeof(req)); - if(n != sizeof(req)){ - printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " - "err = %d\n", os_getpid(), -n); - spin_lock(&ubd_io_lock); - end_request(rq, 0); - spin_unlock(&ubd_io_lock); - return; + err = os_file_modtime(file, &modtime); + if (err < 0) { + printk(KERN_ERR "Failed to get modification time of backing " + "file \"%s\", err = %d\n", file, -err); + return err; } - - ubd_finish(rq, req.error); - reactivate_fd(thread_fd, UBD_IRQ); - do_ubd_request(ubd_queue); + + err = os_file_size(file, &actual); + if (err < 0) { + printk(KERN_ERR "Failed to get size of backing file \"%s\", " + "err = %d\n", file, -err); + return err; + } + + if (actual != size) { + /*__u64 can be a long on AMD64 and with %lu GCC complains; so + * the typecast.*/ + printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header " + "vs backing file\n", (unsigned long long) size, actual); + return -EINVAL; + } + if (modtime != mtime) { + printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs " + "backing file\n", mtime, modtime); + return -EINVAL; + } + return 0; } -static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) +static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow) { - ubd_handler(); - return(IRQ_HANDLED); -} + struct uml_stat buf1, buf2; + int err; -/* Only changed by ubd_init, which is an initcall. */ -static int io_pid = -1; + if (from_cmdline == NULL) + return 0; + if (!strcmp(from_cmdline, from_cow)) + return 0; -void kill_io_thread(void) -{ - if(io_pid != -1) - os_kill_process(io_pid, 1); + err = os_stat_file(from_cmdline, &buf1); + if (err < 0) { + printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline, + -err); + return 0; + } + err = os_stat_file(from_cow, &buf2); + if (err < 0) { + printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow, + -err); + return 1; + } + if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) + return 0; + + printk(KERN_ERR "Backing file mismatch - \"%s\" requested, " + "\"%s\" specified in COW header of \"%s\"\n", + from_cmdline, from_cow, cow); + return 1; } -__uml_exitcall(kill_io_thread); +static int open_ubd_file(char *file, struct openflags *openflags, int shared, + char **backing_file_out, int *bitmap_offset_out, + unsigned long *bitmap_len_out, int *data_offset_out, + int *create_cow_out) +{ + time_t mtime; + unsigned long long size; + __u32 version, align; + char *backing_file; + int fd, err, sectorsize, asked_switch, mode = 0644; + + fd = os_open_file(file, *openflags, mode); + if (fd < 0) { + if ((fd == -ENOENT) && (create_cow_out != NULL)) + *create_cow_out = 1; + if (!openflags->w || + ((fd != -EROFS) && (fd != -EACCES))) + return fd; + openflags->w = 0; + fd = os_open_file(file, *openflags, mode); + if (fd < 0) + return fd; + } + + if (shared) + printk(KERN_INFO "Not locking \"%s\" on the host\n", file); + else { + err = os_lock_file(fd, openflags->w); + if (err < 0) { + printk(KERN_ERR "Failed to lock '%s', err = %d\n", + file, -err); + goto out_close; + } + } + + /* Successful return case! */ + if (backing_file_out == NULL) + return fd; + + err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, + &size, §orsize, &align, bitmap_offset_out); + if (err && (*backing_file_out != NULL)) { + printk(KERN_ERR "Failed to read COW header from COW file " + "\"%s\", errno = %d\n", file, -err); + goto out_close; + } + if (err) + return fd; -static int ubd_file_size(struct ubd *dev, __u64 *size_out) + asked_switch = path_requires_switch(*backing_file_out, backing_file, + file); + + /* Allow switching only if no mismatch. */ + if (asked_switch && !backing_file_mismatch(*backing_file_out, size, + mtime)) { + printk(KERN_ERR "Switching backing file to '%s'\n", + *backing_file_out); + err = write_cow_header(file, fd, *backing_file_out, + sectorsize, align, &size); + if (err) { + printk(KERN_ERR "Switch failed, errno = %d\n", -err); + goto out_close; + } + } else { + *backing_file_out = backing_file; + err = backing_file_mismatch(*backing_file_out, size, mtime); + if (err) + goto out_close; + } + + cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, + bitmap_len_out, data_offset_out); + + return fd; + out_close: + os_close_file(fd); + return err; +} + +static int create_cow_file(char *cow_file, char *backing_file, + struct openflags flags, + int sectorsize, int alignment, int *bitmap_offset_out, + unsigned long *bitmap_len_out, int *data_offset_out) { - char *file; + int err, fd; + + flags.c = 1; + fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL); + if (fd < 0) { + err = fd; + printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n", + cow_file, -err); + goto out; + } - file = dev->cow.file ? dev->cow.file : dev->file; - return(os_file_size(file, size_out)); + err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, + bitmap_offset_out, bitmap_len_out, + data_offset_out); + if (!err) + return fd; + os_close_file(fd); + out: + return err; } -static void ubd_close(struct ubd *dev) +static void ubd_close_dev(struct ubd *ubd_dev) { - os_close_file(dev->fd); - if(dev->cow.file == NULL) + os_close_file(ubd_dev->fd); + if(ubd_dev->cow.file == NULL) return; - os_close_file(dev->cow.fd); - vfree(dev->cow.bitmap); - dev->cow.bitmap = NULL; + os_close_file(ubd_dev->cow.fd); + vfree(ubd_dev->cow.bitmap); + ubd_dev->cow.bitmap = NULL; } -static int ubd_open_dev(struct ubd *dev) +static int ubd_open_dev(struct ubd *ubd_dev) { struct openflags flags; char **back_ptr; int err, create_cow, *create_ptr; + int fd; - dev->openflags = dev->boot_openflags; + ubd_dev->openflags = ubd_dev->boot_openflags; create_cow = 0; - create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; - back_ptr = dev->no_cow ? NULL : &dev->cow.file; - dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr, - &dev->cow.bitmap_offset, &dev->cow.bitmap_len, - &dev->cow.data_offset, create_ptr); - - if((dev->fd == -ENOENT) && create_cow){ - dev->fd = create_cow_file(dev->file, dev->cow.file, - dev->openflags, 1 << 9, PAGE_SIZE, - &dev->cow.bitmap_offset, - &dev->cow.bitmap_len, - &dev->cow.data_offset); - if(dev->fd >= 0){ + create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL; + back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file; + + fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared, + back_ptr, &ubd_dev->cow.bitmap_offset, + &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset, + create_ptr); + + if((fd == -ENOENT) && create_cow){ + fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file, + ubd_dev->openflags, 1 << 9, PAGE_SIZE, + &ubd_dev->cow.bitmap_offset, + &ubd_dev->cow.bitmap_len, + &ubd_dev->cow.data_offset); + if(fd >= 0){ printk(KERN_INFO "Creating \"%s\" as COW file for " - "\"%s\"\n", dev->file, dev->cow.file); + "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file); } } - if(dev->fd < 0){ - printk("Failed to open '%s', errno = %d\n", dev->file, - -dev->fd); - return(dev->fd); + if(fd < 0){ + printk("Failed to open '%s', errno = %d\n", ubd_dev->file, + -fd); + return fd; } + ubd_dev->fd = fd; + + if(ubd_dev->cow.file != NULL){ + blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long)); - if(dev->cow.file != NULL){ err = -ENOMEM; - dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len); - if(dev->cow.bitmap == NULL){ + ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len); + if(ubd_dev->cow.bitmap == NULL){ printk(KERN_ERR "Failed to vmalloc COW bitmap\n"); goto error; } flush_tlb_kernel_vm(); - err = read_cow_bitmap(dev->fd, dev->cow.bitmap, - dev->cow.bitmap_offset, - dev->cow.bitmap_len); + err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap, + ubd_dev->cow.bitmap_offset, + ubd_dev->cow.bitmap_len); if(err < 0) goto error; - flags = dev->openflags; + flags = ubd_dev->openflags; flags.w = 0; - err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, - NULL, NULL); + err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL, + NULL, NULL, NULL, NULL); if(err < 0) goto error; - dev->cow.fd = err; + ubd_dev->cow.fd = err; } - return(0); + return 0; error: - os_close_file(dev->fd); - return(err); + os_close_file(ubd_dev->fd); + return err; +} + +static void ubd_device_release(struct device *dev) +{ + struct ubd *ubd_dev = dev_get_drvdata(dev); + + blk_cleanup_queue(ubd_dev->queue); + *ubd_dev = ((struct ubd) DEFAULT_UBD); } -static int ubd_new_disk(int major, u64 size, int unit, - struct gendisk **disk_out) - +static int ubd_disk_register(int major, u64 size, int unit, + struct gendisk **disk_out) { struct gendisk *disk; - char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")]; - int err; disk = alloc_disk(1 << UBD_SHIFT); if(disk == NULL) - return(-ENOMEM); + return -ENOMEM; disk->major = major; disk->first_minor = unit << UBD_SHIFT; disk->fops = &ubd_blops; set_capacity(disk, size / 512); - if(major == MAJOR_NR){ + if (major == UBD_MAJOR) sprintf(disk->disk_name, "ubd%c", 'a' + unit); - sprintf(disk->devfs_name, "ubd/disc%d", unit); - sprintf(from, "ubd/%d", unit); - sprintf(to, "disc%d/disc", unit); - err = devfs_mk_symlink(from, to); - if(err) - printk("ubd_new_disk failed to make link from %s to " - "%s, error = %d\n", from, to, err); - } - else { + else sprintf(disk->disk_name, "ubd_fake%d", unit); - sprintf(disk->devfs_name, "ubd_fake/disc%d", unit); - } /* sysfs register (not for ide fake devices) */ - if (major == MAJOR_NR) { - ubd_dev[unit].pdev.id = unit; - ubd_dev[unit].pdev.name = DRIVER_NAME; - platform_device_register(&ubd_dev[unit].pdev); - disk->driverfs_dev = &ubd_dev[unit].pdev.dev; + if (major == UBD_MAJOR) { + ubd_devs[unit].pdev.id = unit; + ubd_devs[unit].pdev.name = DRIVER_NAME; + ubd_devs[unit].pdev.dev.release = ubd_device_release; + dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]); + platform_device_register(&ubd_devs[unit].pdev); + disk->driverfs_dev = &ubd_devs[unit].pdev.dev; } - disk->private_data = &ubd_dev[unit]; - disk->queue = ubd_queue; + disk->private_data = &ubd_devs[unit]; + disk->queue = ubd_devs[unit].queue; add_disk(disk); *disk_out = disk; @@ -664,134 +840,163 @@ static int ubd_new_disk(int major, u64 size, int unit, #define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9)) -static int ubd_add(int n) +static int ubd_add(int n, char **error_out) { - struct ubd *dev = &ubd_dev[n]; - int err; + struct ubd *ubd_dev = &ubd_devs[n]; + int err = 0; - err = -ENODEV; - if(dev->file == NULL) + if(ubd_dev->file == NULL) goto out; - if (ubd_open_dev(dev)) + err = ubd_file_size(ubd_dev, &ubd_dev->size); + if(err < 0){ + *error_out = "Couldn't determine size of device's file"; goto out; + } - err = ubd_file_size(dev, &dev->size); - if(err < 0) - goto out_close; + ubd_dev->size = ROUND_BLOCK(ubd_dev->size); - dev->size = ROUND_BLOCK(dev->size); + INIT_LIST_HEAD(&ubd_dev->restart); + sg_init_table(ubd_dev->sg, MAX_SG); - err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); - if(err) - goto out_close; - - if(fake_major != MAJOR_NR) - ubd_new_disk(fake_major, dev->size, n, - &fake_gendisk[n]); + err = -ENOMEM; + ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock); + if (ubd_dev->queue == NULL) { + *error_out = "Failed to initialize device queue"; + goto out; + } + ubd_dev->queue->queuedata = ubd_dev; + blk_queue_flush(ubd_dev->queue, REQ_FLUSH); - /* perhaps this should also be under the "if (fake_major)" above */ - /* using the fake_disk->disk_name and also the fakehd_set name */ + blk_queue_max_segments(ubd_dev->queue, MAX_SG); + err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]); + if(err){ + *error_out = "Failed to register device"; + goto out_cleanup; + } + + if (fake_major != UBD_MAJOR) + ubd_disk_register(fake_major, ubd_dev->size, n, + &fake_gendisk[n]); + + /* + * Perhaps this should also be under the "if (fake_major)" above + * using the fake_disk->disk_name + */ if (fake_ide) make_ide_entries(ubd_gendisk[n]->disk_name); err = 0; -out_close: - ubd_close(dev); out: return err; + +out_cleanup: + blk_cleanup_queue(ubd_dev->queue); + goto out; } -static int ubd_config(char *str) +static int ubd_config(char *str, char **error_out) { - int n, err; + int n, ret; - str = uml_strdup(str); - if(str == NULL){ - printk(KERN_ERR "ubd_config failed to strdup string\n"); - return(1); + /* This string is possibly broken up and stored, so it's only + * freed if ubd_setup_common fails, or if only general options + * were set. + */ + str = kstrdup(str, GFP_KERNEL); + if (str == NULL) { + *error_out = "Failed to allocate memory"; + return -ENOMEM; } - err = ubd_setup_common(str, &n); - if(err){ - kfree(str); - return(-1); + + ret = ubd_setup_common(str, &n, error_out); + if (ret) + goto err_free; + + if (n == -1) { + ret = 0; + goto err_free; } - if(n == -1) return(0); - spin_lock(&ubd_lock); - err = ubd_add(n); - if(err) - ubd_dev[n].file = NULL; - spin_unlock(&ubd_lock); + mutex_lock(&ubd_lock); + ret = ubd_add(n, error_out); + if (ret) + ubd_devs[n].file = NULL; + mutex_unlock(&ubd_lock); - return(err); +out: + return ret; + +err_free: + kfree(str); + goto out; } static int ubd_get_config(char *name, char *str, int size, char **error_out) { - struct ubd *dev; + struct ubd *ubd_dev; int n, len = 0; n = parse_unit(&name); if((n >= MAX_DEV) || (n < 0)){ *error_out = "ubd_get_config : device number out of range"; - return(-1); + return -1; } - dev = &ubd_dev[n]; - spin_lock(&ubd_lock); + ubd_dev = &ubd_devs[n]; + mutex_lock(&ubd_lock); - if(dev->file == NULL){ + if(ubd_dev->file == NULL){ CONFIG_CHUNK(str, size, len, "", 1); goto out; } - CONFIG_CHUNK(str, size, len, dev->file, 0); + CONFIG_CHUNK(str, size, len, ubd_dev->file, 0); - if(dev->cow.file != NULL){ + if(ubd_dev->cow.file != NULL){ CONFIG_CHUNK(str, size, len, ",", 0); - CONFIG_CHUNK(str, size, len, dev->cow.file, 1); + CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1); } else CONFIG_CHUNK(str, size, len, "", 1); out: - spin_unlock(&ubd_lock); - return(len); + mutex_unlock(&ubd_lock); + return len; } static int ubd_id(char **str, int *start_out, int *end_out) { - int n; + int n; n = parse_unit(str); - *start_out = 0; - *end_out = MAX_DEV - 1; - return n; + *start_out = 0; + *end_out = MAX_DEV - 1; + return n; } -static int ubd_remove(int n) +static int ubd_remove(int n, char **error_out) { - struct ubd *dev; + struct gendisk *disk = ubd_gendisk[n]; + struct ubd *ubd_dev; int err = -ENODEV; - spin_lock(&ubd_lock); + mutex_lock(&ubd_lock); - if(ubd_gendisk[n] == NULL) - goto out; - - dev = &ubd_dev[n]; + ubd_dev = &ubd_devs[n]; - if(dev->file == NULL) + if(ubd_dev->file == NULL) goto out; /* you cannot remove a open disk */ err = -EBUSY; - if(dev->count > 0) + if(ubd_dev->count > 0) goto out; - del_gendisk(ubd_gendisk[n]); - put_disk(ubd_gendisk[n]); ubd_gendisk[n] = NULL; + if(disk != NULL){ + del_gendisk(disk); + put_disk(disk); + } if(fake_gendisk[n] != NULL){ del_gendisk(fake_gendisk[n]); @@ -799,23 +1004,26 @@ static int ubd_remove(int n) fake_gendisk[n] = NULL; } - platform_device_unregister(&dev->pdev); - *dev = ((struct ubd) DEFAULT_UBD); err = 0; + platform_device_unregister(&ubd_dev->pdev); out: - spin_unlock(&ubd_lock); + mutex_unlock(&ubd_lock); return err; } +/* All these are called by mconsole in process context and without + * ubd-specific locks. The structure itself is const except for .list. + */ static struct mc_device ubd_mc = { + .list = LIST_HEAD_INIT(ubd_mc.list), .name = "ubd", .config = ubd_config, - .get_config = ubd_get_config, + .get_config = ubd_get_config, .id = ubd_id, .remove = ubd_remove, }; -static int ubd_mc_init(void) +static int __init ubd_mc_init(void) { mconsole_register_dev(&ubd_mc); return 0; @@ -823,42 +1031,57 @@ static int ubd_mc_init(void) __initcall(ubd_mc_init); -static struct device_driver ubd_driver = { - .name = DRIVER_NAME, - .bus = &platform_bus_type, +static int __init ubd0_init(void) +{ + struct ubd *ubd_dev = &ubd_devs[0]; + + mutex_lock(&ubd_lock); + if(ubd_dev->file == NULL) + ubd_dev->file = "root_fs"; + mutex_unlock(&ubd_lock); + + return 0; +} + +__initcall(ubd0_init); + +/* Used in ubd_init, which is an initcall */ +static struct platform_driver ubd_driver = { + .driver = { + .name = DRIVER_NAME, + }, }; -int ubd_init(void) +static int __init ubd_init(void) { - int i; + char *error; + int i, err; - devfs_mk_dir("ubd"); - if (register_blkdev(MAJOR_NR, "ubd")) + if (register_blkdev(UBD_MAJOR, "ubd")) return -1; - ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock); - if (!ubd_queue) { - unregister_blkdev(MAJOR_NR, "ubd"); - return -1; - } - - if (fake_major != MAJOR_NR) { + if (fake_major != UBD_MAJOR) { char name[sizeof("ubd_nnn\0")]; snprintf(name, sizeof(name), "ubd_%d", fake_major); - devfs_mk_dir(name); if (register_blkdev(fake_major, "ubd")) return -1; } - driver_register(&ubd_driver); - for (i = 0; i < MAX_DEV; i++) - ubd_add(i); + platform_driver_register(&ubd_driver); + mutex_lock(&ubd_lock); + for (i = 0; i < MAX_DEV; i++){ + err = ubd_add(i, &error); + if(err) + printk(KERN_ERR "Failed to initialize ubd device %d :" + "%s\n", i, error); + } + mutex_unlock(&ubd_lock); return 0; } late_initcall(ubd_init); -int ubd_driver_init(void){ +static int __init ubd_driver_init(void){ unsigned long stack; int err; @@ -869,59 +1092,61 @@ int ubd_driver_init(void){ * enough. So use anyway the io thread. */ } stack = alloc_stack(0, 0); - io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), + io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), &thread_fd); if(io_pid < 0){ - printk(KERN_ERR + printk(KERN_ERR "ubd : Failed to start I/O thread (errno = %d) - " "falling back to synchronous I/O\n", -io_pid); io_pid = -1; - return(0); + return 0; } - err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, - SA_INTERRUPT, "ubd", ubd_dev); + err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, + 0, "ubd", ubd_devs); if(err != 0) printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); - return(err); + return 0; } device_initcall(ubd_driver_init); -static int ubd_open(struct inode *inode, struct file *filp) +static int ubd_open(struct block_device *bdev, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; - struct ubd *dev = disk->private_data; + struct gendisk *disk = bdev->bd_disk; + struct ubd *ubd_dev = disk->private_data; int err = 0; - if(dev->count == 0){ - err = ubd_open_dev(dev); + mutex_lock(&ubd_mutex); + if(ubd_dev->count == 0){ + err = ubd_open_dev(ubd_dev); if(err){ printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n", - disk->disk_name, dev->file, -err); + disk->disk_name, ubd_dev->file, -err); goto out; } } - dev->count++; - set_disk_ro(disk, !dev->openflags.w); + ubd_dev->count++; + set_disk_ro(disk, !ubd_dev->openflags.w); /* This should no more be needed. And it didn't work anyway to exclude * read-write remounting of filesystems.*/ - /*if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){ - if(--dev->count == 0) ubd_close(dev); + /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){ + if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev); err = -EROFS; }*/ - out: - return(err); +out: + mutex_unlock(&ubd_mutex); + return err; } -static int ubd_release(struct inode * inode, struct file * file) +static void ubd_release(struct gendisk *disk, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; - struct ubd *dev = disk->private_data; + struct ubd *ubd_dev = disk->private_data; - if(--dev->count == 0) - ubd_close(dev); - return(0); + mutex_lock(&ubd_mutex); + if(--ubd_dev->count == 0) + ubd_close_dev(ubd_dev); + mutex_unlock(&ubd_mutex); } static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, @@ -952,8 +1177,8 @@ static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, * by one word. Thanks to Lynn Kerby for the fix and James McMechan * for the original diagnosis. */ - if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / - sizeof(unsigned long) - 1)) + if (*cow_offset == (DIV_ROUND_UP(bitmap_len, + sizeof(unsigned long)) - 1)) (*cow_offset)--; bitmap_words[0] = bitmap[*cow_offset]; @@ -975,38 +1200,27 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, if(req->op == UBD_READ) { for(i = 0; i < req->length >> 9; i++){ if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) - ubd_set_bit(i, (unsigned char *) + ubd_set_bit(i, (unsigned char *) &req->sector_mask); - } + } } else cowify_bitmap(req->offset, req->length, &req->sector_mask, &req->cow_offset, bitmap, bitmap_offset, req->bitmap_words, bitmap_len); } -/* Called with ubd_io_lock held */ -static int prepare_request(struct request *req, struct io_thread_req *io_req) +/* Called with dev->lock held */ +static void prepare_request(struct request *req, struct io_thread_req *io_req, + unsigned long long offset, int page_offset, + int len, struct page *page) { struct gendisk *disk = req->rq_disk; - struct ubd *dev = disk->private_data; - __u64 offset; - int len; - - if(req->rq_status == RQ_INACTIVE) return(1); - - /* This should be impossible now */ - if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ - printk("Write attempted on readonly ubd device %s\n", - disk->disk_name); - end_request(req, 0); - return(1); - } + struct ubd *ubd_dev = disk->private_data; - offset = ((__u64) req->sector) << 9; - len = req->current_nr_sectors << 9; - - io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; - io_req->fds[1] = dev->fd; + io_req->req = req; + io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : + ubd_dev->fd; + io_req->fds[1] = ubd_dev->fd; io_req->cow_offset = -1; io_req->offset = offset; io_req->length = len; @@ -1015,259 +1229,144 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; io_req->offsets[0] = 0; - io_req->offsets[1] = dev->cow.data_offset; - io_req->buffer = req->buffer; + io_req->offsets[1] = ubd_dev->cow.data_offset; + io_req->buffer = page_address(page) + page_offset; io_req->sectorsize = 1 << 9; - if(dev->cow.file != NULL) - cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset, - dev->cow.bitmap_len); - - return(0); -} + if(ubd_dev->cow.file != NULL) + cowify_req(io_req, ubd_dev->cow.bitmap, + ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len); -/* Called with ubd_io_lock held */ -static void do_ubd_request(request_queue_t *q) -{ - struct io_thread_req io_req; - struct request *req; - int err, n; - - if(thread_fd == -1){ - while((req = elv_next_request(q)) != NULL){ - err = prepare_request(req, &io_req); - if(!err){ - do_io(&io_req); - __ubd_finish(req, io_req.error); - } - } - } - else { - if(do_ubd || (req = elv_next_request(q)) == NULL) - return; - err = prepare_request(req, &io_req); - if(!err){ - do_ubd = ubd_handler; - n = os_write_file(thread_fd, (char *) &io_req, - sizeof(io_req)); - if(n != sizeof(io_req)) - printk("write to io thread failed, " - "errno = %d\n", -n); - } - } } -static int ubd_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +/* Called with dev->lock held */ +static void prepare_flush_request(struct request *req, + struct io_thread_req *io_req) { - struct hd_geometry __user *loc = (struct hd_geometry __user *) arg; - struct ubd *dev = inode->i_bdev->bd_disk->private_data; - struct hd_driveid ubd_id = { - .cyls = 0, - .heads = 128, - .sectors = 32, - }; - - switch (cmd) { - struct hd_geometry g; - struct cdrom_volctrl volume; - case HDIO_GETGEO: - if(!loc) return(-EINVAL); - g.heads = 128; - g.sectors = 32; - g.cylinders = dev->size / (128 * 32 * 512); - g.start = get_start_sect(inode->i_bdev); - return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0); + struct gendisk *disk = req->rq_disk; + struct ubd *ubd_dev = disk->private_data; - case HDIO_GET_IDENTITY: - ubd_id.cyls = dev->size / (128 * 32 * 512); - if(copy_to_user((char __user *) arg, (char *) &ubd_id, - sizeof(ubd_id))) - return(-EFAULT); - return(0); - - case CDROMVOLREAD: - if(copy_from_user(&volume, (char __user *) arg, sizeof(volume))) - return(-EFAULT); - volume.channel0 = 255; - volume.channel1 = 255; - volume.channel2 = 255; - volume.channel3 = 255; - if(copy_to_user((char __user *) arg, &volume, sizeof(volume))) - return(-EFAULT); - return(0); - } - return(-EINVAL); + io_req->req = req; + io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : + ubd_dev->fd; + io_req->op = UBD_FLUSH; } -static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) +static bool submit_request(struct io_thread_req *io_req, struct ubd *dev) { - struct uml_stat buf1, buf2; - int err; - - if(from_cmdline == NULL) return(1); - if(!strcmp(from_cmdline, from_cow)) return(1); - - err = os_stat_file(from_cmdline, &buf1); - if(err < 0){ - printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err); - return(1); + int n = os_write_file(thread_fd, &io_req, + sizeof(io_req)); + if (n != sizeof(io_req)) { + if (n != -EAGAIN) + printk("write to io thread failed, " + "errno = %d\n", -n); + else if (list_empty(&dev->restart)) + list_add(&dev->restart, &restart); + + kfree(io_req); + return false; } - err = os_stat_file(from_cow, &buf2); - if(err < 0){ - printk("Couldn't stat '%s', err = %d\n", from_cow, -err); - return(1); - } - if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) - return(1); - - printk("Backing file mismatch - \"%s\" requested,\n" - "\"%s\" specified in COW header of \"%s\"\n", - from_cmdline, from_cow, cow); - return(0); + return true; } -static int backing_file_mismatch(char *file, __u64 size, time_t mtime) +/* Called with dev->lock held */ +static void do_ubd_request(struct request_queue *q) { - unsigned long modtime; - long long actual; - int err; - - err = os_file_modtime(file, &modtime); - if(err < 0){ - printk("Failed to get modification time of backing file " - "\"%s\", err = %d\n", file, -err); - return(err); - } - - err = os_file_size(file, &actual); - if(err < 0){ - printk("Failed to get size of backing file \"%s\", " - "err = %d\n", file, -err); - return(err); - } - - if(actual != size){ - /*__u64 can be a long on AMD64 and with %lu GCC complains; so - * the typecast.*/ - printk("Size mismatch (%llu vs %llu) of COW header vs backing " - "file\n", (unsigned long long) size, actual); - return(-EINVAL); - } - if(modtime != mtime){ - printk("mtime mismatch (%ld vs %ld) of COW header vs backing " - "file\n", mtime, modtime); - return(-EINVAL); - } - return(0); -} - -int read_cow_bitmap(int fd, void *buf, int offset, int len) -{ - int err; - - err = os_seek_file(fd, offset); - if(err < 0) - return(err); - - err = os_read_file(fd, buf, len); - if(err < 0) - return(err); - - return(0); -} + struct io_thread_req *io_req; + struct request *req; -int open_ubd_file(char *file, struct openflags *openflags, - char **backing_file_out, int *bitmap_offset_out, - unsigned long *bitmap_len_out, int *data_offset_out, - int *create_cow_out) -{ - time_t mtime; - unsigned long long size; - __u32 version, align; - char *backing_file; - int fd, err, sectorsize, same, mode = 0644; + while(1){ + struct ubd *dev = q->queuedata; + if(dev->end_sg == 0){ + struct request *req = blk_fetch_request(q); + if(req == NULL) + return; - fd = os_open_file(file, *openflags, mode); - if(fd < 0){ - if((fd == -ENOENT) && (create_cow_out != NULL)) - *create_cow_out = 1; - if(!openflags->w || - ((fd != -EROFS) && (fd != -EACCES))) return(fd); - openflags->w = 0; - fd = os_open_file(file, *openflags, mode); - if(fd < 0) - return(fd); - } + dev->request = req; + dev->rq_pos = blk_rq_pos(req); + dev->start_sg = 0; + dev->end_sg = blk_rq_map_sg(q, req, dev->sg); + } - err = os_lock_file(fd, openflags->w); - if(err < 0){ - printk("Failed to lock '%s', err = %d\n", file, -err); - goto out_close; - } + req = dev->request; - if(backing_file_out == NULL) return(fd); + if (req->cmd_flags & REQ_FLUSH) { + io_req = kmalloc(sizeof(struct io_thread_req), + GFP_ATOMIC); + if (io_req == NULL) { + if (list_empty(&dev->restart)) + list_add(&dev->restart, &restart); + return; + } + prepare_flush_request(req, io_req); + submit_request(io_req, dev); + } - err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, - &size, §orsize, &align, bitmap_offset_out); - if(err && (*backing_file_out != NULL)){ - printk("Failed to read COW header from COW file \"%s\", " - "errno = %d\n", file, -err); - goto out_close; - } - if(err) return(fd); + while(dev->start_sg < dev->end_sg){ + struct scatterlist *sg = &dev->sg[dev->start_sg]; - if(backing_file_out == NULL) return(fd); + io_req = kmalloc(sizeof(struct io_thread_req), + GFP_ATOMIC); + if(io_req == NULL){ + if(list_empty(&dev->restart)) + list_add(&dev->restart, &restart); + return; + } + prepare_request(req, io_req, + (unsigned long long)dev->rq_pos << 9, + sg->offset, sg->length, sg_page(sg)); - same = same_backing_files(*backing_file_out, backing_file, file); + if (submit_request(io_req, dev) == false) + return; - if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){ - printk("Switching backing file to '%s'\n", *backing_file_out); - err = write_cow_header(file, fd, *backing_file_out, - sectorsize, align, &size); - if(err){ - printk("Switch failed, errno = %d\n", -err); - return(err); + dev->rq_pos += sg->length >> 9; + dev->start_sg++; } + dev->end_sg = 0; + dev->request = NULL; } - else { - *backing_file_out = backing_file; - err = backing_file_mismatch(*backing_file_out, size, mtime); - if(err) goto out_close; - } +} - cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, - bitmap_len_out, data_offset_out); +static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct ubd *ubd_dev = bdev->bd_disk->private_data; - return(fd); - out_close: - os_close_file(fd); - return(err); + geo->heads = 128; + geo->sectors = 32; + geo->cylinders = ubd_dev->size / (128 * 32 * 512); + return 0; } -int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, - int sectorsize, int alignment, int *bitmap_offset_out, - unsigned long *bitmap_len_out, int *data_offset_out) +static int ubd_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) { - int err, fd; + struct ubd *ubd_dev = bdev->bd_disk->private_data; + u16 ubd_id[ATA_ID_WORDS]; - flags.c = 1; - fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL); - if(fd < 0){ - err = fd; - printk("Open of COW file '%s' failed, errno = %d\n", cow_file, - -err); - goto out; - } + switch (cmd) { + struct cdrom_volctrl volume; + case HDIO_GET_IDENTITY: + memset(&ubd_id, 0, ATA_ID_WORDS * 2); + ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512); + ubd_id[ATA_ID_HEADS] = 128; + ubd_id[ATA_ID_SECTORS] = 32; + if(copy_to_user((char __user *) arg, (char *) &ubd_id, + sizeof(ubd_id))) + return -EFAULT; + return 0; - err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, - bitmap_offset_out, bitmap_len_out, - data_offset_out); - if(!err) - return(fd); - os_close_file(fd); - out: - return(err); + case CDROMVOLREAD: + if(copy_from_user(&volume, (char __user *) arg, sizeof(volume))) + return -EFAULT; + volume.channel0 = 255; + volume.channel1 = 255; + volume.channel2 = 255; + volume.channel3 = 255; + if(copy_to_user((char __user *) arg, &volume, sizeof(volume))) + return -EFAULT; + return 0; + } + return -EINVAL; } static int update_bitmap(struct io_thread_req *req) @@ -1275,26 +1374,26 @@ static int update_bitmap(struct io_thread_req *req) int n; if(req->cow_offset == -1) - return(0); + return 0; n = os_seek_file(req->fds[1], req->cow_offset); if(n < 0){ printk("do_io - bitmap lseek failed : err = %d\n", -n); - return(1); + return 1; } n = os_write_file(req->fds[1], &req->bitmap_words, - sizeof(req->bitmap_words)); + sizeof(req->bitmap_words)); if(n != sizeof(req->bitmap_words)){ printk("do_io - bitmap update failed, err = %d fd = %d\n", -n, req->fds[1]); - return(1); + return 1; } - return(0); + return 0; } -void do_io(struct io_thread_req *req) +static void do_io(struct io_thread_req *req) { char *buf; unsigned long len; @@ -1302,6 +1401,17 @@ void do_io(struct io_thread_req *req) int err; __u64 off; + if (req->op == UBD_FLUSH) { + /* fds[0] is always either the rw image or our cow file */ + n = os_sync_file(req->fds[0]); + if (n != 0) { + printk("do_io - sync failed err = %d " + "fd = %d\n", -n, req->fds[0]); + req->error = 1; + } + return; + } + nsectors = req->length / req->sectorsize; start = 0; do { @@ -1358,18 +1468,20 @@ void do_io(struct io_thread_req *req) */ int kernel_fd = -1; -/* Only changed by the io thread */ -int io_count = 0; +/* Only changed by the io thread. XXX: currently unused. */ +static int io_count = 0; int io_thread(void *arg) { - struct io_thread_req req; + struct io_thread_req *req; int n; - ignore_sigwinch_sig(); + os_fix_helper_signals(); + while(1){ - n = os_read_file(kernel_fd, &req, sizeof(req)); - if(n != sizeof(req)){ + n = os_read_file(kernel_fd, &req, + sizeof(struct io_thread_req *)); + if(n != sizeof(struct io_thread_req *)){ if(n < 0) printk("io_thread - read failed, fd = %d, " "err = %d\n", kernel_fd, -n); @@ -1380,21 +1492,13 @@ int io_thread(void *arg) continue; } io_count++; - do_io(&req); - n = os_write_file(kernel_fd, &req, sizeof(req)); - if(n != sizeof(req)) + do_io(req); + n = os_write_file(kernel_fd, &req, + sizeof(struct io_thread_req *)); + if(n != sizeof(struct io_thread_req *)) printk("io_thread - write failed, fd = %d, err = %d\n", kernel_fd, -n); } -} -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ + return 0; +} diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index b94d2bc4fe0..e376f9b9c68 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -15,21 +15,11 @@ #include <sys/socket.h> #include <sys/mman.h> #include <sys/param.h> -#include "asm/types.h" -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "ubd_user.h" -#include "os.h" -#include "cow.h" - #include <endian.h> #include <byteswap.h> -void ignore_sigwinch_sig(void) -{ - signal(SIGWINCH, SIG_IGN); -} +#include "ubd.h" +#include <os.h> int start_io_thread(unsigned long sp, int *fd_out) { @@ -44,11 +34,16 @@ int start_io_thread(unsigned long sp, int *fd_out) kernel_fd = fds[0]; *fd_out = fds[1]; - pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, - NULL); + err = os_set_fd_block(*fd_out, 0); + if (err) { + printk("start_io_thread - failed to set nonblocking I/O.\n"); + goto out_close; + } + + pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM, NULL); if(pid < 0){ - printk("start_io_thread - clone failed : errno = %d\n", errno); err = -errno; + printk("start_io_thread - clone failed : errno = %d\n", errno); goto out_close; } @@ -60,16 +55,5 @@ int start_io_thread(unsigned long sp, int *fd_out) kernel_fd = -1; *fd_out = -1; out: - return(err); + return err; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/umcast.h b/arch/um/drivers/umcast.h new file mode 100644 index 00000000000..c190c644091 --- /dev/null +++ b/arch/um/drivers/umcast.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __DRIVERS_UMCAST_H +#define __DRIVERS_UMCAST_H + +#include <net_user.h> + +struct umcast_data { + char *addr; + unsigned short lport; + unsigned short rport; + void *listen_addr; + void *remote_addr; + int ttl; + int unicast; + void *dev; +}; + +extern const struct net_user_info umcast_user_info; + +extern int umcast_user_write(int fd, void *buf, int len, + struct umcast_data *pri); + +#endif diff --git a/arch/um/drivers/umcast_kern.c b/arch/um/drivers/umcast_kern.c new file mode 100644 index 00000000000..f5ba6e37791 --- /dev/null +++ b/arch/um/drivers/umcast_kern.c @@ -0,0 +1,188 @@ +/* + * user-mode-linux networking multicast transport + * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * + * based on the existing uml-networking code, which is + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * + * Licensed under the GPL. + */ + +#include <linux/init.h> +#include <linux/netdevice.h> +#include "umcast.h" +#include <net_kern.h> + +struct umcast_init { + char *addr; + int lport; + int rport; + int ttl; + bool unicast; +}; + +static void umcast_init(struct net_device *dev, void *data) +{ + struct uml_net_private *pri; + struct umcast_data *dpri; + struct umcast_init *init = data; + + pri = netdev_priv(dev); + dpri = (struct umcast_data *) pri->user; + dpri->addr = init->addr; + dpri->lport = init->lport; + dpri->rport = init->rport; + dpri->unicast = init->unicast; + dpri->ttl = init->ttl; + dpri->dev = dev; + + if (dpri->unicast) { + printk(KERN_INFO "ucast backend address: %s:%u listen port: " + "%u\n", dpri->addr, dpri->rport, dpri->lport); + } else { + printk(KERN_INFO "mcast backend multicast address: %s:%u, " + "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl); + } +} + +static int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) +{ + return net_recvfrom(fd, skb_mac_header(skb), + skb->dev->mtu + ETH_HEADER_OTHER); +} + +static int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) +{ + return umcast_user_write(fd, skb->data, skb->len, + (struct umcast_data *) &lp->user); +} + +static const struct net_kern_info umcast_kern_info = { + .init = umcast_init, + .protocol = eth_protocol, + .read = umcast_read, + .write = umcast_write, +}; + +static int mcast_setup(char *str, char **mac_out, void *data) +{ + struct umcast_init *init = data; + char *port_str = NULL, *ttl_str = NULL, *remain; + char *last; + + *init = ((struct umcast_init) + { .addr = "239.192.168.1", + .lport = 1102, + .ttl = 1 }); + + remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str, + NULL); + if (remain != NULL) { + printk(KERN_ERR "mcast_setup - Extra garbage on " + "specification : '%s'\n", remain); + return 0; + } + + if (port_str != NULL) { + init->lport = simple_strtoul(port_str, &last, 10); + if ((*last != '\0') || (last == port_str)) { + printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", + port_str); + return 0; + } + } + + if (ttl_str != NULL) { + init->ttl = simple_strtoul(ttl_str, &last, 10); + if ((*last != '\0') || (last == ttl_str)) { + printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", + ttl_str); + return 0; + } + } + + init->unicast = false; + init->rport = init->lport; + + printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr, + init->lport, init->ttl); + + return 1; +} + +static int ucast_setup(char *str, char **mac_out, void *data) +{ + struct umcast_init *init = data; + char *lport_str = NULL, *rport_str = NULL, *remain; + char *last; + + *init = ((struct umcast_init) + { .addr = "", + .lport = 1102, + .rport = 1102 }); + + remain = split_if_spec(str, mac_out, &init->addr, + &lport_str, &rport_str, NULL); + if (remain != NULL) { + printk(KERN_ERR "ucast_setup - Extra garbage on " + "specification : '%s'\n", remain); + return 0; + } + + if (lport_str != NULL) { + init->lport = simple_strtoul(lport_str, &last, 10); + if ((*last != '\0') || (last == lport_str)) { + printk(KERN_ERR "ucast_setup - Bad listen port : " + "'%s'\n", lport_str); + return 0; + } + } + + if (rport_str != NULL) { + init->rport = simple_strtoul(rport_str, &last, 10); + if ((*last != '\0') || (last == rport_str)) { + printk(KERN_ERR "ucast_setup - Bad remote port : " + "'%s'\n", rport_str); + return 0; + } + } + + init->unicast = true; + + printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n", + init->lport, init->addr, init->rport); + + return 1; +} + +static struct transport mcast_transport = { + .list = LIST_HEAD_INIT(mcast_transport.list), + .name = "mcast", + .setup = mcast_setup, + .user = &umcast_user_info, + .kern = &umcast_kern_info, + .private_size = sizeof(struct umcast_data), + .setup_size = sizeof(struct umcast_init), +}; + +static struct transport ucast_transport = { + .list = LIST_HEAD_INIT(ucast_transport.list), + .name = "ucast", + .setup = ucast_setup, + .user = &umcast_user_info, + .kern = &umcast_kern_info, + .private_size = sizeof(struct umcast_data), + .setup_size = sizeof(struct umcast_init), +}; + +static int register_umcast(void) +{ + register_transport(&mcast_transport); + register_transport(&ucast_transport); + return 0; +} + +late_initcall(register_umcast); diff --git a/arch/um/drivers/umcast_user.c b/arch/um/drivers/umcast_user.c new file mode 100644 index 00000000000..6074184bb51 --- /dev/null +++ b/arch/um/drivers/umcast_user.c @@ -0,0 +1,184 @@ +/* + * user-mode-linux networking multicast transport + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> + * + * based on the existing uml-networking code, which is + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * + * Licensed under the GPL. + * + */ + +#include <unistd.h> +#include <errno.h> +#include <netinet/in.h> +#include "umcast.h" +#include <net_user.h> +#include <um_malloc.h> + +static struct sockaddr_in *new_addr(char *addr, unsigned short port) +{ + struct sockaddr_in *sin; + + sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL); + if (sin == NULL) { + printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in " + "failed\n"); + return NULL; + } + sin->sin_family = AF_INET; + if (addr) + sin->sin_addr.s_addr = in_aton(addr); + else + sin->sin_addr.s_addr = INADDR_ANY; + sin->sin_port = htons(port); + return sin; +} + +static int umcast_user_init(void *data, void *dev) +{ + struct umcast_data *pri = data; + + pri->remote_addr = new_addr(pri->addr, pri->rport); + if (pri->unicast) + pri->listen_addr = new_addr(NULL, pri->lport); + else + pri->listen_addr = pri->remote_addr; + pri->dev = dev; + return 0; +} + +static void umcast_remove(void *data) +{ + struct umcast_data *pri = data; + + kfree(pri->listen_addr); + if (pri->unicast) + kfree(pri->remote_addr); + pri->listen_addr = pri->remote_addr = NULL; +} + +static int umcast_open(void *data) +{ + struct umcast_data *pri = data; + struct sockaddr_in *lsin = pri->listen_addr; + struct sockaddr_in *rsin = pri->remote_addr; + struct ip_mreq mreq; + int fd, yes = 1, err = -EINVAL; + + + if ((!pri->unicast && lsin->sin_addr.s_addr == 0) || + (rsin->sin_addr.s_addr == 0) || + (lsin->sin_port == 0) || (rsin->sin_port == 0)) + goto out; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + + if (fd < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open : data socket failed, " + "errno = %d\n", errno); + goto out; + } + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open: SO_REUSEADDR failed, " + "errno = %d\n", errno); + goto out_close; + } + + if (!pri->unicast) { + /* set ttl according to config */ + if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl, + sizeof(pri->ttl)) < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_TTL " + "failed, error = %d\n", errno); + goto out_close; + } + + /* set LOOP, so data does get fed back to local sockets */ + if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, + &yes, sizeof(yes)) < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_LOOP " + "failed, error = %d\n", errno); + goto out_close; + } + } + + /* bind socket to the address */ + if (bind(fd, (struct sockaddr *) lsin, sizeof(*lsin)) < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open : data bind failed, " + "errno = %d\n", errno); + goto out_close; + } + + if (!pri->unicast) { + /* subscribe to the multicast group */ + mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr; + mreq.imr_interface.s_addr = 0; + if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, + &mreq, sizeof(mreq)) < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open: IP_ADD_MEMBERSHIP " + "failed, error = %d\n", errno); + printk(UM_KERN_ERR "There appears not to be a " + "multicast-capable network interface on the " + "host.\n"); + printk(UM_KERN_ERR "eth0 should be configured in order " + "to use the multicast transport.\n"); + goto out_close; + } + } + + return fd; + + out_close: + close(fd); + out: + return err; +} + +static void umcast_close(int fd, void *data) +{ + struct umcast_data *pri = data; + + if (!pri->unicast) { + struct ip_mreq mreq; + struct sockaddr_in *lsin = pri->listen_addr; + + mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr; + mreq.imr_interface.s_addr = 0; + if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, + &mreq, sizeof(mreq)) < 0) { + printk(UM_KERN_ERR "umcast_close: IP_DROP_MEMBERSHIP " + "failed, error = %d\n", errno); + } + } + + close(fd); +} + +int umcast_user_write(int fd, void *buf, int len, struct umcast_data *pri) +{ + struct sockaddr_in *data_addr = pri->remote_addr; + + return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)); +} + +const struct net_user_info umcast_user_info = { + .init = umcast_user_init, + .open = umcast_open, + .close = umcast_close, + .remove = umcast_remove, + .add_address = NULL, + .delete_address = NULL, + .mtu = ETH_MAX_PACKET, + .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, +}; diff --git a/arch/um/drivers/vde.h b/arch/um/drivers/vde.h new file mode 100644 index 00000000000..fc3a05902ba --- /dev/null +++ b/arch/um/drivers/vde.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2007 Luca Bigliardi (shammash@artha.org). + * Licensed under the GPL. + */ + +#ifndef __UM_VDE_H__ +#define __UM_VDE_H__ + +struct vde_data { + char *vde_switch; + char *descr; + void *args; + void *conn; + void *dev; +}; + +struct vde_init { + char *vde_switch; + char *descr; + int port; + char *group; + int mode; +}; + +extern const struct net_user_info vde_user_info; + +extern void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init); + +extern int vde_user_read(void *conn, void *buf, int len); +extern int vde_user_write(void *conn, void *buf, int len); + +#endif diff --git a/arch/um/drivers/vde_kern.c b/arch/um/drivers/vde_kern.c new file mode 100644 index 00000000000..6a365fadc7c --- /dev/null +++ b/arch/um/drivers/vde_kern.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2007 Luca Bigliardi (shammash@artha.org). + * Licensed under the GPL. + * + * Transport usage: + * ethN=vde,<vde_switch>,<mac addr>,<port>,<group>,<mode>,<description> + * + */ + +#include <linux/init.h> +#include <linux/netdevice.h> +#include <net_kern.h> +#include <net_user.h> +#include "vde.h" + +static void vde_init(struct net_device *dev, void *data) +{ + struct vde_init *init = data; + struct uml_net_private *pri; + struct vde_data *vpri; + + pri = netdev_priv(dev); + vpri = (struct vde_data *) pri->user; + + vpri->vde_switch = init->vde_switch; + vpri->descr = init->descr ? init->descr : "UML vde_transport"; + vpri->args = NULL; + vpri->conn = NULL; + vpri->dev = dev; + + printk("vde backend - %s, ", vpri->vde_switch ? + vpri->vde_switch : "(default socket)"); + + vde_init_libstuff(vpri, init); + + printk("\n"); +} + +static int vde_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) +{ + struct vde_data *pri = (struct vde_data *) &lp->user; + + if (pri->conn != NULL) + return vde_user_read(pri->conn, skb_mac_header(skb), + skb->dev->mtu + ETH_HEADER_OTHER); + + printk(KERN_ERR "vde_read - we have no VDECONN to read from"); + return -EBADF; +} + +static int vde_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) +{ + struct vde_data *pri = (struct vde_data *) &lp->user; + + if (pri->conn != NULL) + return vde_user_write((void *)pri->conn, skb->data, + skb->len); + + printk(KERN_ERR "vde_write - we have no VDECONN to write to"); + return -EBADF; +} + +static const struct net_kern_info vde_kern_info = { + .init = vde_init, + .protocol = eth_protocol, + .read = vde_read, + .write = vde_write, +}; + +static int vde_setup(char *str, char **mac_out, void *data) +{ + struct vde_init *init = data; + char *remain, *port_str = NULL, *mode_str = NULL, *last; + + *init = ((struct vde_init) + { .vde_switch = NULL, + .descr = NULL, + .port = 0, + .group = NULL, + .mode = 0 }); + + remain = split_if_spec(str, &init->vde_switch, mac_out, &port_str, + &init->group, &mode_str, &init->descr, NULL); + + if (remain != NULL) + printk(KERN_WARNING "vde_setup - Ignoring extra data :" + "'%s'\n", remain); + + if (port_str != NULL) { + init->port = simple_strtoul(port_str, &last, 10); + if ((*last != '\0') || (last == port_str)) { + printk(KERN_ERR "vde_setup - Bad port : '%s'\n", + port_str); + return 0; + } + } + + if (mode_str != NULL) { + init->mode = simple_strtoul(mode_str, &last, 8); + if ((*last != '\0') || (last == mode_str)) { + printk(KERN_ERR "vde_setup - Bad mode : '%s'\n", + mode_str); + return 0; + } + } + + printk(KERN_INFO "Configured vde device: %s\n", init->vde_switch ? + init->vde_switch : "(default socket)"); + + return 1; +} + +static struct transport vde_transport = { + .list = LIST_HEAD_INIT(vde_transport.list), + .name = "vde", + .setup = vde_setup, + .user = &vde_user_info, + .kern = &vde_kern_info, + .private_size = sizeof(struct vde_data), + .setup_size = sizeof(struct vde_init), +}; + +static int register_vde(void) +{ + register_transport(&vde_transport); + return 0; +} + +late_initcall(register_vde); diff --git a/arch/um/drivers/vde_user.c b/arch/um/drivers/vde_user.c new file mode 100644 index 00000000000..64cb630d115 --- /dev/null +++ b/arch/um/drivers/vde_user.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007 Luca Bigliardi (shammash@artha.org). + * Licensed under the GPL. + */ + +#include <stddef.h> +#include <errno.h> +#include <libvdeplug.h> +#include <net_user.h> +#include <um_malloc.h> +#include "vde.h" + +static int vde_user_init(void *data, void *dev) +{ + struct vde_data *pri = data; + VDECONN *conn = NULL; + int err = -EINVAL; + + pri->dev = dev; + + conn = vde_open(pri->vde_switch, pri->descr, pri->args); + + if (conn == NULL) { + err = -errno; + printk(UM_KERN_ERR "vde_user_init: vde_open failed, " + "errno = %d\n", errno); + return err; + } + + printk(UM_KERN_INFO "vde backend - connection opened\n"); + + pri->conn = conn; + + return 0; +} + +static int vde_user_open(void *data) +{ + struct vde_data *pri = data; + + if (pri->conn != NULL) + return vde_datafd(pri->conn); + + printk(UM_KERN_WARNING "vde_open - we have no VDECONN to open"); + return -EINVAL; +} + +static void vde_remove(void *data) +{ + struct vde_data *pri = data; + + if (pri->conn != NULL) { + printk(UM_KERN_INFO "vde backend - closing connection\n"); + vde_close(pri->conn); + pri->conn = NULL; + kfree(pri->args); + pri->args = NULL; + return; + } + + printk(UM_KERN_WARNING "vde_remove - we have no VDECONN to remove"); +} + +const struct net_user_info vde_user_info = { + .init = vde_user_init, + .open = vde_user_open, + .close = NULL, + .remove = vde_remove, + .add_address = NULL, + .delete_address = NULL, + .mtu = ETH_MAX_PACKET, + .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, +}; + +void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init) +{ + struct vde_open_args *args; + + vpri->args = uml_kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL); + if (vpri->args == NULL) { + printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args " + "allocation failed"); + return; + } + + args = vpri->args; + + args->port = init->port; + args->group = init->group; + args->mode = init->mode ? init->mode : 0700; + + args->port ? printk("port %d", args->port) : + printk("undefined port"); +} + +int vde_user_read(void *conn, void *buf, int len) +{ + VDECONN *vconn = conn; + int rv; + + if (vconn == NULL) + return 0; + + rv = vde_recv(vconn, buf, len, 0); + if (rv < 0) { + if (errno == EAGAIN) + return 0; + return -errno; + } + else if (rv == 0) + return -ENOTCONN; + + return rv; +} + +int vde_user_write(void *conn, void *buf, int len) +{ + VDECONN *vconn = conn; + + if (vconn == NULL) + return 0; + + return vde_send(vconn, buf, len, 0); +} + diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index b530f1a6540..20e30be4479 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -1,22 +1,18 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ +#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> -#include <string.h> #include <errno.h> +#include <string.h> #include <termios.h> -#include <signal.h> -#include <sched.h> -#include <sys/socket.h> -#include "kern_util.h" #include "chan_user.h" -#include "user_util.h" -#include "user.h" -#include "os.h" +#include <os.h> +#include <um_malloc.h> #include "xterm.h" struct xterm_chan { @@ -26,25 +22,21 @@ struct xterm_chan { int device; int raw; struct termios tt; - unsigned long stack; - int direct_rcv; }; -/* Not static because it's called directly by the tt mode gdb code */ -void *xterm_init(char *str, int device, struct chan_opts *opts) +static void *xterm_init(char *str, int device, const struct chan_opts *opts) { struct xterm_chan *data; - data = malloc(sizeof(*data)); - if(data == NULL) return(NULL); - *data = ((struct xterm_chan) { .pid = -1, + data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); + if (data == NULL) + return NULL; + *data = ((struct xterm_chan) { .pid = -1, .helper_pid = -1, - .device = device, + .device = device, .title = opts->xterm_title, - .raw = opts->raw, - .stack = opts->tramp_stack, - .direct_rcv = !opts->in_kernel } ); - return(data); + .raw = opts->raw } ); + return data; } /* Only changed by xterm_setup, which is a setup */ @@ -58,16 +50,22 @@ static int __init xterm_setup(char *line, int *add) terminal_emulator = line; line = strchr(line, ','); - if(line == NULL) return(0); + if (line == NULL) + return 0; + *line++ = '\0'; - if(*line) title_switch = line; + if (*line) + title_switch = line; line = strchr(line, ','); - if(line == NULL) return(0); + if (line == NULL) + return 0; + *line++ = '\0'; - if(*line) exec_switch = line; + if (*line) + exec_switch = line; - return(0); + return 0; } __uml_setup("xterm=", xterm_setup, @@ -83,144 +81,143 @@ __uml_setup("xterm=", xterm_setup, " are 'xterm=gnome-terminal,-t,-x'.\n\n" ); -/* XXX This badly needs some cleaning up in the error paths - * Not static because it's called directly by the tt mode gdb code - */ -int xterm_open(int input, int output, int primary, void *d, +static int xterm_open(int input, int output, int primary, void *d, char **dev_out) { struct xterm_chan *data = d; - unsigned long stack; int pid, fd, new, err; char title[256], file[] = "/tmp/xterm-pipeXXXXXX"; - char *argv[] = { terminal_emulator, title_switch, title, exec_switch, - "/usr/lib/uml/port-helper", "-uml-socket", + char *argv[] = { terminal_emulator, title_switch, title, exec_switch, + OS_LIB_PATH "/uml/port-helper", "-uml-socket", file, NULL }; - if(os_access(argv[4], OS_ACC_X_OK) < 0) + if (access(argv[4], X_OK) < 0) argv[4] = "port-helper"; - /* Check that DISPLAY is set, this doesn't guarantee the xterm - * will work but w/o it we can be pretty sure it won't. */ - if (!getenv("DISPLAY")) { - printk("xterm_open: $DISPLAY not set.\n"); + /* + * Check that DISPLAY is set, this doesn't guarantee the xterm + * will work but w/o it we can be pretty sure it won't. + */ + if (getenv("DISPLAY") == NULL) { + printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n"); return -ENODEV; } + /* + * This business of getting a descriptor to a temp file, + * deleting the file and closing the descriptor is just to get + * a known-unused name for the Unix socket that we really + * want. + */ fd = mkstemp(file); - if(fd < 0){ + if (fd < 0) { err = -errno; - printk("xterm_open : mkstemp failed, errno = %d\n", errno); + printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n", + errno); return err; } - if(unlink(file)){ + if (unlink(file)) { err = -errno; - printk("xterm_open : unlink failed, errno = %d\n", errno); + printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n", + errno); + close(fd); return err; } - os_close_file(fd); + close(fd); fd = os_create_unix_socket(file, sizeof(file), 1); - if(fd < 0){ - printk("xterm_open : create_unix_socket failed, errno = %d\n", - -fd); - return(fd); + if (fd < 0) { + printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, " + "errno = %d\n", -fd); + return fd; } sprintf(title, data->title, data->device); - stack = data->stack; - pid = run_helper(NULL, NULL, argv, &stack); - if(pid < 0){ - printk("xterm_open : run_helper failed, errno = %d\n", -pid); - return(pid); + pid = run_helper(NULL, NULL, argv); + if (pid < 0) { + err = pid; + printk(UM_KERN_ERR "xterm_open : run_helper failed, " + "errno = %d\n", -err); + goto out_close1; } - if(data->stack == 0) free_stack(stack, 0); + err = os_set_fd_block(fd, 0); + if (err < 0) { + printk(UM_KERN_ERR "xterm_open : failed to set descriptor " + "non-blocking, err = %d\n", -err); + goto out_kill; + } - if (data->direct_rcv) { - new = os_rcv_fd(fd, &data->helper_pid); - } else { - err = os_set_fd_block(fd, 0); - if(err < 0){ - printk("xterm_open : failed to set descriptor " - "non-blocking, err = %d\n", -err); - return(err); - } - new = xterm_fd(fd, &data->helper_pid); + new = xterm_fd(fd, &data->helper_pid); + if (new < 0) { + err = new; + printk(UM_KERN_ERR "xterm_open : os_rcv_fd failed, err = %d\n", + -err); + goto out_kill; } - if(new < 0){ - printk("xterm_open : os_rcv_fd failed, err = %d\n", -new); - goto out; + + err = os_set_fd_block(new, 0); + if (err) { + printk(UM_KERN_ERR "xterm_open : failed to set xterm " + "descriptor non-blocking, err = %d\n", -err); + goto out_close2; } CATCH_EINTR(err = tcgetattr(new, &data->tt)); - if(err){ + if (err) { new = err; - goto out; + goto out_close2; } - if(data->raw){ + if (data->raw) { err = raw(new); - if(err){ + if (err) { new = err; - goto out; + goto out_close2; } } + unlink(file); data->pid = pid; *dev_out = NULL; - out: - unlink(file); - return(new); + + return new; + + out_close2: + close(new); + out_kill: + os_kill_process(pid, 1); + out_close1: + close(fd); + + return err; } -/* Not static because it's called directly by the tt mode gdb code */ -void xterm_close(int fd, void *d) +static void xterm_close(int fd, void *d) { struct xterm_chan *data = d; - - if(data->pid != -1) + + if (data->pid != -1) os_kill_process(data->pid, 1); data->pid = -1; - if(data->helper_pid != -1) + + if (data->helper_pid != -1) os_kill_process(data->helper_pid, 0); data->helper_pid = -1; - os_close_file(fd); -} - -static void xterm_free(void *d) -{ - free(d); -} -static int xterm_console_write(int fd, const char *buf, int n, void *d) -{ - struct xterm_chan *data = d; - - return(generic_console_write(fd, buf, n, &data->tt)); + os_close_file(fd); } -struct chan_ops xterm_ops = { +const struct chan_ops xterm_ops = { .type = "xterm", .init = xterm_init, .open = xterm_open, .close = xterm_close, .read = generic_read, .write = generic_write, - .console_write = xterm_console_write, + .console_write = generic_console_write, .window_size = generic_window_size, - .free = xterm_free, + .free = generic_free, .winch = 1, }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/xterm.h b/arch/um/drivers/xterm.h index f33a6e77b18..56b9c4aba42 100644 --- a/arch/um/drivers/xterm.h +++ b/arch/um/drivers/xterm.h @@ -10,13 +10,3 @@ extern int xterm_fd(int socket, int *pid_out); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c index d269a80f4b0..e8f9957bfbf 100644 --- a/arch/um/drivers/xterm_kern.c +++ b/arch/um/drivers/xterm_kern.c @@ -1,18 +1,14 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/errno.h" -#include "linux/slab.h" -#include "linux/signal.h" -#include "linux/interrupt.h" -#include "asm/irq.h" -#include "irq_user.h" -#include "irq_kern.h" -#include "kern_util.h" -#include "os.h" -#include "xterm.h" +#include <linux/slab.h> +#include <linux/completion.h> +#include <linux/irqreturn.h> +#include <asm/irq.h> +#include <irq_kern.h> +#include <os.h> struct xterm_wait { struct completion ready; @@ -21,18 +17,19 @@ struct xterm_wait { int new_fd; }; -static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t xterm_interrupt(int irq, void *data) { struct xterm_wait *xterm = data; int fd; fd = os_rcv_fd(xterm->fd, &xterm->pid); - if(fd == -EAGAIN) - return(IRQ_NONE); + if (fd == -EAGAIN) + return IRQ_NONE; xterm->new_fd = fd; complete(&xterm->ready); - return(IRQ_HANDLED); + + return IRQ_HANDLED; } int xterm_fd(int socket, int *pid_out) @@ -41,22 +38,20 @@ int xterm_fd(int socket, int *pid_out) int err, ret; data = kmalloc(sizeof(*data), GFP_KERNEL); - if(data == NULL){ + if (data == NULL) { printk(KERN_ERR "xterm_fd : failed to allocate xterm_wait\n"); - return(-ENOMEM); + return -ENOMEM; } /* This is a locked semaphore... */ - *data = ((struct xterm_wait) - { .fd = socket, - .pid = -1, - .new_fd = -1 }); + *data = ((struct xterm_wait) { .fd = socket, + .pid = -1, + .new_fd = -1 }); init_completion(&data->ready); - err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, - SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, - "xterm", data); - if (err){ + err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, + IRQF_SHARED, "xterm", data); + if (err) { printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, " "err = %d\n", err); ret = err; @@ -69,23 +64,12 @@ int xterm_fd(int socket, int *pid_out) * isn't set) this will hang... */ wait_for_completion(&data->ready); - free_irq(XTERM_IRQ, data); + um_free_irq(XTERM_IRQ, data); ret = data->new_fd; *pid_out = data->pid; out: kfree(data); - return(ret); + return ret; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild new file mode 100644 index 00000000000..a5e4b606821 --- /dev/null +++ b/arch/um/include/asm/Kbuild @@ -0,0 +1,28 @@ +generic-y += barrier.h +generic-y += bug.h +generic-y += clkdev.h +generic-y += cputime.h +generic-y += current.h +generic-y += delay.h +generic-y += device.h +generic-y += emergency-restart.h +generic-y += exec.h +generic-y += ftrace.h +generic-y += futex.h +generic-y += hardirq.h +generic-y += hash.h +generic-y += hw_irq.h +generic-y += io.h +generic-y += irq_regs.h +generic-y += kdebug.h +generic-y += mcs_spinlock.h +generic-y += mutex.h +generic-y += param.h +generic-y += pci.h +generic-y += percpu.h +generic-y += preempt.h +generic-y += sections.h +generic-y += switch_to.h +generic-y += topology.h +generic-y += trace_clock.h +generic-y += xor.h diff --git a/arch/um/include/asm/a.out-core.h b/arch/um/include/asm/a.out-core.h new file mode 100644 index 00000000000..995643b1830 --- /dev/null +++ b/arch/um/include/asm/a.out-core.h @@ -0,0 +1,27 @@ +/* a.out coredump register dumper + * + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef __UM_A_OUT_CORE_H +#define __UM_A_OUT_CORE_H + +#ifdef __KERNEL__ + +#include <linux/user.h> + +/* + * fill in the user structure for an a.out core dump + */ +static inline void aout_dump_thread(struct pt_regs *regs, struct user *u) +{ +} + +#endif /* __KERNEL__ */ +#endif /* __UM_A_OUT_CORE_H */ diff --git a/arch/um/include/asm/bugs.h b/arch/um/include/asm/bugs.h new file mode 100644 index 00000000000..6a72e240d5f --- /dev/null +++ b/arch/um/include/asm/bugs.h @@ -0,0 +1,6 @@ +#ifndef __UM_BUGS_H +#define __UM_BUGS_H + +void check_bugs(void); + +#endif diff --git a/arch/um/include/asm/cache.h b/arch/um/include/asm/cache.h new file mode 100644 index 00000000000..19e1bdd6741 --- /dev/null +++ b/arch/um/include/asm/cache.h @@ -0,0 +1,17 @@ +#ifndef __UM_CACHE_H +#define __UM_CACHE_H + + +#if defined(CONFIG_UML_X86) && !defined(CONFIG_64BIT) +# define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) +#elif defined(CONFIG_UML_X86) /* 64-bit */ +# define L1_CACHE_SHIFT 6 /* Should be 7 on Intel */ +#else +/* XXX: this was taken from x86, now it's completely random. Luckily only + * affects SMP padding. */ +# define L1_CACHE_SHIFT 5 +#endif + +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + +#endif diff --git a/arch/um/include/asm/common.lds.S b/arch/um/include/asm/common.lds.S new file mode 100644 index 00000000000..1dd5bd8a8c5 --- /dev/null +++ b/arch/um/include/asm/common.lds.S @@ -0,0 +1,107 @@ +#include <asm-generic/vmlinux.lds.h> + + .fini : { *(.fini) } =0x9090 + _etext = .; + PROVIDE (etext = .); + + . = ALIGN(4096); + _sdata = .; + PROVIDE (sdata = .); + + RODATA + + .unprotected : { *(.unprotected) } + . = ALIGN(4096); + PROVIDE (_unprotected_end = .); + + . = ALIGN(4096); + .note : { *(.note.*) } + EXCEPTION_TABLE(0) + + BUG_TABLE + + .uml.setup.init : { + __uml_setup_start = .; + *(.uml.setup.init) + __uml_setup_end = .; + } + + .uml.help.init : { + __uml_help_start = .; + *(.uml.help.init) + __uml_help_end = .; + } + + .uml.postsetup.init : { + __uml_postsetup_start = .; + *(.uml.postsetup.init) + __uml_postsetup_end = .; + } + + .init.setup : { + INIT_SETUP(0) + } + + PERCPU_SECTION(32) + + .initcall.init : { + INIT_CALLS + } + + .con_initcall.init : { + CON_INITCALL + } + + .uml.initcall.init : { + __uml_initcall_start = .; + *(.uml.initcall.init) + __uml_initcall_end = .; + } + + SECURITY_INIT + + .exitcall : { + __exitcall_begin = .; + *(.exitcall.exit) + __exitcall_end = .; + } + + .uml.exitcall : { + __uml_exitcall_begin = .; + *(.uml.exitcall.exit) + __uml_exitcall_end = .; + } + + . = ALIGN(4); + .altinstructions : { + __alt_instructions = .; + *(.altinstructions) + __alt_instructions_end = .; + } + .altinstr_replacement : { *(.altinstr_replacement) } + /* .exit.text is discard at runtime, not link time, to deal with references + from .altinstructions and .eh_frame */ + .exit.text : { *(.exit.text) } + .exit.data : { *(.exit.data) } + + .preinit_array : { + __preinit_array_start = .; + *(.preinit_array) + __preinit_array_end = .; + } + .init_array : { + __init_array_start = .; + *(.init_array) + __init_array_end = .; + } + .fini_array : { + __fini_array_start = .; + *(.fini_array) + __fini_array_end = .; + } + + . = ALIGN(4096); + .init.ramfs : { + INIT_RAM_FS + } + diff --git a/arch/um/include/asm/dma.h b/arch/um/include/asm/dma.h new file mode 100644 index 00000000000..f88c5860520 --- /dev/null +++ b/arch/um/include/asm/dma.h @@ -0,0 +1,10 @@ +#ifndef __UM_DMA_H +#define __UM_DMA_H + +#include <asm/io.h> + +extern unsigned long uml_physmem; + +#define MAX_DMA_ADDRESS (uml_physmem) + +#endif diff --git a/arch/um/include/asm/fixmap.h b/arch/um/include/asm/fixmap.h new file mode 100644 index 00000000000..3094ea3c73b --- /dev/null +++ b/arch/um/include/asm/fixmap.h @@ -0,0 +1,60 @@ +#ifndef __UM_FIXMAP_H +#define __UM_FIXMAP_H + +#include <asm/processor.h> +#include <asm/kmap_types.h> +#include <asm/archparam.h> +#include <asm/page.h> +#include <linux/threads.h> + +/* + * Here we define all the compile-time 'special' virtual + * addresses. The point is to have a constant address at + * compile time, but to set the physical address only + * in the boot process. We allocate these special addresses + * from the end of virtual memory (0xfffff000) backwards. + * Also this lets us do fail-safe vmalloc(), we + * can guarantee that these special addresses and + * vmalloc()-ed addresses never overlap. + * + * these 'compile-time allocated' memory buffers are + * fixed-size 4k pages. (or larger if used with an increment + * highger than 1) use fixmap_set(idx,phys) to associate + * physical memory with fixmap indices. + * + * TLB entries of such buffers will not be flushed across + * task switches. + */ + +/* + * on UP currently we will have no trace of the fixmap mechanizm, + * no page table allocations, etc. This might change in the + * future, say framebuffers for the console driver(s) could be + * fix-mapped? + */ +enum fixed_addresses { +#ifdef CONFIG_HIGHMEM + FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ + FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, +#endif + __end_of_fixed_addresses +}; + +extern void __set_fixmap (enum fixed_addresses idx, + unsigned long phys, pgprot_t flags); + +/* + * used by vmalloc.c. + * + * Leave one empty page between vmalloc'ed areas and + * the start of the fixmap, and leave one page empty + * at the top of mem.. + */ + +#define FIXADDR_TOP (TASK_SIZE - 2 * PAGE_SIZE) +#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) +#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) + +#include <asm-generic/fixmap.h> + +#endif diff --git a/arch/um/include/asm/irq.h b/arch/um/include/asm/irq.h new file mode 100644 index 00000000000..4a2037f8204 --- /dev/null +++ b/arch/um/include/asm/irq.h @@ -0,0 +1,23 @@ +#ifndef __UM_IRQ_H +#define __UM_IRQ_H + +#define TIMER_IRQ 0 +#define UMN_IRQ 1 +#define CONSOLE_IRQ 2 +#define CONSOLE_WRITE_IRQ 3 +#define UBD_IRQ 4 +#define UM_ETH_IRQ 5 +#define SSL_IRQ 6 +#define SSL_WRITE_IRQ 7 +#define ACCEPT_IRQ 8 +#define MCONSOLE_IRQ 9 +#define WINCH_IRQ 10 +#define SIGIO_WRITE_IRQ 11 +#define TELNETD_IRQ 12 +#define XTERM_IRQ 13 +#define RANDOM_IRQ 14 + +#define LAST_IRQ RANDOM_IRQ +#define NR_IRQS (LAST_IRQ + 1) + +#endif diff --git a/arch/um/include/asm/irqflags.h b/arch/um/include/asm/irqflags.h new file mode 100644 index 00000000000..c780d8a1677 --- /dev/null +++ b/arch/um/include/asm/irqflags.h @@ -0,0 +1,42 @@ +#ifndef __UM_IRQFLAGS_H +#define __UM_IRQFLAGS_H + +extern int get_signals(void); +extern int set_signals(int enable); +extern void block_signals(void); +extern void unblock_signals(void); + +static inline unsigned long arch_local_save_flags(void) +{ + return get_signals(); +} + +static inline void arch_local_irq_restore(unsigned long flags) +{ + set_signals(flags); +} + +static inline void arch_local_irq_enable(void) +{ + unblock_signals(); +} + +static inline void arch_local_irq_disable(void) +{ + block_signals(); +} + +static inline unsigned long arch_local_irq_save(void) +{ + unsigned long flags; + flags = arch_local_save_flags(); + arch_local_irq_disable(); + return flags; +} + +static inline bool arch_irqs_disabled(void) +{ + return arch_local_save_flags() == 0; +} + +#endif diff --git a/arch/um/include/asm/kmap_types.h b/arch/um/include/asm/kmap_types.h new file mode 100644 index 00000000000..2e0a6b1d830 --- /dev/null +++ b/arch/um/include/asm/kmap_types.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __UM_KMAP_TYPES_H +#define __UM_KMAP_TYPES_H + +/* No more #include "asm/arch/kmap_types.h" ! */ + +#define KM_TYPE_NR 14 + +#endif diff --git a/arch/um/include/asm/kvm_para.h b/arch/um/include/asm/kvm_para.h new file mode 100644 index 00000000000..14fab8f0b95 --- /dev/null +++ b/arch/um/include/asm/kvm_para.h @@ -0,0 +1 @@ +#include <asm-generic/kvm_para.h> diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h new file mode 100644 index 00000000000..da705448590 --- /dev/null +++ b/arch/um/include/asm/mmu.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __ARCH_UM_MMU_H +#define __ARCH_UM_MMU_H + +#include <mm_id.h> +#include <asm/mm_context.h> + +typedef struct mm_context { + struct mm_id id; + struct uml_arch_mm_context arch; + struct page *stub_pages[2]; +} mm_context_t; + +extern void __switch_mm(struct mm_id * mm_idp); + +/* Avoid tangled inclusion with asm/ldt.h */ +extern long init_new_ldt(struct mm_context *to_mm, struct mm_context *from_mm); +extern void free_ldt(struct mm_context *mm); + +#endif diff --git a/arch/um/include/asm/mmu_context.h b/arch/um/include/asm/mmu_context.h new file mode 100644 index 00000000000..aa4a743dc4a --- /dev/null +++ b/arch/um/include/asm/mmu_context.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __UM_MMU_CONTEXT_H +#define __UM_MMU_CONTEXT_H + +#include <linux/sched.h> +#include <asm/mmu.h> + +extern void uml_setup_stubs(struct mm_struct *mm); +extern void arch_exit_mmap(struct mm_struct *mm); + +#define deactivate_mm(tsk,mm) do { } while (0) + +extern void force_flush_all(void); + +static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) +{ + /* + * This is called by fs/exec.c and sys_unshare() + * when the new ->mm is used for the first time. + */ + __switch_mm(&new->context.id); + down_write(&new->mmap_sem); + uml_setup_stubs(new); + up_write(&new->mmap_sem); +} + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ + unsigned cpu = smp_processor_id(); + + if(prev != next){ + cpumask_clear_cpu(cpu, mm_cpumask(prev)); + cpumask_set_cpu(cpu, mm_cpumask(next)); + if(next != &init_mm) + __switch_mm(&next->context.id); + } +} + +static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) +{ + uml_setup_stubs(mm); +} + +static inline void enter_lazy_tlb(struct mm_struct *mm, + struct task_struct *tsk) +{ +} + +extern int init_new_context(struct task_struct *task, struct mm_struct *mm); + +extern void destroy_context(struct mm_struct *mm); + +#endif diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h new file mode 100644 index 00000000000..5ff53d9185f --- /dev/null +++ b/arch/um/include/asm/page.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright 2003 PathScale, Inc. + * Licensed under the GPL + */ + +#ifndef __UM_PAGE_H +#define __UM_PAGE_H + +#include <linux/const.h> + +/* PAGE_SHIFT determines the page size */ +#define PAGE_SHIFT 12 +#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#ifndef __ASSEMBLY__ + +struct page; + +#include <linux/types.h> +#include <asm/vm-flags.h> + +/* + * These are used to make use of C type-checking.. + */ + +#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) +#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) + +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +#if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64BIT) + +typedef struct { unsigned long pte_low, pte_high; } pte_t; +typedef struct { unsigned long pmd; } pmd_t; +typedef struct { unsigned long pgd; } pgd_t; +#define pte_val(x) ((x).pte_low | ((unsigned long long) (x).pte_high << 32)) + +#define pte_get_bits(pte, bits) ((pte).pte_low & (bits)) +#define pte_set_bits(pte, bits) ((pte).pte_low |= (bits)) +#define pte_clear_bits(pte, bits) ((pte).pte_low &= ~(bits)) +#define pte_copy(to, from) ({ (to).pte_high = (from).pte_high; \ + smp_wmb(); \ + (to).pte_low = (from).pte_low; }) +#define pte_is_zero(pte) (!((pte).pte_low & ~_PAGE_NEWPAGE) && !(pte).pte_high) +#define pte_set_val(pte, phys, prot) \ + ({ (pte).pte_high = (phys) >> 32; \ + (pte).pte_low = (phys) | pgprot_val(prot); }) + +#define pmd_val(x) ((x).pmd) +#define __pmd(x) ((pmd_t) { (x) } ) + +typedef unsigned long long pfn_t; +typedef unsigned long long phys_t; + +#else + +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pgd; } pgd_t; + +#ifdef CONFIG_3_LEVEL_PGTABLES +typedef struct { unsigned long pmd; } pmd_t; +#define pmd_val(x) ((x).pmd) +#define __pmd(x) ((pmd_t) { (x) } ) +#endif + +#define pte_val(x) ((x).pte) + + +#define pte_get_bits(p, bits) ((p).pte & (bits)) +#define pte_set_bits(p, bits) ((p).pte |= (bits)) +#define pte_clear_bits(p, bits) ((p).pte &= ~(bits)) +#define pte_copy(to, from) ((to).pte = (from).pte) +#define pte_is_zero(p) (!((p).pte & ~_PAGE_NEWPAGE)) +#define pte_set_val(p, phys, prot) (p).pte = (phys | pgprot_val(prot)) + +typedef unsigned long pfn_t; +typedef unsigned long phys_t; + +#endif + +typedef struct { unsigned long pgprot; } pgprot_t; + +typedef struct page *pgtable_t; + +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +extern unsigned long uml_physmem; + +#define PAGE_OFFSET (uml_physmem) +#define KERNELBASE PAGE_OFFSET + +#define __va_space (8*1024*1024) + +#include <mem.h> + +/* Cast to unsigned long before casting to void * to avoid a warning from + * mmap_kmem about cutting a long long down to a void *. Not sure that + * casting is the right thing, but 32-bit UML can't have 64-bit virtual + * addresses + */ +#define __pa(virt) to_phys((void *) (unsigned long) (virt)) +#define __va(phys) to_virt((unsigned long) (phys)) + +#define phys_to_pfn(p) ((pfn_t) ((p) >> PAGE_SHIFT)) +#define pfn_to_phys(pfn) ((phys_t) ((pfn) << PAGE_SHIFT)) + +#define pfn_valid(pfn) ((pfn) < max_mapnr) +#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v))) + +#include <asm-generic/memory_model.h> +#include <asm-generic/getorder.h> + +#endif /* __ASSEMBLY__ */ +#endif /* __UM_PAGE_H */ diff --git a/arch/um/include/asm/pgalloc.h b/arch/um/include/asm/pgalloc.h new file mode 100644 index 00000000000..bf90b2aa200 --- /dev/null +++ b/arch/um/include/asm/pgalloc.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. + * Derived from include/asm-i386/pgalloc.h and include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGALLOC_H +#define __UM_PGALLOC_H + +#include <linux/mm.h> + +#define pmd_populate_kernel(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte))) + +#define pmd_populate(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + \ + ((unsigned long long)page_to_pfn(pte) << \ + (unsigned long long) PAGE_SHIFT))) +#define pmd_pgtable(pmd) pmd_page(pmd) + +/* + * Allocate and free page tables. + */ +extern pgd_t *pgd_alloc(struct mm_struct *); +extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); + +extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long); +extern pgtable_t pte_alloc_one(struct mm_struct *, unsigned long); + +static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) +{ + free_page((unsigned long) pte); +} + +static inline void pte_free(struct mm_struct *mm, pgtable_t pte) +{ + pgtable_page_dtor(pte); + __free_page(pte); +} + +#define __pte_free_tlb(tlb,pte, address) \ +do { \ + pgtable_page_dtor(pte); \ + tlb_remove_page((tlb),(pte)); \ +} while (0) + +#ifdef CONFIG_3_LEVEL_PGTABLES + +static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) +{ + free_page((unsigned long)pmd); +} + +#define __pmd_free_tlb(tlb,x, address) tlb_remove_page((tlb),virt_to_page(x)) +#endif + +#define check_pgt_cache() do { } while (0) + +#endif + diff --git a/arch/um/include/asm/pgtable-2level.h b/arch/um/include/asm/pgtable-2level.h new file mode 100644 index 00000000000..f534b73e753 --- /dev/null +++ b/arch/um/include/asm/pgtable-2level.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. + * Derived from include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGTABLE_2LEVEL_H +#define __UM_PGTABLE_2LEVEL_H + +#include <asm-generic/pgtable-nopmd.h> + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ + +#define PGDIR_SHIFT 22 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * entries per page directory level: the i386 is two-level, so + * we don't really have any PMD directory physically. + */ +#define PTRS_PER_PTE 1024 +#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE) +#define PTRS_PER_PGD 1024 +#define FIRST_USER_ADDRESS 0 + +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %p(%08lx).\n", __FILE__, __LINE__, &(e), \ + pte_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %p(%08lx).\n", __FILE__, __LINE__, &(e), \ + pgd_val(e)) + +static inline int pgd_newpage(pgd_t pgd) { return 0; } +static inline void pgd_mkuptodate(pgd_t pgd) { } + +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval)) + +#define pte_pfn(x) phys_to_pfn(pte_val(x)) +#define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot)) +#define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot)) + +/* + * Bits 0 through 4 are taken + */ +#define PTE_FILE_MAX_BITS 27 + +#define pte_to_pgoff(pte) (pte_val(pte) >> 5) + +#define pgoff_to_pte(off) ((pte_t) { ((off) << 5) + _PAGE_FILE }) + +#endif diff --git a/arch/um/include/asm/pgtable-3level.h b/arch/um/include/asm/pgtable-3level.h new file mode 100644 index 00000000000..0032f9212e7 --- /dev/null +++ b/arch/um/include/asm/pgtable-3level.h @@ -0,0 +1,136 @@ +/* + * Copyright 2003 PathScale Inc + * Derived from include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGTABLE_3LEVEL_H +#define __UM_PGTABLE_3LEVEL_H + +#include <asm-generic/pgtable-nopud.h> + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ + +#ifdef CONFIG_64BIT +#define PGDIR_SHIFT 30 +#else +#define PGDIR_SHIFT 31 +#endif +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* PMD_SHIFT determines the size of the area a second-level page table can + * map + */ + +#define PMD_SHIFT 21 +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* + * entries per page directory level + */ + +#define PTRS_PER_PTE 512 +#ifdef CONFIG_64BIT +#define PTRS_PER_PMD 512 +#define PTRS_PER_PGD 512 +#else +#define PTRS_PER_PMD 1024 +#define PTRS_PER_PGD 1024 +#endif + +#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE) +#define FIRST_USER_ADDRESS 0 + +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pte_val(e)) +#define pmd_ERROR(e) \ + printk("%s:%d: bad pmd %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pmd_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pgd_val(e)) + +#define pud_none(x) (!(pud_val(x) & ~_PAGE_NEWPAGE)) +#define pud_bad(x) ((pud_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) +#define pud_present(x) (pud_val(x) & _PAGE_PRESENT) +#define pud_populate(mm, pud, pmd) \ + set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd))) + +#ifdef CONFIG_64BIT +#define set_pud(pudptr, pudval) set_64bit((u64 *) (pudptr), pud_val(pudval)) +#else +#define set_pud(pudptr, pudval) (*(pudptr) = (pudval)) +#endif + +static inline int pgd_newpage(pgd_t pgd) +{ + return(pgd_val(pgd) & _PAGE_NEWPAGE); +} + +static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; } + +#ifdef CONFIG_64BIT +#define set_pmd(pmdptr, pmdval) set_64bit((u64 *) (pmdptr), pmd_val(pmdval)) +#else +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval)) +#endif + +struct mm_struct; +extern pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address); + +static inline void pud_clear (pud_t *pud) +{ + set_pud(pud, __pud(_PAGE_NEWPAGE)); +} + +#define pud_page(pud) phys_to_page(pud_val(pud) & PAGE_MASK) +#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PAGE_MASK)) + +/* Find an entry in the second-level page table.. */ +#define pmd_offset(pud, address) ((pmd_t *) pud_page_vaddr(*(pud)) + \ + pmd_index(address)) + +static inline unsigned long pte_pfn(pte_t pte) +{ + return phys_to_pfn(pte_val(pte)); +} + +static inline pte_t pfn_pte(pfn_t page_nr, pgprot_t pgprot) +{ + pte_t pte; + phys_t phys = pfn_to_phys(page_nr); + + pte_set_val(pte, phys, pgprot); + return pte; +} + +static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot) +{ + return __pmd((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); +} + +/* + * Bits 0 through 3 are taken in the low part of the pte, + * put the 32 bits of offset into the high part. + */ +#define PTE_FILE_MAX_BITS 32 + +#ifdef CONFIG_64BIT + +#define pte_to_pgoff(p) ((p).pte >> 32) + +#define pgoff_to_pte(off) ((pte_t) { ((off) << 32) | _PAGE_FILE }) + +#else + +#define pte_to_pgoff(pte) ((pte).pte_high) + +#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) }) + +#endif + +#endif + diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h new file mode 100644 index 00000000000..bf974f712af --- /dev/null +++ b/arch/um/include/asm/pgtable.h @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright 2003 PathScale, Inc. + * Derived from include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGTABLE_H +#define __UM_PGTABLE_H + +#include <asm/fixmap.h> + +#define _PAGE_PRESENT 0x001 +#define _PAGE_NEWPAGE 0x002 +#define _PAGE_NEWPROT 0x004 +#define _PAGE_RW 0x020 +#define _PAGE_USER 0x040 +#define _PAGE_ACCESSED 0x080 +#define _PAGE_DIRTY 0x100 +/* If _PAGE_PRESENT is clear, we use these: */ +#define _PAGE_FILE 0x008 /* nonlinear file mapping, saved PTE; unset:swap */ +#define _PAGE_PROTNONE 0x010 /* if the user mapped it with PROT_NONE; + pte_present gives true */ + +#ifdef CONFIG_3_LEVEL_PGTABLES +#include <asm/pgtable-3level.h> +#else +#include <asm/pgtable-2level.h> +#endif + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +/* zero page used for uninitialized stuff */ +extern unsigned long *empty_zero_page; + +#define pgtable_cache_init() do ; while (0) + +/* Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ + +extern unsigned long end_iomem; + +#define VMALLOC_OFFSET (__va_space) +#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define PKMAP_BASE ((FIXADDR_START - LAST_PKMAP * PAGE_SIZE) & PMD_MASK) +#ifdef CONFIG_HIGHMEM +# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) +#else +# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) +#endif +#define MODULES_VADDR VMALLOC_START +#define MODULES_END VMALLOC_END +#define MODULES_LEN (MODULES_VADDR - MODULES_END) + +#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) +#define __PAGE_KERNEL_EXEC \ + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) +#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) + +/* + * The i386 can't do page protection for execute, and considers that the same + * are read. + * Also, write permissions imply read permissions. This is the closest we can + * get.. + */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY +#define __P101 PAGE_READONLY +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY +#define __S101 PAGE_READONLY +#define __S110 PAGE_SHARED +#define __S111 PAGE_SHARED + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) + +#define pte_clear(mm,addr,xp) pte_set_val(*(xp), (phys_t) 0, __pgprot(_PAGE_NEWPAGE)) + +#define pmd_none(x) (!((unsigned long)pmd_val(x) & ~_PAGE_NEWPAGE)) +#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) + +#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) +#define pmd_clear(xp) do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0) + +#define pmd_newpage(x) (pmd_val(x) & _PAGE_NEWPAGE) +#define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEWPAGE) + +#define pud_newpage(x) (pud_val(x) & _PAGE_NEWPAGE) +#define pud_mkuptodate(x) (pud_val(x) &= ~_PAGE_NEWPAGE) + +#define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK) + +#define pte_page(x) pfn_to_page(pte_pfn(x)) + +#define pte_present(x) pte_get_bits(x, (_PAGE_PRESENT | _PAGE_PROTNONE)) + +/* + * ================================= + * Flags checking section. + * ================================= + */ + +static inline int pte_none(pte_t pte) +{ + return pte_is_zero(pte); +} + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +static inline int pte_read(pte_t pte) +{ + return((pte_get_bits(pte, _PAGE_USER)) && + !(pte_get_bits(pte, _PAGE_PROTNONE))); +} + +static inline int pte_exec(pte_t pte){ + return((pte_get_bits(pte, _PAGE_USER)) && + !(pte_get_bits(pte, _PAGE_PROTNONE))); +} + +static inline int pte_write(pte_t pte) +{ + return((pte_get_bits(pte, _PAGE_RW)) && + !(pte_get_bits(pte, _PAGE_PROTNONE))); +} + +/* + * The following only works if pte_present() is not true. + */ +static inline int pte_file(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_FILE); +} + +static inline int pte_dirty(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_DIRTY); +} + +static inline int pte_young(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_ACCESSED); +} + +static inline int pte_newpage(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_NEWPAGE); +} + +static inline int pte_newprot(pte_t pte) +{ + return(pte_present(pte) && (pte_get_bits(pte, _PAGE_NEWPROT))); +} + +static inline int pte_special(pte_t pte) +{ + return 0; +} + +/* + * ================================= + * Flags setting section. + * ================================= + */ + +static inline pte_t pte_mknewprot(pte_t pte) +{ + pte_set_bits(pte, _PAGE_NEWPROT); + return(pte); +} + +static inline pte_t pte_mkclean(pte_t pte) +{ + pte_clear_bits(pte, _PAGE_DIRTY); + return(pte); +} + +static inline pte_t pte_mkold(pte_t pte) +{ + pte_clear_bits(pte, _PAGE_ACCESSED); + return(pte); +} + +static inline pte_t pte_wrprotect(pte_t pte) +{ + pte_clear_bits(pte, _PAGE_RW); + return(pte_mknewprot(pte)); +} + +static inline pte_t pte_mkread(pte_t pte) +{ + pte_set_bits(pte, _PAGE_USER); + return(pte_mknewprot(pte)); +} + +static inline pte_t pte_mkdirty(pte_t pte) +{ + pte_set_bits(pte, _PAGE_DIRTY); + return(pte); +} + +static inline pte_t pte_mkyoung(pte_t pte) +{ + pte_set_bits(pte, _PAGE_ACCESSED); + return(pte); +} + +static inline pte_t pte_mkwrite(pte_t pte) +{ + pte_set_bits(pte, _PAGE_RW); + return(pte_mknewprot(pte)); +} + +static inline pte_t pte_mkuptodate(pte_t pte) +{ + pte_clear_bits(pte, _PAGE_NEWPAGE); + if(pte_present(pte)) + pte_clear_bits(pte, _PAGE_NEWPROT); + return(pte); +} + +static inline pte_t pte_mknewpage(pte_t pte) +{ + pte_set_bits(pte, _PAGE_NEWPAGE); + return(pte); +} + +static inline pte_t pte_mkspecial(pte_t pte) +{ + return(pte); +} + +static inline void set_pte(pte_t *pteptr, pte_t pteval) +{ + pte_copy(*pteptr, pteval); + + /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so + * fix_range knows to unmap it. _PAGE_NEWPROT is specific to + * mapped pages. + */ + + *pteptr = pte_mknewpage(*pteptr); + if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr); +} +#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) + +#define __HAVE_ARCH_PTE_SAME +static inline int pte_same(pte_t pte_a, pte_t pte_b) +{ + return !((pte_val(pte_a) ^ pte_val(pte_b)) & ~_PAGE_NEWPAGE); +} + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ + +#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys)) +#define __virt_to_page(virt) phys_to_page(__pa(virt)) +#define page_to_phys(page) pfn_to_phys((pfn_t) page_to_pfn(page)) +#define virt_to_page(addr) __virt_to_page((const unsigned long) addr) + +#define mk_pte(page, pgprot) \ + ({ pte_t pte; \ + \ + pte_set_val(pte, page_to_phys(page), (pgprot)); \ + if (pte_present(pte)) \ + pte_mknewprot(pte_mknewpage(pte)); \ + pte;}) + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + pte_set_val(pte, (pte_val(pte) & _PAGE_CHG_MASK), newprot); + return pte; +} + +/* + * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD] + * + * this macro returns the index of the entry in the pgd page which would + * control the given virtual address + */ +#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) + +/* + * pgd_offset() returns a (pgd_t *) + * pgd_index() is used get the offset into the pgd page's array of pgd_t's; + */ +#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) + +/* + * a shortcut which implies the use of the kernel's pgd, instead + * of a process's + */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +/* + * the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD] + * + * this macro returns the index of the entry in the pmd page which would + * control the given virtual address + */ +#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) +#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) + +#define pmd_page_vaddr(pmd) \ + ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) + +/* + * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] + * + * this macro returns the index of the entry in the pte page which would + * control the given virtual address + */ +#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset_kernel(dir, address) \ + ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address)) +#define pte_offset_map(dir, address) \ + ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address)) +#define pte_unmap(pte) do { } while (0) + +struct mm_struct; +extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr); + +#define update_mmu_cache(vma,address,ptep) do ; while (0) + +/* Encode and de-code a swap entry */ +#define __swp_type(x) (((x).val >> 5) & 0x1f) +#define __swp_offset(x) ((x).val >> 11) + +#define __swp_entry(type, offset) \ + ((swp_entry_t) { ((type) << 5) | ((offset) << 11) }) +#define __pte_to_swp_entry(pte) \ + ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +#define kern_addr_valid(addr) (1) + +#include <asm-generic/pgtable.h> + +/* Clear a kernel PTE and flush it from the TLB */ +#define kpte_clear_flush(ptep, vaddr) \ +do { \ + pte_clear(&init_mm, (vaddr), (ptep)); \ + __flush_tlb_one((vaddr)); \ +} while (0) + +#endif diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h new file mode 100644 index 00000000000..cbc5edd5a90 --- /dev/null +++ b/arch/um/include/asm/processor-generic.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __UM_PROCESSOR_GENERIC_H +#define __UM_PROCESSOR_GENERIC_H + +struct pt_regs; + +struct task_struct; + +#include <asm/ptrace.h> +#include <registers.h> +#include <sysdep/archsetjmp.h> + +#include <linux/prefetch.h> + +struct mm_struct; + +struct thread_struct { + struct pt_regs regs; + struct pt_regs *segv_regs; + int singlestep_syscall; + void *fault_addr; + jmp_buf *fault_catcher; + struct task_struct *prev_sched; + struct arch_thread arch; + jmp_buf switch_buf; + struct { + int op; + union { + struct { + int pid; + } fork, exec; + struct { + int (*proc)(void *); + void *arg; + } thread; + struct { + void (*proc)(void *); + void *arg; + } cb; + } u; + } request; +}; + +#define INIT_THREAD \ +{ \ + .regs = EMPTY_REGS, \ + .fault_addr = NULL, \ + .prev_sched = NULL, \ + .arch = INIT_ARCH_THREAD, \ + .request = { 0 } \ +} + +static inline void release_thread(struct task_struct *task) +{ +} + +extern unsigned long thread_saved_pc(struct task_struct *t); + +static inline void mm_copy_segments(struct mm_struct *from_mm, + struct mm_struct *new_mm) +{ +} + +#define init_stack (init_thread_union.stack) + +/* + * User space process size: 3GB (default). + */ +extern unsigned long task_size; + +#define TASK_SIZE (task_size) + +#undef STACK_TOP +#undef STACK_TOP_MAX + +extern unsigned long stacksizelim; + +#define STACK_ROOM (stacksizelim) +#define STACK_TOP (TASK_SIZE - 2 * PAGE_SIZE) +#define STACK_TOP_MAX STACK_TOP + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (0x40000000) + +extern void start_thread(struct pt_regs *regs, unsigned long entry, + unsigned long stack); + +struct cpuinfo_um { + unsigned long loops_per_jiffy; + int ipi_pipe[2]; +}; + +extern struct cpuinfo_um boot_cpu_data; + +#define my_cpu_data cpu_data[smp_processor_id()] + +#ifdef CONFIG_SMP +extern struct cpuinfo_um cpu_data[]; +#define current_cpu_data cpu_data[smp_processor_id()] +#else +#define cpu_data (&boot_cpu_data) +#define current_cpu_data boot_cpu_data +#endif + + +#define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf) +extern unsigned long get_wchan(struct task_struct *p); + +#endif diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h new file mode 100644 index 00000000000..cb9b3c47ca8 --- /dev/null +++ b/arch/um/include/asm/ptrace-generic.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __UM_PTRACE_GENERIC_H +#define __UM_PTRACE_GENERIC_H + +#ifndef __ASSEMBLY__ + +#include <asm/ptrace-abi.h> +#include <sysdep/ptrace.h> + +struct pt_regs { + struct uml_pt_regs regs; +}; + +#define arch_has_single_step() (1) + +#define EMPTY_REGS { .regs = EMPTY_UML_PT_REGS } + +#define PT_REGS_IP(r) UPT_IP(&(r)->regs) +#define PT_REGS_SP(r) UPT_SP(&(r)->regs) + +#define PT_REGS_RESTART_SYSCALL(r) UPT_RESTART_SYSCALL(&(r)->regs) + +#define PT_REGS_SYSCALL_NR(r) UPT_SYSCALL_NR(&(r)->regs) + +#define instruction_pointer(regs) PT_REGS_IP(regs) + +struct task_struct; + +extern long subarch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data); +extern unsigned long getreg(struct task_struct *child, int regno); +extern int putreg(struct task_struct *child, int regno, unsigned long value); + +extern int arch_copy_tls(struct task_struct *new); +extern void clear_flushed_tls(struct task_struct *task); +extern void syscall_trace_enter(struct pt_regs *regs); +extern void syscall_trace_leave(struct pt_regs *regs); + +#endif + +#endif diff --git a/arch/um/include/asm/setup.h b/arch/um/include/asm/setup.h new file mode 100644 index 00000000000..99f086301f4 --- /dev/null +++ b/arch/um/include/asm/setup.h @@ -0,0 +1,10 @@ +#ifndef SETUP_H_INCLUDED +#define SETUP_H_INCLUDED + +/* POSIX mandated with _POSIX_ARG_MAX that we can rely on 4096 chars in the + * command line, so this choice is ok. + */ + +#define COMMAND_LINE_SIZE 4096 + +#endif /* SETUP_H_INCLUDED */ diff --git a/arch/um/include/asm/smp.h b/arch/um/include/asm/smp.h new file mode 100644 index 00000000000..e4507938d8c --- /dev/null +++ b/arch/um/include/asm/smp.h @@ -0,0 +1,32 @@ +#ifndef __UM_SMP_H +#define __UM_SMP_H + +#ifdef CONFIG_SMP + +#include <linux/bitops.h> +#include <asm/current.h> +#include <linux/cpumask.h> + +#define raw_smp_processor_id() (current_thread->cpu) + +#define cpu_logical_map(n) (n) +#define cpu_number_map(n) (n) +extern int hard_smp_processor_id(void); +#define NO_PROC_ID -1 + +extern int ncpus; + + +static inline void smp_cpus_done(unsigned int maxcpus) +{ +} + +extern struct task_struct *idle_threads[NR_CPUS]; + +#else + +#define hard_smp_processor_id() 0 + +#endif + +#endif diff --git a/arch/um/include/sysrq.h b/arch/um/include/asm/sysrq.h index c8d332b56b9..c8d332b56b9 100644 --- a/arch/um/include/sysrq.h +++ b/arch/um/include/asm/sysrq.h diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h new file mode 100644 index 00000000000..1c5b2a83046 --- /dev/null +++ b/arch/um/include/asm/thread_info.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __UM_THREAD_INFO_H +#define __UM_THREAD_INFO_H + +#ifndef __ASSEMBLY__ + +#include <asm/types.h> +#include <asm/page.h> +#include <asm/uaccess.h> + +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + __u32 cpu; /* current CPU */ + int preempt_count; /* 0 => preemptable, + <0 => BUG */ + mm_segment_t addr_limit; /* thread address space: + 0-0xBFFFFFFF for user + 0-0xFFFFFFFF for kernel */ + struct restart_block restart_block; + struct thread_info *real_thread; /* Points to non-IRQ stack */ +}; + +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = INIT_PREEMPT_COUNT, \ + .addr_limit = KERNEL_DS, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ + .real_thread = NULL, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + +#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE) +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + struct thread_info *ti; + unsigned long mask = THREAD_SIZE - 1; + void *p; + + asm volatile ("" : "=r" (p) : "0" (&ti)); + ti = (struct thread_info *) (((unsigned long)p) & ~mask); + return ti; +} + +#define THREAD_SIZE_ORDER CONFIG_KERNEL_STACK_ORDER + +#endif + +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_SIGPENDING 1 /* signal pending */ +#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ +#define TIF_RESTART_BLOCK 4 +#define TIF_MEMDIE 5 /* is terminating due to OOM killer */ +#define TIF_SYSCALL_AUDIT 6 +#define TIF_RESTORE_SIGMASK 7 +#define TIF_NOTIFY_RESUME 8 + +#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_MEMDIE (1 << TIF_MEMDIE) +#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) + +#endif diff --git a/arch/um/include/asm/timex.h b/arch/um/include/asm/timex.h new file mode 100644 index 00000000000..0f4ada08f74 --- /dev/null +++ b/arch/um/include/asm/timex.h @@ -0,0 +1,13 @@ +#ifndef __UM_TIMEX_H +#define __UM_TIMEX_H + +typedef unsigned long cycles_t; + +static inline cycles_t get_cycles (void) +{ + return 0; +} + +#define CLOCK_TICK_RATE (HZ) + +#endif diff --git a/arch/um/include/asm/tlb.h b/arch/um/include/asm/tlb.h new file mode 100644 index 00000000000..16eb63fac57 --- /dev/null +++ b/arch/um/include/asm/tlb.h @@ -0,0 +1,134 @@ +#ifndef __UM_TLB_H +#define __UM_TLB_H + +#include <linux/pagemap.h> +#include <linux/swap.h> +#include <asm/percpu.h> +#include <asm/pgalloc.h> +#include <asm/tlbflush.h> + +#define tlb_start_vma(tlb, vma) do { } while (0) +#define tlb_end_vma(tlb, vma) do { } while (0) +#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) + +/* struct mmu_gather is an opaque type used by the mm code for passing around + * any data needed by arch specific code for tlb_remove_page. + */ +struct mmu_gather { + struct mm_struct *mm; + unsigned int need_flush; /* Really unmapped some ptes? */ + unsigned long start; + unsigned long end; + unsigned int fullmm; /* non-zero means full mm flush */ +}; + +static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, + unsigned long address) +{ + if (tlb->start > address) + tlb->start = address; + if (tlb->end < address + PAGE_SIZE) + tlb->end = address + PAGE_SIZE; +} + +static inline void init_tlb_gather(struct mmu_gather *tlb) +{ + tlb->need_flush = 0; + + tlb->start = TASK_SIZE; + tlb->end = 0; + + if (tlb->fullmm) { + tlb->start = 0; + tlb->end = TASK_SIZE; + } +} + +static inline void +tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end) +{ + tlb->mm = mm; + tlb->start = start; + tlb->end = end; + tlb->fullmm = !(start | (end+1)); + + init_tlb_gather(tlb); +} + +extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, + unsigned long end); + +static inline void +tlb_flush_mmu_tlbonly(struct mmu_gather *tlb) +{ + flush_tlb_mm_range(tlb->mm, tlb->start, tlb->end); +} + +static inline void +tlb_flush_mmu_free(struct mmu_gather *tlb) +{ + init_tlb_gather(tlb); +} + +static inline void +tlb_flush_mmu(struct mmu_gather *tlb) +{ + if (!tlb->need_flush) + return; + + tlb_flush_mmu_tlbonly(tlb); + tlb_flush_mmu_free(tlb); +} + +/* tlb_finish_mmu + * Called at the end of the shootdown operation to free up any resources + * that were required. + */ +static inline void +tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) +{ + tlb_flush_mmu(tlb); + + /* keep the page table cache within bounds */ + check_pgt_cache(); +} + +/* tlb_remove_page + * Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), + * while handling the additional races in SMP caused by other CPUs + * caching valid mappings in their TLBs. + */ +static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) +{ + tlb->need_flush = 1; + free_page_and_swap_cache(page); + return 1; /* avoid calling tlb_flush_mmu */ +} + +static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) +{ + __tlb_remove_page(tlb, page); +} + +/** + * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation. + * + * Record the fact that pte's were really umapped in ->need_flush, so we can + * later optimise away the tlb invalidate. This helps when userspace is + * unmapping already-unmapped pages, which happens quite a lot. + */ +#define tlb_remove_tlb_entry(tlb, ptep, address) \ + do { \ + tlb->need_flush = 1; \ + __tlb_remove_tlb_entry(tlb, ptep, address); \ + } while (0) + +#define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr) + +#define pud_free_tlb(tlb, pudp, addr) __pud_free_tlb(tlb, pudp, addr) + +#define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr) + +#define tlb_migrate_finish(mm) do {} while (0) + +#endif diff --git a/arch/um/include/asm/tlbflush.h b/arch/um/include/asm/tlbflush.h new file mode 100644 index 00000000000..614f2c09117 --- /dev/null +++ b/arch/um/include/asm/tlbflush.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __UM_TLBFLUSH_H +#define __UM_TLBFLUSH_H + +#include <linux/mm.h> + +/* + * TLB flushing: + * + * - flush_tlb() flushes the current mm struct TLBs + * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_kernel_vm() flushes the kernel vm area + * - flush_tlb_range(vma, start, end) flushes a range of pages + */ + +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long address); +extern void flush_tlb_kernel_vm(void); +extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); +extern void __flush_tlb_one(unsigned long addr); + +#endif diff --git a/arch/um/include/asm/uaccess.h b/arch/um/include/asm/uaccess.h new file mode 100644 index 00000000000..3f22fbf7ca1 --- /dev/null +++ b/arch/um/include/asm/uaccess.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __UM_UACCESS_H +#define __UM_UACCESS_H + +/* thread_info has a mm_segment_t in it, so put the definition up here */ +typedef struct { + unsigned long seg; +} mm_segment_t; + +#include <linux/thread_info.h> +#include <linux/errno.h> +#include <asm/processor.h> +#include <asm/elf.h> + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons, these macros are grossly misnamed. + */ + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) + +#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) +#define USER_DS MAKE_MM_SEG(TASK_SIZE) + +#define get_ds() (KERNEL_DS) +#define get_fs() (current_thread_info()->addr_limit) +#define set_fs(x) (current_thread_info()->addr_limit = (x)) + +#define segment_eq(a, b) ((a).seg == (b).seg) + +#define __under_task_size(addr, size) \ + (((unsigned long) (addr) < TASK_SIZE) && \ + (((unsigned long) (addr) + (size)) < TASK_SIZE)) + +#define __access_ok_vsyscall(type, addr, size) \ + ((type == VERIFY_READ) && \ + ((unsigned long) (addr) >= FIXADDR_USER_START) && \ + ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \ + ((unsigned long) (addr) + (size) >= (unsigned long)(addr))) + +#define __addr_range_nowrap(addr, size) \ + ((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) + +#define access_ok(type, addr, size) \ + (__addr_range_nowrap(addr, size) && \ + (__under_task_size(addr, size) || \ + __access_ok_vsyscall(type, addr, size) || \ + segment_eq(get_fs(), KERNEL_DS))) + +extern int copy_from_user(void *to, const void __user *from, int n); +extern int copy_to_user(void __user *to, const void *from, int n); + +/* + * strncpy_from_user: - Copy a NUL terminated string from userspace. + * @dst: Destination address, in kernel space. This buffer must be at + * least @count bytes long. + * @src: Source address, in user space. + * @count: Maximum number of bytes to copy, including the trailing NUL. + * + * Copies a NUL-terminated string from userspace to kernel space. + * + * On success, returns the length of the string (not including the trailing + * NUL). + * + * If access to userspace fails, returns -EFAULT (some data may have been + * copied). + * + * If @count is smaller than the length of the string, copies @count bytes + * and returns @count. + */ + +extern int strncpy_from_user(char *dst, const char __user *src, int count); + +/* + * __clear_user: - Zero a block of memory in user space, with less checking. + * @to: Destination address, in user space. + * @n: Number of bytes to zero. + * + * Zero a block of memory in user space. Caller must check + * the specified block with access_ok() before calling this function. + * + * Returns number of bytes that could not be cleared. + * On success, this will be zero. + */ +extern int __clear_user(void __user *mem, int len); + +/* + * clear_user: - Zero a block of memory in user space. + * @to: Destination address, in user space. + * @n: Number of bytes to zero. + * + * Zero a block of memory in user space. + * + * Returns number of bytes that could not be cleared. + * On success, this will be zero. + */ +extern int clear_user(void __user *mem, int len); + +/* + * strlen_user: - Get the size of a string in user space. + * @str: The string to measure. + * @n: The maximum valid length + * + * Get the size of a NUL-terminated string in user space. + * + * Returns the size of the string INCLUDING the terminating NUL. + * On exception, returns 0. + * If the string is too long, returns a value greater than @n. + */ +extern int strnlen_user(const void __user *str, int len); + +#define __copy_from_user(to, from, n) copy_from_user(to, from, n) + +#define __copy_to_user(to, from, n) copy_to_user(to, from, n) + +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + +#define __get_user(x, ptr) \ +({ \ + const __typeof__(*(ptr)) __user *__private_ptr = (ptr); \ + __typeof__(x) __private_val; \ + int __private_ret = -EFAULT; \ + (x) = (__typeof__(*(__private_ptr)))0; \ + if (__copy_from_user((__force void *)&__private_val, (__private_ptr),\ + sizeof(*(__private_ptr))) == 0) { \ + (x) = (__typeof__(*(__private_ptr))) __private_val; \ + __private_ret = 0; \ + } \ + __private_ret; \ +}) + +#define get_user(x, ptr) \ +({ \ + const __typeof__((*(ptr))) __user *private_ptr = (ptr); \ + (access_ok(VERIFY_READ, private_ptr, sizeof(*private_ptr)) ? \ + __get_user(x, private_ptr) : ((x) = (__typeof__(*ptr))0, -EFAULT)); \ +}) + +#define __put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) __user *__private_ptr = ptr; \ + __typeof__(*(__private_ptr)) __private_val; \ + int __private_ret = -EFAULT; \ + __private_val = (__typeof__(*(__private_ptr))) (x); \ + if (__copy_to_user((__private_ptr), &__private_val, \ + sizeof(*(__private_ptr))) == 0) { \ + __private_ret = 0; \ + } \ + __private_ret; \ +}) + +#define put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) __user *private_ptr = (ptr); \ + (access_ok(VERIFY_WRITE, private_ptr, sizeof(*private_ptr)) ? \ + __put_user(x, private_ptr) : -EFAULT); \ +}) + +#define strlen_user(str) strnlen_user(str, ~0U >> 1) + +struct exception_table_entry +{ + unsigned long insn; + unsigned long fixup; +}; + +#endif diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h deleted file mode 100644 index da9a6717e7a..00000000000 --- a/arch/um/include/chan_kern.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __CHAN_KERN_H__ -#define __CHAN_KERN_H__ - -#include "linux/tty.h" -#include "linux/list.h" -#include "linux/console.h" -#include "chan_user.h" -#include "line.h" - -struct chan { - struct list_head list; - char *dev; - unsigned int primary:1; - unsigned int input:1; - unsigned int output:1; - unsigned int opened:1; - int fd; - enum chan_init_pri pri; - struct chan_ops *ops; - void *data; -}; - -extern void chan_interrupt(struct list_head *chans, struct work_struct *task, - struct tty_struct *tty, int irq); -extern int parse_chan_pair(char *str, struct list_head *chans, int pri, - int device, struct chan_opts *opts); -extern int open_chan(struct list_head *chans); -extern int write_chan(struct list_head *chans, const char *buf, int len, - int write_irq); -extern int console_write_chan(struct list_head *chans, const char *buf, - int len); -extern int console_open_chan(struct line *line, struct console *co, - struct chan_opts *opts); -extern void close_chan(struct list_head *chans); -extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); -extern void enable_chan(struct list_head *chans, struct tty_struct *tty); -extern int chan_window_size(struct list_head *chans, - unsigned short *rows_out, - unsigned short *cols_out); -extern int chan_out_fd(struct list_head *chans); -extern int chan_config_string(struct list_head *chans, char *str, int size, - char **error_out); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h deleted file mode 100644 index f77d9aa4c16..00000000000 --- a/arch/um/include/chan_user.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __CHAN_USER_H__ -#define __CHAN_USER_H__ - -#include "init.h" - -struct chan_opts { - void (*announce)(char *dev_name, int dev); - char *xterm_title; - int raw; - unsigned long tramp_stack; - int in_kernel; -}; - -enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; - -struct chan_ops { - char *type; - void *(*init)(char *, int, struct chan_opts *); - int (*open)(int, int, int, void *, char **); - void (*close)(int, void *); - int (*read)(int, char *, void *); - int (*write)(int, const char *, int, void *); - int (*console_write)(int, const char *, int, void *); - int (*window_size)(int, void *, unsigned short *, unsigned short *); - void (*free)(void *); - int winch; -}; - -extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops, - xterm_ops; - -extern void generic_close(int fd, void *unused); -extern int generic_read(int fd, char *c_out, void *unused); -extern int generic_write(int fd, const char *buf, int n, void *unused); -extern int generic_console_write(int fd, const char *buf, int n, void *state); -extern int generic_window_size(int fd, void *unused, unsigned short *rows_out, - unsigned short *cols_out); -extern void generic_free(void *data); - -struct tty_struct; -extern void register_winch(int fd, struct tty_struct *tty); -extern void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty); - -#define __channel_help(fn, prefix) \ -__uml_help(fn, prefix "[0-9]*=<channel description>\n" \ -" Attach a console or serial line to a host channel. See\n" \ -" http://user-mode-linux.sourceforge.net/input.html for a complete\n" \ -" description of this switch.\n\n" \ -); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/choose-mode.h b/arch/um/include/choose-mode.h deleted file mode 100644 index f25fa83a5da..00000000000 --- a/arch/um/include/choose-mode.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __CHOOSE_MODE_H__ -#define __CHOOSE_MODE_H__ - -#include "uml-config.h" - -#if defined(UML_CONFIG_MODE_TT) && defined(UML_CONFIG_MODE_SKAS) -#define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas)) - -extern int mode_tt; -static inline void *__choose_mode(void *tt, void *skas) { - return mode_tt ? tt : skas; -} - -#define __CHOOSE_MODE(tt, skas) (*( (typeof(tt) *) __choose_mode(&(tt), &(skas)))) - -#elif defined(UML_CONFIG_MODE_SKAS) -#define CHOOSE_MODE(tt, skas) (skas) - -#elif defined(UML_CONFIG_MODE_TT) -#define CHOOSE_MODE(tt, skas) (tt) -#endif - -#define CHOOSE_MODE_PROC(tt, skas, args...) \ - CHOOSE_MODE(tt(args), skas(args)) - -#ifndef __CHOOSE_MODE -#define __CHOOSE_MODE(tt, skas) CHOOSE_MODE(tt, skas) -#endif - -#endif diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h deleted file mode 100644 index 356390d1f8b..00000000000 --- a/arch/um/include/common-offsets.h +++ /dev/null @@ -1,17 +0,0 @@ -/* for use by sys-$SUBARCH/kernel-offsets.c */ - -OFFSET(HOST_TASK_REGS, task_struct, thread.regs); -OFFSET(HOST_TASK_PID, task_struct, pid); -DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE); -DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC); -DEFINE_STR(UM_KERN_EMERG, KERN_EMERG); -DEFINE_STR(UM_KERN_ALERT, KERN_ALERT); -DEFINE_STR(UM_KERN_CRIT, KERN_CRIT); -DEFINE_STR(UM_KERN_ERR, KERN_ERR); -DEFINE_STR(UM_KERN_WARNING, KERN_WARNING); -DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE); -DEFINE_STR(UM_KERN_INFO, KERN_INFO); -DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG); -DEFINE(UM_ELF_CLASS, ELF_CLASS); -DEFINE(UM_ELFCLASS32, ELFCLASS32); -DEFINE(UM_ELFCLASS64, ELFCLASS64); diff --git a/arch/um/include/frame_kern.h b/arch/um/include/frame_kern.h deleted file mode 100644 index ce9514f5721..00000000000 --- a/arch/um/include/frame_kern.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __FRAME_KERN_H_ -#define __FRAME_KERN_H_ - -#define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) - -extern int setup_signal_stack_sc(unsigned long stack_top, int sig, - struct k_sigaction *ka, - struct pt_regs *regs, - sigset_t *mask); -extern int setup_signal_stack_si(unsigned long stack_top, int sig, - struct k_sigaction *ka, - struct pt_regs *regs, siginfo_t *info, - sigset_t *mask); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/initrd.h b/arch/um/include/initrd.h deleted file mode 100644 index 439b9a81498..00000000000 --- a/arch/um/include/initrd.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __INITRD_USER_H__ -#define __INITRD_USER_H__ - -extern int load_initrd(char *filename, void *buf, int size); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h deleted file mode 100644 index c222d56b149..00000000000 --- a/arch/um/include/irq_kern.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __IRQ_KERN_H__ -#define __IRQ_KERN_H__ - -#include "linux/interrupt.h" -#include "asm/ptrace.h" - -extern int um_request_irq(unsigned int irq, int fd, int type, - irqreturn_t (*handler)(int, void *, - struct pt_regs *), - unsigned long irqflags, const char * devname, - void *dev_id); -extern int init_aio_irq(int irq, char *name, - irqreturn_t (*handler)(int, void *, struct pt_regs *)); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h deleted file mode 100644 index f724b717213..00000000000 --- a/arch/um/include/irq_user.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __IRQ_USER_H__ -#define __IRQ_USER_H__ - -enum { IRQ_READ, IRQ_WRITE }; - -extern void sigio_handler(int sig, union uml_pt_regs *regs); -extern int activate_fd(int irq, int fd, int type, void *dev_id); -extern void free_irq_by_irq_and_dev(unsigned int irq, void *dev_id); -extern void free_irq_by_fd(int fd); -extern void reactivate_fd(int fd, int irqnum); -extern void deactivate_fd(int fd, int irqnum); -extern int deactivate_all_fds(void); -extern void forward_interrupts(int pid); -extern void init_irq_signals(int on_sigstack); -extern void forward_ipi(int fd, int pid); -extern void free_irq_later(int irq, void *dev_id); -extern int activate_ipi(int fd, int pid); -extern unsigned long irq_lock(void); -extern void irq_unlock(unsigned long flags); -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h deleted file mode 100644 index 1e3170768b5..00000000000 --- a/arch/um/include/kern.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __KERN_H__ -#define __KERN_H__ - -/* These are all user-mode things which are convenient to call directly - * from kernel code and for which writing a wrapper is too much of a pain. - * The regular include files can't be included because this file is included - * only into kernel code, and user-space includes conflict with kernel - * includes. - */ - -extern int errno; - -extern int clone(int (*proc)(void *), void *sp, int flags, void *data); -extern int sleep(int); -extern int printf(char *fmt, ...); -extern char *strerror(int errnum); -extern char *ptsname(int __fd); -extern int munmap(void *, int); -extern void *sbrk(int increment); -extern void *malloc(int size); -extern void perror(char *err); -extern int kill(int pid, int sig); -extern int getuid(void); -extern int getgid(void); -extern int pause(void); -extern int write(int, const void *, int); -extern int exit(int); -extern int close(int); -extern int read(unsigned int, char *, int); -extern int pipe(int *); -extern int sched_yield(void); -extern int ptrace(int op, int pid, long addr, long data); -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h deleted file mode 100644 index e5fec557019..00000000000 --- a/arch/um/include/kern_util.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __KERN_UTIL_H__ -#define __KERN_UTIL_H__ - -#include "linux/threads.h" -#include "sysdep/ptrace.h" -#include "sysdep/faultinfo.h" - -extern int ncpus; -extern char *linux_prog; -extern char *gdb_init; -extern int kmalloc_ok; -extern int timer_irq_inited; -extern int jail; -extern int nsyscalls; - -extern struct task_struct *idle_threads[NR_CPUS]; - -#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK)) -#define UML_ROUND_UP(addr) \ - UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) - -extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg); -extern unsigned long stack_sp(unsigned long page); -extern int kernel_thread_proc(void *data); -extern void syscall_segv(int sig); -extern int current_pid(void); -extern unsigned long alloc_stack(int order, int atomic); -extern int do_signal(void); -extern int is_stack_fault(unsigned long sp); -extern unsigned long segv(struct faultinfo fi, unsigned long ip, - int is_user, void *sc); -extern int handle_page_fault(unsigned long address, unsigned long ip, - int is_write, int is_user, int *code_out); -extern void syscall_ready(void); -extern void set_tracing(void *t, int tracing); -extern int is_tracing(void *task); -extern int segv_syscall(void); -extern void kern_finish_exec(void *task, int new_pid, unsigned long stack); -extern int page_size(void); -extern unsigned long page_mask(void); -extern int need_finish_fork(void); -extern void free_stack(unsigned long stack, int order); -extern void add_input_request(int op, void (*proc)(int), void *arg); -extern char *current_cmd(void); -extern void timer_handler(int sig, union uml_pt_regs *regs); -extern int set_signals(int enable); -extern void force_sigbus(void); -extern int pid_to_processor_id(int pid); -extern void block_signals(void); -extern void unblock_signals(void); -extern void deliver_signals(void *t); -extern int next_syscall_index(int max); -extern int next_trap_index(int max); -extern void default_idle(void); -extern void finish_fork(void); -extern void paging_init(void); -extern void init_flush_vm(void); -extern void *syscall_sp(void *t); -extern void syscall_trace(union uml_pt_regs *regs, int entryexit); -extern int hz(void); -extern void uml_idle_timer(void); -extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs); -extern int external_pid(void *t); -extern void boot_timer_handler(int sig); -extern void interrupt_end(void); -extern void initial_thread_cb(void (*proc)(void *), void *arg); -extern int debugger_signal(int status, int pid); -extern void debugger_parent_signal(int status, int pid); -extern void child_signal(int pid, int status); -extern int init_ptrace_proxy(int idle_pid, int startup, int stop); -extern int init_parent_proxy(int pid); -extern int singlestepping(void *t); -extern void check_stack_overflow(void *ptr); -extern void relay_signal(int sig, union uml_pt_regs *regs); -extern void not_implemented(void); -extern int user_context(unsigned long sp); -extern void timer_irq(union uml_pt_regs *regs); -extern void unprotect_stack(unsigned long stack); -extern void do_uml_exitcalls(void); -extern int attach_debugger(int idle_pid, int pid, int stop); -extern void bad_segv(struct faultinfo fi, unsigned long ip); -extern int config_gdb(char *str); -extern int remove_gdb(void); -extern char *uml_strdup(char *string); -extern void unprotect_kernel_mem(void); -extern void protect_kernel_mem(void); -extern void uml_cleanup(void); -extern void set_current(void *t); -extern void lock_signalled_task(void *t); -extern void IPI_handler(int cpu); -extern int jail_setup(char *line, int *add); -extern void *get_init_task(void); -extern int clear_user_proc(void *buf, int size); -extern int copy_to_user_proc(void *to, void *from, int size); -extern int copy_from_user_proc(void *to, void *from, int size); -extern int strlen_user_proc(char *str); -extern void bus_handler(int sig, union uml_pt_regs *regs); -extern void winch(int sig, union uml_pt_regs *regs); -extern long execute_syscall(void *r); -extern int smp_sigio_handler(void); -extern void *get_current(void); -extern struct task_struct *get_task(int pid, int require); -extern void machine_halt(void); -extern int is_syscall(unsigned long addr); -extern void arch_switch(void); -extern void free_irq(unsigned int, void *); -extern int um_in_interrupt(void); -extern int cpu(void); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/line.h b/arch/um/include/line.h deleted file mode 100644 index 5323d22a6ca..00000000000 --- a/arch/um/include/line.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __LINE_H__ -#define __LINE_H__ - -#include "linux/list.h" -#include "linux/workqueue.h" -#include "linux/tty.h" -#include "linux/interrupt.h" -#include "linux/spinlock.h" -#include "chan_user.h" -#include "mconsole_kern.h" - -struct line_driver { - char *name; - char *device_name; - char *devfs_name; - short major; - short minor_start; - short type; - short subtype; - int read_irq; - char *read_irq_name; - int write_irq; - char *write_irq_name; - char *symlink_from; - char *symlink_to; - struct mc_device mc; -}; - -struct line { - char *init_str; - int init_pri; - struct list_head chan_list; - int valid; - int count; - /*This lock is actually, mostly, local to*/ - spinlock_t lock; - - /* Yes, this is a real circular buffer. - * XXX: And this should become a struct kfifo! - * - * buffer points to a buffer allocated on demand, of length - * LINE_BUFSIZE, head to the start of the ring, tail to the end.*/ - char *buffer; - char *head; - char *tail; - - int sigio; - struct work_struct task; - struct line_driver *driver; - int have_irq; -}; - -#define LINE_INIT(str, d) \ - { init_str : str, \ - init_pri : INIT_STATIC, \ - chan_list : { }, \ - valid : 1, \ - buffer : NULL, \ - head : NULL, \ - tail : NULL, \ - sigio : 0, \ - driver : d, \ - have_irq : 0 } - -struct lines { - int num; -}; - -#define LINES_INIT(n) { num : n } - -extern void line_close(struct tty_struct *tty, struct file * filp); -extern int line_open(struct line *lines, struct tty_struct *tty, - struct chan_opts *opts); -extern int line_setup(struct line *lines, unsigned int sizeof_lines, char *init, - int all_allowed); -extern int line_write(struct tty_struct *tty, const unsigned char *buf, int len); -extern void line_put_char(struct tty_struct *tty, unsigned char ch); -extern void line_set_termios(struct tty_struct *tty, struct termios * old); -extern int line_chars_in_buffer(struct tty_struct *tty); -extern void line_flush_buffer(struct tty_struct *tty); -extern void line_flush_chars(struct tty_struct *tty); -extern int line_write_room(struct tty_struct *tty); -extern int line_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg); - -extern char *add_xterm_umid(char *base); -extern int line_setup_irq(int fd, int input, int output, struct tty_struct *tty); -extern void line_close_chan(struct line *line); -extern void line_disable(struct tty_struct *tty, int current_irq); -extern struct tty_driver * line_register_devfs(struct lines *set, - struct line_driver *line_driver, - struct tty_operations *driver, - struct line *lines, - int nlines); -extern void lines_init(struct line *lines, int nlines); -extern void close_lines(struct line *lines, int nlines); - -extern int line_config(struct line *lines, unsigned int sizeof_lines, char *str); -extern int line_id(char **str, int *start_out, int *end_out); -extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n); -extern int line_get_config(char *dev, struct line *lines, unsigned int sizeof_lines, char *str, - int size, char **error_out); - -#endif diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h deleted file mode 100644 index e8ff0d8fa61..00000000000 --- a/arch/um/include/mem.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2002, 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#ifndef __MEM_H__ -#define __MEM_H__ - -#include "linux/types.h" - -extern int phys_mapping(unsigned long phys, __u64 *offset_out); -extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w); -extern int is_remapped(void *virt); -extern int physmem_remove_mapping(void *virt); -extern void physmem_forget_descriptor(int fd); - -extern unsigned long uml_physmem; -static inline unsigned long to_phys(void *virt) -{ - return(((unsigned long) virt) - uml_physmem); -} - -static inline void *to_virt(unsigned long phys) -{ - return((void *) uml_physmem + phys); -} - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/mem_kern.h b/arch/um/include/mem_kern.h deleted file mode 100644 index cb7e196d366..00000000000 --- a/arch/um/include/mem_kern.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#ifndef __MEM_KERN_H__ -#define __MEM_KERN_H__ - -#include "linux/list.h" -#include "linux/types.h" - -struct remapper { - struct list_head list; - int (*proc)(int, unsigned long, int, __u64); -}; - -extern void register_remapper(struct remapper *info); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/mode.h b/arch/um/include/mode.h deleted file mode 100644 index 786cf563eb0..00000000000 --- a/arch/um/include/mode.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __MODE_H__ -#define __MODE_H__ - -#include "uml-config.h" - -#ifdef UML_CONFIG_MODE_TT -#include "mode-tt.h" -#endif - -#ifdef UML_CONFIG_MODE_SKAS -#include "mode-skas.h" -#endif - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/mode_kern.h b/arch/um/include/mode_kern.h deleted file mode 100644 index 2d88afd0cf1..00000000000 --- a/arch/um/include/mode_kern.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __MODE_KERN_H__ -#define __MODE_KERN_H__ - -#include "linux/config.h" - -#ifdef CONFIG_MODE_TT -#include "mode_kern-tt.h" -#endif - -#ifdef CONFIG_MODE_SKAS -#include "mode_kern-skas.h" -#endif - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/os.h b/arch/um/include/os.h deleted file mode 100644 index 2cccfa5b8ab..00000000000 --- a/arch/um/include/os.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __OS_H__ -#define __OS_H__ - -#include "uml-config.h" -#include "asm/types.h" -#include "../os/include/file.h" - -#define OS_TYPE_FILE 1 -#define OS_TYPE_DIR 2 -#define OS_TYPE_SYMLINK 3 -#define OS_TYPE_CHARDEV 4 -#define OS_TYPE_BLOCKDEV 5 -#define OS_TYPE_FIFO 6 -#define OS_TYPE_SOCK 7 - -/* os_access() flags */ -#define OS_ACC_F_OK 0 /* Test for existence. */ -#define OS_ACC_X_OK 1 /* Test for execute permission. */ -#define OS_ACC_W_OK 2 /* Test for write permission. */ -#define OS_ACC_R_OK 4 /* Test for read permission. */ -#define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ - -/* - * types taken from stat_file() in hostfs_user.c - * (if they are wrong here, they are wrong there...). - */ -struct uml_stat { - int ust_dev; /* device */ - unsigned long long ust_ino; /* inode */ - int ust_mode; /* protection */ - int ust_nlink; /* number of hard links */ - int ust_uid; /* user ID of owner */ - int ust_gid; /* group ID of owner */ - unsigned long long ust_size; /* total size, in bytes */ - int ust_blksize; /* blocksize for filesystem I/O */ - unsigned long long ust_blocks; /* number of blocks allocated */ - unsigned long ust_atime; /* time of last access */ - unsigned long ust_mtime; /* time of last modification */ - unsigned long ust_ctime; /* time of last change */ -}; - -struct openflags { - unsigned int r : 1; - unsigned int w : 1; - unsigned int s : 1; /* O_SYNC */ - unsigned int c : 1; /* O_CREAT */ - unsigned int t : 1; /* O_TRUNC */ - unsigned int a : 1; /* O_APPEND */ - unsigned int e : 1; /* O_EXCL */ - unsigned int cl : 1; /* FD_CLOEXEC */ -}; - -#define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \ - .t = 0, .a = 0, .e = 0, .cl = 0 }) - -static inline struct openflags of_read(struct openflags flags) -{ - flags.r = 1; - return(flags); -} - -static inline struct openflags of_write(struct openflags flags) -{ - flags.w = 1; - return(flags); -} - -static inline struct openflags of_rdwr(struct openflags flags) -{ - return(of_read(of_write(flags))); -} - -static inline struct openflags of_set_rw(struct openflags flags, int r, int w) -{ - flags.r = r; - flags.w = w; - return(flags); -} - -static inline struct openflags of_sync(struct openflags flags) -{ - flags.s = 1; - return(flags); -} - -static inline struct openflags of_create(struct openflags flags) -{ - flags.c = 1; - return(flags); -} - -static inline struct openflags of_trunc(struct openflags flags) -{ - flags.t = 1; - return(flags); -} - -static inline struct openflags of_append(struct openflags flags) -{ - flags.a = 1; - return(flags); -} - -static inline struct openflags of_excl(struct openflags flags) -{ - flags.e = 1; - return(flags); -} - -static inline struct openflags of_cloexec(struct openflags flags) -{ - flags.cl = 1; - return(flags); -} - -extern int os_stat_file(const char *file_name, struct uml_stat *buf); -extern int os_stat_fd(const int fd, struct uml_stat *buf); -extern int os_access(const char *file, int mode); -extern void os_print_error(int error, const char* str); -extern int os_get_exec_close(int fd, int *close_on_exec); -extern int os_set_exec_close(int fd, int close_on_exec); -extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); -extern int os_window_size(int fd, int *rows, int *cols); -extern int os_new_tty_pgrp(int fd, int pid); -extern int os_get_ifname(int fd, char *namebuf); -extern int os_set_slip(int fd); -extern int os_set_owner(int fd, int pid); -extern int os_sigio_async(int master, int slave); -extern int os_mode_fd(int fd, int mode); - -extern int os_seek_file(int fd, __u64 offset); -extern int os_open_file(char *file, struct openflags flags, int mode); -extern int os_read_file(int fd, void *buf, int len); -extern int os_write_file(int fd, const void *buf, int count); -extern int os_file_size(char *file, unsigned long long *size_out); -extern int os_file_modtime(char *file, unsigned long *modtime); -extern int os_pipe(int *fd, int stream, int close_on_exec); -extern int os_set_fd_async(int fd, int owner); -extern int os_clear_fd_async(int fd); -extern int os_set_fd_block(int fd, int blocking); -extern int os_accept_connection(int fd); -extern int os_create_unix_socket(char *file, int len, int close_on_exec); -extern int os_shutdown_socket(int fd, int r, int w); -extern void os_close_file(int fd); -extern int os_rcv_fd(int fd, int *helper_pid_out); -extern int create_unix_socket(char *file, int len, int close_on_exec); -extern int os_connect_socket(char *name); -extern int os_file_type(char *file); -extern int os_file_mode(char *file, struct openflags *mode_out); -extern int os_lock_file(int fd, int excl); - -/* start_up.c */ -extern void os_early_checks(void); -extern int can_do_skas(void); - -/* Make sure they are clear when running in TT mode. Required by - * SEGV_MAYBE_FIXABLE */ -#ifdef UML_CONFIG_MODE_SKAS -#define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0) -#else -#define clear_can_do_skas() do {} while (0) -#endif - -/* mem.c */ -extern int create_mem_file(unsigned long long len); - -/* process.c */ -extern unsigned long os_process_pc(int pid); -extern int os_process_parent(int pid); -extern void os_stop_process(int pid); -extern void os_kill_process(int pid, int reap_child); -extern void os_kill_ptraced_process(int pid, int reap_child); -extern void os_usr1_process(int pid); -extern int os_getpid(void); -extern int os_getpgrp(void); -extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); -extern void init_new_thread_signals(int altstack); -extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); - -extern int os_map_memory(void *virt, int fd, unsigned long long off, - unsigned long len, int r, int w, int x); -extern int os_protect_memory(void *addr, unsigned long len, - int r, int w, int x); -extern int os_unmap_memory(void *addr, int len); -extern void os_flush_stdout(void); -extern unsigned long long os_usecs(void); - -/* tt.c - * for tt mode only (will be deleted in future...) - */ -extern int protect_memory(unsigned long addr, unsigned long len, - int r, int w, int x, int must_succeed); -extern void forward_pending_sigio(int target); -extern int start_fork_tramp(void *arg, unsigned long temp_stack, - int clone_flags, int (*tramp)(void *)); - -/* uaccess.c */ -extern unsigned long __do_user_copy(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher, - void (*op)(void *to, const void *from, - int n), int *faulted_out); - -/* helper.c */ -extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, - unsigned long *stack_out); -extern int run_helper_thread(int (*proc)(void *), void *arg, - unsigned int flags, unsigned long *stack_out, - int stack_order); -extern int helper_wait(int pid); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/process.h b/arch/um/include/process.h deleted file mode 100644 index 5af9157ff54..00000000000 --- a/arch/um/include/process.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __PROCESS_H__ -#define __PROCESS_H__ - -#include <signal.h> - -extern void sig_handler(int sig, struct sigcontext sc); -extern void alarm_handler(int sig, struct sigcontext sc); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h deleted file mode 100644 index 4892e5fcef0..00000000000 --- a/arch/um/include/registers.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2004 PathScale, Inc - * Licensed under the GPL - */ - -#ifndef __REGISTERS_H -#define __REGISTERS_H - -#include "sysdep/ptrace.h" - -extern void init_thread_registers(union uml_pt_regs *to); -extern int save_fp_registers(int pid, unsigned long *fp_regs); -extern int restore_fp_registers(int pid, unsigned long *fp_regs); -extern void save_registers(int pid, union uml_pt_regs *regs); -extern void restore_registers(int pid, union uml_pt_regs *regs); -extern void init_registers(int pid); -extern void get_safe_registers(unsigned long * regs); -extern void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer); - -#endif diff --git a/arch/um/include/aio.h b/arch/um/include/shared/aio.h index 423bae9153f..423bae9153f 100644 --- a/arch/um/include/aio.h +++ b/arch/um/include/shared/aio.h diff --git a/arch/um/include/shared/arch.h b/arch/um/include/shared/arch.h new file mode 100644 index 00000000000..4f46abda060 --- /dev/null +++ b/arch/um/include/shared/arch.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __ARCH_H__ +#define __ARCH_H__ + +#include <sysdep/ptrace.h> + +extern void arch_check_bugs(void); +extern int arch_fixup(unsigned long address, struct uml_pt_regs *regs); +extern void arch_examine_signal(int sig, struct uml_pt_regs *regs); + +#endif diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h new file mode 100644 index 00000000000..41c8c774ec1 --- /dev/null +++ b/arch/um/include/shared/as-layout.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __START_H__ +#define __START_H__ + +#include <generated/asm-offsets.h> + +/* + * Stolen from linux/const.h, which can't be directly included since + * this is used in userspace code, which has no access to the kernel + * headers. Changed to be suitable for adding casts to the start, + * rather than "UL" to the end. + */ + +/* Some constant macros are used in both assembler and + * C code. Therefore we cannot annotate them always with + * 'UL' and other type specifiers unilaterally. We + * use the following macros to deal with this. + */ + +#ifdef __ASSEMBLY__ +#define _UML_AC(X, Y) (Y) +#else +#define __UML_AC(X, Y) (X(Y)) +#define _UML_AC(X, Y) __UML_AC(X, Y) +#endif + +#define STUB_START _UML_AC(, 0x100000) +#define STUB_CODE _UML_AC((unsigned long), STUB_START) +#define STUB_DATA _UML_AC((unsigned long), STUB_CODE + UM_KERN_PAGE_SIZE) +#define STUB_END _UML_AC((unsigned long), STUB_DATA + UM_KERN_PAGE_SIZE) + +#ifndef __ASSEMBLY__ + +#include <sysdep/ptrace.h> + +struct cpu_task { + int pid; + void *task; +}; + +extern struct cpu_task cpu_tasks[]; + +extern unsigned long high_physmem; +extern unsigned long uml_physmem; +extern unsigned long uml_reserved; +extern unsigned long end_vm; +extern unsigned long start_vm; +extern unsigned long long highmem; + +extern unsigned long brk_start; + +extern unsigned long host_task_size; + +extern int linux_main(int argc, char **argv); + +struct siginfo; +extern void (*sig_info[])(int, struct siginfo *si, struct uml_pt_regs *); + +#endif + +#endif diff --git a/arch/um/include/shared/common-offsets.h b/arch/um/include/shared/common-offsets.h new file mode 100644 index 00000000000..c9230680902 --- /dev/null +++ b/arch/um/include/shared/common-offsets.h @@ -0,0 +1,41 @@ +/* for use by sys-$SUBARCH/kernel-offsets.c */ + +DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE); + +DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE); +DEFINE(UM_KERN_PAGE_MASK, PAGE_MASK); +DEFINE(UM_KERN_PAGE_SHIFT, PAGE_SHIFT); +DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC); + +DEFINE(UM_ELF_CLASS, ELF_CLASS); +DEFINE(UM_ELFCLASS32, ELFCLASS32); +DEFINE(UM_ELFCLASS64, ELFCLASS64); + +DEFINE(UM_NR_CPUS, NR_CPUS); + +DEFINE(UM_GFP_KERNEL, GFP_KERNEL); +DEFINE(UM_GFP_ATOMIC, GFP_ATOMIC); + +/* For crypto assembler code. */ +DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); + +DEFINE(UM_THREAD_SIZE, THREAD_SIZE); + +DEFINE(UM_HZ, HZ); + +DEFINE(UM_USEC_PER_SEC, USEC_PER_SEC); +DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC); +DEFINE(UM_NSEC_PER_USEC, NSEC_PER_USEC); + +#ifdef CONFIG_PRINTK +DEFINE(UML_CONFIG_PRINTK, CONFIG_PRINTK); +#endif +#ifdef CONFIG_NO_HZ_COMMON +DEFINE(UML_CONFIG_NO_HZ_COMMON, CONFIG_NO_HZ_COMMON); +#endif +#ifdef CONFIG_UML_X86 +DEFINE(UML_CONFIG_UML_X86, CONFIG_UML_X86); +#endif +#ifdef CONFIG_64BIT +DEFINE(UML_CONFIG_64BIT, CONFIG_64BIT); +#endif diff --git a/arch/um/include/elf_user.h b/arch/um/include/shared/elf_user.h index 53516b63727..53516b63727 100644 --- a/arch/um/include/elf_user.h +++ b/arch/um/include/shared/elf_user.h diff --git a/arch/um/include/shared/frame_kern.h b/arch/um/include/shared/frame_kern.h new file mode 100644 index 00000000000..f2ca5702a4e --- /dev/null +++ b/arch/um/include/shared/frame_kern.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __FRAME_KERN_H_ +#define __FRAME_KERN_H_ + +extern int setup_signal_stack_sc(unsigned long stack_top, int sig, + struct k_sigaction *ka, + struct pt_regs *regs, + sigset_t *mask); +extern int setup_signal_stack_si(unsigned long stack_top, int sig, + struct k_sigaction *ka, + struct pt_regs *regs, struct siginfo *info, + sigset_t *mask); + +#endif + diff --git a/arch/um/include/init.h b/arch/um/include/shared/init.h index cbd79a8d213..b3906f860a8 100644 --- a/arch/um/include/init.h +++ b/arch/um/include/shared/init.h @@ -27,7 +27,7 @@ * sign followed by value, e.g.: * * static int init_variable __initdata = 0; - * static char linux_logo[] __initdata = { 0x32, 0x36, ... }; + * static const char linux_logo[] __initconst = { 0x32, 0x36, ... }; * * Don't forget to initialize data not at file scope, i.e. within a function, * as gcc otherwise puts the data into the bss section and not into the init @@ -40,17 +40,39 @@ typedef int (*initcall_t)(void); typedef void (*exitcall_t)(void); +#ifndef __KERNEL__ +#ifndef __section +# define __section(S) __attribute__ ((__section__(#S))) +#endif + +#if __GNUC__ == 3 + +#if __GNUC_MINOR__ >= 3 +# define __used __attribute__((__used__)) +#else +# define __used __attribute__((__unused__)) +#endif + +#else +#if __GNUC__ == 4 +# define __used __attribute__((__used__)) +#endif +#endif + +#else +#include <linux/compiler.h> +#endif /* These are for everybody (although not all archs will actually discard it in modules) */ -#define __init __attribute__ ((__section__ (".init.text"))) -#define __initdata __attribute__ ((__section__ (".init.data"))) -#define __exitdata __attribute__ ((__section__(".exit.data"))) -#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) +#define __init __section(.init.text) +#define __initdata __section(.init.data) +#define __exitdata __section(.exit.data) +#define __exit_call __used __section(.exitcall.exit) #ifdef MODULE -#define __exit __attribute__ ((__section__(".exit.text"))) +#define __exit __section(.exit.text) #else -#define __exit __attribute_used__ __attribute__ ((__section__(".exit.text"))) +#define __exit __used __section(.exit.text) #endif #endif @@ -103,16 +125,16 @@ extern struct uml_param __uml_setup_start, __uml_setup_end; * Mark functions and data as being only used at initialization * or exit time. */ -#define __uml_init_setup __attribute_used__ __attribute__ ((__section__ (".uml.setup.init"))) -#define __uml_setup_help __attribute_used__ __attribute__ ((__section__ (".uml.help.init"))) -#define __uml_init_call __attribute_used__ __attribute__ ((__section__ (".uml.initcall.init"))) -#define __uml_postsetup_call __attribute_used__ __attribute__ ((__section__ (".uml.postsetup.init"))) -#define __uml_exit_call __attribute_used__ __attribute__ ((__section__ (".uml.exitcall.exit"))) +#define __uml_init_setup __used __section(.uml.setup.init) +#define __uml_setup_help __used __section(.uml.help.init) +#define __uml_init_call __used __section(.uml.initcall.init) +#define __uml_postsetup_call __used __section(.uml.postsetup.init) +#define __uml_exit_call __used __section(.uml.exitcall.exit) #ifndef __KERNEL__ #define __define_initcall(level,fn) \ - static initcall_t __initcall_##fn __attribute_used__ \ + static initcall_t __initcall_##fn __used \ __attribute__((__section__(".initcall" level ".init"))) = fn /* Userspace initcalls shouldn't depend on anything in the kernel, so we'll @@ -122,19 +144,8 @@ extern struct uml_param __uml_setup_start, __uml_setup_end; #define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn -#define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) +#define __init_call __used __section(.initcall.init) #endif #endif /* _LINUX_UML_INIT_H */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/shared/irq_kern.h b/arch/um/include/shared/irq_kern.h new file mode 100644 index 00000000000..e05bd667de1 --- /dev/null +++ b/arch/um/include/shared/irq_kern.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __IRQ_KERN_H__ +#define __IRQ_KERN_H__ + +#include <linux/interrupt.h> +#include <asm/ptrace.h> + +extern int um_request_irq(unsigned int irq, int fd, int type, + irq_handler_t handler, + unsigned long irqflags, const char * devname, + void *dev_id); +void um_free_irq(unsigned int irq, void *dev); +#endif + diff --git a/arch/um/include/shared/irq_user.h b/arch/um/include/shared/irq_user.h new file mode 100644 index 00000000000..df563305395 --- /dev/null +++ b/arch/um/include/shared/irq_user.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __IRQ_USER_H__ +#define __IRQ_USER_H__ + +#include <sysdep/ptrace.h> + +struct irq_fd { + struct irq_fd *next; + void *id; + int fd; + int type; + int irq; + int events; + int current_events; +}; + +enum { IRQ_READ, IRQ_WRITE }; + +struct siginfo; +extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); +extern void free_irq_by_fd(int fd); +extern void reactivate_fd(int fd, int irqnum); +extern void deactivate_fd(int fd, int irqnum); +extern int deactivate_all_fds(void); +extern int activate_ipi(int fd, int pid); + +#endif diff --git a/arch/um/include/shared/kern.h b/arch/um/include/shared/kern.h new file mode 100644 index 00000000000..6cd01240bbf --- /dev/null +++ b/arch/um/include/shared/kern.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __KERN_H__ +#define __KERN_H__ + +/* These are all user-mode things which are convenient to call directly + * from kernel code and for which writing a wrapper is too much of a pain. + * The regular include files can't be included because this file is included + * only into kernel code, and user-space includes conflict with kernel + * includes. + */ + +extern int printf(const char *fmt, ...); +extern void *sbrk(int increment); +extern int pause(void); +extern void exit(int); + +#endif + diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h new file mode 100644 index 00000000000..83a91f97633 --- /dev/null +++ b/arch/um/include/shared/kern_util.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __KERN_UTIL_H__ +#define __KERN_UTIL_H__ + +#include <sysdep/ptrace.h> +#include <sysdep/faultinfo.h> + +struct siginfo; + +extern int uml_exitcode; + +extern int ncpus; +extern int kmalloc_ok; + +#define UML_ROUND_UP(addr) \ + ((((unsigned long) addr) + PAGE_SIZE - 1) & PAGE_MASK) + +extern unsigned long alloc_stack(int order, int atomic); +extern void free_stack(unsigned long stack, int order); + +extern int do_signal(void); +extern void interrupt_end(void); +extern void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs); + +extern unsigned long segv(struct faultinfo fi, unsigned long ip, + int is_user, struct uml_pt_regs *regs); +extern int handle_page_fault(unsigned long address, unsigned long ip, + int is_write, int is_user, int *code_out); + +extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs); +extern int smp_sigio_handler(void); +extern void initial_thread_cb(void (*proc)(void *), void *arg); +extern int is_syscall(unsigned long addr); + +extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); + +extern int start_uml(void); +extern void paging_init(void); + +extern void uml_cleanup(void); +extern void do_uml_exitcalls(void); + +/* + * Are we disallowed to sleep? Used to choose between GFP_KERNEL and + * GFP_ATOMIC. + */ +extern int __cant_sleep(void); +extern int get_current_pid(void); +extern int copy_from_user_proc(void *to, void *from, int size); +extern int cpu(void); +extern char *uml_strdup(const char *string); + +extern unsigned long to_irq_stack(unsigned long *mask_out); +extern unsigned long from_irq_stack(int nested); + +extern void syscall_trace(struct uml_pt_regs *regs, int entryexit); +extern int singlestepping(void *t); + +extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); +extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs); +extern void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); +extern void fatal_sigsegv(void) __attribute__ ((noreturn)); + + +#endif diff --git a/arch/um/include/shared/longjmp.h b/arch/um/include/shared/longjmp.h new file mode 100644 index 00000000000..9bdddf4c405 --- /dev/null +++ b/arch/um/include/shared/longjmp.h @@ -0,0 +1,23 @@ +#ifndef __UML_LONGJMP_H +#define __UML_LONGJMP_H + +#include <sysdep/archsetjmp.h> +#include <os.h> + +extern int setjmp(jmp_buf); +extern void longjmp(jmp_buf, int); + +#define UML_LONGJMP(buf, val) do { \ + longjmp(*buf, val); \ +} while(0) + +#define UML_SETJMP(buf) ({ \ + int n; \ + volatile int enable; \ + enable = get_signals(); \ + n = setjmp(*buf); \ + if(n != 0) \ + set_signals(enable); \ + n; }) + +#endif diff --git a/arch/um/include/shared/mem.h b/arch/um/include/shared/mem.h new file mode 100644 index 00000000000..5cd40e99e8d --- /dev/null +++ b/arch/um/include/shared/mem.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __MEM_H__ +#define __MEM_H__ + +extern int phys_mapping(unsigned long phys, unsigned long long *offset_out); + +extern unsigned long uml_physmem; +static inline unsigned long to_phys(void *virt) +{ + return(((unsigned long) virt) - uml_physmem); +} + +static inline void *to_virt(unsigned long phys) +{ + return((void *) uml_physmem + phys); +} + +#endif diff --git a/arch/um/include/mem_user.h b/arch/um/include/shared/mem_user.h index a1064c5823b..46384acd547 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/shared/mem_user.h @@ -46,10 +46,6 @@ extern int iomem_size; #define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1)) -extern unsigned long host_task_size; -extern unsigned long task_size; - -extern void check_devanon(void); extern int init_mem_user(void); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); @@ -60,9 +56,7 @@ extern void setup_physmem(unsigned long start, unsigned long usable, unsigned long len, unsigned long long highmem); extern void add_iomem(char *name, int fd, unsigned long size); extern unsigned long phys_offset(unsigned long phys); -extern void unmap_physmem(void); extern void map_memory(unsigned long virt, unsigned long phys, unsigned long len, int r, int w, int x); -extern unsigned long get_kmem_end(void); #endif diff --git a/arch/um/include/net_kern.h b/arch/um/include/shared/net_kern.h index f7de6df60dd..012ac87d490 100644 --- a/arch/um/include/net_kern.h +++ b/arch/um/include/shared/net_kern.h @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2002 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -11,14 +11,13 @@ #include <linux/skbuff.h> #include <linux/socket.h> #include <linux/list.h> +#include <linux/workqueue.h> struct uml_net { struct list_head list; struct net_device *dev; struct platform_device pdev; int index; - unsigned char mac[ETH_ALEN]; - int have_mac; }; struct uml_net_private { @@ -26,58 +25,45 @@ struct uml_net_private { spinlock_t lock; struct net_device *dev; struct timer_list tl; - struct net_device_stats stats; + + struct work_struct work; int fd; unsigned char mac[ETH_ALEN]; - int have_mac; + int max_packet; unsigned short (*protocol)(struct sk_buff *); int (*open)(void *); void (*close)(int, void *); void (*remove)(void *); - int (*read)(int, struct sk_buff **skb, struct uml_net_private *); - int (*write)(int, struct sk_buff **skb, struct uml_net_private *); - + int (*read)(int, struct sk_buff *skb, struct uml_net_private *); + int (*write)(int, struct sk_buff *skb, struct uml_net_private *); + void (*add_address)(unsigned char *, unsigned char *, void *); void (*delete_address)(unsigned char *, unsigned char *, void *); - int (*set_mtu)(int mtu, void *); - int user[1]; + char user[0]; }; struct net_kern_info { void (*init)(struct net_device *, void *); unsigned short (*protocol)(struct sk_buff *); - int (*read)(int, struct sk_buff **skb, struct uml_net_private *); - int (*write)(int, struct sk_buff **skb, struct uml_net_private *); + int (*read)(int, struct sk_buff *skb, struct uml_net_private *); + int (*write)(int, struct sk_buff *skb, struct uml_net_private *); }; struct transport { struct list_head list; - char *name; - int (*setup)(char *, char **, void *); - struct net_user_info *user; - struct net_kern_info *kern; - int private_size; - int setup_size; + const char *name; + int (* const setup)(char *, char **, void *); + const struct net_user_info *user; + const struct net_kern_info *kern; + const int private_size; + const int setup_size; }; extern struct net_device *ether_init(int); extern unsigned short ether_protocol(struct sk_buff *); -extern int setup_etheraddr(char *str, unsigned char *addr); -extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra); -extern int tap_setup_common(char *str, char *type, char **dev_name, +extern int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, char **gate_addr); extern void register_transport(struct transport *new); extern unsigned short eth_protocol(struct sk_buff *skb); #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/net_user.h b/arch/um/include/shared/net_user.h index 800c403920b..3dabbe128e4 100644 --- a/arch/um/include/net_user.h +++ b/arch/um/include/shared/net_user.h @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -8,27 +8,25 @@ #define ETH_ADDR_LEN (6) #define ETH_HEADER_ETHERTAP (16) -#define ETH_HEADER_OTHER (14) +#define ETH_HEADER_OTHER (26) /* 14 for ethernet + VLAN + MPLS for crazy people */ #define ETH_MAX_PACKET (1500) #define UML_NET_VERSION (4) struct net_user_info { - void (*init)(void *, void *); + int (*init)(void *, void *); int (*open)(void *); void (*close)(int, void *); void (*remove)(void *); - int (*set_mtu)(int mtu, void *); void (*add_address)(unsigned char *, unsigned char *, void *); void (*delete_address)(unsigned char *, unsigned char *, void *); int max_packet; + int mtu; }; extern void ether_user_init(void *data, void *dev); -extern void dev_ip_addr(void *d, unsigned char *bin_buf); -extern void set_ether_mac(void *d, unsigned char *addr); -extern void iter_addresses(void *d, void (*cb)(unsigned char *, - unsigned char *, void *), +extern void iter_addresses(void *d, void (*cb)(unsigned char *, + unsigned char *, void *), void *arg); extern void *get_output_buffer(int *len_out); @@ -53,14 +51,3 @@ extern char *split_if_spec(char *str, ...); extern int dev_netmask(void *d, void *m); #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h new file mode 100644 index 00000000000..08eec0b691b --- /dev/null +++ b/arch/um/include/shared/os.h @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __OS_H__ +#define __OS_H__ + +#include <stdarg.h> +#include <irq_user.h> +#include <longjmp.h> +#include <mm_id.h> + +#define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) + +#define OS_TYPE_FILE 1 +#define OS_TYPE_DIR 2 +#define OS_TYPE_SYMLINK 3 +#define OS_TYPE_CHARDEV 4 +#define OS_TYPE_BLOCKDEV 5 +#define OS_TYPE_FIFO 6 +#define OS_TYPE_SOCK 7 + +/* os_access() flags */ +#define OS_ACC_F_OK 0 /* Test for existence. */ +#define OS_ACC_X_OK 1 /* Test for execute permission. */ +#define OS_ACC_W_OK 2 /* Test for write permission. */ +#define OS_ACC_R_OK 4 /* Test for read permission. */ +#define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ + +#ifdef CONFIG_64BIT +#define OS_LIB_PATH "/usr/lib64/" +#else +#define OS_LIB_PATH "/usr/lib/" +#endif + +/* + * types taken from stat_file() in hostfs_user.c + * (if they are wrong here, they are wrong there...). + */ +struct uml_stat { + int ust_dev; /* device */ + unsigned long long ust_ino; /* inode */ + int ust_mode; /* protection */ + int ust_nlink; /* number of hard links */ + int ust_uid; /* user ID of owner */ + int ust_gid; /* group ID of owner */ + unsigned long long ust_size; /* total size, in bytes */ + int ust_blksize; /* blocksize for filesystem I/O */ + unsigned long long ust_blocks; /* number of blocks allocated */ + unsigned long ust_atime; /* time of last access */ + unsigned long ust_mtime; /* time of last modification */ + unsigned long ust_ctime; /* time of last change */ +}; + +struct openflags { + unsigned int r : 1; + unsigned int w : 1; + unsigned int s : 1; /* O_SYNC */ + unsigned int c : 1; /* O_CREAT */ + unsigned int t : 1; /* O_TRUNC */ + unsigned int a : 1; /* O_APPEND */ + unsigned int e : 1; /* O_EXCL */ + unsigned int cl : 1; /* FD_CLOEXEC */ +}; + +#define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \ + .t = 0, .a = 0, .e = 0, .cl = 0 }) + +static inline struct openflags of_read(struct openflags flags) +{ + flags.r = 1; + return flags; +} + +static inline struct openflags of_write(struct openflags flags) +{ + flags.w = 1; + return flags; +} + +static inline struct openflags of_rdwr(struct openflags flags) +{ + return of_read(of_write(flags)); +} + +static inline struct openflags of_set_rw(struct openflags flags, int r, int w) +{ + flags.r = r; + flags.w = w; + return flags; +} + +static inline struct openflags of_sync(struct openflags flags) +{ + flags.s = 1; + return flags; +} + +static inline struct openflags of_create(struct openflags flags) +{ + flags.c = 1; + return flags; +} + +static inline struct openflags of_trunc(struct openflags flags) +{ + flags.t = 1; + return flags; +} + +static inline struct openflags of_append(struct openflags flags) +{ + flags.a = 1; + return flags; +} + +static inline struct openflags of_excl(struct openflags flags) +{ + flags.e = 1; + return flags; +} + +static inline struct openflags of_cloexec(struct openflags flags) +{ + flags.cl = 1; + return flags; +} + +/* file.c */ +extern int os_stat_file(const char *file_name, struct uml_stat *buf); +extern int os_stat_fd(const int fd, struct uml_stat *buf); +extern int os_access(const char *file, int mode); +extern int os_set_exec_close(int fd); +extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); +extern int os_get_ifname(int fd, char *namebuf); +extern int os_set_slip(int fd); +extern int os_mode_fd(int fd, int mode); +extern int os_fsync_file(int fd); + +extern int os_seek_file(int fd, unsigned long long offset); +extern int os_open_file(const char *file, struct openflags flags, int mode); +extern int os_read_file(int fd, void *buf, int len); +extern int os_write_file(int fd, const void *buf, int count); +extern int os_sync_file(int fd); +extern int os_file_size(const char *file, unsigned long long *size_out); +extern int os_file_modtime(const char *file, unsigned long *modtime); +extern int os_pipe(int *fd, int stream, int close_on_exec); +extern int os_set_fd_async(int fd); +extern int os_clear_fd_async(int fd); +extern int os_set_fd_block(int fd, int blocking); +extern int os_accept_connection(int fd); +extern int os_create_unix_socket(const char *file, int len, int close_on_exec); +extern int os_shutdown_socket(int fd, int r, int w); +extern void os_close_file(int fd); +extern int os_rcv_fd(int fd, int *helper_pid_out); +extern int create_unix_socket(char *file, int len, int close_on_exec); +extern int os_connect_socket(const char *name); +extern int os_file_type(char *file); +extern int os_file_mode(const char *file, struct openflags *mode_out); +extern int os_lock_file(int fd, int excl); +extern void os_flush_stdout(void); +extern int os_stat_filesystem(char *path, long *bsize_out, + long long *blocks_out, long long *bfree_out, + long long *bavail_out, long long *files_out, + long long *ffree_out, void *fsid_out, + int fsid_size, long *namelen_out, + long *spare_out); +extern int os_change_dir(char *dir); +extern int os_fchange_dir(int fd); +extern unsigned os_major(unsigned long long dev); +extern unsigned os_minor(unsigned long long dev); +extern unsigned long long os_makedev(unsigned major, unsigned minor); + +/* start_up.c */ +extern void os_early_checks(void); +extern void can_do_skas(void); +extern void os_check_bugs(void); +extern void check_host_supports_tls(int *supports_tls, int *tls_min); + +/* mem.c */ +extern int create_mem_file(unsigned long long len); + +/* process.c */ +extern unsigned long os_process_pc(int pid); +extern int os_process_parent(int pid); +extern void os_stop_process(int pid); +extern void os_kill_process(int pid, int reap_child); +extern void os_kill_ptraced_process(int pid, int reap_child); +extern long os_ptrace_ldt(long pid, long addr, long data); + +extern int os_getpid(void); +extern int os_getpgrp(void); + +extern void init_new_thread_signals(void); + +extern int os_map_memory(void *virt, int fd, unsigned long long off, + unsigned long len, int r, int w, int x); +extern int os_protect_memory(void *addr, unsigned long len, + int r, int w, int x); +extern int os_unmap_memory(void *addr, int len); +extern int os_drop_memory(void *addr, int length); +extern int can_drop_memory(void); +extern void os_flush_stdout(void); +extern int os_mincore(void *addr, unsigned long len); + +/* execvp.c */ +extern int execvp_noalloc(char *buf, const char *file, char *const argv[]); +/* helper.c */ +extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv); +extern int run_helper_thread(int (*proc)(void *), void *arg, + unsigned int flags, unsigned long *stack_out); +extern int helper_wait(int pid); + + +/* umid.c */ +extern int umid_file_name(char *name, char *buf, int len); +extern int set_umid(char *name); +extern char *get_umid(void); + +/* signal.c */ +extern void timer_init(void); +extern void set_sigstack(void *sig_stack, int size); +extern void remove_sigstack(void); +extern void set_handler(int sig); +extern int change_sig(int signal, int on); +extern void block_signals(void); +extern void unblock_signals(void); +extern int get_signals(void); +extern int set_signals(int enable); +extern int os_is_signal_stack(void); + +/* util.c */ +extern void stack_protections(unsigned long address); +extern int raw(int fd); +extern void setup_machinename(char *machine_out); +extern void setup_hostinfo(char *buf, int len); +extern void os_dump_core(void) __attribute__ ((noreturn)); +extern void um_early_printk(const char *s, unsigned int n); +extern void os_fix_helper_signals(void); + +/* time.c */ +extern void idle_sleep(unsigned long long nsecs); +extern int set_interval(void); +extern int timer_one_shot(int ticks); +extern long long disable_timer(void); +extern void uml_idle_timer(void); +extern long long os_nsecs(void); + +/* skas/mem.c */ +extern long run_syscall_stub(struct mm_id * mm_idp, + int syscall, unsigned long *args, long expected, + void **addr, int done); +extern long syscall_stub_data(struct mm_id * mm_idp, + unsigned long *data, int data_count, + void **addr, void **stub_addr); +extern int map(struct mm_id * mm_idp, unsigned long virt, + unsigned long len, int prot, int phys_fd, + unsigned long long offset, int done, void **data); +extern int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, + int done, void **data); +extern int protect(struct mm_id * mm_idp, unsigned long addr, + unsigned long len, unsigned int prot, int done, void **data); + +/* skas/process.c */ +extern int is_skas_winch(int pid, int fd, void *data); +extern int start_userspace(unsigned long stub_stack); +extern int copy_context_skas0(unsigned long stack, int pid); +extern void userspace(struct uml_pt_regs *regs); +extern int map_stub_pages(int fd, unsigned long code, unsigned long data, + unsigned long stack); +extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); +extern void switch_threads(jmp_buf *me, jmp_buf *you); +extern int start_idle_thread(void *stack, jmp_buf *switch_buf); +extern void initial_thread_cb_skas(void (*proc)(void *), + void *arg); +extern void halt_skas(void); +extern void reboot_skas(void); + +/* irq.c */ +extern int os_waiting_for_events(struct irq_fd *active_fds); +extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds); +extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, + struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2); +extern void os_free_irq_later(struct irq_fd *active_fds, + int irq, void *dev_id); +extern int os_get_pollfd(int i); +extern void os_set_pollfd(int i, int fd); +extern void os_set_ioignore(void); + +/* sigio.c */ +extern int add_sigio_fd(int fd); +extern int ignore_sigio_fd(int fd); +extern void maybe_sigio_broken(int fd, int read); +extern void sigio_broken(int fd, int read); + +/* sys-x86_64/prctl.c */ +extern int os_arch_prctl(int pid, int code, unsigned long *addr); + +/* tty.c */ +extern int get_pty(void); + +/* sys-$ARCH/task_size.c */ +extern unsigned long os_get_top_address(void); + +#endif diff --git a/arch/um/include/ptrace_user.h b/arch/um/include/shared/ptrace_user.h index f3450e6bc18..56b2f284b10 100644 --- a/arch/um/include/ptrace_user.h +++ b/arch/um/include/shared/ptrace_user.h @@ -1,21 +1,16 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #ifndef __PTRACE_USER_H__ #define __PTRACE_USER_H__ -#include "sysdep/ptrace_user.h" +#include <sys/ptrace.h> +#include <sysdep/ptrace_user.h> extern int ptrace_getregs(long pid, unsigned long *regs_out); extern int ptrace_setregs(long pid, unsigned long *regs_in); -extern int ptrace_getfpregs(long pid, unsigned long *regs_out); -extern int ptrace_setfpregs(long pid, unsigned long *regs); -extern void arch_enter_kernel(void *task, int pid); -extern void arch_leave_kernel(void *task, int pid); -extern void ptrace_pokeuser(unsigned long addr, unsigned long data); - /* syscall emulation path in ptrace */ @@ -35,7 +30,7 @@ extern void ptrace_pokeuser(unsigned long addr, unsigned long data); * recompilation. So, we use PTRACE_OLDSETOPTIONS in UML. * We also want to be able to build the kernel on 2.4, which doesn't * have PTRACE_OLDSETOPTIONS. So, if it is missing, we declare - * PTRACE_OLDSETOPTIONS to to be the same as PTRACE_SETOPTIONS. + * PTRACE_OLDSETOPTIONS to be the same as PTRACE_SETOPTIONS. * * On architectures, that start to support PTRACE_O_TRACESYSGOOD on * linux 2.6, PTRACE_OLDSETOPTIONS never is defined, and also isn't @@ -54,7 +49,8 @@ extern int sysemu_supported; (((int[3][3] ) { \ { PTRACE_SYSCALL, PTRACE_SYSCALL, PTRACE_SINGLESTEP }, \ { PTRACE_SYSEMU, PTRACE_SYSEMU, PTRACE_SINGLESTEP }, \ - { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, PTRACE_SYSEMU_SINGLESTEP }}) \ + { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, \ + PTRACE_SYSEMU_SINGLESTEP } }) \ [sysemu_mode][singlestep_mode]) #endif diff --git a/arch/um/include/shared/registers.h b/arch/um/include/shared/registers.h new file mode 100644 index 00000000000..f5b76355ad7 --- /dev/null +++ b/arch/um/include/shared/registers.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2004 PathScale, Inc + * Licensed under the GPL + */ + +#ifndef __REGISTERS_H +#define __REGISTERS_H + +#include <sysdep/ptrace.h> +#include <sysdep/archsetjmp.h> + +extern int save_fp_registers(int pid, unsigned long *fp_regs); +extern int restore_fp_registers(int pid, unsigned long *fp_regs); +extern int save_fpx_registers(int pid, unsigned long *fp_regs); +extern int restore_fpx_registers(int pid, unsigned long *fp_regs); +extern int save_registers(int pid, struct uml_pt_regs *regs); +extern int restore_registers(int pid, struct uml_pt_regs *regs); +extern int init_registers(int pid); +extern void get_safe_registers(unsigned long *regs, unsigned long *fp_regs); +extern unsigned long get_thread_reg(int reg, jmp_buf *buf); +extern int get_fp_registers(int pid, unsigned long *regs); +extern int put_fp_registers(int pid, unsigned long *regs); + +#endif diff --git a/arch/um/include/shared/sigio.h b/arch/um/include/shared/sigio.h new file mode 100644 index 00000000000..434f1a9ae4b --- /dev/null +++ b/arch/um/include/shared/sigio.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SIGIO_H__ +#define __SIGIO_H__ + +extern int write_sigio_irq(int fd); +extern int register_sigio_fd(int fd); +extern void sigio_lock(void); +extern void sigio_unlock(void); + +#endif diff --git a/arch/um/kernel/skas/include/mm_id.h b/arch/um/include/shared/skas/mm_id.h index 48dd0989dda..48dd0989dda 100644 --- a/arch/um/kernel/skas/include/mm_id.h +++ b/arch/um/include/shared/skas/mm_id.h diff --git a/arch/um/kernel/skas/include/proc_mm.h b/arch/um/include/shared/skas/proc_mm.h index cce61a67905..90280920960 100644 --- a/arch/um/kernel/skas/include/proc_mm.h +++ b/arch/um/include/shared/skas/proc_mm.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -22,13 +22,13 @@ struct mm_mmap { struct mm_munmap { unsigned long addr; - unsigned long len; + unsigned long len; }; struct mm_mprotect { unsigned long addr; unsigned long len; - unsigned int prot; + unsigned int prot; }; struct proc_mm_op { @@ -42,14 +42,3 @@ struct proc_mm_op { }; #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/shared/skas/skas.h b/arch/um/include/shared/skas/skas.h new file mode 100644 index 00000000000..c45df961c87 --- /dev/null +++ b/arch/um/include/shared/skas/skas.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_H +#define __SKAS_H + +#include <sysdep/ptrace.h> + +extern int userspace_pid[]; +extern int proc_mm, ptrace_faultinfo, ptrace_ldt; +extern int skas_needs_stub; + +extern int user_thread(unsigned long stack, int flags); +extern void new_thread_handler(void); +extern void handle_syscall(struct uml_pt_regs *regs); +extern int new_mm(unsigned long stack); +extern long execute_syscall_skas(void *r); +extern unsigned long current_stub_stack(void); + +#endif diff --git a/arch/um/kernel/skas/include/stub-data.h b/arch/um/include/shared/skas/stub-data.h index f6ed92c3727..f6ed92c3727 100644 --- a/arch/um/kernel/skas/include/stub-data.h +++ b/arch/um/include/shared/skas/stub-data.h diff --git a/arch/um/include/shared/skas_ptrace.h b/arch/um/include/shared/skas_ptrace.h new file mode 100644 index 00000000000..630a9c92b93 --- /dev/null +++ b/arch/um/include/shared/skas_ptrace.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_PTRACE_H +#define __SKAS_PTRACE_H + +#define PTRACE_FAULTINFO 52 +#define PTRACE_SWITCH_MM 55 + +#include <sysdep/skas_ptrace.h> + +#endif diff --git a/arch/um/include/shared/um_malloc.h b/arch/um/include/shared/um_malloc.h new file mode 100644 index 00000000000..6395fef6b69 --- /dev/null +++ b/arch/um/include/shared/um_malloc.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> + * Licensed under the GPL + */ + +#ifndef __UM_MALLOC_H__ +#define __UM_MALLOC_H__ + +#include <generated/asm-offsets.h> + +extern void *uml_kmalloc(int size, int flags); +extern void kfree(const void *ptr); + +extern void *vmalloc(unsigned long size); +extern void vfree(void *ptr); + +#endif /* __UM_MALLOC_H__ */ + + diff --git a/arch/um/include/shared/user.h b/arch/um/include/shared/user.h new file mode 100644 index 00000000000..cef06856333 --- /dev/null +++ b/arch/um/include/shared/user.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __USER_H__ +#define __USER_H__ + +#include <generated/asm-offsets.h> + +/* + * The usual definition - copied here because the kernel provides its own, + * fancier, type-safe, definition. Using that one would require + * copying too much infrastructure for my taste, so userspace files + * get less checking than kernel files. + */ +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/* This is to get size_t */ +#ifdef __KERNEL__ +#include <linux/types.h> +#else +#include <stddef.h> +#endif + +extern void panic(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +/* Requires preincluding include/linux/kern_levels.h */ +#define UM_KERN_EMERG KERN_EMERG +#define UM_KERN_ALERT KERN_ALERT +#define UM_KERN_CRIT KERN_CRIT +#define UM_KERN_ERR KERN_ERR +#define UM_KERN_WARNING KERN_WARNING +#define UM_KERN_NOTICE KERN_NOTICE +#define UM_KERN_INFO KERN_INFO +#define UM_KERN_DEBUG KERN_DEBUG +#define UM_KERN_CONT KERN_CONT + +#ifdef UML_CONFIG_PRINTK +extern int printk(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); +#else +static inline int printk(const char *fmt, ...) +{ + return 0; +} +#endif + +extern int in_aton(char *str); +extern size_t strlcpy(char *, const char *, size_t); +extern size_t strlcat(char *, const char *, size_t); + +/* Copied from linux/compiler-gcc.h since we can't include it directly */ +#define barrier() __asm__ __volatile__("": : :"memory") + +#endif diff --git a/arch/um/include/sigcontext.h b/arch/um/include/sigcontext.h deleted file mode 100644 index 59816ca7a8d..00000000000 --- a/arch/um/include/sigcontext.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __UML_SIGCONTEXT_H__ -#define __UML_SIGCONTEXT_H__ - -#include "sysdep/sigcontext.h" - -extern int sc_size(void *data); -extern void sc_to_sc(void *to_ptr, void *from_ptr); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sigio.h b/arch/um/include/sigio.h deleted file mode 100644 index 37d76e29a14..00000000000 --- a/arch/um/include/sigio.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SIGIO_H__ -#define __SIGIO_H__ - -extern int write_sigio_irq(int fd); -extern int register_sigio_fd(int fd); -extern int read_sigio_fd(int fd); -extern int add_sigio_fd(int fd, int read); -extern int ignore_sigio_fd(int fd); -extern void sigio_lock(void); -extern void sigio_unlock(void); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/signal_kern.h b/arch/um/include/signal_kern.h deleted file mode 100644 index aeb5d5ab1df..00000000000 --- a/arch/um/include/signal_kern.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SIGNAL_KERN_H__ -#define __SIGNAL_KERN_H__ - -extern int have_signals(void *t); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/signal_user.h b/arch/um/include/signal_user.h deleted file mode 100644 index b075e543d86..00000000000 --- a/arch/um/include/signal_user.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SIGNAL_USER_H__ -#define __SIGNAL_USER_H__ - -extern int signal_stack_size; - -extern int change_sig(int signal, int on); -extern void set_sigstack(void *stack, int size); -extern void set_handler(int sig, void (*handler)(int), int flags, ...); -extern int set_signals(int enable); -extern int get_signals(void); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/skas_ptrace.h b/arch/um/include/skas_ptrace.h deleted file mode 100644 index cd2327d09c8..00000000000 --- a/arch/um/include/skas_ptrace.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SKAS_PTRACE_H -#define __SKAS_PTRACE_H - -#define PTRACE_FAULTINFO 52 -#define PTRACE_SWITCH_MM 55 - -#include "sysdep/skas_ptrace.h" - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/skas_ptregs.h b/arch/um/include/skas_ptregs.h deleted file mode 100644 index 73db19e9c07..00000000000 --- a/arch/um/include/skas_ptregs.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __SKAS_PT_REGS_ -#define __SKAS_PT_REGS_ - -#include <user_constants.h> - -#endif diff --git a/arch/um/include/syscall.h b/arch/um/include/syscall.h deleted file mode 100644 index dda1df901a0..00000000000 --- a/arch/um/include/syscall.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSCALL_USER_H -#define __SYSCALL_USER_H - -extern int record_syscall_start(int syscall); -extern void record_syscall_end(int index, long result); - -#endif diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h deleted file mode 100644 index 764ba4db478..00000000000 --- a/arch/um/include/sysdep-i386/checksum.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Licensed under the GPL - */ - -#ifndef __UM_SYSDEP_CHECKSUM_H -#define __UM_SYSDEP_CHECKSUM_H - -#include "linux/in6.h" -#include "linux/string.h" - -/* - * computes the checksum of a memory block at buff, length len, - * and adds in "sum" (32-bit) - * - * returns a 32-bit number suitable for feeding into itself - * or csum_tcpudp_magic - * - * this function must be called with even lengths, except - * for the last fragment, which may be odd - * - * it's best to have buff aligned on a 32-bit boundary - */ -unsigned int csum_partial(const unsigned char * buff, int len, - unsigned int sum); - -/* - * Note: when you get a NULL pointer exception here this means someone - * passed in an incorrect kernel address to one of these functions. - * - * If you use these functions directly please don't forget the - * access_ok(). - */ - -static __inline__ -unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst, - int len, int sum) -{ - memcpy(dst, src, len); - return(csum_partial(dst, len, sum)); -} - -/* - * the same as csum_partial, but copies from src while it - * checksums, and handles user-space pointer exceptions correctly, when needed. - * - * here even more important to align src and dst on a 32-bit (or even - * better 64-bit) boundary - */ - -static __inline__ -unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, - int len, int sum, int *err_ptr) -{ - if(copy_from_user(dst, src, len)){ - *err_ptr = -EFAULT; - return(-1); - } - - return csum_partial(dst, len, sum); -} - -/* - * These are the old (and unsafe) way of doing checksums, a warning message - * will be printed if they are used and an exception occurs. - * - * these functions should go away after some time. - */ - -#define csum_partial_copy_fromuser csum_partial_copy_from_user - -/* - * This is a version of ip_compute_csum() optimized for IP headers, - * which always checksum on 4 octet boundaries. - * - * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by - * Arnt Gulbrandsen. - */ -static inline unsigned short ip_fast_csum(unsigned char * iph, - unsigned int ihl) -{ - unsigned int sum; - - __asm__ __volatile__( - "movl (%1), %0 ;\n" - "subl $4, %2 ;\n" - "jbe 2f ;\n" - "addl 4(%1), %0 ;\n" - "adcl 8(%1), %0 ;\n" - "adcl 12(%1), %0 ;\n" -"1: adcl 16(%1), %0 ;\n" - "lea 4(%1), %1 ;\n" - "decl %2 ;\n" - "jne 1b ;\n" - "adcl $0, %0 ;\n" - "movl %0, %2 ;\n" - "shrl $16, %0 ;\n" - "addw %w2, %w0 ;\n" - "adcl $0, %0 ;\n" - "notl %0 ;\n" -"2: ;\n" - /* Since the input registers which are loaded with iph and ipl - are modified, we must also specify them as outputs, or gcc - will assume they contain their original values. */ - : "=r" (sum), "=r" (iph), "=r" (ihl) - : "1" (iph), "2" (ihl) - : "memory"); - return(sum); -} - -/* - * Fold a partial checksum - */ - -static inline unsigned int csum_fold(unsigned int sum) -{ - __asm__( - "addl %1, %0 ;\n" - "adcl $0xffff, %0 ;\n" - : "=r" (sum) - : "r" (sum << 16), "0" (sum & 0xffff0000) - ); - return (~sum) >> 16; -} - -static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, - unsigned long daddr, - unsigned short len, - unsigned short proto, - unsigned int sum) -{ - __asm__( - "addl %1, %0 ;\n" - "adcl %2, %0 ;\n" - "adcl %3, %0 ;\n" - "adcl $0, %0 ;\n" - : "=r" (sum) - : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum)); - return sum; -} - -/* - * computes the checksum of the TCP/UDP pseudo-header - * returns a 16-bit checksum, already complemented - */ -static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, - unsigned long daddr, - unsigned short len, - unsigned short proto, - unsigned int sum) -{ - return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); -} - -/* - * this routine is used for miscellaneous IP-like checksums, mainly - * in icmp.c - */ - -static inline unsigned short ip_compute_csum(unsigned char * buff, int len) -{ - return csum_fold (csum_partial(buff, len, 0)); -} - -#define _HAVE_ARCH_IPV6_CSUM -static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, - struct in6_addr *daddr, - __u32 len, - unsigned short proto, - unsigned int sum) -{ - __asm__( - "addl 0(%1), %0 ;\n" - "adcl 4(%1), %0 ;\n" - "adcl 8(%1), %0 ;\n" - "adcl 12(%1), %0 ;\n" - "adcl 0(%2), %0 ;\n" - "adcl 4(%2), %0 ;\n" - "adcl 8(%2), %0 ;\n" - "adcl 12(%2), %0 ;\n" - "adcl %3, %0 ;\n" - "adcl %4, %0 ;\n" - "adcl $0, %0 ;\n" - : "=&r" (sum) - : "r" (saddr), "r" (daddr), - "r"(htonl(len)), "r"(htonl(proto)), "0"(sum)); - - return csum_fold(sum); -} - -/* - * Copy and checksum to user - */ -#define HAVE_CSUM_COPY_USER -static __inline__ unsigned int csum_and_copy_to_user(const unsigned char *src, - unsigned char *dst, - int len, int sum, int *err_ptr) -{ - if (access_ok(VERIFY_WRITE, dst, len)){ - if(copy_to_user(dst, src, len)){ - *err_ptr = -EFAULT; - return(-1); - } - - return csum_partial(src, len, sum); - } - - if (len) - *err_ptr = -EFAULT; - - return -1; /* invalid checksum */ -} - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-i386/faultinfo.h b/arch/um/include/sysdep-i386/faultinfo.h deleted file mode 100644 index db437cc373b..00000000000 --- a/arch/um/include/sysdep-i386/faultinfo.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2004 Fujitsu Siemens Computers GmbH - * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com> - * Licensed under the GPL - */ - -#ifndef __FAULTINFO_I386_H -#define __FAULTINFO_I386_H - -/* this structure contains the full arch-specific faultinfo - * from the traps. - * On i386, ptrace_faultinfo unfortunately doesn't provide - * all the info, since trap_no is missing. - * All common elements are defined at the same position in - * both structures, thus making it easy to copy the - * contents without knowledge about the structure elements. - */ -struct faultinfo { - int error_code; /* in ptrace_faultinfo misleadingly called is_write */ - unsigned long cr2; /* in ptrace_faultinfo called addr */ - int trap_no; /* missing in ptrace_faultinfo */ -}; - -#define FAULT_WRITE(fi) ((fi).error_code & 2) -#define FAULT_ADDRESS(fi) ((fi).cr2) - -#define PTRACE_FULL_FAULTINFO 0 - -#endif diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h deleted file mode 100644 index c8ee9559f3a..00000000000 --- a/arch/um/include/sysdep-i386/ptrace.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_I386_PTRACE_H -#define __SYSDEP_I386_PTRACE_H - -#include "uml-config.h" -#include "user_constants.h" -#include "sysdep/faultinfo.h" -#include "choose-mode.h" - -#define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long)) -#define MAX_REG_OFFSET (UM_FRAME_SIZE) - -extern void update_debugregs(int seq); - -/* syscall emulation path in ptrace */ - -#ifndef PTRACE_SYSEMU -#define PTRACE_SYSEMU 31 -#endif - -void set_using_sysemu(int value); -int get_using_sysemu(void); -extern int sysemu_supported; - -#ifdef UML_CONFIG_MODE_TT -#include "sysdep/sc.h" -#endif - -#ifdef UML_CONFIG_MODE_SKAS - -#include "skas_ptregs.h" - -#define REGS_IP(r) ((r)[HOST_IP]) -#define REGS_SP(r) ((r)[HOST_SP]) -#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS]) -#define REGS_EAX(r) ((r)[HOST_EAX]) -#define REGS_EBX(r) ((r)[HOST_EBX]) -#define REGS_ECX(r) ((r)[HOST_ECX]) -#define REGS_EDX(r) ((r)[HOST_EDX]) -#define REGS_ESI(r) ((r)[HOST_ESI]) -#define REGS_EDI(r) ((r)[HOST_EDI]) -#define REGS_EBP(r) ((r)[HOST_EBP]) -#define REGS_CS(r) ((r)[HOST_CS]) -#define REGS_SS(r) ((r)[HOST_SS]) -#define REGS_DS(r) ((r)[HOST_DS]) -#define REGS_ES(r) ((r)[HOST_ES]) -#define REGS_FS(r) ((r)[HOST_FS]) -#define REGS_GS(r) ((r)[HOST_GS]) - -#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res) - -#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) - -#endif -#ifndef PTRACE_SYSEMU_SINGLESTEP -#define PTRACE_SYSEMU_SINGLESTEP 32 -#endif - -union uml_pt_regs { -#ifdef UML_CONFIG_MODE_TT - struct tt_regs { - long syscall; - void *sc; - struct faultinfo faultinfo; - } tt; -#endif -#ifdef UML_CONFIG_MODE_SKAS - struct skas_regs { - unsigned long regs[HOST_FRAME_SIZE]; - unsigned long fp[HOST_FP_SIZE]; - unsigned long xfp[HOST_XFP_SIZE]; - struct faultinfo faultinfo; - long syscall; - int is_user; - } skas; -#endif -}; - -#define EMPTY_UML_PT_REGS { } - -extern int mode_tt; - -#define UPT_SC(r) ((r)->tt.sc) -#define UPT_IP(r) \ - __CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs)) -#define UPT_SP(r) \ - __CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs)) -#define UPT_EFLAGS(r) \ - __CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs)) -#define UPT_EAX(r) \ - __CHOOSE_MODE(SC_EAX(UPT_SC(r)), REGS_EAX((r)->skas.regs)) -#define UPT_EBX(r) \ - __CHOOSE_MODE(SC_EBX(UPT_SC(r)), REGS_EBX((r)->skas.regs)) -#define UPT_ECX(r) \ - __CHOOSE_MODE(SC_ECX(UPT_SC(r)), REGS_ECX((r)->skas.regs)) -#define UPT_EDX(r) \ - __CHOOSE_MODE(SC_EDX(UPT_SC(r)), REGS_EDX((r)->skas.regs)) -#define UPT_ESI(r) \ - __CHOOSE_MODE(SC_ESI(UPT_SC(r)), REGS_ESI((r)->skas.regs)) -#define UPT_EDI(r) \ - __CHOOSE_MODE(SC_EDI(UPT_SC(r)), REGS_EDI((r)->skas.regs)) -#define UPT_EBP(r) \ - __CHOOSE_MODE(SC_EBP(UPT_SC(r)), REGS_EBP((r)->skas.regs)) -#define UPT_ORIG_EAX(r) \ - __CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall) -#define UPT_CS(r) \ - __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs)) -#define UPT_SS(r) \ - __CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs)) -#define UPT_DS(r) \ - __CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs)) -#define UPT_ES(r) \ - __CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs)) -#define UPT_FS(r) \ - __CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs)) -#define UPT_GS(r) \ - __CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs)) - -#define UPT_SYSCALL_ARG1(r) UPT_EBX(r) -#define UPT_SYSCALL_ARG2(r) UPT_ECX(r) -#define UPT_SYSCALL_ARG3(r) UPT_EDX(r) -#define UPT_SYSCALL_ARG4(r) UPT_ESI(r) -#define UPT_SYSCALL_ARG5(r) UPT_EDI(r) -#define UPT_SYSCALL_ARG6(r) UPT_EBP(r) - -extern int user_context(unsigned long sp); - -#define UPT_IS_USER(r) \ - CHOOSE_MODE(user_context(UPT_SP(r)), (r)->skas.is_user) - -struct syscall_args { - unsigned long args[6]; -}; - -#define SYSCALL_ARGS(r) ((struct syscall_args) \ - { .args = { UPT_SYSCALL_ARG1(r), \ - UPT_SYSCALL_ARG2(r), \ - UPT_SYSCALL_ARG3(r), \ - UPT_SYSCALL_ARG4(r), \ - UPT_SYSCALL_ARG5(r), \ - UPT_SYSCALL_ARG6(r) } } ) - -#define UPT_REG(regs, reg) \ - ({ unsigned long val; \ - switch(reg){ \ - case EIP: val = UPT_IP(regs); break; \ - case UESP: val = UPT_SP(regs); break; \ - case EAX: val = UPT_EAX(regs); break; \ - case EBX: val = UPT_EBX(regs); break; \ - case ECX: val = UPT_ECX(regs); break; \ - case EDX: val = UPT_EDX(regs); break; \ - case ESI: val = UPT_ESI(regs); break; \ - case EDI: val = UPT_EDI(regs); break; \ - case EBP: val = UPT_EBP(regs); break; \ - case ORIG_EAX: val = UPT_ORIG_EAX(regs); break; \ - case CS: val = UPT_CS(regs); break; \ - case SS: val = UPT_SS(regs); break; \ - case DS: val = UPT_DS(regs); break; \ - case ES: val = UPT_ES(regs); break; \ - case FS: val = UPT_FS(regs); break; \ - case GS: val = UPT_GS(regs); break; \ - case EFL: val = UPT_EFLAGS(regs); break; \ - default : \ - panic("Bad register in UPT_REG : %d\n", reg); \ - val = -1; \ - } \ - val; \ - }) - - -#define UPT_SET(regs, reg, val) \ - do { \ - switch(reg){ \ - case EIP: UPT_IP(regs) = val; break; \ - case UESP: UPT_SP(regs) = val; break; \ - case EAX: UPT_EAX(regs) = val; break; \ - case EBX: UPT_EBX(regs) = val; break; \ - case ECX: UPT_ECX(regs) = val; break; \ - case EDX: UPT_EDX(regs) = val; break; \ - case ESI: UPT_ESI(regs) = val; break; \ - case EDI: UPT_EDI(regs) = val; break; \ - case EBP: UPT_EBP(regs) = val; break; \ - case ORIG_EAX: UPT_ORIG_EAX(regs) = val; break; \ - case CS: UPT_CS(regs) = val; break; \ - case SS: UPT_SS(regs) = val; break; \ - case DS: UPT_DS(regs) = val; break; \ - case ES: UPT_ES(regs) = val; break; \ - case FS: UPT_FS(regs) = val; break; \ - case GS: UPT_GS(regs) = val; break; \ - case EFL: UPT_EFLAGS(regs) = val; break; \ - default : \ - panic("Bad register in UPT_SET : %d\n", reg); \ - break; \ - } \ - } while (0) - -#define UPT_SET_SYSCALL_RETURN(r, res) \ - CHOOSE_MODE(SC_SET_SYSCALL_RETURN(UPT_SC(r), (res)), \ - REGS_SET_SYSCALL_RETURN((r)->skas.regs, (res))) - -#define UPT_RESTART_SYSCALL(r) \ - CHOOSE_MODE(SC_RESTART_SYSCALL(UPT_SC(r)), \ - REGS_RESTART_SYSCALL((r)->skas.regs)) - -#define UPT_ORIG_SYSCALL(r) UPT_EAX(r) -#define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r) -#define UPT_SYSCALL_RET(r) UPT_EAX(r) - -#define UPT_FAULTINFO(r) \ - CHOOSE_MODE((&(r)->tt.faultinfo), (&(r)->skas.faultinfo)) - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h deleted file mode 100644 index 899aa4b2a78..00000000000 --- a/arch/um/include/sysdep-i386/ptrace_user.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_I386_PTRACE_USER_H__ -#define __SYSDEP_I386_PTRACE_USER_H__ - -#include <sys/ptrace.h> -#include <linux/ptrace.h> -#include <asm/ptrace.h> - -#define PT_OFFSET(r) ((r) * sizeof(long)) - -#define PT_SYSCALL_NR(regs) ((regs)[ORIG_EAX]) -#define PT_SYSCALL_NR_OFFSET PT_OFFSET(ORIG_EAX) - -#define PT_SYSCALL_ARG1_OFFSET PT_OFFSET(EBX) -#define PT_SYSCALL_ARG2_OFFSET PT_OFFSET(ECX) -#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX) -#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI) -#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI) -#define PT_SYSCALL_ARG6_OFFSET PT_OFFSET(EBP) - -#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX) - -#define REGS_SYSCALL_NR EAX /* This is used before a system call */ -#define REGS_SYSCALL_ARG1 EBX -#define REGS_SYSCALL_ARG2 ECX -#define REGS_SYSCALL_ARG3 EDX -#define REGS_SYSCALL_ARG4 ESI -#define REGS_SYSCALL_ARG5 EDI -#define REGS_SYSCALL_ARG6 EBP - -#define REGS_IP_INDEX EIP -#define REGS_SP_INDEX UESP - -#define PT_IP_OFFSET PT_OFFSET(EIP) -#define PT_IP(regs) ((regs)[EIP]) -#define PT_SP_OFFSET PT_OFFSET(UESP) -#define PT_SP(regs) ((regs)[UESP]) - -#ifndef FRAME_SIZE -#define FRAME_SIZE (17) -#endif -#define FRAME_SIZE_OFFSET (FRAME_SIZE * sizeof(unsigned long)) - -#define FP_FRAME_SIZE (27) -#define FPX_FRAME_SIZE (128) - -#ifdef PTRACE_GETREGS -#define UM_HAVE_GETREGS -#endif - -#ifdef PTRACE_SETREGS -#define UM_HAVE_SETREGS -#endif - -#ifdef PTRACE_GETFPREGS -#define UM_HAVE_GETFPREGS -#endif - -#ifdef PTRACE_SETFPREGS -#define UM_HAVE_SETFPREGS -#endif - -#ifdef PTRACE_GETFPXREGS -#define UM_HAVE_GETFPXREGS -#endif - -#ifdef PTRACE_SETFPXREGS -#define UM_HAVE_SETFPXREGS -#endif - -#endif diff --git a/arch/um/include/sysdep-i386/sc.h b/arch/um/include/sysdep-i386/sc.h deleted file mode 100644 index c57d1780ad3..00000000000 --- a/arch/um/include/sysdep-i386/sc.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __SYSDEP_I386_SC_H -#define __SYSDEP_I386_SC_H - -#include <user_constants.h> - -#define SC_OFFSET(sc, field) \ - *((unsigned long *) &(((char *) (sc))[HOST_##field])) -#define SC_FP_OFFSET(sc, field) \ - *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[HOST_##field])) -#define SC_FP_OFFSET_PTR(sc, field, type) \ - ((type *) &(((char *) (SC_FPSTATE(sc)))[HOST_##field])) - -#define SC_IP(sc) SC_OFFSET(sc, SC_IP) -#define SC_SP(sc) SC_OFFSET(sc, SC_SP) -#define SC_FS(sc) SC_OFFSET(sc, SC_FS) -#define SC_GS(sc) SC_OFFSET(sc, SC_GS) -#define SC_DS(sc) SC_OFFSET(sc, SC_DS) -#define SC_ES(sc) SC_OFFSET(sc, SC_ES) -#define SC_SS(sc) SC_OFFSET(sc, SC_SS) -#define SC_CS(sc) SC_OFFSET(sc, SC_CS) -#define SC_EFLAGS(sc) SC_OFFSET(sc, SC_EFLAGS) -#define SC_EAX(sc) SC_OFFSET(sc, SC_EAX) -#define SC_EBX(sc) SC_OFFSET(sc, SC_EBX) -#define SC_ECX(sc) SC_OFFSET(sc, SC_ECX) -#define SC_EDX(sc) SC_OFFSET(sc, SC_EDX) -#define SC_EDI(sc) SC_OFFSET(sc, SC_EDI) -#define SC_ESI(sc) SC_OFFSET(sc, SC_ESI) -#define SC_EBP(sc) SC_OFFSET(sc, SC_EBP) -#define SC_TRAPNO(sc) SC_OFFSET(sc, SC_TRAPNO) -#define SC_ERR(sc) SC_OFFSET(sc, SC_ERR) -#define SC_CR2(sc) SC_OFFSET(sc, SC_CR2) -#define SC_FPSTATE(sc) SC_OFFSET(sc, SC_FPSTATE) -#define SC_SIGMASK(sc) SC_OFFSET(sc, SC_SIGMASK) -#define SC_FP_CW(sc) SC_FP_OFFSET(sc, SC_FP_CW) -#define SC_FP_SW(sc) SC_FP_OFFSET(sc, SC_FP_SW) -#define SC_FP_TAG(sc) SC_FP_OFFSET(sc, SC_FP_TAG) -#define SC_FP_IPOFF(sc) SC_FP_OFFSET(sc, SC_FP_IPOFF) -#define SC_FP_CSSEL(sc) SC_FP_OFFSET(sc, SC_FP_CSSEL) -#define SC_FP_DATAOFF(sc) SC_FP_OFFSET(sc, SC_FP_DATAOFF) -#define SC_FP_DATASEL(sc) SC_FP_OFFSET(sc, SC_FP_DATASEL) -#define SC_FP_ST(sc) SC_FP_OFFSET_PTR(sc, SC_FP_ST, struct _fpstate) -#define SC_FXSR_ENV(sc) SC_FP_OFFSET_PTR(sc, SC_FXSR_ENV, void) - -#endif diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h deleted file mode 100644 index 23fd2644d7e..00000000000 --- a/arch/um/include/sysdep-i386/sigcontext.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYS_SIGCONTEXT_I386_H -#define __SYS_SIGCONTEXT_I386_H - -#include "uml-config.h" -#include <sysdep/sc.h> - -#define IP_RESTART_SYSCALL(ip) ((ip) -= 2) - -#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc)) -#define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result) - -#define GET_FAULTINFO_FROM_SC(fi,sc) \ - { \ - (fi).cr2 = SC_CR2(sc); \ - (fi).error_code = SC_ERR(sc); \ - (fi).trap_no = SC_TRAPNO(sc); \ - } - -/* ptrace expects that, at the start of a system call, %eax contains - * -ENOSYS, so this makes it so. - */ -#define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0) - -/* This is Page Fault */ -#define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) - -/* SKAS3 has no trap_no on i386, but get_skas_faultinfo() sets it to 0. */ -#ifdef UML_CONFIG_MODE_SKAS -#define SEGV_MAYBE_FIXABLE(fi) ((fi)->trap_no == 0 && ptrace_faultinfo) -#else -#define SEGV_MAYBE_FIXABLE(fi) 0 -#endif - -extern unsigned long *sc_sigmask(void *sc_ptr); -extern int sc_get_fpregs(unsigned long buf, void *sc_ptr); - -#endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-i386/signal.h b/arch/um/include/sysdep-i386/signal.h deleted file mode 100644 index 07518b16213..00000000000 --- a/arch/um/include/sysdep-i386/signal.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2004 PathScale, Inc - * Licensed under the GPL - */ - -#ifndef __I386_SIGNAL_H_ -#define __I386_SIGNAL_H_ - -#include <signal.h> - -#define ARCH_SIGHDLR_PARAM int sig - -#define ARCH_GET_SIGCONTEXT(sc, sig) \ - do sc = (struct sigcontext *) (&sig + 1); while(0) - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-i386/skas_ptrace.h b/arch/um/include/sysdep-i386/skas_ptrace.h deleted file mode 100644 index e27b8a79177..00000000000 --- a/arch/um/include/sysdep-i386/skas_ptrace.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_I386_SKAS_PTRACE_H -#define __SYSDEP_I386_SKAS_PTRACE_H - -struct ptrace_faultinfo { - int is_write; - unsigned long addr; -}; - -struct ptrace_ldt { - int func; - void *ptr; - unsigned long bytecount; -}; - -#define PTRACE_LDT 54 - -#endif diff --git a/arch/um/include/sysdep-i386/stub.h b/arch/um/include/sysdep-i386/stub.h deleted file mode 100644 index a49ceb199ee..00000000000 --- a/arch/um/include/sysdep-i386/stub.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_STUB_H -#define __SYSDEP_STUB_H - -#include <asm/ptrace.h> -#include <asm/unistd.h> - -extern void stub_segv_handler(int sig); -extern void stub_clone_handler(void); - -#define STUB_SYSCALL_RET EAX -#define STUB_MMAP_NR __NR_mmap2 -#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT) - -static inline long stub_syscall1(long syscall, long arg1) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1)); - - return ret; -} - -static inline long stub_syscall2(long syscall, long arg1, long arg2) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2)); - - return ret; -} - -static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2), "d" (arg3)); - - return ret; -} - -static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, - long arg4) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2), "d" (arg3), "S" (arg4)); - - return ret; -} - -static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, - long arg4, long arg5) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5)); - - return ret; -} - -static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3, - long arg4, long arg5, long arg6) -{ - long ret; - - __asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; " - "int $0x80 ; pop %%ebp" - : "=a" (ret) - : "g" (syscall), "b" (arg1), "c" (arg2), "d" (arg3), - "S" (arg4), "D" (arg5), "0" (arg6)); - - return ret; -} - -static inline void trap_myself(void) -{ - __asm("int3"); -} - -#endif diff --git a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h deleted file mode 100644 index 57bd79efbee..00000000000 --- a/arch/um/include/sysdep-i386/syscalls.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "asm/unistd.h" -#include "sysdep/ptrace.h" - -typedef long syscall_handler_t(struct pt_regs); - -/* Not declared on x86, incompatible declarations on x86_64, so these have - * to go here rather than in sys_call_table.c - */ -extern syscall_handler_t sys_rt_sigaction; - -extern syscall_handler_t old_mmap_i386; - -extern syscall_handler_t *sys_call_table[]; - -#define EXECUTE_SYSCALL(syscall, regs) \ - ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) - -extern long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); diff --git a/arch/um/include/sysdep-i386/thread.h b/arch/um/include/sysdep-i386/thread.h deleted file mode 100644 index 243fed44d78..00000000000 --- a/arch/um/include/sysdep-i386/thread.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __UM_THREAD_H -#define __UM_THREAD_H - -#include <kern_constants.h> - -#define TASK_DEBUGREGS(task) ((unsigned long *) &(((char *) (task))[HOST_TASK_DEBUGREGS])) -#ifdef UML_CONFIG_MODE_TT -#define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[HOST_TASK_EXTERN_PID])) -#endif - -#endif diff --git a/arch/um/include/sysdep-ia64/ptrace.h b/arch/um/include/sysdep-ia64/ptrace.h deleted file mode 100644 index 42dd8fb6f2f..00000000000 --- a/arch/um/include/sysdep-ia64/ptrace.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_IA64_PTRACE_H -#define __SYSDEP_IA64_PTRACE_H - -struct sys_pt_regs { - int foo; -}; - -#define EMPTY_REGS { 0 } - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-ia64/sigcontext.h b/arch/um/include/sysdep-ia64/sigcontext.h deleted file mode 100644 index f15fb25260b..00000000000 --- a/arch/um/include/sysdep-ia64/sigcontext.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_IA64_SIGCONTEXT_H -#define __SYSDEP_IA64_SIGCONTEXT_H - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-ia64/syscalls.h b/arch/um/include/sysdep-ia64/syscalls.h deleted file mode 100644 index 4a1f46ef1eb..00000000000 --- a/arch/um/include/sysdep-ia64/syscalls.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_IA64_SYSCALLS_H -#define __SYSDEP_IA64_SYSCALLS_H - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-x86_64/checksum.h b/arch/um/include/sysdep-x86_64/checksum.h deleted file mode 100644 index ea97005af69..00000000000 --- a/arch/um/include/sysdep-x86_64/checksum.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed under the GPL - */ - -#ifndef __UM_SYSDEP_CHECKSUM_H -#define __UM_SYSDEP_CHECKSUM_H - -#include "linux/string.h" -#include "linux/in6.h" -#include "asm/uaccess.h" - -extern unsigned csum_partial(const unsigned char *buff, unsigned len, - unsigned sum); - -/* - * Note: when you get a NULL pointer exception here this means someone - * passed in an incorrect kernel address to one of these functions. - * - * If you use these functions directly please don't forget the - * access_ok(). - */ - -static __inline__ -unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst, - int len, int sum) -{ - memcpy(dst, src, len); - return(csum_partial(dst, len, sum)); -} - -static __inline__ -unsigned int csum_partial_copy_from_user(const unsigned char *src, - unsigned char *dst, int len, int sum, - int *err_ptr) -{ - if(copy_from_user(dst, src, len)){ - *err_ptr = -EFAULT; - return(-1); - } - return csum_partial(dst, len, sum); -} - -/** - * csum_fold - Fold and invert a 32bit checksum. - * sum: 32bit unfolded sum - * - * Fold a 32bit running checksum to 16bit and invert it. This is usually - * the last step before putting a checksum into a packet. - * Make sure not to mix with 64bit checksums. - */ -static inline unsigned int csum_fold(unsigned int sum) -{ - __asm__( - " addl %1,%0\n" - " adcl $0xffff,%0" - : "=r" (sum) - : "r" (sum << 16), "0" (sum & 0xffff0000) - ); - return (~sum) >> 16; -} - -/** - * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum. - * @saddr: source address - * @daddr: destination address - * @len: length of packet - * @proto: ip protocol of packet - * @sum: initial sum to be added in (32bit unfolded) - * - * Returns the pseudo header checksum the input data. Result is - * 32bit unfolded. - */ -static inline unsigned long -csum_tcpudp_nofold(unsigned saddr, unsigned daddr, unsigned short len, - unsigned short proto, unsigned int sum) -{ - asm(" addl %1, %0\n" - " adcl %2, %0\n" - " adcl %3, %0\n" - " adcl $0, %0\n" - : "=r" (sum) - : "g" (daddr), "g" (saddr), "g" ((ntohs(len)<<16)+proto*256), "0" (sum)); - return sum; -} - -/* - * computes the checksum of the TCP/UDP pseudo-header - * returns a 16-bit checksum, already complemented - */ -static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, - unsigned long daddr, - unsigned short len, - unsigned short proto, - unsigned int sum) -{ - return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); -} - -/** - * ip_fast_csum - Compute the IPv4 header checksum efficiently. - * iph: ipv4 header - * ihl: length of header / 4 - */ -static inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) -{ - unsigned int sum; - - asm( " movl (%1), %0\n" - " subl $4, %2\n" - " jbe 2f\n" - " addl 4(%1), %0\n" - " adcl 8(%1), %0\n" - " adcl 12(%1), %0\n" - "1: adcl 16(%1), %0\n" - " lea 4(%1), %1\n" - " decl %2\n" - " jne 1b\n" - " adcl $0, %0\n" - " movl %0, %2\n" - " shrl $16, %0\n" - " addw %w2, %w0\n" - " adcl $0, %0\n" - " notl %0\n" - "2:" - /* Since the input registers which are loaded with iph and ipl - are modified, we must also specify them as outputs, or gcc - will assume they contain their original values. */ - : "=r" (sum), "=r" (iph), "=r" (ihl) - : "1" (iph), "2" (ihl) - : "memory"); - return(sum); -} - -static inline unsigned add32_with_carry(unsigned a, unsigned b) -{ - asm("addl %2,%0\n\t" - "adcl $0,%0" - : "=r" (a) - : "0" (a), "r" (b)); - return a; -} - -extern unsigned short ip_compute_csum(unsigned char * buff, int len); - -#endif diff --git a/arch/um/include/sysdep-x86_64/faultinfo.h b/arch/um/include/sysdep-x86_64/faultinfo.h deleted file mode 100644 index cb917b0d566..00000000000 --- a/arch/um/include/sysdep-x86_64/faultinfo.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2004 Fujitsu Siemens Computers GmbH - * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com> - * Licensed under the GPL - */ - -#ifndef __FAULTINFO_X86_64_H -#define __FAULTINFO_X86_64_H - -/* this structure contains the full arch-specific faultinfo - * from the traps. - * On i386, ptrace_faultinfo unfortunately doesn't provide - * all the info, since trap_no is missing. - * All common elements are defined at the same position in - * both structures, thus making it easy to copy the - * contents without knowledge about the structure elements. - */ -struct faultinfo { - int error_code; /* in ptrace_faultinfo misleadingly called is_write */ - unsigned long cr2; /* in ptrace_faultinfo called addr */ - int trap_no; /* missing in ptrace_faultinfo */ -}; - -#define FAULT_WRITE(fi) ((fi).error_code & 2) -#define FAULT_ADDRESS(fi) ((fi).cr2) - -#define PTRACE_FULL_FAULTINFO 1 - -#endif diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h deleted file mode 100644 index 8d353f0feec..00000000000 --- a/arch/um/include/sysdep-x86_64/ptrace.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_64_PTRACE_H -#define __SYSDEP_X86_64_PTRACE_H - -#include "uml-config.h" -#include "user_constants.h" -#include "sysdep/faultinfo.h" - -#define MAX_REG_OFFSET (UM_FRAME_SIZE) -#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long)) - -#ifdef UML_CONFIG_MODE_TT -#include "sysdep/sc.h" -#endif - -#ifdef UML_CONFIG_MODE_SKAS -#include "skas_ptregs.h" - -#define REGS_IP(r) ((r)[HOST_IP]) -#define REGS_SP(r) ((r)[HOST_SP]) - -#define REGS_RBX(r) ((r)[HOST_RBX]) -#define REGS_RCX(r) ((r)[HOST_RCX]) -#define REGS_RDX(r) ((r)[HOST_RDX]) -#define REGS_RSI(r) ((r)[HOST_RSI]) -#define REGS_RDI(r) ((r)[HOST_RDI]) -#define REGS_RBP(r) ((r)[HOST_RBP]) -#define REGS_RAX(r) ((r)[HOST_RAX]) -#define REGS_R8(r) ((r)[HOST_R8]) -#define REGS_R9(r) ((r)[HOST_R9]) -#define REGS_R10(r) ((r)[HOST_R10]) -#define REGS_R11(r) ((r)[HOST_R11]) -#define REGS_R12(r) ((r)[HOST_R12]) -#define REGS_R13(r) ((r)[HOST_R13]) -#define REGS_R14(r) ((r)[HOST_R14]) -#define REGS_R15(r) ((r)[HOST_R15]) -#define REGS_CS(r) ((r)[HOST_CS]) -#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS]) -#define REGS_SS(r) ((r)[HOST_SS]) - -#define HOST_FS_BASE 21 -#define HOST_GS_BASE 22 -#define HOST_DS 23 -#define HOST_ES 24 -#define HOST_FS 25 -#define HOST_GS 26 - -#define REGS_FS_BASE(r) ((r)[HOST_FS_BASE]) -#define REGS_GS_BASE(r) ((r)[HOST_GS_BASE]) -#define REGS_DS(r) ((r)[HOST_DS]) -#define REGS_ES(r) ((r)[HOST_ES]) -#define REGS_FS(r) ((r)[HOST_FS]) -#define REGS_GS(r) ((r)[HOST_GS]) - -#define REGS_ORIG_RAX(r) ((r)[HOST_ORIG_RAX]) - -#define REGS_SET_SYSCALL_RETURN(r, res) REGS_RAX(r) = (res) - -#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) - -#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type) - -#define REGS_FAULT_ADDR(r) ((r)->fault_addr) - -#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type) - -#define REGS_TRAP(r) ((r)->trap_type) - -#define REGS_ERR(r) ((r)->fault_type) - -#endif - -#include "choose-mode.h" - -/* XXX */ -union uml_pt_regs { -#ifdef UML_CONFIG_MODE_TT - struct tt_regs { - long syscall; - unsigned long orig_rax; - void *sc; - struct faultinfo faultinfo; - } tt; -#endif -#ifdef UML_CONFIG_MODE_SKAS - struct skas_regs { - /* XXX */ - unsigned long regs[27]; - unsigned long fp[65]; - struct faultinfo faultinfo; - long syscall; - int is_user; - } skas; -#endif -}; - -#define EMPTY_UML_PT_REGS { } - -/* XXX */ -extern int mode_tt; - -#define UPT_RBX(r) __CHOOSE_MODE(SC_RBX(UPT_SC(r)), REGS_RBX((r)->skas.regs)) -#define UPT_RCX(r) __CHOOSE_MODE(SC_RCX(UPT_SC(r)), REGS_RCX((r)->skas.regs)) -#define UPT_RDX(r) __CHOOSE_MODE(SC_RDX(UPT_SC(r)), REGS_RDX((r)->skas.regs)) -#define UPT_RSI(r) __CHOOSE_MODE(SC_RSI(UPT_SC(r)), REGS_RSI((r)->skas.regs)) -#define UPT_RDI(r) __CHOOSE_MODE(SC_RDI(UPT_SC(r)), REGS_RDI((r)->skas.regs)) -#define UPT_RBP(r) __CHOOSE_MODE(SC_RBP(UPT_SC(r)), REGS_RBP((r)->skas.regs)) -#define UPT_RAX(r) __CHOOSE_MODE(SC_RAX(UPT_SC(r)), REGS_RAX((r)->skas.regs)) -#define UPT_R8(r) __CHOOSE_MODE(SC_R8(UPT_SC(r)), REGS_R8((r)->skas.regs)) -#define UPT_R9(r) __CHOOSE_MODE(SC_R9(UPT_SC(r)), REGS_R9((r)->skas.regs)) -#define UPT_R10(r) __CHOOSE_MODE(SC_R10(UPT_SC(r)), REGS_R10((r)->skas.regs)) -#define UPT_R11(r) __CHOOSE_MODE(SC_R11(UPT_SC(r)), REGS_R11((r)->skas.regs)) -#define UPT_R12(r) __CHOOSE_MODE(SC_R12(UPT_SC(r)), REGS_R12((r)->skas.regs)) -#define UPT_R13(r) __CHOOSE_MODE(SC_R13(UPT_SC(r)), REGS_R13((r)->skas.regs)) -#define UPT_R14(r) __CHOOSE_MODE(SC_R14(UPT_SC(r)), REGS_R14((r)->skas.regs)) -#define UPT_R15(r) __CHOOSE_MODE(SC_R15(UPT_SC(r)), REGS_R15((r)->skas.regs)) -#define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs)) -#define UPT_FS(r) __CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs)) -#define UPT_GS(r) __CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs)) -#define UPT_DS(r) __CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs)) -#define UPT_ES(r) __CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs)) -#define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs)) -#define UPT_ORIG_RAX(r) \ - __CHOOSE_MODE((r)->tt.orig_rax, REGS_ORIG_RAX((r)->skas.regs)) - -#define UPT_IP(r) __CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs)) -#define UPT_SP(r) __CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs)) - -#define UPT_EFLAGS(r) \ - __CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs)) -#define UPT_SC(r) ((r)->tt.sc) -#define UPT_SYSCALL_NR(r) __CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall) -#define UPT_SYSCALL_RET(r) UPT_RAX(r) - -extern int user_context(unsigned long sp); - -#define UPT_IS_USER(r) \ - CHOOSE_MODE(user_context(UPT_SP(r)), (r)->skas.is_user) - -#define UPT_SYSCALL_ARG1(r) UPT_RDI(r) -#define UPT_SYSCALL_ARG2(r) UPT_RSI(r) -#define UPT_SYSCALL_ARG3(r) UPT_RDX(r) -#define UPT_SYSCALL_ARG4(r) UPT_R10(r) -#define UPT_SYSCALL_ARG5(r) UPT_R8(r) -#define UPT_SYSCALL_ARG6(r) UPT_R9(r) - -struct syscall_args { - unsigned long args[6]; -}; - -#define SYSCALL_ARGS(r) ((struct syscall_args) \ - { .args = { UPT_SYSCALL_ARG1(r), \ - UPT_SYSCALL_ARG2(r), \ - UPT_SYSCALL_ARG3(r), \ - UPT_SYSCALL_ARG4(r), \ - UPT_SYSCALL_ARG5(r), \ - UPT_SYSCALL_ARG6(r) } } ) - -#define UPT_REG(regs, reg) \ - ({ unsigned long val; \ - switch(reg){ \ - case R8: val = UPT_R8(regs); break; \ - case R9: val = UPT_R9(regs); break; \ - case R10: val = UPT_R10(regs); break; \ - case R11: val = UPT_R11(regs); break; \ - case R12: val = UPT_R12(regs); break; \ - case R13: val = UPT_R13(regs); break; \ - case R14: val = UPT_R14(regs); break; \ - case R15: val = UPT_R15(regs); break; \ - case RIP: val = UPT_IP(regs); break; \ - case RSP: val = UPT_SP(regs); break; \ - case RAX: val = UPT_RAX(regs); break; \ - case RBX: val = UPT_RBX(regs); break; \ - case RCX: val = UPT_RCX(regs); break; \ - case RDX: val = UPT_RDX(regs); break; \ - case RSI: val = UPT_RSI(regs); break; \ - case RDI: val = UPT_RDI(regs); break; \ - case RBP: val = UPT_RBP(regs); break; \ - case ORIG_RAX: val = UPT_ORIG_RAX(regs); break; \ - case CS: val = UPT_CS(regs); break; \ - case EFLAGS: val = UPT_EFLAGS(regs); break; \ - default : \ - panic("Bad register in UPT_REG : %d\n", reg); \ - val = -1; \ - } \ - val; \ - }) - - -#define UPT_SET(regs, reg, val) \ - ({ unsigned long __upt_val = val; \ - switch(reg){ \ - case R8: UPT_R8(regs) = __upt_val; break; \ - case R9: UPT_R9(regs) = __upt_val; break; \ - case R10: UPT_R10(regs) = __upt_val; break; \ - case R11: UPT_R11(regs) = __upt_val; break; \ - case R12: UPT_R12(regs) = __upt_val; break; \ - case R13: UPT_R13(regs) = __upt_val; break; \ - case R14: UPT_R14(regs) = __upt_val; break; \ - case R15: UPT_R15(regs) = __upt_val; break; \ - case RIP: UPT_IP(regs) = __upt_val; break; \ - case RSP: UPT_SP(regs) = __upt_val; break; \ - case RAX: UPT_RAX(regs) = __upt_val; break; \ - case RBX: UPT_RBX(regs) = __upt_val; break; \ - case RCX: UPT_RCX(regs) = __upt_val; break; \ - case RDX: UPT_RDX(regs) = __upt_val; break; \ - case RSI: UPT_RSI(regs) = __upt_val; break; \ - case RDI: UPT_RDI(regs) = __upt_val; break; \ - case RBP: UPT_RBP(regs) = __upt_val; break; \ - case ORIG_RAX: UPT_ORIG_RAX(regs) = __upt_val; break; \ - case CS: UPT_CS(regs) = __upt_val; break; \ - case EFLAGS: UPT_EFLAGS(regs) = __upt_val; break; \ - default : \ - panic("Bad register in UPT_SET : %d\n", reg); \ - break; \ - } \ - __upt_val; \ - }) - -#define UPT_SET_SYSCALL_RETURN(r, res) \ - CHOOSE_MODE(SC_SET_SYSCALL_RETURN(UPT_SC(r), (res)), \ - REGS_SET_SYSCALL_RETURN((r)->skas.regs, (res))) - -#define UPT_RESTART_SYSCALL(r) \ - CHOOSE_MODE(SC_RESTART_SYSCALL(UPT_SC(r)), \ - REGS_RESTART_SYSCALL((r)->skas.regs)) - -#define UPT_SEGV_IS_FIXABLE(r) \ - CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \ - REGS_SEGV_IS_FIXABLE(&r->skas)) - -#define UPT_FAULTINFO(r) \ - CHOOSE_MODE((&(r)->tt.faultinfo), (&(r)->skas.faultinfo)) - -#endif diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h deleted file mode 100644 index 128faf02736..00000000000 --- a/arch/um/include/sysdep-x86_64/ptrace_user.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_64_PTRACE_USER_H__ -#define __SYSDEP_X86_64_PTRACE_USER_H__ - -#define __FRAME_OFFSETS -#include <sys/ptrace.h> -#include <linux/ptrace.h> -#include <asm/ptrace.h> -#undef __FRAME_OFFSETS - -#define PT_INDEX(off) ((off) / sizeof(unsigned long)) - -#define PT_SYSCALL_NR(regs) ((regs)[PT_INDEX(ORIG_RAX)]) -#define PT_SYSCALL_NR_OFFSET (ORIG_RAX) - -#define PT_SYSCALL_ARG1(regs) (((unsigned long *) (regs))[PT_INDEX(RDI)]) -#define PT_SYSCALL_ARG1_OFFSET (RDI) - -#define PT_SYSCALL_ARG2(regs) (((unsigned long *) (regs))[PT_INDEX(RSI)]) -#define PT_SYSCALL_ARG2_OFFSET (RSI) - -#define PT_SYSCALL_ARG3(regs) (((unsigned long *) (regs))[PT_INDEX(RDX)]) -#define PT_SYSCALL_ARG3_OFFSET (RDX) - -#define PT_SYSCALL_ARG4(regs) (((unsigned long *) (regs))[PT_INDEX(RCX)]) -#define PT_SYSCALL_ARG4_OFFSET (RCX) - -#define PT_SYSCALL_ARG5(regs) (((unsigned long *) (regs))[PT_INDEX(R8)]) -#define PT_SYSCALL_ARG5_OFFSET (R8) - -#define PT_SYSCALL_ARG6(regs) (((unsigned long *) (regs))[PT_INDEX(R9)]) -#define PT_SYSCALL_ARG6_OFFSET (R9) - -#define PT_SYSCALL_RET_OFFSET (RAX) - -#define PT_IP_OFFSET (RIP) -#define PT_IP(regs) ((regs)[PT_INDEX(RIP)]) - -#define PT_SP_OFFSET (RSP) -#define PT_SP(regs) ((regs)[PT_INDEX(RSP)]) - -#define PT_ORIG_RAX_OFFSET (ORIG_RAX) -#define PT_ORIG_RAX(regs) ((regs)[PT_INDEX(ORIG_RAX)]) - -/* x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though - * it's defined in the kernel's include/linux/ptrace.h. Additionally, use the - * 2.4 name and value for 2.4 host compatibility. - */ -#ifndef PTRACE_OLDSETOPTIONS -#define PTRACE_OLDSETOPTIONS 21 -#endif - -/* These are before the system call, so the the system call number is RAX - * rather than ORIG_RAX, and arg4 is R10 rather than RCX - */ -#define REGS_SYSCALL_NR PT_INDEX(RAX) -#define REGS_SYSCALL_ARG1 PT_INDEX(RDI) -#define REGS_SYSCALL_ARG2 PT_INDEX(RSI) -#define REGS_SYSCALL_ARG3 PT_INDEX(RDX) -#define REGS_SYSCALL_ARG4 PT_INDEX(R10) -#define REGS_SYSCALL_ARG5 PT_INDEX(R8) -#define REGS_SYSCALL_ARG6 PT_INDEX(R9) - -#define REGS_IP_INDEX PT_INDEX(RIP) -#define REGS_SP_INDEX PT_INDEX(RSP) - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-x86_64/sc.h b/arch/um/include/sysdep-x86_64/sc.h deleted file mode 100644 index a160d9fcc59..00000000000 --- a/arch/um/include/sysdep-x86_64/sc.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __SYSDEP_X86_64_SC_H -#define __SYSDEP_X86_64_SC_H - -/* Copyright (C) 2003 - 2004 PathScale, Inc - * Released under the GPL - */ - -#include <user_constants.h> - -#define SC_OFFSET(sc, field) \ - *((unsigned long *) &(((char *) (sc))[HOST_##field])) - -#define SC_RBX(sc) SC_OFFSET(sc, SC_RBX) -#define SC_RCX(sc) SC_OFFSET(sc, SC_RCX) -#define SC_RDX(sc) SC_OFFSET(sc, SC_RDX) -#define SC_RSI(sc) SC_OFFSET(sc, SC_RSI) -#define SC_RDI(sc) SC_OFFSET(sc, SC_RDI) -#define SC_RBP(sc) SC_OFFSET(sc, SC_RBP) -#define SC_RAX(sc) SC_OFFSET(sc, SC_RAX) -#define SC_R8(sc) SC_OFFSET(sc, SC_R8) -#define SC_R9(sc) SC_OFFSET(sc, SC_R9) -#define SC_R10(sc) SC_OFFSET(sc, SC_R10) -#define SC_R11(sc) SC_OFFSET(sc, SC_R11) -#define SC_R12(sc) SC_OFFSET(sc, SC_R12) -#define SC_R13(sc) SC_OFFSET(sc, SC_R13) -#define SC_R14(sc) SC_OFFSET(sc, SC_R14) -#define SC_R15(sc) SC_OFFSET(sc, SC_R15) -#define SC_IP(sc) SC_OFFSET(sc, SC_IP) -#define SC_SP(sc) SC_OFFSET(sc, SC_SP) -#define SC_CR2(sc) SC_OFFSET(sc, SC_CR2) -#define SC_ERR(sc) SC_OFFSET(sc, SC_ERR) -#define SC_TRAPNO(sc) SC_OFFSET(sc, SC_TRAPNO) -#define SC_CS(sc) SC_OFFSET(sc, SC_CS) -#define SC_FS(sc) SC_OFFSET(sc, SC_FS) -#define SC_GS(sc) SC_OFFSET(sc, SC_GS) -#define SC_EFLAGS(sc) SC_OFFSET(sc, SC_EFLAGS) -#define SC_SIGMASK(sc) SC_OFFSET(sc, SC_SIGMASK) -#if 0 -#define SC_ORIG_RAX(sc) SC_OFFSET(sc, SC_ORIG_RAX) -#define SC_DS(sc) SC_OFFSET(sc, SC_DS) -#define SC_ES(sc) SC_OFFSET(sc, SC_ES) -#define SC_SS(sc) SC_OFFSET(sc, SC_SS) -#endif - -#endif diff --git a/arch/um/include/sysdep-x86_64/sigcontext.h b/arch/um/include/sysdep-x86_64/sigcontext.h deleted file mode 100644 index 41073235e7a..00000000000 --- a/arch/um/include/sysdep-x86_64/sigcontext.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_64_SIGCONTEXT_H -#define __SYSDEP_X86_64_SIGCONTEXT_H - -#include <sysdep/sc.h> - -#define IP_RESTART_SYSCALL(ip) ((ip) -= 2) - -#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc)) -#define SC_SET_SYSCALL_RETURN(sc, result) SC_RAX(sc) = (result) - -#define SC_FAULT_ADDR(sc) SC_CR2(sc) -#define SC_FAULT_TYPE(sc) SC_ERR(sc) - -#define GET_FAULTINFO_FROM_SC(fi,sc) \ - { \ - (fi).cr2 = SC_CR2(sc); \ - (fi).error_code = SC_ERR(sc); \ - (fi).trap_no = SC_TRAPNO(sc); \ - } - -/* ptrace expects that, at the start of a system call, %eax contains - * -ENOSYS, so this makes it so. - */ - -#define SC_START_SYSCALL(sc) do SC_RAX(sc) = -ENOSYS; while(0) - -/* This is Page Fault */ -#define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) - -/* No broken SKAS API, which doesn't pass trap_no, here. */ -#define SEGV_MAYBE_FIXABLE(fi) 0 - -extern unsigned long *sc_sigmask(void *sc_ptr); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ - diff --git a/arch/um/include/sysdep-x86_64/signal.h b/arch/um/include/sysdep-x86_64/signal.h deleted file mode 100644 index 6142897af3d..00000000000 --- a/arch/um/include/sysdep-x86_64/signal.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2004 PathScale, Inc - * Licensed under the GPL - */ - -#ifndef __X86_64_SIGNAL_H_ -#define __X86_64_SIGNAL_H_ - -#define ARCH_SIGHDLR_PARAM int sig - -#define ARCH_GET_SIGCONTEXT(sc, sig_addr) \ - do { \ - struct ucontext *__uc; \ - asm("movq %%rdx, %0" : "=r" (__uc)); \ - sc = (struct sigcontext *) &__uc->uc_mcontext; \ - } while(0) - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-x86_64/skas_ptrace.h b/arch/um/include/sysdep-x86_64/skas_ptrace.h deleted file mode 100644 index 95db4be786e..00000000000 --- a/arch/um/include/sysdep-x86_64/skas_ptrace.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_64_SKAS_PTRACE_H -#define __SYSDEP_X86_64_SKAS_PTRACE_H - -struct ptrace_faultinfo { - int is_write; - unsigned long addr; -}; - -struct ptrace_ldt { - int func; - void *ptr; - unsigned long bytecount; -}; - -#define PTRACE_LDT 54 - -#endif diff --git a/arch/um/include/sysdep-x86_64/stub.h b/arch/um/include/sysdep-x86_64/stub.h deleted file mode 100644 index 2bd6e7a9728..00000000000 --- a/arch/um/include/sysdep-x86_64/stub.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_STUB_H -#define __SYSDEP_STUB_H - -#include <asm/ptrace.h> -#include <asm/unistd.h> -#include <sysdep/ptrace_user.h> - -extern void stub_segv_handler(int sig); -extern void stub_clone_handler(void); - -#define STUB_SYSCALL_RET PT_INDEX(RAX) -#define STUB_MMAP_NR __NR_mmap -#define MMAP_OFFSET(o) (o) - -#define __syscall_clobber "r11","rcx","memory" -#define __syscall "syscall" - -static inline long stub_syscall2(long syscall, long arg1, long arg2) -{ - long ret; - - __asm__ volatile (__syscall - : "=a" (ret) - : "0" (syscall), "D" (arg1), "S" (arg2) : __syscall_clobber ); - - return ret; -} - -static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) -{ - long ret; - - __asm__ volatile (__syscall - : "=a" (ret) - : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3) - : __syscall_clobber ); - - return ret; -} - -static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, - long arg4) -{ - long ret; - - __asm__ volatile ("movq %5,%%r10 ; " __syscall - : "=a" (ret) - : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3), - "g" (arg4) - : __syscall_clobber, "r10" ); - - return ret; -} - -static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, - long arg4, long arg5) -{ - long ret; - - __asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; " __syscall - : "=a" (ret) - : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3), - "g" (arg4), "g" (arg5) - : __syscall_clobber, "r10", "r8" ); - - return ret; -} - -static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3, - long arg4, long arg5, long arg6) -{ - long ret; - - __asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; " - "movq %7, %%r9; " __syscall : "=a" (ret) - : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3), - "g" (arg4), "g" (arg5), "g" (arg6) - : __syscall_clobber, "r10", "r8", "r9" ); - - return ret; -} - -static inline void trap_myself(void) -{ - __asm("int3"); -} - -#endif diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h deleted file mode 100644 index e06f83e80f4..00000000000 --- a/arch/um/include/sysdep-x86_64/syscalls.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_64_SYSCALLS_H__ -#define __SYSDEP_X86_64_SYSCALLS_H__ - -#include <linux/msg.h> -#include <linux/shm.h> - -typedef long syscall_handler_t(void); - -extern syscall_handler_t *ia32_sys_call_table[]; - -extern syscall_handler_t *sys_call_table[]; - -#define EXECUTE_SYSCALL(syscall, regs) \ - (((long (*)(long, long, long, long, long, long)) \ - (*sys_call_table[syscall]))(UPT_SYSCALL_ARG1(®s->regs), \ - UPT_SYSCALL_ARG2(®s->regs), \ - UPT_SYSCALL_ARG3(®s->regs), \ - UPT_SYSCALL_ARG4(®s->regs), \ - UPT_SYSCALL_ARG5(®s->regs), \ - UPT_SYSCALL_ARG6(®s->regs))) - -extern long old_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -extern syscall_handler_t sys_modify_ldt; -extern syscall_handler_t sys_arch_prctl; - -#define NR_syscalls (__NR_syscall_max + 1) - -#endif diff --git a/arch/um/include/sysdep-x86_64/thread.h b/arch/um/include/sysdep-x86_64/thread.h deleted file mode 100644 index cbef3e1697f..00000000000 --- a/arch/um/include/sysdep-x86_64/thread.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __UM_THREAD_H -#define __UM_THREAD_H - -#include <kern_constants.h> - -#ifdef UML_CONFIG_MODE_TT -#define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[HOST_TASK_EXTERN_PID])) -#endif - -#endif diff --git a/arch/um/include/task.h b/arch/um/include/task.h deleted file mode 100644 index 6375ba7203c..00000000000 --- a/arch/um/include/task.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __TASK_H -#define __TASK_H - -#include <kern_constants.h> - -#define TASK_REGS(task) ((union uml_pt_regs *) &(((char *) (task))[HOST_TASK_REGS])) -#define TASK_PID(task) *((int *) &(((char *) (task))[HOST_TASK_PID])) - -#endif diff --git a/arch/um/include/tempfile.h b/arch/um/include/tempfile.h deleted file mode 100644 index e36d9e0f510..00000000000 --- a/arch/um/include/tempfile.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __TEMPFILE_H__ -#define __TEMPFILE_H__ - -extern int make_tempfile(const char *template, char **tempname, int do_unlink); - -#endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h deleted file mode 100644 index 17d7ef2141f..00000000000 --- a/arch/um/include/time_user.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __TIME_USER_H__ -#define __TIME_USER_H__ - -extern void timer(void); -extern void switch_timers(int to_real); -extern void idle_sleep(int secs); -extern void enable_timer(void); -extern void prepare_timer(void * ptr); -extern void disable_timer(void); -extern unsigned long time_lock(void); -extern void time_unlock(unsigned long); -extern void user_time_init(void); - -#endif diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h deleted file mode 100644 index 8efc1e0f1b8..00000000000 --- a/arch/um/include/tlb.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __TLB_H__ -#define __TLB_H__ - -#include "um_mmu.h" - -struct host_vm_op { - enum { NONE, MMAP, MUNMAP, MPROTECT } type; - union { - struct { - unsigned long addr; - unsigned long len; - unsigned int r:1; - unsigned int w:1; - unsigned int x:1; - int fd; - __u64 offset; - } mmap; - struct { - unsigned long addr; - unsigned long len; - } munmap; - struct { - unsigned long addr; - unsigned long len; - unsigned int r:1; - unsigned int w:1; - unsigned int x:1; - } mprotect; - } u; -}; - -extern void force_flush_all(void); -extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr, - unsigned long end_addr, int force, - int (*do_ops)(union mm_context *, - struct host_vm_op *, int, int, - void **)); -extern int flush_tlb_kernel_range_common(unsigned long start, - unsigned long end); - -#endif diff --git a/arch/um/include/ubd_user.h b/arch/um/include/ubd_user.h deleted file mode 100644 index bb66517f073..00000000000 --- a/arch/um/include/ubd_user.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com) - * Licensed under the GPL - */ - -#ifndef __UM_UBD_USER_H -#define __UM_UBD_USER_H - -extern void ignore_sigwinch_sig(void); -extern int start_io_thread(unsigned long sp, int *fds_out); -extern int io_thread(void *arg); -extern int kernel_fd; - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/um_mmu.h b/arch/um/include/um_mmu.h deleted file mode 100644 index 0fa64323830..00000000000 --- a/arch/um/include/um_mmu.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __ARCH_UM_MMU_H -#define __ARCH_UM_MMU_H - -#include "uml-config.h" -#include "choose-mode.h" - -#ifdef UML_CONFIG_MODE_TT -#include "mmu-tt.h" -#endif - -#ifdef UML_CONFIG_MODE_SKAS -#include "mmu-skas.h" -#endif - -typedef union mm_context { -#ifdef UML_CONFIG_MODE_TT - struct mmu_context_tt tt; -#endif -#ifdef UML_CONFIG_MODE_SKAS - struct mmu_context_skas skas; -#endif -} mm_context_t; - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h deleted file mode 100644 index 84c0868cd56..00000000000 --- a/arch/um/include/um_uaccess.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __ARCH_UM_UACCESS_H -#define __ARCH_UM_UACCESS_H - -#include "linux/config.h" -#include "choose-mode.h" - -#ifdef CONFIG_MODE_TT -#include "uaccess-tt.h" -#endif - -#ifdef CONFIG_MODE_SKAS -#include "uaccess-skas.h" -#endif - -#define access_ok(type, addr, size) \ - CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size) - -static inline int copy_from_user(void *to, const void __user *from, int n) -{ - return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to, - from, n)); -} - -static inline int copy_to_user(void __user *to, const void *from, int n) -{ - return(CHOOSE_MODE_PROC(copy_to_user_tt, copy_to_user_skas, to, - from, n)); -} - -/* - * strncpy_from_user: - Copy a NUL terminated string from userspace. - * @dst: Destination address, in kernel space. This buffer must be at - * least @count bytes long. - * @src: Source address, in user space. - * @count: Maximum number of bytes to copy, including the trailing NUL. - * - * Copies a NUL-terminated string from userspace to kernel space. - * - * On success, returns the length of the string (not including the trailing - * NUL). - * - * If access to userspace fails, returns -EFAULT (some data may have been - * copied). - * - * If @count is smaller than the length of the string, copies @count bytes - * and returns @count. - */ - -static inline int strncpy_from_user(char *dst, const char __user *src, int count) -{ - return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas, - dst, src, count)); -} - -/* - * __clear_user: - Zero a block of memory in user space, with less checking. - * @to: Destination address, in user space. - * @n: Number of bytes to zero. - * - * Zero a block of memory in user space. Caller must check - * the specified block with access_ok() before calling this function. - * - * Returns number of bytes that could not be cleared. - * On success, this will be zero. - */ -static inline int __clear_user(void *mem, int len) -{ - return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len)); -} - -/* - * clear_user: - Zero a block of memory in user space. - * @to: Destination address, in user space. - * @n: Number of bytes to zero. - * - * Zero a block of memory in user space. - * - * Returns number of bytes that could not be cleared. - * On success, this will be zero. - */ -static inline int clear_user(void __user *mem, int len) -{ - return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len)); -} - -/* - * strlen_user: - Get the size of a string in user space. - * @str: The string to measure. - * @n: The maximum valid length - * - * Get the size of a NUL-terminated string in user space. - * - * Returns the size of the string INCLUDING the terminating NUL. - * On exception, returns 0. - * If the string is too long, returns a value greater than @n. - */ -static inline int strnlen_user(const void __user *str, long len) -{ - return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len)); -} - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/umid.h b/arch/um/include/umid.h deleted file mode 100644 index 11373c851f1..00000000000 --- a/arch/um/include/umid.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __UMID_H__ -#define __UMID_H__ - -extern int umid_file_name(char *name, char *buf, int len); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/uml_uaccess.h b/arch/um/include/uml_uaccess.h deleted file mode 100644 index c0df11d06f5..00000000000 --- a/arch/um/include/uml_uaccess.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __UML_UACCESS_H__ -#define __UML_UACCESS_H__ - -extern int __do_copy_to_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher); -void __do_copy(void *to, const void *from, int n); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/user.h b/arch/um/include/user.h deleted file mode 100644 index 0f865ef4691..00000000000 --- a/arch/um/include/user.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __USER_H__ -#define __USER_H__ - -extern void panic(const char *fmt, ...); -extern int printk(const char *fmt, ...); -extern void schedule(void); -extern void *um_kmalloc(int size); -extern void *um_kmalloc_atomic(int size); -extern void kfree(void *ptr); -extern int in_aton(char *str); -extern int open_gdb_chan(void); -/* These use size_t, however unsigned long is correct on both i386 and x86_64. */ -extern unsigned long strlcpy(char *, const char *, unsigned long); -extern unsigned long strlcat(char *, const char *, unsigned long); -extern void *um_vmalloc(int size); -extern void vfree(void *ptr); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h deleted file mode 100644 index bb505e01d99..00000000000 --- a/arch/um/include/user_util.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __USER_UTIL_H__ -#define __USER_UTIL_H__ - -#include "sysdep/ptrace.h" - -#define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) - -extern int mode_tt; - -extern int grantpt(int __fd); -extern int unlockpt(int __fd); -extern char *ptsname(int __fd); - -struct cpu_task { - int pid; - void *task; -}; - -extern struct cpu_task cpu_tasks[]; - -struct signal_info { - void (*handler)(int, union uml_pt_regs *); - int is_irq; -}; - -extern struct signal_info sig_info[]; - -extern unsigned long low_physmem; -extern unsigned long high_physmem; -extern unsigned long uml_physmem; -extern unsigned long uml_reserved; -extern unsigned long end_vm; -extern unsigned long start_vm; -extern unsigned long highmem; - -extern char host_info[]; - -extern char saved_command_line[]; - -extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; -extern unsigned long _unprotected_end; -extern unsigned long brk_start; - -extern int pty_output_sigio; -extern int pty_close_sigio; - -extern void stop(void); -extern void stack_protections(unsigned long address); -extern void task_protections(unsigned long address); -extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); -extern void *add_signal_handler(int sig, void (*handler)(int)); -extern int linux_main(int argc, char **argv); -extern void set_cmdline(char *cmd); -extern void input_cb(void (*proc)(void *), void *arg, int arg_len); -extern int get_pty(void); -extern void *um_kmalloc(int size); -extern int switcheroo(int fd, int prot, void *from, void *to, int size); -extern void setup_machinename(char *machine_out); -extern void setup_hostinfo(void); -extern void do_exec(int old_pid, int new_pid); -extern void tracer_panic(char *msg, ...); -extern char *get_umid(int only_if_set); -extern void do_longjmp(void *p, int val); -extern int detach(int pid, int sig); -extern int attach(int pid); -extern void kill_child_dead(int pid); -extern int cont(int pid); -extern void check_sigio(void); -extern void write_sigio_workaround(void); -extern void arch_check_bugs(void); -extern int cpu_feature(char *what, char *buf, int len); -extern int arch_handle_signal(int sig, union uml_pt_regs *regs); -extern int arch_fixup(unsigned long address, void *sc_ptr); -extern void arch_init_thread(void); -extern int setjmp_wrapper(void (*proc)(void *, void *), ...); -extern int raw(int fd); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 3de9d21e36b..d8b78a03855 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -1,30 +1,26 @@ # -# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux,intel}.com) # Licensed under the GPL # +CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START) \ + -DELF_ARCH=$(LDS_ELF_ARCH) \ + -DELF_FORMAT=$(LDS_ELF_FORMAT) \ + $(LDS_EXTRA) extra-y := vmlinux.lds clean-files := -obj-y = config.o exec_kern.o exitcode.o \ - init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \ - process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ - signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o time.o \ - time_kern.o tlb.o trap_kern.o trap_user.o uaccess.o um_arch.o \ - umid.o user_util.o +obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \ + physmem.o process.o ptrace.o reboot.o sigio.o \ + signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o \ + um_arch.o umid.o maccess.o skas/ obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o -obj-$(CONFIG_TTY_LOG) += tty_log.o -obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_MODE_TT) += tt/ -obj-$(CONFIG_MODE_SKAS) += skas/ - -user-objs-$(CONFIG_TTY_LOG) += tty_log.o - -USER_OBJS := $(user-objs-y) config.o time.o tty_log.o umid.o user_util.o +USER_OBJS := config.o include arch/um/scripts/Makefile.rules @@ -37,7 +33,7 @@ $(obj)/config.tmp: $(objtree)/.config FORCE $(call if_changed,quote1) quiet_cmd_quote1 = QUOTE $@ - cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' \ + cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n",/' \ $< > $@ $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE @@ -45,9 +41,9 @@ $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE quiet_cmd_quote2 = QUOTE $@ cmd_quote2 = sed -e '/CONFIG/{' \ - -e 's/"CONFIG"\;/""/' \ + -e 's/"CONFIG"//' \ -e 'r $(obj)/config.tmp' \ -e 'a \' \ - -e '""\;' \ + -e '""' \ -e '}' \ $< > $@ diff --git a/arch/um/kernel/asm-offsets.c b/arch/um/kernel/asm-offsets.c index c13a64a288f..1fb12235ab9 100644 --- a/arch/um/kernel/asm-offsets.c +++ b/arch/um/kernel/asm-offsets.c @@ -1 +1 @@ -/* Dummy file to make kbuild happy - unused! */ +#include <sysdep/kernel-offsets.h> diff --git a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in index c062cbfe386..972bf165956 100644 --- a/arch/um/kernel/config.c.in +++ b/arch/um/kernel/config.c.in @@ -5,13 +5,17 @@ #include <stdio.h> #include <stdlib.h> -#include "init.h" +#include <init.h> -static __initdata char *config = "CONFIG"; +static __initdata const char *config[] = { +"CONFIG" +}; static int __init print_config(char *line, int *add) { - printf("%s", config); + int i; + for (i = 0; i < sizeof(config)/sizeof(config[0]); i++) + printf("%s", config[i]); exit(0); } @@ -20,13 +24,3 @@ __uml_setup("--showconfig", print_config, " Prints the config file that this UML binary was generated from.\n\n" ); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index 2517ecb8bf2..adde088aeef 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -1,4 +1,5 @@ #include <asm-generic/vmlinux.lds.h> +#include <asm/page.h> OUTPUT_FORMAT(ELF_FORMAT) OUTPUT_ARCH(ELF_ARCH) @@ -10,22 +11,16 @@ SECTIONS PROVIDE (__executable_start = START); . = START + SIZEOF_HEADERS; .interp : { *(.interp) } - /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start - * is remapped.*/ __binary_start = .; . = ALIGN(4096); /* Init code and data */ - _stext = .; - __init_begin = .; - .init.text : { - _sinittext = .; - *(.init.text) - _einittext = .; - } + _text = .; + INIT_TEXT_SECTION(PAGE_SIZE) - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); /* Read-only sections, merged into text segment: */ .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } @@ -53,14 +48,25 @@ SECTIONS .rela.got : { *(.rela.got) } .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } + .rel.plt : { + *(.rel.plt) + PROVIDE_HIDDEN(__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN(__rel_iplt_end = .); + } + .rela.plt : { + *(.rela.plt) + PROVIDE_HIDDEN(__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN(__rela_iplt_end = .); + } .init : { KEEP (*(.init)) } =0x90909090 .plt : { *(.plt) } .text : { - *(.text) + _stext = .; + TEXT_TEXT SCHED_TEXT LOCK_TEXT *(.fixup) @@ -68,21 +74,25 @@ SECTIONS /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) - . = ALIGN(4096); - __syscall_stub_start = .; - *(.__syscall_stub*) - __syscall_stub_end = .; - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); } =0x90909090 + . = ALIGN(PAGE_SIZE); + .syscall_stub : { + __syscall_stub_start = .; + *(.__syscall_stub*) + __syscall_stub_end = .; + } .fini : { KEEP (*(.fini)) } =0x90909090 .kstrtab : { *(.kstrtab) } - #include "asm/common.lds.S" + #include <asm/common.lds.S> - init.data : { *(.init.data) } + __init_begin = .; + init.data : { INIT_DATA } + __init_end = .; /* Ensure the __preinit_array_start label is properly aligned. We could instead move the label definition inside the section, but @@ -93,9 +103,11 @@ SECTIONS .init_array : { *(.init_array) } .fini_array : { *(.fini_array) } .data : { - . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ - *(.data.init_task) - *(.data .data.* .gnu.linkonce.d.*) + INIT_TASK_DATA(KERNEL_STACK_SIZE) + . = ALIGN(KERNEL_STACK_SIZE); + *(.data..init_irqstack) + DATA_DATA + *(.data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } .data1 : { *(.data1) } @@ -133,8 +145,8 @@ SECTIONS .got : { *(.got.plt) *(.got) } _edata = .; PROVIDE (edata = .); - __bss_start = .; .bss : { + __bss_start = .; *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) @@ -144,10 +156,13 @@ SECTIONS . = ALIGN(32 / 8); . = ALIGN(32 / 8); } + __bss_stop = .; _end = .; PROVIDE (end = .); STABS_DEBUG DWARF_DEBUG + + DISCARDS } diff --git a/arch/um/kernel/early_printk.c b/arch/um/kernel/early_printk.c new file mode 100644 index 00000000000..4a0800bc37b --- /dev/null +++ b/arch/um/kernel/early_printk.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/console.h> +#include <linux/init.h> +#include <os.h> + +static void early_console_write(struct console *con, const char *s, unsigned int n) +{ + um_early_printk(s, n); +} + +static struct console early_console_dev = { + .name = "earlycon", + .write = early_console_write, + .flags = CON_BOOT, + .index = -1, +}; + +static int __init setup_early_printk(char *buf) +{ + if (!early_console) { + early_console = &early_console_dev; + register_console(&early_console_dev); + } + return 0; +} + +early_param("earlyprintk", setup_early_printk); diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c new file mode 100644 index 00000000000..0d7103c9eff --- /dev/null +++ b/arch/um/kernel/exec.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <linux/stddef.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <asm/current.h> +#include <asm/processor.h> +#include <asm/uaccess.h> +#include <as-layout.h> +#include <mem_user.h> +#include <skas.h> +#include <os.h> + +void flush_thread(void) +{ + void *data = NULL; + int ret; + + arch_flush_thread(¤t->thread.arch); + + ret = unmap(¤t->mm->context.id, 0, STUB_START, 0, &data); + ret = ret || unmap(¤t->mm->context.id, STUB_END, + host_task_size - STUB_END, 1, &data); + if (ret) { + printk(KERN_ERR "flush_thread - clearing address space failed, " + "err = %d\n", ret); + force_sig(SIGKILL, current); + } + get_safe_registers(current_pt_regs()->regs.gp, + current_pt_regs()->regs.fp); + + __switch_mm(¤t->mm->context.id); +} + +void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) +{ + PT_REGS_IP(regs) = eip; + PT_REGS_SP(regs) = esp; + current->ptrace &= ~PT_DTRACE; +#ifdef SUBARCH_EXECVE1 + SUBARCH_EXECVE1(regs->regs); +#endif +} +EXPORT_SYMBOL(start_thread); diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c deleted file mode 100644 index efd222ffe20..00000000000 --- a/arch/um/kernel/exec_kern.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/slab.h" -#include "linux/smp_lock.h" -#include "linux/ptrace.h" -#include "asm/ptrace.h" -#include "asm/pgtable.h" -#include "asm/tlbflush.h" -#include "asm/uaccess.h" -#include "user_util.h" -#include "kern_util.h" -#include "mem_user.h" -#include "kern.h" -#include "irq_user.h" -#include "tlb.h" -#include "os.h" -#include "time_user.h" -#include "choose-mode.h" -#include "mode_kern.h" - -void flush_thread(void) -{ - CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); -} - -void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) -{ - CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); -} - -extern void log_exec(char **argv, void *tty); - -static long execve1(char *file, char __user * __user *argv, - char *__user __user *env) -{ - long error; - -#ifdef CONFIG_TTY_LOG - log_exec(argv, current->tty); -#endif - error = do_execve(file, argv, env, ¤t->thread.regs); - if (error == 0){ - task_lock(current); - current->ptrace &= ~PT_DTRACE; - task_unlock(current); - set_cmdline(current_cmd()); - } - return(error); -} - -long um_execve(char *file, char __user *__user *argv, char __user *__user *env) -{ - long err; - - err = execve1(file, argv, env); - if(!err) - do_longjmp(current->thread.exec_buf, 1); - return(err); -} - -long sys_execve(char *file, char __user *__user *argv, - char __user *__user *env) -{ - long error; - char *filename; - - lock_kernel(); - filename = getname((char __user *) file); - error = PTR_ERR(filename); - if (IS_ERR(filename)) goto out; - error = execve1(filename, argv, env); - putname(filename); - out: - unlock_kernel(); - return(error); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index d21ebad666b..41ebbfebb33 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -1,73 +1,80 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/init.h" -#include "linux/ctype.h" -#include "linux/proc_fs.h" -#include "asm/uaccess.h" +#include <linux/ctype.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/types.h> +#include <asm/uaccess.h> -/* If read and write race, the read will still atomically read a valid +/* + * If read and write race, the read will still atomically read a valid * value. */ int uml_exitcode = 0; -static int read_proc_exitcode(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int exitcode_proc_show(struct seq_file *m, void *v) { - int len; + int val; + + /* + * Save uml_exitcode in a local so that we don't need to guarantee + * that sprintf accesses it atomically. + */ + val = uml_exitcode; + seq_printf(m, "%d\n", val); + return 0; +} - len = sprintf(page, "%d\n", uml_exitcode); - len -= off; - if(len <= off+count) *eof = 1; - *start = page + off; - if(len > count) len = count; - if(len < 0) len = 0; - return(len); +static int exitcode_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, exitcode_proc_show, NULL); } -static int write_proc_exitcode(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static ssize_t exitcode_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) { char *end, buf[sizeof("nnnnn\0")]; + size_t size; int tmp; - if(copy_from_user(buf, buffer, count)) - return(-EFAULT); + size = min(count, sizeof(buf)); + if (copy_from_user(buf, buffer, size)) + return -EFAULT; + tmp = simple_strtol(buf, &end, 0); - if((*end != '\0') && !isspace(*end)) - return(-EINVAL); + if ((*end != '\0') && !isspace(*end)) + return -EINVAL; + uml_exitcode = tmp; - return(count); + return count; } +static const struct file_operations exitcode_proc_fops = { + .owner = THIS_MODULE, + .open = exitcode_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = exitcode_proc_write, +}; + static int make_proc_exitcode(void) { struct proc_dir_entry *ent; - ent = create_proc_entry("exitcode", 0600, &proc_root); - if(ent == NULL){ + ent = proc_create("exitcode", 0600, NULL, &exitcode_proc_fops); + if (ent == NULL) { printk(KERN_WARNING "make_proc_exitcode : Failed to register " "/proc/exitcode\n"); - return(0); + return 0; } - - ent->read_proc = read_proc_exitcode; - ent->write_proc = write_proc_exitcode; - - return(0); + return 0; } __initcall(make_proc_exitcode); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c index 2c86e7fdb01..1bf61266da8 100644 --- a/arch/um/kernel/gmon_syms.c +++ b/arch/um/kernel/gmon_syms.c @@ -1,34 +1,9 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/module.h" +#include <linux/module.h> -extern void __bb_init_func(void *); +extern void __bb_init_func(void *) __attribute__((weak)); EXPORT_SYMBOL(__bb_init_func); - -/* This is defined (and referred to in profiling stub code) only by some GCC - * versions in libgcov. - * - * Since SuSE backported the fix, we cannot handle it depending on GCC version. - * So, unconditinally export it. But also give it a weak declaration, which will - * be overriden by any other one. - */ - -extern void __gcov_init(void *) __attribute__((weak)); -EXPORT_SYMBOL(__gcov_init); - -extern void __gcov_merge_add(void *) __attribute__((weak)); -EXPORT_SYMBOL(__gcov_merge_add); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/gprof_syms.c b/arch/um/kernel/gprof_syms.c index 9244f018d44..74ddb44288a 100644 --- a/arch/um/kernel/gprof_syms.c +++ b/arch/um/kernel/gprof_syms.c @@ -1,20 +1,9 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/module.h" +#include <linux/module.h> extern void mcount(void); EXPORT_SYMBOL(mcount); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c deleted file mode 100644 index 49ed5ddf070..00000000000 --- a/arch/um/kernel/init_task.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/config.h" -#include "linux/mm.h" -#include "linux/module.h" -#include "linux/sched.h" -#include "linux/init_task.h" -#include "linux/mqueue.h" -#include "asm/uaccess.h" -#include "asm/pgtable.h" -#include "user_util.h" -#include "mem_user.h" -#include "os.h" - -static struct fs_struct init_fs = INIT_FS; -struct mm_struct init_mm = INIT_MM(init_mm); -static struct files_struct init_files = INIT_FILES; -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -EXPORT_SYMBOL(init_mm); - -/* - * Initial task structure. - * - * All other task structs will be allocated on slabs in fork.c - */ - -struct task_struct init_task = INIT_TASK(init_task); - -EXPORT_SYMBOL(init_task); - -/* - * Initial thread structure. - * - * We need to make sure that this is 16384-byte aligned due to the - * way process stacks are handled. This is done by having a special - * "init_task" linker map entry.. - */ - -union thread_union init_thread_union -__attribute__((__section__(".data.init_task"))) = -{ INIT_THREAD_INFO(init_task) }; - -void unprotect_stack(unsigned long stack) -{ - os_protect_memory((void *) stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, - 1, 1, 0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c index 82ecf904b09..55cead809b1 100644 --- a/arch/um/kernel/initrd.c +++ b/arch/um/kernel/initrd.c @@ -1,20 +1,18 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/init.h" -#include "linux/bootmem.h" -#include "linux/initrd.h" -#include "asm/types.h" -#include "user_util.h" -#include "kern_util.h" -#include "initrd.h" -#include "init.h" -#include "os.h" +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/initrd.h> +#include <asm/types.h> +#include <init.h> +#include <os.h> /* Changed by uml_initrd_setup, which is a setup */ static char *initrd __initdata = NULL; +static int load_initrd(char *filename, void *buf, int size); static int __init read_initrd(void) { @@ -22,12 +20,29 @@ static int __init read_initrd(void) long long size; int err; - if(initrd == NULL) return 0; + if (initrd == NULL) + return 0; + err = os_file_size(initrd, &size); - if(err) return 0; + if (err) + return 0; + + /* + * This is necessary because alloc_bootmem craps out if you + * ask for no memory. + */ + if (size == 0) { + printk(KERN_ERR "\"%s\" is a zero-size initrd\n", initrd); + return 0; + } + area = alloc_bootmem(size); - if(area == NULL) return 0; - if(load_initrd(initrd, area, size) == -1) return 0; + if (area == NULL) + return 0; + + if (load_initrd(initrd, area, size) == -1) + return 0; + initrd_start = (unsigned long) area; initrd_end = initrd_start + size; return 0; @@ -47,32 +62,24 @@ __uml_setup("initrd=", uml_initrd_setup, " name of the file containing the image.\n\n" ); -int load_initrd(char *filename, void *buf, int size) +static int load_initrd(char *filename, void *buf, int size) { int fd, n; fd = os_open_file(filename, of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Opening '%s' failed - err = %d\n", filename, -fd); - return(-1); + if (fd < 0) { + printk(KERN_ERR "Opening '%s' failed - err = %d\n", filename, + -fd); + return -1; } n = os_read_file(fd, buf, size); - if(n != size){ - printk("Read of %d bytes from '%s' failed, err = %d\n", size, + if (n != size) { + printk(KERN_ERR "Read of %d bytes from '%s' failed, " + "err = %d\n", size, filename, -n); - return(-1); + return -1; } os_close_file(fd); - return(0); + return 0; } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index bbf94bf2921..1d8505b1e29 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -1,198 +1,473 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c: * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar */ -#include "linux/config.h" -#include "linux/kernel.h" -#include "linux/module.h" -#include "linux/smp.h" -#include "linux/kernel_stat.h" -#include "linux/interrupt.h" -#include "linux/random.h" -#include "linux/slab.h" -#include "linux/file.h" -#include "linux/proc_fs.h" -#include "linux/init.h" -#include "linux/seq_file.h" -#include "linux/profile.h" -#include "linux/hardirq.h" -#include "asm/irq.h" -#include "asm/hw_irq.h" -#include "asm/atomic.h" -#include "asm/signal.h" -#include "asm/system.h" -#include "asm/errno.h" -#include "asm/uaccess.h" -#include "user_util.h" -#include "kern_util.h" -#include "irq_user.h" -#include "irq_kern.h" -#include "os.h" +#include <linux/cpumask.h> +#include <linux/hardirq.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> /* - * Generic, controller-independent functions: + * This list is accessed under irq_lock, except in sigio_handler, + * where it is safe from being modified. IRQ handlers won't change it - + * if an IRQ source has vanished, it will be freed by free_irqs just + * before returning from sigio_handler. That will process a separate + * list of irqs to free, with its own locking, coming back here to + * remove list elements, taking the irq_lock to do so. */ +static struct irq_fd *active_fds = NULL; +static struct irq_fd **last_irq_ptr = &active_fds; + +extern void free_irqs(void); + +void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) +{ + struct irq_fd *irq_fd; + int n; + + if (smp_sigio_handler()) + return; + + while (1) { + n = os_waiting_for_events(active_fds); + if (n <= 0) { + if (n == -EINTR) + continue; + else break; + } + + for (irq_fd = active_fds; irq_fd != NULL; + irq_fd = irq_fd->next) { + if (irq_fd->current_events != 0) { + irq_fd->current_events = 0; + do_IRQ(irq_fd->irq, regs); + } + } + } + + free_irqs(); +} + +static DEFINE_SPINLOCK(irq_lock); + +static int activate_fd(int irq, int fd, int type, void *dev_id) +{ + struct pollfd *tmp_pfd; + struct irq_fd *new_fd, *irq_fd; + unsigned long flags; + int events, err, n; + + err = os_set_fd_async(fd); + if (err < 0) + goto out; + + err = -ENOMEM; + new_fd = kmalloc(sizeof(struct irq_fd), GFP_KERNEL); + if (new_fd == NULL) + goto out; + + if (type == IRQ_READ) + events = UM_POLLIN | UM_POLLPRI; + else events = UM_POLLOUT; + *new_fd = ((struct irq_fd) { .next = NULL, + .id = dev_id, + .fd = fd, + .type = type, + .irq = irq, + .events = events, + .current_events = 0 } ); + + err = -EBUSY; + spin_lock_irqsave(&irq_lock, flags); + for (irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next) { + if ((irq_fd->fd == fd) && (irq_fd->type == type)) { + printk(KERN_ERR "Registering fd %d twice\n", fd); + printk(KERN_ERR "Irqs : %d, %d\n", irq_fd->irq, irq); + printk(KERN_ERR "Ids : 0x%p, 0x%p\n", irq_fd->id, + dev_id); + goto out_unlock; + } + } + + if (type == IRQ_WRITE) + fd = -1; + + tmp_pfd = NULL; + n = 0; + + while (1) { + n = os_create_pollfd(fd, events, tmp_pfd, n); + if (n == 0) + break; + + /* + * n > 0 + * It means we couldn't put new pollfd to current pollfds + * and tmp_fds is NULL or too small for new pollfds array. + * Needed size is equal to n as minimum. + * + * Here we have to drop the lock in order to call + * kmalloc, which might sleep. + * If something else came in and changed the pollfds array + * so we will not be able to put new pollfd struct to pollfds + * then we free the buffer tmp_fds and try again. + */ + spin_unlock_irqrestore(&irq_lock, flags); + kfree(tmp_pfd); + + tmp_pfd = kmalloc(n, GFP_KERNEL); + if (tmp_pfd == NULL) + goto out_kfree; + + spin_lock_irqsave(&irq_lock, flags); + } + + *last_irq_ptr = new_fd; + last_irq_ptr = &new_fd->next; + + spin_unlock_irqrestore(&irq_lock, flags); + + /* + * This calls activate_fd, so it has to be outside the critical + * section. + */ + maybe_sigio_broken(fd, (type == IRQ_READ)); + + return 0; + + out_unlock: + spin_unlock_irqrestore(&irq_lock, flags); + out_kfree: + kfree(new_fd); + out: + return err; +} + +static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) +{ + unsigned long flags; + + spin_lock_irqsave(&irq_lock, flags); + os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr); + spin_unlock_irqrestore(&irq_lock, flags); +} + +struct irq_and_dev { + int irq; + void *dev; +}; + +static int same_irq_and_dev(struct irq_fd *irq, void *d) +{ + struct irq_and_dev *data = d; + + return ((irq->irq == data->irq) && (irq->id == data->dev)); +} + +static void free_irq_by_irq_and_dev(unsigned int irq, void *dev) +{ + struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq, + .dev = dev }); + + free_irq_by_cb(same_irq_and_dev, &data); +} + +static int same_fd(struct irq_fd *irq, void *fd) +{ + return (irq->fd == *((int *)fd)); +} + +void free_irq_by_fd(int fd) +{ + free_irq_by_cb(same_fd, &fd); +} + +/* Must be called with irq_lock held */ +static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) +{ + struct irq_fd *irq; + int i = 0; + int fdi; + + for (irq = active_fds; irq != NULL; irq = irq->next) { + if ((irq->fd == fd) && (irq->irq == irqnum)) + break; + i++; + } + if (irq == NULL) { + printk(KERN_ERR "find_irq_by_fd doesn't have descriptor %d\n", + fd); + goto out; + } + fdi = os_get_pollfd(i); + if ((fdi != -1) && (fdi != fd)) { + printk(KERN_ERR "find_irq_by_fd - mismatch between active_fds " + "and pollfds, fd %d vs %d, need %d\n", irq->fd, + fdi, fd); + irq = NULL; + goto out; + } + *index_out = i; + out: + return irq; +} + +void reactivate_fd(int fd, int irqnum) +{ + struct irq_fd *irq; + unsigned long flags; + int i; + + spin_lock_irqsave(&irq_lock, flags); + irq = find_irq_by_fd(fd, irqnum, &i); + if (irq == NULL) { + spin_unlock_irqrestore(&irq_lock, flags); + return; + } + os_set_pollfd(i, irq->fd); + spin_unlock_irqrestore(&irq_lock, flags); + + add_sigio_fd(fd); +} -int show_interrupts(struct seq_file *p, void *v) +void deactivate_fd(int fd, int irqnum) { - int i = *(loff_t *) v, j; - struct irqaction * action; + struct irq_fd *irq; unsigned long flags; + int i; - if (i == 0) { - seq_printf(p, " "); - for_each_online_cpu(j) - seq_printf(p, "CPU%d ",j); - seq_putc(p, '\n'); + spin_lock_irqsave(&irq_lock, flags); + irq = find_irq_by_fd(fd, irqnum, &i); + if (irq == NULL) { + spin_unlock_irqrestore(&irq_lock, flags); + return; } - if (i < NR_IRQS) { - spin_lock_irqsave(&irq_desc[i].lock, flags); - action = irq_desc[i].action; - if (!action) - goto skip; - seq_printf(p, "%3d: ",i); -#ifndef CONFIG_SMP - seq_printf(p, "%10u ", kstat_irqs(i)); -#else - for_each_online_cpu(j) - seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); -#endif - seq_printf(p, " %14s", irq_desc[i].handler->typename); - seq_printf(p, " %s", action->name); - - for (action=action->next; action; action = action->next) - seq_printf(p, ", %s", action->name); - - seq_putc(p, '\n'); -skip: - spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } else if (i == NR_IRQS) { - seq_putc(p, '\n'); + os_set_pollfd(i, -1); + spin_unlock_irqrestore(&irq_lock, flags); + + ignore_sigio_fd(fd); +} +EXPORT_SYMBOL(deactivate_fd); + +/* + * Called just before shutdown in order to provide a clean exec + * environment in case the system is rebooting. No locking because + * that would cause a pointless shutdown hang if something hadn't + * released the lock. + */ +int deactivate_all_fds(void) +{ + struct irq_fd *irq; + int err; + + for (irq = active_fds; irq != NULL; irq = irq->next) { + err = os_clear_fd_async(irq->fd); + if (err) + return err; } + /* If there is a signal already queued, after unblocking ignore it */ + os_set_ioignore(); return 0; } /* - * do_IRQ handles all normal device IRQ's (the special + * do_IRQ handles all normal device IRQs (the special * SMP cross-CPU interrupts have their own specific * handlers). */ -unsigned int do_IRQ(int irq, union uml_pt_regs *regs) +unsigned int do_IRQ(int irq, struct uml_pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs); + irq_enter(); + generic_handle_irq(irq); + irq_exit(); + set_irq_regs(old_regs); + return 1; +} + +void um_free_irq(unsigned int irq, void *dev) { - irq_enter(); - __do_IRQ(irq, (struct pt_regs *) regs); - irq_exit(); - return 1; + free_irq_by_irq_and_dev(irq, dev); + free_irq(irq, dev); } +EXPORT_SYMBOL(um_free_irq); int um_request_irq(unsigned int irq, int fd, int type, - irqreturn_t (*handler)(int, void *, struct pt_regs *), + irq_handler_t handler, unsigned long irqflags, const char * devname, void *dev_id) { int err; - err = request_irq(irq, handler, irqflags, devname, dev_id); - if(err) - return(err); - - if(fd != -1) + if (fd != -1) { err = activate_fd(irq, fd, type, dev_id); - return(err); -} -EXPORT_SYMBOL(um_request_irq); -EXPORT_SYMBOL(reactivate_fd); - -static DEFINE_SPINLOCK(irq_spinlock); - -unsigned long irq_lock(void) -{ - unsigned long flags; + if (err) + return err; + } - spin_lock_irqsave(&irq_spinlock, flags); - return(flags); + return request_irq(irq, handler, irqflags, devname, dev_id); } -void irq_unlock(unsigned long flags) -{ - spin_unlock_irqrestore(&irq_spinlock, flags); -} +EXPORT_SYMBOL(um_request_irq); +EXPORT_SYMBOL(reactivate_fd); -/* hw_interrupt_type must define (startup || enable) && - * (shutdown || disable) && end */ -static void dummy(unsigned int irq) +/* + * irq_chip must define at least enable/disable and ack when + * the edge handler is used. + */ +static void dummy(struct irq_data *d) { } /* This is used for everything else than the timer. */ -static struct hw_interrupt_type normal_irq_type = { - .typename = "SIGIO", - .release = free_irq_by_irq_and_dev, - .disable = dummy, - .enable = dummy, - .ack = dummy, - .end = dummy +static struct irq_chip normal_irq_type = { + .name = "SIGIO", + .irq_disable = dummy, + .irq_enable = dummy, + .irq_ack = dummy, + .irq_mask = dummy, + .irq_unmask = dummy, }; -static struct hw_interrupt_type SIGVTALRM_irq_type = { - .typename = "SIGVTALRM", - .release = free_irq_by_irq_and_dev, - .shutdown = dummy, /* never called */ - .disable = dummy, - .enable = dummy, - .ack = dummy, - .end = dummy +static struct irq_chip SIGVTALRM_irq_type = { + .name = "SIGVTALRM", + .irq_disable = dummy, + .irq_enable = dummy, + .irq_ack = dummy, + .irq_mask = dummy, + .irq_unmask = dummy, }; void __init init_IRQ(void) { int i; - irq_desc[TIMER_IRQ].status = IRQ_DISABLED; - irq_desc[TIMER_IRQ].action = NULL; - irq_desc[TIMER_IRQ].depth = 1; - irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type; - enable_irq(TIMER_IRQ); - for(i=1;i<NR_IRQS;i++){ - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].handler = &normal_irq_type; - enable_irq(i); - } + irq_set_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq); + + for (i = 1; i < NR_IRQS; i++) + irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq); } -int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *, - struct pt_regs *)) +/* + * IRQ stack entry and exit: + * + * Unlike i386, UML doesn't receive IRQs on the normal kernel stack + * and switch over to the IRQ stack after some preparation. We use + * sigaltstack to receive signals on a separate stack from the start. + * These two functions make sure the rest of the kernel won't be too + * upset by being on a different stack. The IRQ stack has a + * thread_info structure at the bottom so that current et al continue + * to work. + * + * to_irq_stack copies the current task's thread_info to the IRQ stack + * thread_info and sets the tasks's stack to point to the IRQ stack. + * + * from_irq_stack copies the thread_info struct back (flags may have + * been modified) and resets the task's stack pointer. + * + * Tricky bits - + * + * What happens when two signals race each other? UML doesn't block + * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal + * could arrive while a previous one is still setting up the + * thread_info. + * + * There are three cases - + * The first interrupt on the stack - sets up the thread_info and + * handles the interrupt + * A nested interrupt interrupting the copying of the thread_info - + * can't handle the interrupt, as the stack is in an unknown state + * A nested interrupt not interrupting the copying of the + * thread_info - doesn't do any setup, just handles the interrupt + * + * The first job is to figure out whether we interrupted stack setup. + * This is done by xchging the signal mask with thread_info->pending. + * If the value that comes back is zero, then there is no setup in + * progress, and the interrupt can be handled. If the value is + * non-zero, then there is stack setup in progress. In order to have + * the interrupt handled, we leave our signal in the mask, and it will + * be handled by the upper handler after it has set up the stack. + * + * Next is to figure out whether we are the outer handler or a nested + * one. As part of setting up the stack, thread_info->real_thread is + * set to non-NULL (and is reset to NULL on exit). This is the + * nesting indicator. If it is non-NULL, then the stack is already + * set up and the handler can run. + */ + +static unsigned long pending_mask; + +unsigned long to_irq_stack(unsigned long *mask_out) { - int fds[2], err; + struct thread_info *ti; + unsigned long mask, old; + int nested; - err = os_pipe(fds, 1, 1); - if(err){ - printk("init_aio_irq - os_pipe failed, err = %d\n", -err); - goto out; + mask = xchg(&pending_mask, *mask_out); + if (mask != 0) { + /* + * If any interrupts come in at this point, we want to + * make sure that their bits aren't lost by our + * putting our bit in. So, this loop accumulates bits + * until xchg returns the same value that we put in. + * When that happens, there were no new interrupts, + * and pending_mask contains a bit for each interrupt + * that came in. + */ + old = *mask_out; + do { + old |= mask; + mask = xchg(&pending_mask, old); + } while (mask != old); + return 1; } - err = um_request_irq(irq, fds[0], IRQ_READ, handler, - SA_INTERRUPT | SA_SAMPLE_RANDOM, name, - (void *) (long) fds[0]); - if(err){ - printk("init_aio_irq - : um_request_irq failed, err = %d\n", - err); - goto out_close; + ti = current_thread_info(); + nested = (ti->real_thread != NULL); + if (!nested) { + struct task_struct *task; + struct thread_info *tti; + + task = cpu_tasks[ti->cpu].task; + tti = task_thread_info(task); + + *ti = *tti; + ti->real_thread = tti; + task->stack = ti; } - err = fds[1]; - goto out; + mask = xchg(&pending_mask, 0); + *mask_out |= mask | nested; + return 0; +} - out_close: - os_close_file(fds[0]); - os_close_file(fds[1]); - out: - return(err); +unsigned long from_irq_stack(int nested) +{ + struct thread_info *ti, *to; + unsigned long mask; + + ti = current_thread_info(); + + pending_mask = 1; + + to = ti->real_thread; + current->stack = to; + ti->real_thread = NULL; + *to = *ti; + + mask = xchg(&pending_mask, 0); + return mask & ~1; } + diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c deleted file mode 100644 index c3ccaf24f3e..00000000000 --- a/arch/um/kernel/irq_user.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> -#include <string.h> -#include <sys/poll.h> -#include <sys/types.h> -#include <sys/time.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "process.h" -#include "signal_user.h" -#include "sigio.h" -#include "irq_user.h" -#include "os.h" - -struct irq_fd { - struct irq_fd *next; - void *id; - int fd; - int type; - int irq; - int pid; - int events; - int current_events; - int freed; -}; - -static struct irq_fd *active_fds = NULL; -static struct irq_fd **last_irq_ptr = &active_fds; - -static struct pollfd *pollfds = NULL; -static int pollfds_num = 0; -static int pollfds_size = 0; - -extern int io_count, intr_count; - -void sigio_handler(int sig, union uml_pt_regs *regs) -{ - struct irq_fd *irq_fd, *next; - int i, n; - - if(smp_sigio_handler()) return; - while(1){ - n = poll(pollfds, pollfds_num, 0); - if(n < 0){ - if(errno == EINTR) continue; - printk("sigio_handler : poll returned %d, " - "errno = %d\n", n, errno); - break; - } - if(n == 0) break; - - irq_fd = active_fds; - for(i = 0; i < pollfds_num; i++){ - if(pollfds[i].revents != 0){ - irq_fd->current_events = pollfds[i].revents; - pollfds[i].fd = -1; - } - irq_fd = irq_fd->next; - } - - for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){ - next = irq_fd->next; - if(irq_fd->current_events != 0){ - irq_fd->current_events = 0; - do_IRQ(irq_fd->irq, regs); - - /* This is here because the next irq may be - * freed in the handler. If a console goes - * away, both the read and write irqs will be - * freed. After do_IRQ, ->next will point to - * a good IRQ. - * Irqs can't be freed inside their handlers, - * so the next best thing is to have them - * marked as needing freeing, so that they - * can be freed here. - */ - next = irq_fd->next; - if(irq_fd->freed){ - free_irq(irq_fd->irq, irq_fd->id); - } - } - } - } -} - -int activate_ipi(int fd, int pid) -{ - return(os_set_fd_async(fd, pid)); -} - -static void maybe_sigio_broken(int fd, int type) -{ - if(isatty(fd)){ - if((type == IRQ_WRITE) && !pty_output_sigio){ - write_sigio_workaround(); - add_sigio_fd(fd, 0); - } - else if((type == IRQ_READ) && !pty_close_sigio){ - write_sigio_workaround(); - add_sigio_fd(fd, 1); - } - } -} - -int activate_fd(int irq, int fd, int type, void *dev_id) -{ - struct pollfd *tmp_pfd; - struct irq_fd *new_fd, *irq_fd; - unsigned long flags; - int pid, events, err, n, size; - - pid = os_getpid(); - err = os_set_fd_async(fd, pid); - if(err < 0) - goto out; - - new_fd = um_kmalloc(sizeof(*new_fd)); - err = -ENOMEM; - if(new_fd == NULL) - goto out; - - if(type == IRQ_READ) events = POLLIN | POLLPRI; - else events = POLLOUT; - *new_fd = ((struct irq_fd) { .next = NULL, - .id = dev_id, - .fd = fd, - .type = type, - .irq = irq, - .pid = pid, - .events = events, - .current_events = 0, - .freed = 0 } ); - - /* Critical section - locked by a spinlock because this stuff can - * be changed from interrupt handlers. The stuff above is done - * outside the lock because it allocates memory. - */ - - /* Actually, it only looks like it can be called from interrupt - * context. The culprit is reactivate_fd, which calls - * maybe_sigio_broken, which calls write_sigio_workaround, - * which calls activate_fd. However, write_sigio_workaround should - * only be called once, at boot time. That would make it clear that - * this is called only from process context, and can be locked with - * a semaphore. - */ - flags = irq_lock(); - for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ - if((irq_fd->fd == fd) && (irq_fd->type == type)){ - printk("Registering fd %d twice\n", fd); - printk("Irqs : %d, %d\n", irq_fd->irq, irq); - printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id); - goto out_unlock; - } - } - - n = pollfds_num; - if(n == pollfds_size){ - while(1){ - /* Here we have to drop the lock in order to call - * kmalloc, which might sleep. If something else - * came in and changed the pollfds array, we free - * the buffer and try again. - */ - irq_unlock(flags); - size = (pollfds_num + 1) * sizeof(pollfds[0]); - tmp_pfd = um_kmalloc(size); - flags = irq_lock(); - if(tmp_pfd == NULL) - goto out_unlock; - if(n == pollfds_size) - break; - kfree(tmp_pfd); - } - if(pollfds != NULL){ - memcpy(tmp_pfd, pollfds, - sizeof(pollfds[0]) * pollfds_size); - kfree(pollfds); - } - pollfds = tmp_pfd; - pollfds_size++; - } - - if(type == IRQ_WRITE) - fd = -1; - - pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, - .events = events, - .revents = 0 }); - pollfds_num++; - - *last_irq_ptr = new_fd; - last_irq_ptr = &new_fd->next; - - irq_unlock(flags); - - /* This calls activate_fd, so it has to be outside the critical - * section. - */ - maybe_sigio_broken(fd, type); - - return(0); - - out_unlock: - irq_unlock(flags); - kfree(new_fd); - out: - return(err); -} - -static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) -{ - struct irq_fd **prev; - unsigned long flags; - int i = 0; - - flags = irq_lock(); - prev = &active_fds; - while(*prev != NULL){ - if((*test)(*prev, arg)){ - struct irq_fd *old_fd = *prev; - if((pollfds[i].fd != -1) && - (pollfds[i].fd != (*prev)->fd)){ - printk("free_irq_by_cb - mismatch between " - "active_fds and pollfds, fd %d vs %d\n", - (*prev)->fd, pollfds[i].fd); - goto out; - } - - pollfds_num--; - - /* This moves the *whole* array after pollfds[i] (though - * it doesn't spot as such)! */ - - memmove(&pollfds[i], &pollfds[i + 1], - (pollfds_num - i) * sizeof(pollfds[0])); - - if(last_irq_ptr == &old_fd->next) - last_irq_ptr = prev; - *prev = (*prev)->next; - if(old_fd->type == IRQ_WRITE) - ignore_sigio_fd(old_fd->fd); - kfree(old_fd); - continue; - } - prev = &(*prev)->next; - i++; - } - out: - irq_unlock(flags); -} - -struct irq_and_dev { - int irq; - void *dev; -}; - -static int same_irq_and_dev(struct irq_fd *irq, void *d) -{ - struct irq_and_dev *data = d; - - return((irq->irq == data->irq) && (irq->id == data->dev)); -} - -void free_irq_by_irq_and_dev(unsigned int irq, void *dev) -{ - struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq, - .dev = dev }); - - free_irq_by_cb(same_irq_and_dev, &data); -} - -static int same_fd(struct irq_fd *irq, void *fd) -{ - return(irq->fd == *((int *) fd)); -} - -void free_irq_by_fd(int fd) -{ - free_irq_by_cb(same_fd, &fd); -} - -static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) -{ - struct irq_fd *irq; - int i = 0; - - for(irq=active_fds; irq != NULL; irq = irq->next){ - if((irq->fd == fd) && (irq->irq == irqnum)) break; - i++; - } - if(irq == NULL){ - printk("find_irq_by_fd doesn't have descriptor %d\n", fd); - goto out; - } - if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){ - printk("find_irq_by_fd - mismatch between active_fds and " - "pollfds, fd %d vs %d, need %d\n", irq->fd, - pollfds[i].fd, fd); - irq = NULL; - goto out; - } - *index_out = i; - out: - return(irq); -} - -void free_irq_later(int irq, void *dev_id) -{ - struct irq_fd *irq_fd; - unsigned long flags; - - flags = irq_lock(); - for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ - if((irq_fd->irq == irq) && (irq_fd->id == dev_id)) - break; - } - if(irq_fd == NULL){ - printk("free_irq_later found no irq, irq = %d, " - "dev_id = 0x%p\n", irq, dev_id); - goto out; - } - irq_fd->freed = 1; - out: - irq_unlock(flags); -} - -void reactivate_fd(int fd, int irqnum) -{ - struct irq_fd *irq; - unsigned long flags; - int i; - - flags = irq_lock(); - irq = find_irq_by_fd(fd, irqnum, &i); - if(irq == NULL){ - irq_unlock(flags); - return; - } - - pollfds[i].fd = irq->fd; - - irq_unlock(flags); - - /* This calls activate_fd, so it has to be outside the critical - * section. - */ - maybe_sigio_broken(fd, irq->type); -} - -void deactivate_fd(int fd, int irqnum) -{ - struct irq_fd *irq; - unsigned long flags; - int i; - - flags = irq_lock(); - irq = find_irq_by_fd(fd, irqnum, &i); - if(irq == NULL) - goto out; - pollfds[i].fd = -1; - out: - irq_unlock(flags); -} - -int deactivate_all_fds(void) -{ - struct irq_fd *irq; - int err; - - for(irq=active_fds;irq != NULL;irq = irq->next){ - err = os_clear_fd_async(irq->fd); - if(err) - return(err); - } - /* If there is a signal already queued, after unblocking ignore it */ - set_handler(SIGIO, SIG_IGN, 0, -1); - - return(0); -} - -void forward_ipi(int fd, int pid) -{ - int err; - - err = os_set_owner(fd, pid); - if(err < 0) - printk("forward_ipi: set_owner failed, fd = %d, me = %d, " - "target = %d, err = %d\n", fd, os_getpid(), pid, -err); -} - -void forward_interrupts(int pid) -{ - struct irq_fd *irq; - unsigned long flags; - int err; - - flags = irq_lock(); - for(irq=active_fds;irq != NULL;irq = irq->next){ - err = os_set_owner(irq->fd, pid); - if(err < 0){ - /* XXX Just remove the irq rather than - * print out an infinite stream of these - */ - printk("Failed to forward %d to pid %d, err = %d\n", - irq->fd, pid, -err); - } - - irq->pid = pid; - } - irq_unlock(flags); -} - -void init_irq_signals(int on_sigstack) -{ - __sighandler_t h; - int flags; - - flags = on_sigstack ? SA_ONSTACK : 0; - if(timer_irq_inited) h = (__sighandler_t) alarm_handler; - else h = boot_timer_handler; - - set_handler(SIGVTALRM, h, flags | SA_RESTART, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); - set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - signal(SIGWINCH, SIG_IGN); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 7713e7a6f47..543c0475693 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -1,65 +1,17 @@ /* - * Copyright (C) 2001 - 2004 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/module.h" -#include "linux/string.h" -#include "linux/smp_lock.h" -#include "linux/spinlock.h" -#include "linux/highmem.h" -#include "asm/current.h" -#include "asm/processor.h" -#include "asm/unistd.h" -#include "asm/pgalloc.h" -#include "asm/pgtable.h" -#include "asm/page.h" -#include "asm/tlbflush.h" -#include "kern_util.h" -#include "user_util.h" -#include "mem_user.h" -#include "os.h" +#include <linux/module.h> +#include <os.h> -EXPORT_SYMBOL(stop); -EXPORT_SYMBOL(uml_physmem); EXPORT_SYMBOL(set_signals); EXPORT_SYMBOL(get_signals); -EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(sys_waitpid); -EXPORT_SYMBOL(task_size); -EXPORT_SYMBOL(flush_tlb_range); -EXPORT_SYMBOL(host_task_size); -EXPORT_SYMBOL(arch_validate); -EXPORT_SYMBOL(get_kmem_end); - -EXPORT_SYMBOL(high_physmem); -EXPORT_SYMBOL(empty_zero_page); -EXPORT_SYMBOL(um_virt_to_phys); -EXPORT_SYMBOL(mode_tt); -EXPORT_SYMBOL(handle_page_fault); -EXPORT_SYMBOL(find_iomem); -EXPORT_SYMBOL(end_iomem); - -#ifdef CONFIG_MODE_TT -EXPORT_SYMBOL(strncpy_from_user_tt); -EXPORT_SYMBOL(copy_from_user_tt); -EXPORT_SYMBOL(copy_to_user_tt); -#endif - -#ifdef CONFIG_MODE_SKAS -EXPORT_SYMBOL(strncpy_from_user_skas); -EXPORT_SYMBOL(copy_to_user_skas); -EXPORT_SYMBOL(copy_from_user_skas); -EXPORT_SYMBOL(clear_user_skas); -#endif -EXPORT_SYMBOL(uml_strdup); EXPORT_SYMBOL(os_stat_fd); EXPORT_SYMBOL(os_stat_file); EXPORT_SYMBOL(os_access); -EXPORT_SYMBOL(os_print_error); -EXPORT_SYMBOL(os_get_exec_close); EXPORT_SYMBOL(os_set_exec_close); EXPORT_SYMBOL(os_getpid); EXPORT_SYMBOL(os_open_file); @@ -83,28 +35,10 @@ EXPORT_SYMBOL(os_connect_socket); EXPORT_SYMBOL(os_accept_connection); EXPORT_SYMBOL(os_rcv_fd); EXPORT_SYMBOL(run_helper); -EXPORT_SYMBOL(start_thread); -EXPORT_SYMBOL(dump_thread); - -EXPORT_SYMBOL(do_gettimeofday); -EXPORT_SYMBOL(do_settimeofday); - -/* This is here because UML expands open to sys_open, not to a system - * call instruction. - */ -EXPORT_SYMBOL(sys_open); -EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_read); -EXPORT_SYMBOL(sys_wait4); - -#ifdef CONFIG_SMP - -/* required for SMP */ - -extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); -EXPORT_SYMBOL(__write_lock_failed); - -extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); -EXPORT_SYMBOL(__read_lock_failed); +EXPORT_SYMBOL(os_major); +EXPORT_SYMBOL(os_minor); +EXPORT_SYMBOL(os_makedev); -#endif +EXPORT_SYMBOL(add_sigio_fd); +EXPORT_SYMBOL(ignore_sigio_fd); +EXPORT_SYMBOL(sigio_broken); diff --git a/arch/um/kernel/maccess.c b/arch/um/kernel/maccess.c new file mode 100644 index 00000000000..1f3d5c4910d --- /dev/null +++ b/arch/um/kernel/maccess.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 Richard Weinberger <richrd@nod.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/uaccess.h> +#include <linux/kernel.h> +#include <os.h> + +long probe_kernel_read(void *dst, const void *src, size_t size) +{ + void *psrc = (void *)rounddown((unsigned long)src, PAGE_SIZE); + + if ((unsigned long)src < PAGE_SIZE || size <= 0) + return -EFAULT; + + if (os_mincore(psrc, size + src - psrc) <= 0) + return -EFAULT; + + return __probe_kernel_read(dst, src, size); +} diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index fa4f915be5c..8636e905426 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -1,106 +1,78 @@ /* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/stddef.h" -#include "linux/kernel.h" -#include "linux/mm.h" -#include "linux/bootmem.h" -#include "linux/swap.h" -#include "linux/highmem.h" -#include "linux/gfp.h" -#include "asm/page.h" -#include "asm/fixmap.h" -#include "asm/pgalloc.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" -#include "mem_user.h" -#include "uml_uaccess.h" -#include "os.h" -#include "linux/types.h" -#include "linux/string.h" -#include "init.h" -#include "kern_constants.h" - -extern char __binary_start; - -/* Changed during early boot */ +#include <linux/stddef.h> +#include <linux/module.h> +#include <linux/bootmem.h> +#include <linux/highmem.h> +#include <linux/mm.h> +#include <linux/swap.h> +#include <linux/slab.h> +#include <asm/fixmap.h> +#include <asm/page.h> +#include <as-layout.h> +#include <init.h> +#include <kern.h> +#include <kern_util.h> +#include <mem_user.h> +#include <os.h> + +/* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */ unsigned long *empty_zero_page = NULL; -unsigned long *empty_bad_page = NULL; +EXPORT_SYMBOL(empty_zero_page); +/* allocated in paging_init and unchanged thereafter */ +static unsigned long *empty_bad_page = NULL; + +/* + * Initialized during boot, and readonly for initializing page tables + * afterwards + */ pgd_t swapper_pg_dir[PTRS_PER_PGD]; -unsigned long highmem; + +/* Initialized at boot time, and readonly after that */ +unsigned long long highmem; int kmalloc_ok = 0; +/* Used during early boot */ static unsigned long brk_end; -void unmap_physmem(void) -{ - os_unmap_memory((void *) brk_end, uml_reserved - brk_end); -} - -static void map_cb(void *unused) -{ - map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); -} - #ifdef CONFIG_HIGHMEM static void setup_highmem(unsigned long highmem_start, unsigned long highmem_len) { - struct page *page; unsigned long highmem_pfn; int i; highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT; - for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){ - page = &mem_map[highmem_pfn + i]; - ClearPageReserved(page); - set_page_count(page, 1); - __free_page(page); - } + for (i = 0; i < highmem_len >> PAGE_SHIFT; i++) + free_highmem_page(&mem_map[highmem_pfn + i]); } #endif -void mem_init(void) +void __init mem_init(void) { - unsigned long start; - - max_low_pfn = (high_physmem - uml_physmem) >> PAGE_SHIFT; - - /* clear the zero-page */ - memset((void *) empty_zero_page, 0, PAGE_SIZE); + /* clear the zero-page */ + memset(empty_zero_page, 0, PAGE_SIZE); /* Map in the area just after the brk now that kmalloc is about * to be turned on. */ brk_end = (unsigned long) UML_ROUND_UP(sbrk(0)); - map_cb(NULL); - initial_thread_cb(map_cb, NULL); + map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); free_bootmem(__pa(brk_end), uml_reserved - brk_end); uml_reserved = brk_end; - /* Fill in any hole at the start of the binary */ - start = (unsigned long) &__binary_start & PAGE_MASK; - if(uml_physmem != start){ - map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem, - 1, 1, 0); - } - /* this will put all low memory onto the freelists */ - totalram_pages = free_all_bootmem(); - totalhigh_pages = highmem >> PAGE_SHIFT; - totalram_pages += totalhigh_pages; - num_physpages = totalram_pages; - max_pfn = totalram_pages; - printk(KERN_INFO "Memory: %luk available\n", - (unsigned long) nr_free_pages() << (PAGE_SHIFT-10)); - kmalloc_ok = 1; - + free_all_bootmem(); + max_low_pfn = totalram_pages; #ifdef CONFIG_HIGHMEM setup_highmem(end_iomem, highmem); #endif + max_pfn = totalram_pages; + mem_init_print_info(NULL); + kmalloc_ok = 1; } /* @@ -128,7 +100,7 @@ static void __init one_md_table_init(pud_t *pud) #endif } -static void __init fixrange_init(unsigned long start, unsigned long end, +static void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) { pgd_t *pgd; @@ -147,7 +119,7 @@ static void __init fixrange_init(unsigned long start, unsigned long end, if (pud_none(*pud)) one_md_table_init(pud); pmd = pmd_offset(pud, vaddr); - for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) { + for (; (j < PTRS_PER_PMD) && (vaddr < end); pmd++, j++) { one_page_table_init(pmd); vaddr += PMD_SIZE; } @@ -161,7 +133,7 @@ pgprot_t kmap_prot; #define kmap_get_fixmap_pte(vaddr) \ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\ - (vaddr)), (vaddr)) + (vaddr)), (vaddr)) static void __init kmap_init(void) { @@ -174,7 +146,7 @@ static void __init kmap_init(void) kmap_prot = PAGE_KERNEL; } -static void init_highmem(void) +static void __init init_highmem(void) { pgd_t *pgd; pud_t *pud; @@ -206,36 +178,42 @@ static void __init fixaddr_user_init( void) pud_t *pud; pmd_t *pmd; pte_t *pte; - unsigned long paddr, vaddr = FIXADDR_USER_START; + phys_t p; + unsigned long v, vaddr = FIXADDR_USER_START; - if ( ! size ) + if (!size) return; fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir); - paddr = (unsigned long)alloc_bootmem_low_pages( size); - memcpy( (void *)paddr, (void *)FIXADDR_USER_START, size); - paddr = __pa(paddr); - for ( ; size > 0; size-=PAGE_SIZE, vaddr+=PAGE_SIZE, paddr+=PAGE_SIZE){ + v = (unsigned long) alloc_bootmem_low_pages(size); + memcpy((void *) v , (void *) FIXADDR_USER_START, size); + p = __pa(v); + for ( ; size > 0; size -= PAGE_SIZE, vaddr += PAGE_SIZE, + p += PAGE_SIZE) { pgd = swapper_pg_dir + pgd_index(vaddr); pud = pud_offset(pgd, vaddr); pmd = pmd_offset(pud, vaddr); pte = pte_offset_kernel(pmd, vaddr); - pte_set_val( (*pte), paddr, PAGE_READONLY); + pte_set_val(*pte, p, PAGE_READONLY); } #endif } -void paging_init(void) +void __init paging_init(void) { unsigned long zones_size[MAX_NR_ZONES], vaddr; int i; empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); - for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) + for (i = 0; i < ARRAY_SIZE(zones_size); i++) zones_size[i] = 0; - zones_size[ZONE_DMA] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); + + zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) - + (uml_physmem >> PAGE_SHIFT); +#ifdef CONFIG_HIGHMEM zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT; +#endif free_area_init(zones_size); /* @@ -252,34 +230,8 @@ void paging_init(void) #endif } -struct page *arch_validate(struct page *page, gfp_t mask, int order) -{ - unsigned long addr, zero = 0; - int i; - - again: - if(page == NULL) return(page); - if(PageHighMem(page)) return(page); - - addr = (unsigned long) page_address(page); - for(i = 0; i < (1 << order); i++){ - current->thread.fault_addr = (void *) addr; - if(__do_copy_to_user((void __user *) addr, &zero, - sizeof(zero), - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)){ - if(!(mask & __GFP_WAIT)) return(NULL); - else break; - } - addr += PAGE_SIZE; - } - - if(i == (1 << order)) return(page); - page = alloc_pages(mask, order); - goto again; -} - -/* This can't do anything because nothing in the kernel image can be freed +/* + * This can't do anything because nothing in the kernel image can be freed * since it's not in kernel physical memory. */ @@ -288,55 +240,13 @@ void free_initmem(void) } #ifdef CONFIG_BLK_DEV_INITRD - void free_initrd_mem(unsigned long start, unsigned long end) { - if (start < end) - printk ("Freeing initrd memory: %ldk freed\n", - (end - start) >> 10); - for (; start < end; start += PAGE_SIZE) { - ClearPageReserved(virt_to_page(start)); - set_page_count(virt_to_page(start), 1); - free_page(start); - totalram_pages++; - } + free_reserved_area((void *)start, (void *)end, -1, "initrd"); } - #endif -void show_mem(void) -{ - int pfn, total = 0, reserved = 0; - int shared = 0, cached = 0; - int highmem = 0; - struct page *page; - - printk("Mem-info:\n"); - show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - pfn = max_mapnr; - while(pfn-- > 0) { - page = pfn_to_page(pfn); - total++; - if(PageHighMem(page)) - highmem++; - if(PageReserved(page)) - reserved++; - else if(PageSwapCache(page)) - cached++; - else if(page_count(page)) - shared += page_count(page) - 1; - } - printk("%d pages of RAM\n", total); - printk("%d pages of HIGHMEM\n", highmem); - printk("%d reserved pages\n", reserved); - printk("%d pages shared\n", shared); - printk("%d pages swap cached\n", cached); -} - -/* - * Allocate and free page tables. - */ +/* Allocate and free page tables. */ pgd_t *pgd_alloc(struct mm_struct *mm) { @@ -344,14 +254,14 @@ pgd_t *pgd_alloc(struct mm_struct *mm) if (pgd) { memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); } return pgd; } -void pgd_free(pgd_t *pgd) +void pgd_free(struct mm_struct *mm, pgd_t *pgd) { free_page((unsigned long) pgd); } @@ -364,31 +274,33 @@ pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) return pte; } -struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) +pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address) { struct page *pte; - + pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); + if (!pte) + return NULL; + if (!pgtable_page_ctor(pte)) { + __free_page(pte); + return NULL; + } return pte; } -struct iomem_region *iomem_regions = NULL; -int iomem_size = 0; +#ifdef CONFIG_3_LEVEL_PGTABLES +pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL); -extern int parse_iomem(char *str, int *add) __init; + if (pmd) + memset(pmd, 0, PAGE_SIZE); -__uml_setup("iomem=", parse_iomem, -"iomem=<name>,<file>\n" -" Configure <file> as an IO memory region named <name>.\n\n" -); + return pmd; +} +#endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +void *uml_kmalloc(int size, int flags) +{ + return kmalloc(size, flags); +} diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index f3b583a878a..30fdd5d0067 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -1,254 +1,29 @@ /* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/mm.h" -#include "linux/rbtree.h" -#include "linux/slab.h" -#include "linux/vmalloc.h" -#include "linux/bootmem.h" -#include "linux/module.h" -#include "asm/types.h" -#include "asm/pgtable.h" -#include "kern_util.h" -#include "user_util.h" -#include "mode_kern.h" -#include "mem.h" -#include "mem_user.h" -#include "os.h" -#include "kern.h" -#include "init.h" - -struct phys_desc { - struct rb_node rb; - int fd; - __u64 offset; - void *virt; - unsigned long phys; - struct list_head list; -}; - -static struct rb_root phys_mappings = RB_ROOT; - -static struct rb_node **find_rb(void *virt) -{ - struct rb_node **n = &phys_mappings.rb_node; - struct phys_desc *d; - - while(*n != NULL){ - d = rb_entry(*n, struct phys_desc, rb); - if(d->virt == virt) - return(n); - - if(d->virt > virt) - n = &(*n)->rb_left; - else - n = &(*n)->rb_right; - } - - return(n); -} - -static struct phys_desc *find_phys_mapping(void *virt) -{ - struct rb_node **n = find_rb(virt); - - if(*n == NULL) - return(NULL); - - return(rb_entry(*n, struct phys_desc, rb)); -} - -static void insert_phys_mapping(struct phys_desc *desc) -{ - struct rb_node **n = find_rb(desc->virt); - - if(*n != NULL) - panic("Physical remapping for %p already present", - desc->virt); - - rb_link_node(&desc->rb, (*n)->rb_parent, n); - rb_insert_color(&desc->rb, &phys_mappings); -} - -LIST_HEAD(descriptor_mappings); - -struct desc_mapping { - int fd; - struct list_head list; - struct list_head pages; -}; - -static struct desc_mapping *find_mapping(int fd) -{ - struct desc_mapping *desc; - struct list_head *ele; - - list_for_each(ele, &descriptor_mappings){ - desc = list_entry(ele, struct desc_mapping, list); - if(desc->fd == fd) - return(desc); - } - - return(NULL); -} - -static struct desc_mapping *descriptor_mapping(int fd) -{ - struct desc_mapping *desc; - - desc = find_mapping(fd); - if(desc != NULL) - return(desc); - - desc = kmalloc(sizeof(*desc), GFP_ATOMIC); - if(desc == NULL) - return(NULL); - - *desc = ((struct desc_mapping) - { .fd = fd, - .list = LIST_HEAD_INIT(desc->list), - .pages = LIST_HEAD_INIT(desc->pages) }); - list_add(&desc->list, &descriptor_mappings); - - return(desc); -} - -int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) -{ - struct desc_mapping *fd_maps; - struct phys_desc *desc; - unsigned long phys; - int err; - - fd_maps = descriptor_mapping(fd); - if(fd_maps == NULL) - return(-ENOMEM); - - phys = __pa(virt); - desc = find_phys_mapping(virt); - if(desc != NULL) - panic("Address 0x%p is already substituted\n", virt); - - err = -ENOMEM; - desc = kmalloc(sizeof(*desc), GFP_ATOMIC); - if(desc == NULL) - goto out; - - *desc = ((struct phys_desc) - { .fd = fd, - .offset = offset, - .virt = virt, - .phys = __pa(virt), - .list = LIST_HEAD_INIT(desc->list) }); - insert_phys_mapping(desc); - - list_add(&desc->list, &fd_maps->pages); - - virt = (void *) ((unsigned long) virt & PAGE_MASK); - err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0); - if(!err) - goto out; - - rb_erase(&desc->rb, &phys_mappings); - kfree(desc); - out: - return(err); -} +#include <linux/module.h> +#include <linux/bootmem.h> +#include <linux/mm.h> +#include <linux/pfn.h> +#include <asm/page.h> +#include <as-layout.h> +#include <init.h> +#include <kern.h> +#include <mem_user.h> +#include <os.h> static int physmem_fd = -1; -static void remove_mapping(struct phys_desc *desc) -{ - void *virt = desc->virt; - int err; - - rb_erase(&desc->rb, &phys_mappings); - list_del(&desc->list); - kfree(desc); - - err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0); - if(err) - panic("Failed to unmap block device page from physical memory, " - "errno = %d", -err); -} - -int physmem_remove_mapping(void *virt) -{ - struct phys_desc *desc; - - virt = (void *) ((unsigned long) virt & PAGE_MASK); - desc = find_phys_mapping(virt); - if(desc == NULL) - return(0); - - remove_mapping(desc); - return(1); -} - -void physmem_forget_descriptor(int fd) -{ - struct desc_mapping *desc; - struct phys_desc *page; - struct list_head *ele, *next; - __u64 offset; - void *addr; - int err; - - desc = find_mapping(fd); - if(desc == NULL) - return; - - list_for_each_safe(ele, next, &desc->pages){ - page = list_entry(ele, struct phys_desc, list); - offset = page->offset; - addr = page->virt; - remove_mapping(page); - err = os_seek_file(fd, offset); - if(err) - panic("physmem_forget_descriptor - failed to seek " - "to %lld in fd %d, error = %d\n", - offset, fd, -err); - err = os_read_file(fd, addr, PAGE_SIZE); - if(err < 0) - panic("physmem_forget_descriptor - failed to read " - "from fd %d to 0x%p, error = %d\n", - fd, addr, -err); - } - - list_del(&desc->list); - kfree(desc); -} - -EXPORT_SYMBOL(physmem_forget_descriptor); -EXPORT_SYMBOL(physmem_remove_mapping); -EXPORT_SYMBOL(physmem_subst_mapping); - -void arch_free_page(struct page *page, int order) -{ - void *virt; - int i; - - for(i = 0; i < (1 << order); i++){ - virt = __va(page_to_phys(page + i)); - physmem_remove_mapping(virt); - } -} - -int is_remapped(void *virt) -{ - struct phys_desc *desc = find_phys_mapping(virt); - - return(desc != NULL); -} - /* Changed during early boot */ unsigned long high_physmem; +EXPORT_SYMBOL(high_physmem); extern unsigned long long physmem_size; -int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) +int __init init_maps(unsigned long physmem, unsigned long iomem, + unsigned long highmem) { struct page *p, *map; unsigned long phys_len, phys_pages, highmem_len, highmem_pages; @@ -265,37 +40,21 @@ int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) highmem_len = highmem_pages * sizeof(struct page); total_pages = phys_pages + iomem_pages + highmem_pages; - total_len = phys_len + iomem_pages + highmem_len; - - if(kmalloc_ok){ - map = kmalloc(total_len, GFP_KERNEL); - if(map == NULL) - map = vmalloc(total_len); - } - else map = alloc_bootmem_low_pages(total_len); + total_len = phys_len + iomem_len + highmem_len; - if(map == NULL) - return(-ENOMEM); + map = alloc_bootmem_low_pages(total_len); + if (map == NULL) + return -ENOMEM; - for(i = 0; i < total_pages; i++){ + for (i = 0; i < total_pages; i++) { p = &map[i]; - set_page_count(p, 0); + memset(p, 0, sizeof(struct page)); SetPageReserved(p); INIT_LIST_HEAD(&p->lru); } max_mapnr = total_pages; - return(0); -} - -/* Changed during early boot */ -static unsigned long kmem_top = 0; - -unsigned long get_kmem_end(void) -{ - if(kmem_top == 0) - kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); - return(kmem_top); + return 0; } void map_memory(unsigned long virt, unsigned long phys, unsigned long len, @@ -306,9 +65,9 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, fd = phys_mapping(phys, &offset); err = os_map_memory((void *) virt, fd, offset, len, r, w, x); - if(err) { - if(err == -ENOMEM) - printk("try increasing the host's " + if (err) { + if (err == -ENOMEM) + printk(KERN_ERR "try increasing the host's " "/proc/sys/vm/max_map_count to <physical " "memory size>/4096\n"); panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, " @@ -316,12 +75,10 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, } } -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +extern int __syscall_stub_start; -extern int __syscall_stub_start, __binary_start; - -void setup_physmem(unsigned long start, unsigned long reserve_end, - unsigned long len, unsigned long long highmem) +void __init setup_physmem(unsigned long start, unsigned long reserve_end, + unsigned long len, unsigned long long highmem) { unsigned long reserve = reserve_end - start; int pfn = PFN_UP(__pa(reserve_end)); @@ -332,42 +89,41 @@ void setup_physmem(unsigned long start, unsigned long reserve_end, offset = uml_reserved - uml_physmem; err = os_map_memory((void *) uml_reserved, physmem_fd, offset, - len - offset, 1, 1, 0); - if(err < 0){ - os_print_error(err, "Mapping memory"); + len - offset, 1, 1, 1); + if (err < 0) { + printf("setup_physmem - mapping %ld bytes of memory at 0x%p " + "failed - errno = %d\n", len - offset, + (void *) uml_reserved, err); exit(1); } - /* Special kludge - This page will be mapped in to userspace processes + /* + * Special kludge - This page will be mapped in to userspace processes * from physmem_fd, so it needs to be written out there. */ os_seek_file(physmem_fd, __pa(&__syscall_stub_start)); os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE); + os_fsync_file(physmem_fd); bootmap_size = init_bootmem(pfn, pfn + delta); free_bootmem(__pa(reserve_end) + bootmap_size, len - bootmap_size - reserve); } -int phys_mapping(unsigned long phys, __u64 *offset_out) +int phys_mapping(unsigned long phys, unsigned long long *offset_out) { - struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK)); int fd = -1; - if(desc != NULL){ - fd = desc->fd; - *offset_out = desc->offset; - } - else if(phys < physmem_size){ + if (phys < physmem_size) { fd = physmem_fd; *offset_out = phys; } - else if(phys < __pa(end_iomem)){ + else if (phys < __pa(end_iomem)) { struct iomem_region *region = iomem_regions; - while(region != NULL){ - if((phys >= region->phys) && - (phys < region->phys + region->size)){ + while (region != NULL) { + if ((phys >= region->phys) && + (phys < region->phys + region->size)) { fd = region->fd; *offset_out = phys - region->phys; break; @@ -375,12 +131,12 @@ int phys_mapping(unsigned long phys, __u64 *offset_out) region = region->next; } } - else if(phys < __pa(end_iomem) + highmem){ + else if (phys < __pa(end_iomem) + highmem) { fd = physmem_fd; *offset_out = phys - iomem_size; } - return(fd); + return fd; } static int __init uml_mem_setup(char *line, int *add) @@ -399,32 +155,52 @@ __uml_setup("mem=", uml_mem_setup, " Example: mem=64M\n\n" ); +extern int __init parse_iomem(char *str, int *add); + +__uml_setup("iomem=", parse_iomem, +"iomem=<name>,<file>\n" +" Configure <file> as an IO memory region named <name>.\n\n" +); + +/* + * This list is constructed in parse_iomem and addresses filled in in + * setup_iomem, both of which run during early boot. Afterwards, it's + * unchanged. + */ +struct iomem_region *iomem_regions; + +/* Initialized in parse_iomem and unchanged thereafter */ +int iomem_size; + unsigned long find_iomem(char *driver, unsigned long *len_out) { struct iomem_region *region = iomem_regions; - while(region != NULL){ - if(!strcmp(region->driver, driver)){ + while (region != NULL) { + if (!strcmp(region->driver, driver)) { *len_out = region->size; - return(region->virt); + return region->virt; } + + region = region->next; } - return(0); + return 0; } +EXPORT_SYMBOL(find_iomem); -int setup_iomem(void) +static int setup_iomem(void) { struct iomem_region *region = iomem_regions; unsigned long iomem_start = high_physmem + PAGE_SIZE; int err; - while(region != NULL){ + while (region != NULL) { err = os_map_memory((void *) iomem_start, region->fd, 0, region->size, 1, 1, 0); - if(err) - printk("Mapping iomem region for driver '%s' failed, " - "errno = %d\n", region->driver, -err); + if (err) + printk(KERN_ERR "Mapping iomem region for driver '%s' " + "failed, errno = %d\n", region->driver, -err); else { region->virt = iomem_start; region->phys = __pa(region->virt); @@ -434,18 +210,7 @@ int setup_iomem(void) region = region->next; } - return(0); + return 0; } __initcall(setup_iomem); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c new file mode 100644 index 00000000000..f17bca8ed2c --- /dev/null +++ b/arch/um/kernel/process.c @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright 2003 PathScale, Inc. + * Licensed under the GPL + */ + +#include <linux/stddef.h> +#include <linux/err.h> +#include <linux/hardirq.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/personality.h> +#include <linux/proc_fs.h> +#include <linux/ptrace.h> +#include <linux/random.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/tick.h> +#include <linux/threads.h> +#include <linux/tracehook.h> +#include <asm/current.h> +#include <asm/pgtable.h> +#include <asm/mmu_context.h> +#include <asm/uaccess.h> +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> +#include <skas.h> + +/* + * This is a per-cpu array. A processor only modifies its entry and it only + * cares about its entry, so it's OK if another processor is modifying its + * entry. + */ +struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; + +static inline int external_pid(void) +{ + /* FIXME: Need to look up userspace_pid by cpu */ + return userspace_pid[0]; +} + +int pid_to_processor_id(int pid) +{ + int i; + + for (i = 0; i < ncpus; i++) { + if (cpu_tasks[i].pid == pid) + return i; + } + return -1; +} + +void free_stack(unsigned long stack, int order) +{ + free_pages(stack, order); +} + +unsigned long alloc_stack(int order, int atomic) +{ + unsigned long page; + gfp_t flags = GFP_KERNEL; + + if (atomic) + flags = GFP_ATOMIC; + page = __get_free_pages(flags, order); + + return page; +} + +static inline void set_current(struct task_struct *task) +{ + cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) + { external_pid(), task }); +} + +extern void arch_switch_to(struct task_struct *to); + +void *__switch_to(struct task_struct *from, struct task_struct *to) +{ + to->thread.prev_sched = from; + set_current(to); + + switch_threads(&from->thread.switch_buf, &to->thread.switch_buf); + arch_switch_to(current); + + return current->thread.prev_sched; +} + +void interrupt_end(void) +{ + if (need_resched()) + schedule(); + if (test_thread_flag(TIF_SIGPENDING)) + do_signal(); + if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) + tracehook_notify_resume(¤t->thread.regs); +} + +void exit_thread(void) +{ +} + +int get_current_pid(void) +{ + return task_pid_nr(current); +} + +/* + * This is called magically, by its address being stuffed in a jmp_buf + * and being longjmp-d to. + */ +void new_thread_handler(void) +{ + int (*fn)(void *), n; + void *arg; + + if (current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); + current->thread.prev_sched = NULL; + + fn = current->thread.request.u.thread.proc; + arg = current->thread.request.u.thread.arg; + + /* + * callback returns only if the kernel thread execs a process + */ + n = fn(arg); + userspace(¤t->thread.regs.regs); +} + +/* Called magically, see new_thread_handler above */ +void fork_handler(void) +{ + force_flush_all(); + + schedule_tail(current->thread.prev_sched); + + /* + * XXX: if interrupt_end() calls schedule, this call to + * arch_switch_to isn't needed. We could want to apply this to + * improve performance. -bb + */ + arch_switch_to(current); + + current->thread.prev_sched = NULL; + + userspace(¤t->thread.regs.regs); +} + +int copy_thread(unsigned long clone_flags, unsigned long sp, + unsigned long arg, struct task_struct * p) +{ + void (*handler)(void); + int kthread = current->flags & PF_KTHREAD; + int ret = 0; + + p->thread = (struct thread_struct) INIT_THREAD; + + if (!kthread) { + memcpy(&p->thread.regs.regs, current_pt_regs(), + sizeof(p->thread.regs.regs)); + PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0); + if (sp != 0) + REGS_SP(p->thread.regs.regs.gp) = sp; + + handler = fork_handler; + + arch_copy_thread(¤t->thread.arch, &p->thread.arch); + } else { + get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp); + p->thread.request.u.thread.proc = (int (*)(void *))sp; + p->thread.request.u.thread.arg = (void *)arg; + handler = new_thread_handler; + } + + new_thread(task_stack_page(p), &p->thread.switch_buf, handler); + + if (!kthread) { + clear_flushed_tls(p); + + /* + * Set a new TLS for the child thread? + */ + if (clone_flags & CLONE_SETTLS) + ret = arch_copy_tls(p); + } + + return ret; +} + +void initial_thread_cb(void (*proc)(void *), void *arg) +{ + int save_kmalloc_ok = kmalloc_ok; + + kmalloc_ok = 0; + initial_thread_cb_skas(proc, arg); + kmalloc_ok = save_kmalloc_ok; +} + +void arch_cpu_idle(void) +{ + unsigned long long nsecs; + + cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); + nsecs = disable_timer(); + idle_sleep(nsecs); + local_irq_enable(); +} + +int __cant_sleep(void) { + return in_atomic() || irqs_disabled() || in_interrupt(); + /* Is in_interrupt() really needed? */ +} + +int user_context(unsigned long sp) +{ + unsigned long stack; + + stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER); + return stack != (unsigned long) current_thread_info(); +} + +extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; + +void do_uml_exitcalls(void) +{ + exitcall_t *call; + + call = &__uml_exitcall_end; + while (--call >= &__uml_exitcall_begin) + (*call)(); +} + +char *uml_strdup(const char *string) +{ + return kstrdup(string, GFP_KERNEL); +} +EXPORT_SYMBOL(uml_strdup); + +int copy_to_user_proc(void __user *to, void *from, int size) +{ + return copy_to_user(to, from, size); +} + +int copy_from_user_proc(void *to, void __user *from, int size) +{ + return copy_from_user(to, from, size); +} + +int clear_user_proc(void __user *buf, int size) +{ + return clear_user(buf, size); +} + +int strlen_user_proc(char __user *str) +{ + return strlen_user(str); +} + +int smp_sigio_handler(void) +{ +#ifdef CONFIG_SMP + int cpu = current_thread_info()->cpu; + IPI_handler(cpu); + if (cpu != 0) + return 1; +#endif + return 0; +} + +int cpu(void) +{ + return current_thread_info()->cpu; +} + +static atomic_t using_sysemu = ATOMIC_INIT(0); +int sysemu_supported; + +void set_using_sysemu(int value) +{ + if (value > sysemu_supported) + return; + atomic_set(&using_sysemu, value); +} + +int get_using_sysemu(void) +{ + return atomic_read(&using_sysemu); +} + +static int sysemu_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%d\n", get_using_sysemu()); + return 0; +} + +static int sysemu_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, sysemu_proc_show, NULL); +} + +static ssize_t sysemu_proc_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + char tmp[2]; + + if (copy_from_user(tmp, buf, 1)) + return -EFAULT; + + if (tmp[0] >= '0' && tmp[0] <= '2') + set_using_sysemu(tmp[0] - '0'); + /* We use the first char, but pretend to write everything */ + return count; +} + +static const struct file_operations sysemu_proc_fops = { + .owner = THIS_MODULE, + .open = sysemu_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = sysemu_proc_write, +}; + +int __init make_proc_sysemu(void) +{ + struct proc_dir_entry *ent; + if (!sysemu_supported) + return 0; + + ent = proc_create("sysemu", 0600, NULL, &sysemu_proc_fops); + + if (ent == NULL) + { + printk(KERN_WARNING "Failed to register /proc/sysemu\n"); + return 0; + } + + return 0; +} + +late_initcall(make_proc_sysemu); + +int singlestepping(void * t) +{ + struct task_struct *task = t ? t : current; + + if (!(task->ptrace & PT_DTRACE)) + return 0; + + if (task->thread.singlestep_syscall) + return 1; + + return 2; +} + +/* + * Only x86 and x86_64 have an arch_align_stack(). + * All other arches have "#define arch_align_stack(x) (x)" + * in their asm/exec.h + * As this is included in UML from asm-um/system-generic.h, + * we can use it to behave as the subarch does. + */ +#ifndef arch_align_stack +unsigned long arch_align_stack(unsigned long sp) +{ + if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) + sp -= get_random_int() % 8192; + return sp & ~0xf; +} +#endif + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long stack_page, sp, ip; + bool seen_sched = 0; + + if ((p == NULL) || (p == current) || (p->state == TASK_RUNNING)) + return 0; + + stack_page = (unsigned long) task_stack_page(p); + /* Bail if the process has no kernel stack for some reason */ + if (stack_page == 0) + return 0; + + sp = p->thread.switch_buf->JB_SP; + /* + * Bail if the stack pointer is below the bottom of the kernel + * stack for some reason + */ + if (sp < stack_page) + return 0; + + while (sp < stack_page + THREAD_SIZE) { + ip = *((unsigned long *) sp); + if (in_sched_functions(ip)) + /* Ignore everything until we're above the scheduler */ + seen_sched = 1; + else if (kernel_text_address(ip) && seen_sched) + return ip; + + sp += sizeof(unsigned long); + } + + return 0; +} + +int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu) +{ + int cpu = current_thread_info()->cpu; + + return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu); +} + diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c deleted file mode 100644 index 34b54a3e213..00000000000 --- a/arch/um/kernel/process_kern.c +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Copyright 2003 PathScale, Inc. - * Licensed under the GPL - */ - -#include "linux/config.h" -#include "linux/kernel.h" -#include "linux/sched.h" -#include "linux/interrupt.h" -#include "linux/string.h" -#include "linux/mm.h" -#include "linux/slab.h" -#include "linux/utsname.h" -#include "linux/fs.h" -#include "linux/utime.h" -#include "linux/smp_lock.h" -#include "linux/module.h" -#include "linux/init.h" -#include "linux/capability.h" -#include "linux/vmalloc.h" -#include "linux/spinlock.h" -#include "linux/proc_fs.h" -#include "linux/ptrace.h" -#include "linux/random.h" -#include "asm/unistd.h" -#include "asm/mman.h" -#include "asm/segment.h" -#include "asm/stat.h" -#include "asm/pgtable.h" -#include "asm/processor.h" -#include "asm/tlbflush.h" -#include "asm/uaccess.h" -#include "asm/user.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" -#include "signal_kern.h" -#include "signal_user.h" -#include "init.h" -#include "irq_user.h" -#include "mem_user.h" -#include "time_user.h" -#include "tlb.h" -#include "frame_kern.h" -#include "sigcontext.h" -#include "os.h" -#include "mode.h" -#include "mode_kern.h" -#include "choose-mode.h" - -/* This is a per-cpu array. A processor only modifies its entry and it only - * cares about its entry, so it's OK if another processor is modifying its - * entry. - */ -struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; - -int external_pid(void *t) -{ - struct task_struct *task = t ? t : current; - - return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task)); -} - -int pid_to_processor_id(int pid) -{ - int i; - - for(i = 0; i < ncpus; i++){ - if(cpu_tasks[i].pid == pid) return(i); - } - return(-1); -} - -void free_stack(unsigned long stack, int order) -{ - free_pages(stack, order); -} - -unsigned long alloc_stack(int order, int atomic) -{ - unsigned long page; - gfp_t flags = GFP_KERNEL; - - if (atomic) - flags = GFP_ATOMIC; - page = __get_free_pages(flags, order); - if(page == 0) - return(0); - stack_protections(page); - return(page); -} - -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - int pid; - - current->thread.request.u.thread.proc = fn; - current->thread.request.u.thread.arg = arg; - pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, - ¤t->thread.regs, 0, NULL, NULL); - if(pid < 0) - panic("do_fork failed in kernel_thread, errno = %d", pid); - return(pid); -} - -void set_current(void *t) -{ - struct task_struct *task = t; - - cpu_tasks[task->thread_info->cpu] = ((struct cpu_task) - { external_pid(task), task }); -} - -void *_switch_to(void *prev, void *next, void *last) -{ - struct task_struct *from = prev; - struct task_struct *to= next; - - to->thread.prev_sched = from; - set_current(to); - - do { - current->thread.saved_task = NULL ; - CHOOSE_MODE_PROC(switch_to_tt, switch_to_skas, prev, next); - if(current->thread.saved_task) - show_regs(&(current->thread.regs)); - next= current->thread.saved_task; - prev= current; - } while(current->thread.saved_task); - - return(current->thread.prev_sched); - -} - -void interrupt_end(void) -{ - if(need_resched()) schedule(); - if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal(); -} - -void release_thread(struct task_struct *task) -{ - CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task)); -} - -void exit_thread(void) -{ - unprotect_stack((unsigned long) current_thread); -} - -void *get_current(void) -{ - return(current); -} - -int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, - unsigned long stack_top, struct task_struct * p, - struct pt_regs *regs) -{ - p->thread = (struct thread_struct) INIT_THREAD; - return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, - clone_flags, sp, stack_top, p, regs)); -} - -void initial_thread_cb(void (*proc)(void *), void *arg) -{ - int save_kmalloc_ok = kmalloc_ok; - - kmalloc_ok = 0; - CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, - arg); - kmalloc_ok = save_kmalloc_ok; -} - -unsigned long stack_sp(unsigned long page) -{ - return(page + PAGE_SIZE - sizeof(void *)); -} - -int current_pid(void) -{ - return(current->pid); -} - -void default_idle(void) -{ - CHOOSE_MODE(uml_idle_timer(), (void) 0); - - atomic_inc(&init_mm.mm_count); - current->mm = &init_mm; - current->active_mm = &init_mm; - - while(1){ - /* endless idle loop with no priority at all */ - - /* - * although we are an idle CPU, we do not want to - * get into the scheduler unnecessarily. - */ - if(need_resched()) - schedule(); - - idle_sleep(10); - } -} - -void cpu_idle(void) -{ - CHOOSE_MODE(init_idle_tt(), init_idle_skas()); -} - -int page_size(void) -{ - return(PAGE_SIZE); -} - -void *um_virt_to_phys(struct task_struct *task, unsigned long addr, - pte_t *pte_out) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - pte_t ptent; - - if(task->mm == NULL) - return(ERR_PTR(-EINVAL)); - pgd = pgd_offset(task->mm, addr); - if(!pgd_present(*pgd)) - return(ERR_PTR(-EINVAL)); - - pud = pud_offset(pgd, addr); - if(!pud_present(*pud)) - return(ERR_PTR(-EINVAL)); - - pmd = pmd_offset(pud, addr); - if(!pmd_present(*pmd)) - return(ERR_PTR(-EINVAL)); - - pte = pte_offset_kernel(pmd, addr); - ptent = *pte; - if(!pte_present(ptent)) - return(ERR_PTR(-EINVAL)); - - if(pte_out != NULL) - *pte_out = ptent; - return((void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK)); -} - -char *current_cmd(void) -{ -#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM) - return("(Unknown)"); -#else - void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL); - return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr); -#endif -} - -void force_sigbus(void) -{ - printk(KERN_ERR "Killing pid %d because of a lack of memory\n", - current->pid); - lock_kernel(); - sigaddset(¤t->pending.signal, SIGBUS); - recalc_sigpending(); - current->flags |= PF_SIGNALED; - do_exit(SIGBUS | 0x80); -} - -void dump_thread(struct pt_regs *regs, struct user *u) -{ -} - -void enable_hlt(void) -{ - panic("enable_hlt"); -} - -EXPORT_SYMBOL(enable_hlt); - -void disable_hlt(void) -{ - panic("disable_hlt"); -} - -EXPORT_SYMBOL(disable_hlt); - -void *um_kmalloc(int size) -{ - return(kmalloc(size, GFP_KERNEL)); -} - -void *um_kmalloc_atomic(int size) -{ - return(kmalloc(size, GFP_ATOMIC)); -} - -void *um_vmalloc(int size) -{ - return(vmalloc(size)); -} - -unsigned long get_fault_addr(void) -{ - return((unsigned long) current->thread.fault_addr); -} - -EXPORT_SYMBOL(get_fault_addr); - -void not_implemented(void) -{ - printk(KERN_DEBUG "Something isn't implemented in here\n"); -} - -EXPORT_SYMBOL(not_implemented); - -int user_context(unsigned long sp) -{ - unsigned long stack; - - stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER); - return(stack != (unsigned long) current_thread); -} - -extern void remove_umid_dir(void); - -__uml_exitcall(remove_umid_dir); - -extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; - -void do_uml_exitcalls(void) -{ - exitcall_t *call; - - call = &__uml_exitcall_end; - while (--call >= &__uml_exitcall_begin) - (*call)(); -} - -char *uml_strdup(char *string) -{ - return kstrdup(string, GFP_KERNEL); -} - -int copy_to_user_proc(void __user *to, void *from, int size) -{ - return(copy_to_user(to, from, size)); -} - -int copy_from_user_proc(void *to, void __user *from, int size) -{ - return(copy_from_user(to, from, size)); -} - -int clear_user_proc(void __user *buf, int size) -{ - return(clear_user(buf, size)); -} - -int strlen_user_proc(char __user *str) -{ - return(strlen_user(str)); -} - -int smp_sigio_handler(void) -{ -#ifdef CONFIG_SMP - int cpu = current_thread->cpu; - IPI_handler(cpu); - if(cpu != 0) - return(1); -#endif - return(0); -} - -int um_in_interrupt(void) -{ - return(in_interrupt()); -} - -int cpu(void) -{ - return(current_thread->cpu); -} - -static atomic_t using_sysemu = ATOMIC_INIT(0); -int sysemu_supported; - -void set_using_sysemu(int value) -{ - if (value > sysemu_supported) - return; - atomic_set(&using_sysemu, value); -} - -int get_using_sysemu(void) -{ - return atomic_read(&using_sysemu); -} - -static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data) -{ - if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/ - *eof = 1; - - return strlen(buf); -} - -static int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data) -{ - char tmp[2]; - - if (copy_from_user(tmp, buf, 1)) - return -EFAULT; - - if (tmp[0] >= '0' && tmp[0] <= '2') - set_using_sysemu(tmp[0] - '0'); - return count; /*We use the first char, but pretend to write everything*/ -} - -int __init make_proc_sysemu(void) -{ - struct proc_dir_entry *ent; - if (!sysemu_supported) - return 0; - - ent = create_proc_entry("sysemu", 0600, &proc_root); - - if (ent == NULL) - { - printk(KERN_WARNING "Failed to register /proc/sysemu\n"); - return(0); - } - - ent->read_proc = proc_read_sysemu; - ent->write_proc = proc_write_sysemu; - - return 0; -} - -late_initcall(make_proc_sysemu); - -int singlestepping(void * t) -{ - struct task_struct *task = t ? t : current; - - if ( ! (task->ptrace & PT_DTRACE) ) - return(0); - - if (task->thread.singlestep_syscall) - return(1); - - return 2; -} - -/* - * Only x86 and x86_64 have an arch_align_stack(). - * All other arches have "#define arch_align_stack(x) (x)" - * in their asm/system.h - * As this is included in UML from asm-um/system-generic.h, - * we can use it to behave as the subarch does. - */ -#ifndef arch_align_stack -unsigned long arch_align_stack(unsigned long sp) -{ - if (randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} -#endif diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 98e09395c09..694d551c889 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -1,34 +1,34 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/sched.h" -#include "linux/mm.h" -#include "linux/errno.h" -#include "linux/smp_lock.h" -#include "linux/security.h" -#include "linux/ptrace.h" -#include "linux/audit.h" -#ifdef CONFIG_PROC_MM -#include "linux/proc_mm.h" +#include <linux/audit.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/tracehook.h> +#include <asm/uaccess.h> +#include <skas_ptrace.h> + + + +void user_enable_single_step(struct task_struct *child) +{ + child->ptrace |= PT_DTRACE; + child->thread.singlestep_syscall = 0; + +#ifdef SUBARCH_SET_SINGLESTEPPING + SUBARCH_SET_SINGLESTEPPING(child, 1); #endif -#include "asm/ptrace.h" -#include "asm/uaccess.h" -#include "kern_util.h" -#include "skas_ptrace.h" -#include "sysdep/ptrace.h" +} -static inline void set_singlestepping(struct task_struct *child, int on) +void user_disable_single_step(struct task_struct *child) { - if (on) - child->ptrace |= PT_DTRACE; - else - child->ptrace &= ~PT_DTRACE; - child->thread.singlestep_syscall = 0; + child->ptrace &= ~PT_DTRACE; + child->thread.singlestep_syscall = 0; #ifdef SUBARCH_SET_SINGLESTEPPING - SUBARCH_SET_SINGLESTEPPING(child, on); + SUBARCH_SET_SINGLESTEPPING(child, 0); #endif } @@ -36,115 +36,45 @@ static inline void set_singlestepping(struct task_struct *child, int on) * Called by kernel/ptrace.c when detaching.. */ void ptrace_disable(struct task_struct *child) -{ - set_singlestepping(child,0); +{ + user_disable_single_step(child); } extern int peek_user(struct task_struct * child, long addr, long data); extern int poke_user(struct task_struct * child, long addr, long data); -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int i, ret; + unsigned long __user *p = (void __user *)data; + void __user *vp = p; switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - ret = -EIO; - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp, (unsigned long __user *) data); - break; - } - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: - ret = peek_user(child, addr, data); - break; - - /* when I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = -EIO; - if (access_process_vm(child, addr, &data, sizeof(data), - 1) != sizeof(data)) - break; - ret = 0; - break; - - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - ret = poke_user(child, addr, data); - break; - - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - ret = -EIO; - if (!valid_signal(data)) - break; - - set_singlestepping(child, 0); - if (request == PTRACE_SYSCALL) { - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - } - else { - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - } - child->exit_code = data; - wake_up_process(child); - ret = 0; + case PTRACE_PEEKUSR: + ret = peek_user(child, addr, data); break; - } -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - - set_singlestepping(child, 0); - child->exit_code = SIGKILL; - wake_up_process(child); + /* write the word at location addr in the USER area */ + case PTRACE_POKEUSR: + ret = poke_user(child, addr, data); break; - } - case PTRACE_SINGLESTEP: { /* set the trap flag. */ + case PTRACE_SYSEMU: + case PTRACE_SYSEMU_SINGLESTEP: ret = -EIO; - if (!valid_signal(data)) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - set_singlestepping(child, 1); - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; break; - } - - case PTRACE_DETACH: - /* detach a process that was attached. */ - ret = ptrace_detach(child, data); - break; #ifdef PTRACE_GETREGS case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - if (!access_ok(VERIFY_WRITE, (unsigned long *)data, - MAX_REG_OFFSET)) { + if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) { ret = -EIO; break; } for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { - __put_user(getreg(child, i), - (unsigned long __user *) data); - data += sizeof(long); + __put_user(getreg(child, i), p); + p++; } ret = 0; break; @@ -153,50 +83,36 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef PTRACE_SETREGS case PTRACE_SETREGS: { /* Set all gp regs in the child. */ unsigned long tmp = 0; - if (!access_ok(VERIFY_READ, (unsigned *)data, - MAX_REG_OFFSET)) { + if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) { ret = -EIO; break; } for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { - __get_user(tmp, (unsigned long __user *) data); + __get_user(tmp, p); putreg(child, i, tmp); - data += sizeof(long); + p++; } ret = 0; break; } #endif -#ifdef PTRACE_GETFPREGS - case PTRACE_GETFPREGS: /* Get the child FPU state. */ - ret = get_fpregs(data, child); - break; -#endif -#ifdef PTRACE_SETFPREGS - case PTRACE_SETFPREGS: /* Set the child FPU state. */ - ret = set_fpregs(data, child); + case PTRACE_GET_THREAD_AREA: + ret = ptrace_get_thread_area(child, addr, vp); break; -#endif -#ifdef PTRACE_GETFPXREGS - case PTRACE_GETFPXREGS: /* Get the child FPU state. */ - ret = get_fpxregs(data, child); - break; -#endif -#ifdef PTRACE_SETFPXREGS - case PTRACE_SETFPXREGS: /* Set the child FPU state. */ - ret = set_fpxregs(data, child); + + case PTRACE_SET_THREAD_AREA: + ret = ptrace_set_thread_area(child, addr, vp); break; -#endif + case PTRACE_FAULTINFO: { - /* Take the info from thread->arch->faultinfo, - * but transfer max. sizeof(struct ptrace_faultinfo). - * On i386, ptrace_faultinfo is smaller! - */ - ret = copy_to_user((unsigned long __user *) data, - &child->thread.arch.faultinfo, - sizeof(struct ptrace_faultinfo)); - if(ret) - break; + /* + * Take the info from thread->arch->faultinfo, + * but transfer max. sizeof(struct ptrace_faultinfo). + * On i386, ptrace_faultinfo is smaller! + */ + ret = copy_to_user(p, &child->thread.arch.faultinfo, + sizeof(struct ptrace_faultinfo)) ? + -EIO : 0; break; } @@ -204,46 +120,30 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_LDT: { struct ptrace_ldt ldt; - if(copy_from_user(&ldt, (unsigned long __user *) data, - sizeof(ldt))){ + if (copy_from_user(&ldt, p, sizeof(ldt))) { ret = -EIO; break; } - /* This one is confusing, so just punt and return -EIO for + /* + * This one is confusing, so just punt and return -EIO for * now */ ret = -EIO; break; } #endif -#ifdef CONFIG_PROC_MM - case PTRACE_SWITCH_MM: { - struct mm_struct *old = child->mm; - struct mm_struct *new = proc_mm_get_mm(data); - - if(IS_ERR(new)){ - ret = PTR_ERR(new); - break; - } - - atomic_inc(&new->mm_users); - child->mm = new; - child->active_mm = new; - mmput(old); - ret = 0; - break; - } -#endif default: ret = ptrace_request(child, request, addr, data); + if (ret == -EIO) + ret = subarch_ptrace(child, request, addr, data); break; } return ret; } -void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs, +static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs, int error_code) { struct siginfo info; @@ -255,56 +155,44 @@ void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs, /* User-mode eip? */ info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL; - /* Send us the fakey SIGTRAP */ + /* Send us the fake SIGTRAP */ force_sig_info(SIGTRAP, &info, tsk); } -/* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and +/* + * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check */ -void syscall_trace(union uml_pt_regs *regs, int entryexit) +void syscall_trace_enter(struct pt_regs *regs) { - int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit; - int tracesysgood; - - if (unlikely(current->audit_context)) { - if (!entryexit) - audit_syscall_entry(current, - HOST_AUDIT_ARCH, - UPT_SYSCALL_NR(regs), - UPT_SYSCALL_ARG1(regs), - UPT_SYSCALL_ARG2(regs), - UPT_SYSCALL_ARG3(regs), - UPT_SYSCALL_ARG4(regs)); - else audit_syscall_exit(current, - AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), - UPT_SYSCALL_RET(regs)); - } - - /* Fake a debug trap */ - if (is_singlestep) - send_sigtrap(current, regs, 0); + audit_syscall_entry(HOST_AUDIT_ARCH, + UPT_SYSCALL_NR(®s->regs), + UPT_SYSCALL_ARG1(®s->regs), + UPT_SYSCALL_ARG2(®s->regs), + UPT_SYSCALL_ARG3(®s->regs), + UPT_SYSCALL_ARG4(®s->regs)); if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; - if (!(current->ptrace & PT_PTRACED)) - return; + tracehook_report_syscall_entry(regs); +} - /* the 0x80 provides a way for the tracing parent to distinguish - between a syscall stop and SIGTRAP delivery */ - tracesysgood = (current->ptrace & PT_TRACESYSGOOD); - ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0)); +void syscall_trace_leave(struct pt_regs *regs) +{ + int ptraced = current->ptrace; - if (entryexit) /* force do_signal() --> is_syscall() */ - set_thread_flag(TIF_SIGPENDING); + audit_syscall_exit(regs); - /* this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } + /* Fake a debug trap */ + if (ptraced & PT_DTRACE) + send_sigtrap(current, ®s->regs, 0); + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + + tracehook_report_syscall_exit(regs, 0); + /* force do_signal() --> is_syscall() */ + if (ptraced & PT_PTRACED) + set_thread_flag(TIF_SIGPENDING); } diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index a637e885c58..ced8903921a 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -1,72 +1,64 @@ /* - * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/module.h" -#include "linux/sched.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" -#include "os.h" -#include "mode.h" -#include "choose-mode.h" +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/oom.h> +#include <kern_util.h> +#include <os.h> +#include <skas.h> -#ifdef CONFIG_SMP -static void kill_idlers(int me) -{ -#ifdef CONFIG_MODE_TT - struct task_struct *p; - int i; - - for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){ - p = idle_threads[i]; - if((p != NULL) && (p->thread.mode.tt.extern_pid != me)) - os_kill_process(p->thread.mode.tt.extern_pid, 0); - } -#endif -} -#endif +void (*pm_power_off)(void); static void kill_off_processes(void) { - CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas()); -#ifdef CONFIG_SMP - kill_idlers(os_getpid()); -#endif + if (proc_mm) + /* + * FIXME: need to loop over userspace_pids + */ + os_kill_ptraced_process(userspace_pid[0], 1); + else { + struct task_struct *p; + int pid; + + read_lock(&tasklist_lock); + for_each_process(p) { + struct task_struct *t; + + t = find_lock_task_mm(p); + if (!t) + continue; + pid = t->mm->context.id.u.pid; + task_unlock(t); + os_kill_ptraced_process(pid, 1); + } + read_unlock(&tasklist_lock); + } } void uml_cleanup(void) { - kmalloc_ok = 0; + kmalloc_ok = 0; do_uml_exitcalls(); kill_off_processes(); } void machine_restart(char * __unused) { - uml_cleanup(); - CHOOSE_MODE(reboot_tt(), reboot_skas()); + uml_cleanup(); + reboot_skas(); } void machine_power_off(void) { - uml_cleanup(); - CHOOSE_MODE(halt_tt(), halt_skas()); + uml_cleanup(); + halt_skas(); } void machine_halt(void) { machine_power_off(); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/resource.c b/arch/um/kernel/resource.c deleted file mode 100644 index 32188e12e8a..00000000000 --- a/arch/um/kernel/resource.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/pci.h" - -unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, - unsigned long start, unsigned long size) -{ - return start; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c new file mode 100644 index 00000000000..b5e0cbb3438 --- /dev/null +++ b/arch/um/kernel/sigio.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) + * Licensed under the GPL + */ + +#include <linux/interrupt.h> +#include <irq_kern.h> +#include <os.h> +#include <sigio.h> + +/* Protected by sigio_lock() called from write_sigio_workaround */ +static int sigio_irq_fd = -1; + +static irqreturn_t sigio_interrupt(int irq, void *data) +{ + char c; + + os_read_file(sigio_irq_fd, &c, sizeof(c)); + reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); + return IRQ_HANDLED; +} + +int write_sigio_irq(int fd) +{ + int err; + + err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, + 0, "write sigio", NULL); + if (err) { + printk(KERN_ERR "write_sigio_irq : um_request_irq failed, " + "err = %d\n", err); + return -1; + } + sigio_irq_fd = fd; + return 0; +} + +/* These are called from os-Linux/sigio.c to protect its pollfds arrays. */ +static DEFINE_SPINLOCK(sigio_spinlock); + +void sigio_lock(void) +{ + spin_lock(&sigio_spinlock); +} + +void sigio_unlock(void) +{ + spin_unlock(&sigio_spinlock); +} diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c deleted file mode 100644 index 229988463c4..00000000000 --- a/arch/um/kernel/sigio_kern.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/kernel.h" -#include "linux/list.h" -#include "linux/slab.h" -#include "linux/signal.h" -#include "linux/interrupt.h" -#include "init.h" -#include "sigio.h" -#include "irq_user.h" -#include "irq_kern.h" - -/* Protected by sigio_lock() called from write_sigio_workaround */ -static int sigio_irq_fd = -1; - -static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused) -{ - read_sigio_fd(sigio_irq_fd); - reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); - return(IRQ_HANDLED); -} - -int write_sigio_irq(int fd) -{ - int err; - - err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, - SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", - NULL); - if(err){ - printk("write_sigio_irq : um_request_irq failed, err = %d\n", - err); - return(-1); - } - sigio_irq_fd = fd; - return(0); -} - -static DEFINE_SPINLOCK(sigio_spinlock); - -void sigio_lock(void) -{ - spin_lock(&sigio_spinlock); -} - -void sigio_unlock(void) -{ - spin_unlock(&sigio_spinlock); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c deleted file mode 100644 index 3fbfd956bfe..00000000000 --- a/arch/um/kernel/sigio_user.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <unistd.h> -#include <stdlib.h> -#include <termios.h> -#include <pty.h> -#include <signal.h> -#include <errno.h> -#include <string.h> -#include <sched.h> -#include <sys/socket.h> -#include <sys/poll.h> -#include "init.h" -#include "user.h" -#include "kern_util.h" -#include "user_util.h" -#include "sigio.h" -#include "os.h" - -/* Changed during early boot */ -int pty_output_sigio = 0; -int pty_close_sigio = 0; - -/* Used as a flag during SIGIO testing early in boot */ -static volatile int got_sigio = 0; - -void __init handler(int sig) -{ - got_sigio = 1; -} - -struct openpty_arg { - int master; - int slave; - int err; -}; - -static void openpty_cb(void *arg) -{ - struct openpty_arg *info = arg; - - info->err = 0; - if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) - info->err = -errno; -} - -void __init check_one_sigio(void (*proc)(int, int)) -{ - struct sigaction old, new; - struct openpty_arg pty = { .master = -1, .slave = -1 }; - int master, slave, err; - - initial_thread_cb(openpty_cb, &pty); - if(pty.err){ - printk("openpty failed, errno = %d\n", -pty.err); - return; - } - - master = pty.master; - slave = pty.slave; - - if((master == -1) || (slave == -1)){ - printk("openpty failed to allocate a pty\n"); - return; - } - - /* Not now, but complain so we now where we failed. */ - err = raw(master); - if (err < 0) - panic("check_sigio : __raw failed, errno = %d\n", -err); - - err = os_sigio_async(master, slave); - if(err < 0) - panic("tty_fds : sigio_async failed, err = %d\n", -err); - - if(sigaction(SIGIO, NULL, &old) < 0) - panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); - new = old; - new.sa_handler = handler; - if(sigaction(SIGIO, &new, NULL) < 0) - panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); - - got_sigio = 0; - (*proc)(master, slave); - - os_close_file(master); - os_close_file(slave); - - if(sigaction(SIGIO, &old, NULL) < 0) - panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); -} - -static void tty_output(int master, int slave) -{ - int n; - char buf[512]; - - printk("Checking that host ptys support output SIGIO..."); - - memset(buf, 0, sizeof(buf)); - - while(os_write_file(master, buf, sizeof(buf)) > 0) ; - if(errno != EAGAIN) - panic("check_sigio : write failed, errno = %d\n", errno); - while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; - - if (got_sigio) { - printk("Yes\n"); - pty_output_sigio = 1; - } else if (n == -EAGAIN) { - printk("No, enabling workaround\n"); - } else { - panic("check_sigio : read failed, err = %d\n", n); - } -} - -static void tty_close(int master, int slave) -{ - printk("Checking that host ptys support SIGIO on close..."); - - os_close_file(slave); - if(got_sigio){ - printk("Yes\n"); - pty_close_sigio = 1; - } - else printk("No, enabling workaround\n"); -} - -void __init check_sigio(void) -{ - if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && - (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ - printk("No pseudo-terminals available - skipping pty SIGIO " - "check\n"); - return; - } - check_one_sigio(tty_output); - check_one_sigio(tty_close); -} - -/* Protected by sigio_lock(), also used by sigio_cleanup, which is an - * exitcall. - */ -static int write_sigio_pid = -1; - -/* These arrays are initialized before the sigio thread is started, and - * the descriptors closed after it is killed. So, it can't see them change. - * On the UML side, they are changed under the sigio_lock. - */ -static int write_sigio_fds[2] = { -1, -1 }; -static int sigio_private[2] = { -1, -1 }; - -struct pollfds { - struct pollfd *poll; - int size; - int used; -}; - -/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread - * synchronizes with it. - */ -struct pollfds current_poll = { - .poll = NULL, - .size = 0, - .used = 0 -}; - -struct pollfds next_poll = { - .poll = NULL, - .size = 0, - .used = 0 -}; - -static int write_sigio_thread(void *unused) -{ - struct pollfds *fds, tmp; - struct pollfd *p; - int i, n, respond_fd; - char c; - - signal(SIGWINCH, SIG_IGN); - fds = ¤t_poll; - while(1){ - n = poll(fds->poll, fds->used, -1); - if(n < 0){ - if(errno == EINTR) continue; - printk("write_sigio_thread : poll returned %d, " - "errno = %d\n", n, errno); - } - for(i = 0; i < fds->used; i++){ - p = &fds->poll[i]; - if(p->revents == 0) continue; - if(p->fd == sigio_private[1]){ - n = os_read_file(sigio_private[1], &c, sizeof(c)); - if(n != sizeof(c)) - printk("write_sigio_thread : " - "read failed, err = %d\n", -n); - tmp = current_poll; - current_poll = next_poll; - next_poll = tmp; - respond_fd = sigio_private[1]; - } - else { - respond_fd = write_sigio_fds[1]; - fds->used--; - memmove(&fds->poll[i], &fds->poll[i + 1], - (fds->used - i) * sizeof(*fds->poll)); - } - - n = os_write_file(respond_fd, &c, sizeof(c)); - if(n != sizeof(c)) - printk("write_sigio_thread : write failed, " - "err = %d\n", -n); - } - } -} - -static int need_poll(int n) -{ - if(n <= next_poll.size){ - next_poll.used = n; - return(0); - } - if(next_poll.poll != NULL) kfree(next_poll.poll); - next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); - if(next_poll.poll == NULL){ - printk("need_poll : failed to allocate new pollfds\n"); - next_poll.size = 0; - next_poll.used = 0; - return(-1); - } - next_poll.size = n; - next_poll.used = n; - return(0); -} - -/* Must be called with sigio_lock held, because it's needed by the marked - * critical section. */ -static void update_thread(void) -{ - unsigned long flags; - int n; - char c; - - flags = set_signals(0); - n = os_write_file(sigio_private[0], &c, sizeof(c)); - if(n != sizeof(c)){ - printk("update_thread : write failed, err = %d\n", -n); - goto fail; - } - - n = os_read_file(sigio_private[0], &c, sizeof(c)); - if(n != sizeof(c)){ - printk("update_thread : read failed, err = %d\n", -n); - goto fail; - } - - set_signals(flags); - return; - fail: - /* Critical section start */ - if(write_sigio_pid != -1) - os_kill_process(write_sigio_pid, 1); - write_sigio_pid = -1; - os_close_file(sigio_private[0]); - os_close_file(sigio_private[1]); - os_close_file(write_sigio_fds[0]); - os_close_file(write_sigio_fds[1]); - /* Critical section end */ - set_signals(flags); -} - -int add_sigio_fd(int fd, int read) -{ - int err = 0, i, n, events; - - sigio_lock(); - for(i = 0; i < current_poll.used; i++){ - if(current_poll.poll[i].fd == fd) - goto out; - } - - n = current_poll.used + 1; - err = need_poll(n); - if(err) - goto out; - - for(i = 0; i < current_poll.used; i++) - next_poll.poll[i] = current_poll.poll[i]; - - if(read) events = POLLIN; - else events = POLLOUT; - - next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd, - .events = events, - .revents = 0 }); - update_thread(); - out: - sigio_unlock(); - return(err); -} - -int ignore_sigio_fd(int fd) -{ - struct pollfd *p; - int err = 0, i, n = 0; - - sigio_lock(); - for(i = 0; i < current_poll.used; i++){ - if(current_poll.poll[i].fd == fd) break; - } - if(i == current_poll.used) - goto out; - - err = need_poll(current_poll.used - 1); - if(err) - goto out; - - for(i = 0; i < current_poll.used; i++){ - p = ¤t_poll.poll[i]; - if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i]; - } - if(n == i){ - printk("ignore_sigio_fd : fd %d not found\n", fd); - err = -1; - goto out; - } - - update_thread(); - out: - sigio_unlock(); - return(err); -} - -static int setup_initial_poll(int fd) -{ - struct pollfd *p; - - p = um_kmalloc_atomic(sizeof(struct pollfd)); - if(p == NULL){ - printk("setup_initial_poll : failed to allocate poll\n"); - return(-1); - } - *p = ((struct pollfd) { .fd = fd, - .events = POLLIN, - .revents = 0 }); - current_poll = ((struct pollfds) { .poll = p, - .used = 1, - .size = 1 }); - return(0); -} - -void write_sigio_workaround(void) -{ - unsigned long stack; - int err; - - sigio_lock(); - if(write_sigio_pid != -1) - goto out; - - err = os_pipe(write_sigio_fds, 1, 1); - if(err < 0){ - printk("write_sigio_workaround - os_pipe 1 failed, " - "err = %d\n", -err); - goto out; - } - err = os_pipe(sigio_private, 1, 1); - if(err < 0){ - printk("write_sigio_workaround - os_pipe 2 failed, " - "err = %d\n", -err); - goto out_close1; - } - if(setup_initial_poll(sigio_private[1])) - goto out_close2; - - write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, - CLONE_FILES | CLONE_VM, &stack, 0); - - if(write_sigio_pid < 0) goto out_close2; - - if(write_sigio_irq(write_sigio_fds[0])) - goto out_kill; - - out: - sigio_unlock(); - return; - - out_kill: - os_kill_process(write_sigio_pid, 1); - write_sigio_pid = -1; - out_close2: - os_close_file(sigio_private[0]); - os_close_file(sigio_private[1]); - out_close1: - os_close_file(write_sigio_fds[0]); - os_close_file(write_sigio_fds[1]); - sigio_unlock(); -} - -int read_sigio_fd(int fd) -{ - int n; - char c; - - n = os_read_file(fd, &c, sizeof(c)); - if(n != sizeof(c)){ - if(n < 0) { - printk("read_sigio_fd - read failed, err = %d\n", -n); - return(n); - } - else { - printk("read_sigio_fd - short read, bytes = %d\n", n); - return(-EIO); - } - } - return(n); -} - -static void sigio_cleanup(void) -{ - if (write_sigio_pid != -1) { - os_kill_process(write_sigio_pid, 1); - write_sigio_pid = -1; - } -} - -__uml_exitcall(sigio_cleanup); diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c new file mode 100644 index 00000000000..f57e02e7910 --- /dev/null +++ b/arch/um/kernel/signal.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <linux/module.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <asm/siginfo.h> +#include <asm/signal.h> +#include <asm/unistd.h> +#include <frame_kern.h> +#include <kern_util.h> + +EXPORT_SYMBOL(block_signals); +EXPORT_SYMBOL(unblock_signals); + +/* + * OK, we're invoking a handler + */ +static void handle_signal(struct pt_regs *regs, unsigned long signr, + struct k_sigaction *ka, struct siginfo *info) +{ + sigset_t *oldset = sigmask_to_save(); + int singlestep = 0; + unsigned long sp; + int err; + + if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) + singlestep = 1; + + /* Did we come from a system call? */ + if (PT_REGS_SYSCALL_NR(regs) >= 0) { + /* If so, check system call restarting.. */ + switch (PT_REGS_SYSCALL_RET(regs)) { + case -ERESTART_RESTARTBLOCK: + case -ERESTARTNOHAND: + PT_REGS_SYSCALL_RET(regs) = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + PT_REGS_SYSCALL_RET(regs) = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + PT_REGS_RESTART_SYSCALL(regs); + PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); + break; + } + } + + sp = PT_REGS_SP(regs); + if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0)) + sp = current->sas_ss_sp + current->sas_ss_size; + +#ifdef CONFIG_ARCH_HAS_SC_SIGNALS + if (!(ka->sa.sa_flags & SA_SIGINFO)) + err = setup_signal_stack_sc(sp, signr, ka, regs, oldset); + else +#endif + err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset); + + if (err) + force_sigsegv(signr, current); + else + signal_delivered(signr, info, ka, regs, singlestep); +} + +static int kern_do_signal(struct pt_regs *regs) +{ + struct k_sigaction ka_copy; + struct siginfo info; + int sig, handled_sig = 0; + + while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) { + handled_sig = 1; + /* Whee! Actually deliver the signal. */ + handle_signal(regs, sig, &ka_copy, &info); + } + + /* Did we come from a system call? */ + if (!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)) { + /* Restart the system call - no handlers present */ + switch (PT_REGS_SYSCALL_RET(regs)) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); + PT_REGS_RESTART_SYSCALL(regs); + break; + case -ERESTART_RESTARTBLOCK: + PT_REGS_ORIG_SYSCALL(regs) = __NR_restart_syscall; + PT_REGS_RESTART_SYSCALL(regs); + break; + } + } + + /* + * This closes a way to execute a system call on the host. If + * you set a breakpoint on a system call instruction and singlestep + * from it, the tracing thread used to PTRACE_SINGLESTEP the process + * rather than PTRACE_SYSCALL it, allowing the system call to execute + * on the host. The tracing thread will check this flag and + * PTRACE_SYSCALL if necessary. + */ + if (current->ptrace & PT_DTRACE) + current->thread.singlestep_syscall = + is_syscall(PT_REGS_IP(¤t->thread.regs)); + + /* + * if there's no signal to deliver, we just put the saved sigmask + * back + */ + if (!handled_sig) + restore_saved_sigmask(); + return handled_sig; +} + +int do_signal(void) +{ + return kern_do_signal(¤t->thread.regs); +} diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c deleted file mode 100644 index 03618bd13d5..00000000000 --- a/arch/um/kernel/signal_kern.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/config.h" -#include "linux/stddef.h" -#include "linux/sys.h" -#include "linux/sched.h" -#include "linux/wait.h" -#include "linux/kernel.h" -#include "linux/smp_lock.h" -#include "linux/module.h" -#include "linux/slab.h" -#include "linux/tty.h" -#include "linux/binfmts.h" -#include "linux/ptrace.h" -#include "asm/signal.h" -#include "asm/uaccess.h" -#include "asm/unistd.h" -#include "user_util.h" -#include "asm/ucontext.h" -#include "kern_util.h" -#include "signal_kern.h" -#include "signal_user.h" -#include "kern.h" -#include "frame_kern.h" -#include "sigcontext.h" -#include "mode.h" - -EXPORT_SYMBOL(block_signals); -EXPORT_SYMBOL(unblock_signals); - -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) - -/* - * OK, we're invoking a handler - */ -static int handle_signal(struct pt_regs *regs, unsigned long signr, - struct k_sigaction *ka, siginfo_t *info, - sigset_t *oldset) -{ - unsigned long sp; - int err; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - /* Did we come from a system call? */ - if(PT_REGS_SYSCALL_NR(regs) >= 0){ - /* If so, check system call restarting.. */ - switch(PT_REGS_SYSCALL_RET(regs)){ - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - PT_REGS_SYSCALL_RET(regs) = -EINTR; - break; - - case -ERESTARTSYS: - if (!(ka->sa.sa_flags & SA_RESTART)) { - PT_REGS_SYSCALL_RET(regs) = -EINTR; - break; - } - /* fallthrough */ - case -ERESTARTNOINTR: - PT_REGS_RESTART_SYSCALL(regs); - PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); - break; - } - } - - sp = PT_REGS_SP(regs); - if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0)) - sp = current->sas_ss_sp + current->sas_ss_size; - -#ifdef CONFIG_ARCH_HAS_SC_SIGNALS - if(!(ka->sa.sa_flags & SA_SIGINFO)) - err = setup_signal_stack_sc(sp, signr, ka, regs, oldset); - else -#endif - err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset); - - if(err){ - spin_lock_irq(¤t->sighand->siglock); - current->blocked = *oldset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - force_sigsegv(signr, current); - } else { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka->sa.sa_mask); - if(!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } - - return err; -} - -static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset) -{ - struct k_sigaction ka_copy; - siginfo_t info; - int sig, handled_sig = 0; - - while((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0){ - handled_sig = 1; - /* Whee! Actually deliver the signal. */ - if(!handle_signal(regs, sig, &ka_copy, &info, oldset)) - break; - } - - /* Did we come from a system call? */ - if(!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)){ - /* Restart the system call - no handlers present */ - if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND || - PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS || - PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){ - PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); - PT_REGS_RESTART_SYSCALL(regs); - } - else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){ - PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall; - PT_REGS_RESTART_SYSCALL(regs); - } - } - - /* This closes a way to execute a system call on the host. If - * you set a breakpoint on a system call instruction and singlestep - * from it, the tracing thread used to PTRACE_SINGLESTEP the process - * rather than PTRACE_SYSCALL it, allowing the system call to execute - * on the host. The tracing thread will check this flag and - * PTRACE_SYSCALL if necessary. - */ - if(current->ptrace & PT_DTRACE) - current->thread.singlestep_syscall = - is_syscall(PT_REGS_IP(¤t->thread.regs)); - return(handled_sig); -} - -int do_signal(void) -{ - return(kern_do_signal(¤t->thread.regs, ¤t->blocked)); -} - -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -long sys_sigsuspend(int history0, int history1, old_sigset_t mask) -{ - sigset_t saveset; - - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if(kern_do_signal(¤t->thread.regs, &saveset)) - return(-EINTR); - } -} - -long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) -{ - sigset_t saveset, newset; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (kern_do_signal(¤t->thread.regs, &saveset)) - return(-EINTR); - } -} - -long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) -{ - return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c deleted file mode 100644 index 62f457835fb..00000000000 --- a/arch/um/kernel/signal_user.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <signal.h> -#include <errno.h> -#include <stdarg.h> -#include <string.h> -#include <sys/mman.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "signal_user.h" -#include "signal_kern.h" -#include "sysdep/sigcontext.h" -#include "sigcontext.h" - -void set_sigstack(void *sig_stack, int size) -{ - stack_t stack = ((stack_t) { .ss_flags = 0, - .ss_sp = (__ptr_t) sig_stack, - .ss_size = size - sizeof(void *) }); - - if(sigaltstack(&stack, NULL) != 0) - panic("enabling signal stack failed, errno = %d\n", errno); -} - -void set_handler(int sig, void (*handler)(int), int flags, ...) -{ - struct sigaction action; - va_list ap; - int mask; - - va_start(ap, flags); - action.sa_handler = handler; - sigemptyset(&action.sa_mask); - while((mask = va_arg(ap, int)) != -1){ - sigaddset(&action.sa_mask, mask); - } - va_end(ap); - action.sa_flags = flags; - action.sa_restorer = NULL; - if(sigaction(sig, &action, NULL) < 0) - panic("sigaction failed"); -} - -int change_sig(int signal, int on) -{ - sigset_t sigset, old; - - sigemptyset(&sigset); - sigaddset(&sigset, signal); - sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old); - return(!sigismember(&old, signal)); -} - -/* Both here and in set/get_signal we don't touch SIGPROF, because we must not - * disable profiling; it's safe because the profiling code does not interact - * with the kernel code at all.*/ - -static void change_signals(int type) -{ - sigset_t mask; - - sigemptyset(&mask); - sigaddset(&mask, SIGVTALRM); - sigaddset(&mask, SIGALRM); - sigaddset(&mask, SIGIO); - if(sigprocmask(type, &mask, NULL) < 0) - panic("Failed to change signal mask - errno = %d", errno); -} - -void block_signals(void) -{ - change_signals(SIG_BLOCK); -} - -void unblock_signals(void) -{ - change_signals(SIG_UNBLOCK); -} - -/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled - * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to - * be able to profile all of UML, not just the non-critical sections. If - * profiling is not thread-safe, then that is not my problem. We can disable - * profiling when SMP is enabled in that case. - */ -#define SIGIO_BIT 0 -#define SIGVTALRM_BIT 1 - -static int enable_mask(sigset_t *mask) -{ - int sigs; - - sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT; - sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT; - sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT; - return(sigs); -} - -int get_signals(void) -{ - sigset_t mask; - - if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0) - panic("Failed to get signal mask"); - return(enable_mask(&mask)); -} - -int set_signals(int enable) -{ - sigset_t mask; - int ret; - - sigemptyset(&mask); - if(enable & (1 << SIGIO_BIT)) - sigaddset(&mask, SIGIO); - if(enable & (1 << SIGVTALRM_BIT)){ - sigaddset(&mask, SIGVTALRM); - sigaddset(&mask, SIGALRM); - } - - /* This is safe - sigprocmask is guaranteed to copy locally the - * value of new_set, do his work and then, at the end, write to - * old_set. - */ - if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) - panic("Failed to enable signals"); - ret = enable_mask(&mask); - sigemptyset(&mask); - if((enable & (1 << SIGIO_BIT)) == 0) - sigaddset(&mask, SIGIO); - if((enable & (1 << SIGVTALRM_BIT)) == 0){ - sigaddset(&mask, SIGVTALRM); - sigaddset(&mask, SIGALRM); - } - if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0) - panic("Failed to block signals"); - - return(ret); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index 8de471b59c1..0b76d8869c9 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -1,14 +1,15 @@ -# -# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com) +# +# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) # Licensed under the GPL # -obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ - syscall.o tlb.o trap_user.o uaccess.o +obj-y := clone.o mmu.o process.o syscall.o uaccess.o -USER_OBJS := process.o clone.o +# clone.o is in the stub, so it can't be built with profiling +# GCC hardened also auto-enables -fpic, but we need %ebx so it can't work -> +# disable it -include arch/um/scripts/Makefile.rules +CFLAGS_clone.o := $(CFLAGS_NO_HARDENING) +UNPROFILE_OBJS := clone.o -# clone.o is in the stub, so it can't be built with profiling -$(obj)/clone.o : c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) +include arch/um/scripts/Makefile.rules diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c index 4dc55f10cd1..289771dadf8 100644 --- a/arch/um/kernel/skas/clone.c +++ b/arch/um/kernel/skas/clone.c @@ -1,44 +1,56 @@ -#include <sched.h> +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + #include <signal.h> -#include <sys/mman.h> -#include <sys/time.h> +#include <sched.h> #include <asm/unistd.h> -#include <asm/page.h> -#include "ptrace_user.h" -#include "skas.h" -#include "stub-data.h" -#include "uml-config.h" -#include "sysdep/stub.h" - -/* This is in a separate file because it needs to be compiled with any +#include <sys/time.h> +#include <as-layout.h> +#include <ptrace_user.h> +#include <stub-data.h> +#include <sysdep/stub.h> + +/* + * This is in a separate file because it needs to be compiled with any * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled + * + * Use UM_KERN_PAGE_SIZE instead of PAGE_SIZE because that calls getpagesize + * on some systems. */ + void __attribute__ ((__section__ (".__syscall_stub"))) stub_clone_handler(void) { + struct stub_data *data = (struct stub_data *) STUB_DATA; long err; - struct stub_data *from = (struct stub_data *) UML_CONFIG_STUB_DATA; err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, - UML_CONFIG_STUB_DATA + PAGE_SIZE / 2 - - sizeof(void *)); - if(err != 0) + STUB_DATA + UM_KERN_PAGE_SIZE / 2 - sizeof(void *)); + if (err != 0) goto out; err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0); - if(err) + if (err) goto out; err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL, - (long) &from->timer, 0); - if(err) + (long) &data->timer, 0); + if (err) goto out; - err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA, PAGE_SIZE, - PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, - from->fd, from->offset); + remap_stack(data->fd, data->offset); + goto done; + out: - /* save current result. Parent: pid; child: retcode of mmap */ - from->err = err; + /* + * save current result. + * Parent: pid; + * child: retcode of mmap already saved and it jumps around this + * assignment + */ + data->err = err; + done: trap_myself(); } diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c deleted file mode 100644 index 77ed7bbab21..00000000000 --- a/arch/um/kernel/skas/exec_kern.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/kernel.h" -#include "asm/current.h" -#include "asm/page.h" -#include "asm/signal.h" -#include "asm/ptrace.h" -#include "asm/uaccess.h" -#include "asm/mmu_context.h" -#include "tlb.h" -#include "skas.h" -#include "um_mmu.h" -#include "os.h" - -void flush_thread_skas(void) -{ - force_flush_all(); - switch_mm_skas(¤t->mm->context.skas.id); -} - -void start_thread_skas(struct pt_regs *regs, unsigned long eip, - unsigned long esp) -{ - set_fs(USER_DS); - PT_REGS_IP(regs) = eip; - PT_REGS_SP(regs) = esp; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h deleted file mode 100644 index 44110c521e4..00000000000 --- a/arch/um/kernel/skas/include/mmu-skas.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SKAS_MMU_H -#define __SKAS_MMU_H - -#include "linux/config.h" -#include "mm_id.h" -#include "asm/ldt.h" - -struct mmu_context_skas { - struct mm_id id; - unsigned long last_page_table; -#ifdef CONFIG_3_LEVEL_PGTABLES - unsigned long last_pmd; -#endif - uml_ldt_t ldt; -}; - -extern void switch_mm_skas(struct mm_id * mm_idp); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h deleted file mode 100644 index bcd26a6a388..00000000000 --- a/arch/um/kernel/skas/include/mode-skas.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __MODE_SKAS_H__ -#define __MODE_SKAS_H__ - -#include <sysdep/ptrace.h> - -extern unsigned long exec_regs[]; -extern unsigned long exec_fp_regs[]; -extern unsigned long exec_fpx_regs[]; -extern int have_fpx_regs; - -extern void sig_handler_common_skas(int sig, void *sc_ptr); -extern void halt_skas(void); -extern void reboot_skas(void); -extern void kill_off_processes_skas(void); -extern int is_skas_winch(int pid, int fd, void *data); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/include/mode_kern-skas.h b/arch/um/kernel/skas/include/mode_kern-skas.h deleted file mode 100644 index c97a80dfe37..00000000000 --- a/arch/um/kernel/skas/include/mode_kern-skas.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SKAS_MODE_KERN_H__ -#define __SKAS_MODE_KERN_H__ - -#include "linux/sched.h" -#include "asm/page.h" -#include "asm/ptrace.h" - -extern void flush_thread_skas(void); -extern void switch_to_skas(void *prev, void *next); -extern void start_thread_skas(struct pt_regs *regs, unsigned long eip, - unsigned long esp); -extern int copy_thread_skas(int nr, unsigned long clone_flags, - unsigned long sp, unsigned long stack_top, - struct task_struct *p, struct pt_regs *regs); -extern void release_thread_skas(struct task_struct *task); -extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); -extern void init_idle_skas(void); -extern void flush_tlb_kernel_range_skas(unsigned long start, - unsigned long end); -extern void flush_tlb_kernel_vm_skas(void); -extern void __flush_tlb_one_skas(unsigned long addr); -extern void flush_tlb_range_skas(struct vm_area_struct *vma, - unsigned long start, unsigned long end); -extern void flush_tlb_mm_skas(struct mm_struct *mm); -extern void force_flush_all_skas(void); -extern long execute_syscall_skas(void *r); -extern void before_mem_skas(unsigned long unused); -extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, - unsigned long *task_size_out); -extern int start_uml_skas(void); -extern int external_pid_skas(struct task_struct *task); -extern int thread_pid_skas(struct task_struct *task); - -#define kmem_end_skas (host_task_size - 1024 * 1024) - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h deleted file mode 100644 index daa2f85b684..00000000000 --- a/arch/um/kernel/skas/include/skas.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SKAS_H -#define __SKAS_H - -#include "mm_id.h" -#include "sysdep/ptrace.h" - -extern int userspace_pid[]; -extern int proc_mm, ptrace_faultinfo, ptrace_ldt; -extern int skas_needs_stub; - -extern void switch_threads(void *me, void *next); -extern void thread_wait(void *sw, void *fb); -extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, - void (*handler)(int)); -extern int start_idle_thread(void *stack, void *switch_buf_ptr, - void **fork_buf_ptr); -extern int user_thread(unsigned long stack, int flags); -extern void userspace(union uml_pt_regs *regs); -extern void new_thread_proc(void *stack, void (*handler)(int sig)); -extern void remove_sigstack(void); -extern void new_thread_handler(int sig); -extern void handle_syscall(union uml_pt_regs *regs); -extern int map(struct mm_id * mm_idp, unsigned long virt, - unsigned long len, int r, int w, int x, int phys_fd, - unsigned long long offset, int done, void **data); -extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, - int done, void **data); -extern int protect(struct mm_id * mm_idp, unsigned long addr, - unsigned long len, int r, int w, int x, int done, - void **data); -extern void user_signal(int sig, union uml_pt_regs *regs, int pid); -extern int new_mm(int from, unsigned long stack); -extern int start_userspace(unsigned long stub_stack); -extern int copy_context_skas0(unsigned long stack, int pid); -extern void get_skas_faultinfo(int pid, struct faultinfo * fi); -extern long execute_syscall_skas(void *r); -extern unsigned long current_stub_stack(void); -extern long run_syscall_stub(struct mm_id * mm_idp, - int syscall, unsigned long *args, long expected, - void **addr, int done); -extern long syscall_stub_data(struct mm_id * mm_idp, - unsigned long *data, int data_count, - void **addr, void **stub_addr); - -#endif diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h deleted file mode 100644 index 7da0c2def0e..00000000000 --- a/arch/um/kernel/skas/include/uaccess-skas.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SKAS_UACCESS_H -#define __SKAS_UACCESS_H - -#include "asm/errno.h" -#include "asm/fixmap.h" - -#define access_ok_skas(type, addr, size) \ - ((segment_eq(get_fs(), KERNEL_DS)) || \ - (((unsigned long) (addr) < TASK_SIZE) && \ - ((unsigned long) (addr) + (size) <= TASK_SIZE)) || \ - ((type == VERIFY_READ ) && \ - ((unsigned long) (addr) >= FIXADDR_USER_START) && \ - ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \ - ((unsigned long) (addr) + (size) >= (unsigned long)(addr)))) - -extern int copy_from_user_skas(void *to, const void __user *from, int n); -extern int copy_to_user_skas(void __user *to, const void *from, int n); -extern int strncpy_from_user_skas(char *dst, const char __user *src, int count); -extern int __clear_user_skas(void __user *mem, int len); -extern int clear_user_skas(void __user *mem, int len); -extern int strnlen_user_skas(const void __user *str, int len); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c deleted file mode 100644 index 88ab96c609c..00000000000 --- a/arch/um/kernel/skas/mem.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/config.h" -#include "linux/mm.h" -#include "asm/pgtable.h" -#include "mem_user.h" -#include "skas.h" - -unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, - unsigned long *task_size_out) -{ - /* Round up to the nearest 4M */ - unsigned long top = ROUND_4M((unsigned long) &arg); - -#ifdef CONFIG_HOST_TASK_SIZE - *host_size_out = CONFIG_HOST_TASK_SIZE; - *task_size_out = CONFIG_HOST_TASK_SIZE; -#else - *host_size_out = top; - if (!skas_needs_stub) - *task_size_out = top; - else *task_size_out = CONFIG_STUB_START & PGDIR_MASK; -#endif - return(((unsigned long) set_task_sizes_skas) & ~0xffffff); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c deleted file mode 100644 index 1d89640bd50..00000000000 --- a/arch/um/kernel/skas/mem_user.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <signal.h> -#include <errno.h> -#include <string.h> -#include <sys/mman.h> -#include <sys/wait.h> -#include <asm/page.h> -#include <asm/unistd.h> -#include "mem_user.h" -#include "mem.h" -#include "skas.h" -#include "user.h" -#include "os.h" -#include "proc_mm.h" -#include "ptrace_user.h" -#include "user_util.h" -#include "kern_util.h" -#include "task.h" -#include "registers.h" -#include "uml-config.h" -#include "sysdep/ptrace.h" -#include "sysdep/stub.h" - -extern unsigned long batch_syscall_stub, __syscall_stub_start; - -extern void wait_stub_done(int pid, int sig, char * fname); - -static inline unsigned long *check_init_stack(struct mm_id * mm_idp, - unsigned long *stack) -{ - if(stack == NULL){ - stack = (unsigned long *) mm_idp->stack + 2; - *stack = 0; - } - return stack; -} - -extern int proc_mm; - -int single_count = 0; -int multi_count = 0; -int multi_op_count = 0; - -static long do_syscall_stub(struct mm_id *mm_idp, void **addr) -{ - unsigned long regs[MAX_REG_NR]; - unsigned long *data; - unsigned long *syscall; - long ret, offset; - int n, pid = mm_idp->u.pid; - - if(proc_mm) -#warning Need to look up userspace_pid by cpu - pid = userspace_pid[0]; - - multi_count++; - - get_safe_registers(regs); - regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + - ((unsigned long) &batch_syscall_stub - - (unsigned long) &__syscall_stub_start); - n = ptrace_setregs(pid, regs); - if(n < 0) - panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", - n); - - wait_stub_done(pid, 0, "do_syscall_stub"); - - /* When the stub stops, we find the following values on the - * beginning of the stack: - * (long )return_value - * (long )offset to failed sycall-data (0, if no error) - */ - ret = *((unsigned long *) mm_idp->stack); - offset = *((unsigned long *) mm_idp->stack + 1); - if (offset) { - data = (unsigned long *)(mm_idp->stack + - offset - UML_CONFIG_STUB_DATA); - syscall = (unsigned long *)((unsigned long)data + data[0]); - printk("do_syscall_stub: syscall %ld failed, return value = " - "0x%lx, expected return value = 0x%lx\n", - syscall[0], ret, syscall[7]); - printk(" syscall parameters: " - "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", - syscall[1], syscall[2], syscall[3], - syscall[4], syscall[5], syscall[6]); - for(n = 1; n < data[0]/sizeof(long); n++) { - if(n == 1) - printk(" additional syscall data:"); - if(n % 4 == 1) - printk("\n "); - printk(" 0x%lx", data[n]); - } - if(n > 1) - printk("\n"); - } - else ret = 0; - - *addr = check_init_stack(mm_idp, NULL); - - return ret; -} - -long run_syscall_stub(struct mm_id * mm_idp, int syscall, - unsigned long *args, long expected, void **addr, - int done) -{ - unsigned long *stack = check_init_stack(mm_idp, *addr); - - if(done && *addr == NULL) - single_count++; - - *stack += sizeof(long); - stack += *stack / sizeof(long); - - *stack++ = syscall; - *stack++ = args[0]; - *stack++ = args[1]; - *stack++ = args[2]; - *stack++ = args[3]; - *stack++ = args[4]; - *stack++ = args[5]; - *stack++ = expected; - *stack = 0; - multi_op_count++; - - if(!done && ((((unsigned long) stack) & ~PAGE_MASK) < - PAGE_SIZE - 10 * sizeof(long))){ - *addr = stack; - return 0; - } - - return do_syscall_stub(mm_idp, addr); -} - -long syscall_stub_data(struct mm_id * mm_idp, - unsigned long *data, int data_count, - void **addr, void **stub_addr) -{ - unsigned long *stack; - int ret = 0; - - /* If *addr still is uninitialized, it *must* contain NULL. - * Thus in this case do_syscall_stub correctly won't be called. - */ - if((((unsigned long) *addr) & ~PAGE_MASK) >= - PAGE_SIZE - (10 + data_count) * sizeof(long)) { - ret = do_syscall_stub(mm_idp, addr); - /* in case of error, don't overwrite data on stack */ - if(ret) - return ret; - } - - stack = check_init_stack(mm_idp, *addr); - *addr = stack; - - *stack = data_count * sizeof(long); - - memcpy(stack + 1, data, data_count * sizeof(long)); - - *stub_addr = (void *)(((unsigned long)(stack + 1) & ~PAGE_MASK) + - UML_CONFIG_STUB_DATA); - - return 0; -} - -int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, - int r, int w, int x, int phys_fd, unsigned long long offset, - int done, void **data) -{ - int prot, ret; - - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | - (x ? PROT_EXEC : 0); - - if(proc_mm){ - struct proc_mm_op map; - int fd = mm_idp->u.mm_fd; - - map = ((struct proc_mm_op) { .op = MM_MMAP, - .u = - { .mmap = - { .addr = virt, - .len = len, - .prot = prot, - .flags = MAP_SHARED | - MAP_FIXED, - .fd = phys_fd, - .offset= offset - } } } ); - ret = os_write_file(fd, &map, sizeof(map)); - if(ret != sizeof(map)) - printk("map : /proc/mm map failed, err = %d\n", -ret); - else ret = 0; - } - else { - unsigned long args[] = { virt, len, prot, - MAP_SHARED | MAP_FIXED, phys_fd, - MMAP_OFFSET(offset) }; - - ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, - data, done); - } - - return ret; -} - -int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, - void **data) -{ - int ret; - - if(proc_mm){ - struct proc_mm_op unmap; - int fd = mm_idp->u.mm_fd; - - unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, - .u = - { .munmap = - { .addr = - (unsigned long) addr, - .len = len } } } ); - ret = os_write_file(fd, &unmap, sizeof(unmap)); - if(ret != sizeof(unmap)) - printk("unmap - proc_mm write returned %d\n", ret); - else ret = 0; - } - else { - unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, - 0 }; - - ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, - data, done); - if(ret < 0) - printk("munmap stub failed, errno = %d\n", ret); - } - - return ret; -} - -int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, - int r, int w, int x, int done, void **data) -{ - struct proc_mm_op protect; - int prot, ret; - - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | - (x ? PROT_EXEC : 0); - - if(proc_mm){ - int fd = mm_idp->u.mm_fd; - protect = ((struct proc_mm_op) { .op = MM_MPROTECT, - .u = - { .mprotect = - { .addr = - (unsigned long) addr, - .len = len, - .prot = prot } } } ); - - ret = os_write_file(fd, &protect, sizeof(protect)); - if(ret != sizeof(protect)) - printk("protect failed, err = %d", -ret); - else ret = 0; - } - else { - unsigned long args[] = { addr, len, prot, 0, 0, 0 }; - - ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, - data, done); - } - - return ret; -} - -void before_mem_skas(unsigned long unused) -{ -} diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 677871f1b37..007d5503f49 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -1,23 +1,16 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/sched.h" -#include "linux/list.h" -#include "linux/spinlock.h" -#include "linux/slab.h" -#include "linux/errno.h" -#include "linux/mm.h" -#include "asm/current.h" -#include "asm/segment.h" -#include "asm/mmu.h" -#include "asm/pgalloc.h" -#include "asm/pgtable.h" -#include "asm/ldt.h" -#include "os.h" -#include "skas.h" +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <asm/pgalloc.h> +#include <asm/pgtable.h> +#include <as-layout.h> +#include <os.h> +#include <skas.h> extern int __syscall_stub_start; @@ -38,98 +31,63 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc, if (!pmd) goto out_pmd; - pte = pte_alloc_map(mm, pmd, proc); + pte = pte_alloc_map(mm, NULL, pmd, proc); if (!pte) goto out_pte; - /* There's an interaction between the skas0 stub pages, stack - * randomization, and the BUG at the end of exit_mmap. exit_mmap - * checks that the number of page tables freed is the same as had - * been allocated. If the stack is on the last page table page, - * then the stack pte page will be freed, and if not, it won't. To - * avoid having to know where the stack is, or if the process mapped - * something at the top of its address space for some other reason, - * we set TASK_SIZE to end at the start of the last page table. - * This keeps exit_mmap off the last page, but introduces a leak - * of that page. So, we hang onto it here and free it in - * destroy_context_skas. - */ - - mm->context.skas.last_page_table = pmd_page_kernel(*pmd); -#ifdef CONFIG_3_LEVEL_PGTABLES - mm->context.skas.last_pmd = (unsigned long) __va(pud_val(*pud)); -#endif - *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT)); - *pte = pte_mkexec(*pte); - *pte = pte_wrprotect(*pte); - return(0); + *pte = pte_mkread(*pte); + return 0; - out_pmd: - pud_free(pud); out_pte: - pmd_free(pmd); + pmd_free(mm, pmd); + out_pmd: + pud_free(mm, pud); out: - return(-ENOMEM); + return -ENOMEM; } -int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) +int init_new_context(struct task_struct *task, struct mm_struct *mm) { - struct mmu_context_skas *from_mm = NULL; - struct mmu_context_skas *to_mm = &mm->context.skas; + struct mm_context *from_mm = NULL; + struct mm_context *to_mm = &mm->context; unsigned long stack = 0; - int from_fd, ret = -ENOMEM; + int ret = -ENOMEM; - if(skas_needs_stub){ + if (skas_needs_stub) { stack = get_zeroed_page(GFP_KERNEL); - if(stack == 0) + if (stack == 0) goto out; - - /* This zeros the entry that pgd_alloc didn't, needed since - * we are about to reinitialize it, and want mm.nr_ptes to - * be accurate. - */ - mm->pgd[USER_PTRS_PER_PGD] = __pgd(0); - - ret = init_stub_pte(mm, CONFIG_STUB_CODE, - (unsigned long) &__syscall_stub_start); - if(ret) - goto out_free; - - ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack); - if(ret) - goto out_free; - - mm->nr_ptes--; } to_mm->id.stack = stack; - if(current->mm != NULL && current->mm != &init_mm) - from_mm = ¤t->mm->context.skas; - - if(proc_mm){ - if(from_mm) - from_fd = from_mm->id.u.mm_fd; - else from_fd = -1; - - ret = new_mm(from_fd, stack); - if(ret < 0){ - printk("init_new_context_skas - new_mm failed, " - "errno = %d\n", ret); + if (current->mm != NULL && current->mm != &init_mm) + from_mm = ¤t->mm->context; + + if (proc_mm) { + ret = new_mm(stack); + if (ret < 0) { + printk(KERN_ERR "init_new_context_skas - " + "new_mm failed, errno = %d\n", ret); goto out_free; } to_mm->id.u.mm_fd = ret; } else { - if(from_mm) + if (from_mm) to_mm->id.u.pid = copy_context_skas0(stack, from_mm->id.u.pid); else to_mm->id.u.pid = start_userspace(stack); + + if (to_mm->id.u.pid < 0) { + ret = to_mm->id.u.pid; + goto out_free; + } } ret = init_new_ldt(to_mm, from_mm); - if(ret < 0){ - printk("init_new_context_skas - init_ldt" + if (ret < 0) { + printk(KERN_ERR "init_new_context_skas - init_ldt" " failed, errno = %d\n", ret); goto out_free; } @@ -137,28 +95,84 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) return 0; out_free: - if(to_mm->id.stack != 0) + if (to_mm->id.stack != 0) free_page(to_mm->id.stack); out: return ret; } -void destroy_context_skas(struct mm_struct *mm) +void uml_setup_stubs(struct mm_struct *mm) +{ + int err, ret; + + if (!skas_needs_stub) + return; + + ret = init_stub_pte(mm, STUB_CODE, + (unsigned long) &__syscall_stub_start); + if (ret) + goto out; + + ret = init_stub_pte(mm, STUB_DATA, mm->context.id.stack); + if (ret) + goto out; + + mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start); + mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack); + + /* dup_mmap already holds mmap_sem */ + err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START, + VM_READ | VM_MAYREAD | VM_EXEC | + VM_MAYEXEC | VM_DONTCOPY | VM_PFNMAP, + mm->context.stub_pages); + if (err) { + printk(KERN_ERR "install_special_mapping returned %d\n", err); + goto out; + } + return; + +out: + force_sigsegv(SIGSEGV, current); +} + +void arch_exit_mmap(struct mm_struct *mm) +{ + pte_t *pte; + + pte = virt_to_pte(mm, STUB_CODE); + if (pte != NULL) + pte_clear(mm, STUB_CODE, pte); + + pte = virt_to_pte(mm, STUB_DATA); + if (pte == NULL) + return; + + pte_clear(mm, STUB_DATA, pte); +} + +void destroy_context(struct mm_struct *mm) { - struct mmu_context_skas *mmu = &mm->context.skas; + struct mm_context *mmu = &mm->context; - if(proc_mm) + if (proc_mm) os_close_file(mmu->id.u.mm_fd); - else + else { + /* + * If init_new_context wasn't called, this will be + * zero, resulting in a kill(0), which will result in the + * whole UML suddenly dying. Also, cover negative and + * 1 cases, since they shouldn't happen either. + */ + if (mmu->id.u.pid < 2) { + printk(KERN_ERR "corrupt mm_context - pid = %d\n", + mmu->id.u.pid); + return; + } os_kill_ptraced_process(mmu->id.u.pid, 1); + } - if(!proc_mm || !ptrace_faultinfo){ + if (skas_needs_stub) free_page(mmu->id.stack); - pte_lock_deinit(virt_to_page(mmu->last_page_table)); - pte_free_kernel((pte_t *) mmu->last_page_table); - dec_page_state(nr_page_table_pages); -#ifdef CONFIG_3_LEVEL_PGTABLES - pmd_free((pmd_t *) mmu->last_pmd); -#endif - } + + free_ldt(mmu); } diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 599d679bd4f..4da11b3c8dd 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -1,581 +1,81 @@ -/* - * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com) +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> -#include <setjmp.h> -#include <sched.h> -#include <sys/wait.h> -#include <sys/mman.h> -#include <sys/user.h> -#include <sys/time.h> -#include <asm/unistd.h> -#include <asm/types.h> -#include "user.h" -#include "ptrace_user.h" -#include "time_user.h" -#include "sysdep/ptrace.h" -#include "user_util.h" -#include "kern_util.h" -#include "skas.h" -#include "stub-data.h" -#include "mm_id.h" -#include "sysdep/sigcontext.h" -#include "sysdep/stub.h" -#include "os.h" -#include "proc_mm.h" -#include "skas_ptrace.h" -#include "chan_user.h" -#include "signal_user.h" -#include "registers.h" -#include "mem.h" -#include "uml-config.h" -#include "process.h" - -int is_skas_winch(int pid, int fd, void *data) -{ - if(pid != os_getpgrp()) - return(0); - - register_winch_irq(-1, fd, -1, data); - return(1); -} +#include <linux/init.h> +#include <linux/sched.h> +#include <as-layout.h> +#include <kern.h> +#include <os.h> +#include <skas.h> -void wait_stub_done(int pid, int sig, char * fname) +int new_mm(unsigned long stack) { - int n, status, err; - - do { - if ( sig != -1 ) { - err = ptrace(PTRACE_CONT, pid, 0, sig); - if(err) - panic("%s : continue failed, errno = %d\n", - fname, errno); - } - sig = 0; + int fd, err; - CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); - } while((n >= 0) && WIFSTOPPED(status) && - ((WSTOPSIG(status) == SIGVTALRM) || - /* running UML inside a detached screen can cause - * SIGWINCHes - */ - (WSTOPSIG(status) == SIGWINCH))); + fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); + if (fd < 0) + return fd; - if((n < 0) || !WIFSTOPPED(status) || - (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){ - unsigned long regs[FRAME_SIZE]; - if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) - printk("Failed to get registers from stub, " - "errno = %d\n", errno); - else { - int i; - - printk("Stub registers -\n"); - for(i = 0; i < FRAME_SIZE; i++) - printk("\t%d - %lx\n", i, regs[i]); + if (skas_needs_stub) { + err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack); + if (err) { + os_close_file(fd); + return err; } - panic("%s : failed to wait for SIGUSR1/SIGTRAP, " - "pid = %d, n = %d, errno = %d, status = 0x%x\n", - fname, pid, n, errno, status); - } -} - -void get_skas_faultinfo(int pid, struct faultinfo * fi) -{ - int err; - - if(ptrace_faultinfo){ - err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); - if(err) - panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " - "errno = %d\n", errno); - - /* Special handling for i386, which has different structs */ - if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) - memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, - sizeof(struct faultinfo) - - sizeof(struct ptrace_faultinfo)); - } - else { - wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo"); - - /* faultinfo is prepared by the stub-segv-handler at start of - * the stub stack page. We just have to copy it. - */ - memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); - } -} - -static void handle_segv(int pid, union uml_pt_regs * regs) -{ - get_skas_faultinfo(pid, ®s->skas.faultinfo); - segv(regs->skas.faultinfo, 0, 1, NULL); -} - -/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ -static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu) -{ - int err, status; - - /* Mark this as a syscall */ - UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs); - - if (!local_using_sysemu) - { - err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); - if(err < 0) - panic("handle_trap - nullifying syscall failed errno = %d\n", - errno); - - err = ptrace(PTRACE_SYSCALL, pid, 0, 0); - if(err < 0) - panic("handle_trap - continuing to end of syscall failed, " - "errno = %d\n", errno); - - CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); - if((err < 0) || !WIFSTOPPED(status) || - (WSTOPSIG(status) != SIGTRAP + 0x80)) - panic("handle_trap - failed to wait at end of syscall, " - "errno = %d, status = %d\n", errno, status); } - handle_syscall(regs); + return fd; } -extern int __syscall_stub_start; -int stub_code_fd = -1; -__u64 stub_code_offset; +extern void start_kernel(void); -static int userspace_tramp(void *stack) +static int __init start_kernel_proc(void *unused) { - void *addr; + int pid; - ptrace(PTRACE_TRACEME, 0, 0, 0); - - init_new_thread_signals(1); - enable_timer(); - - if(!proc_mm){ - /* This has a pte, but it can't be mapped in with the usual - * tlb_flush mechanism because this is part of that mechanism - */ - addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(), - PROT_EXEC, MAP_FIXED | MAP_PRIVATE, - stub_code_fd, stub_code_offset); - if(addr == MAP_FAILED){ - printk("mapping stub code failed, errno = %d\n", - errno); - exit(1); - } - - if(stack != NULL){ - int fd; - __u64 offset; - - fd = phys_mapping(to_phys(stack), &offset); - addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(), - PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_SHARED, fd, offset); - if(addr == MAP_FAILED){ - printk("mapping stub stack failed, " - "errno = %d\n", errno); - exit(1); - } - } - } - if(!ptrace_faultinfo){ - unsigned long v = UML_CONFIG_STUB_CODE + - (unsigned long) stub_segv_handler - - (unsigned long) &__syscall_stub_start; - - set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size()); - set_handler(SIGSEGV, (void *) v, SA_ONSTACK, - SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, - SIGUSR1, -1); - } - - os_stop_process(os_getpid()); - return(0); -} - -/* Each element set once, and only accessed by a single processor anyway */ -#undef NR_CPUS -#define NR_CPUS 1 -int userspace_pid[NR_CPUS]; - -int start_userspace(unsigned long stub_stack) -{ - void *stack; - unsigned long sp; - int pid, status, n, flags; - - if ( stub_code_fd == -1 ) - stub_code_fd = phys_mapping(to_phys(&__syscall_stub_start), - &stub_code_offset); - - stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if(stack == MAP_FAILED) - panic("start_userspace : mmap failed, errno = %d", errno); - sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); - - flags = CLONE_FILES | SIGCHLD; - if(proc_mm) flags |= CLONE_VM; - pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); - if(pid < 0) - panic("start_userspace : clone failed, errno = %d", errno); - - do { - CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); - if(n < 0) - panic("start_userspace : wait failed, errno = %d", - errno); - } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); - - if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) - panic("start_userspace : expected SIGSTOP, got status = %d", - status); - - if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, (void *)PTRACE_O_TRACESYSGOOD) < 0) - panic("start_userspace : PTRACE_SETOPTIONS failed, errno=%d\n", - errno); - - if(munmap(stack, PAGE_SIZE) < 0) - panic("start_userspace : munmap failed, errno = %d\n", errno); - - return(pid); -} - -void userspace(union uml_pt_regs *regs) -{ - int err, status, op, pid = userspace_pid[0]; - int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/ - - while(1){ - restore_registers(pid, regs); - - /* Now we set local_using_sysemu to be used for one loop */ - local_using_sysemu = get_using_sysemu(); - - op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL)); - - err = ptrace(op, pid, 0, 0); - if(err) - panic("userspace - could not resume userspace process, " - "pid=%d, ptrace operation = %d, errno = %d\n", - op, errno); - - CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); - if(err < 0) - panic("userspace - waitpid failed, errno = %d\n", - errno); - - regs->skas.is_user = 1; - save_registers(pid, regs); - UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ - - if(WIFSTOPPED(status)){ - switch(WSTOPSIG(status)){ - case SIGSEGV: - if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo) - user_signal(SIGSEGV, regs, pid); - else handle_segv(pid, regs); - break; - case SIGTRAP + 0x80: - handle_trap(pid, regs, local_using_sysemu); - break; - case SIGTRAP: - relay_signal(SIGTRAP, regs); - break; - case SIGIO: - case SIGVTALRM: - case SIGILL: - case SIGBUS: - case SIGFPE: - case SIGWINCH: - user_signal(WSTOPSIG(status), regs, pid); - break; - default: - printk("userspace - child stopped with signal " - "%d\n", WSTOPSIG(status)); - } - pid = userspace_pid[0]; - interrupt_end(); - - /* Avoid -ERESTARTSYS handling in host */ - PT_SYSCALL_NR(regs->skas.regs) = -1; - } - } -} -#define INIT_JMP_NEW_THREAD 0 -#define INIT_JMP_REMOVE_SIGSTACK 1 -#define INIT_JMP_CALLBACK 2 -#define INIT_JMP_HALT 3 -#define INIT_JMP_REBOOT 4 - - -int copy_context_skas0(unsigned long new_stack, int pid) -{ - int err; - unsigned long regs[MAX_REG_NR]; - unsigned long current_stack = current_stub_stack(); - struct stub_data *data = (struct stub_data *) current_stack; - struct stub_data *child_data = (struct stub_data *) new_stack; - __u64 new_offset; - int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset); - - /* prepare offset and fd of child's stack as argument for parent's - * and child's mmap2 calls - */ - *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset), - .fd = new_fd, - .timer = ((struct itimerval) - { { 0, 1000000 / hz() }, - { 0, 1000000 / hz() }})}); - get_safe_registers(regs); - - /* Set parent's instruction pointer to start of clone-stub */ - regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + - (unsigned long) stub_clone_handler - - (unsigned long) &__syscall_stub_start; - regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE - - sizeof(void *); - err = ptrace_setregs(pid, regs); - if(err < 0) - panic("copy_context_skas0 : PTRACE_SETREGS failed, " - "pid = %d, errno = %d\n", pid, errno); - - /* set a well known return code for detection of child write failure */ - child_data->err = 12345678; - - /* Wait, until parent has finished its work: read child's pid from - * parent's stack, and check, if bad result. - */ - wait_stub_done(pid, 0, "copy_context_skas0"); - - pid = data->err; - if(pid < 0) - panic("copy_context_skas0 - stub-parent reports error %d\n", - pid); - - /* Wait, until child has finished too: read child's result from - * child's stack and check it. - */ - wait_stub_done(pid, -1, "copy_context_skas0"); - if (child_data->err != UML_CONFIG_STUB_DATA) - panic("copy_context_skas0 - stub-child reports error %d\n", - child_data->err); - - if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, - (void *)PTRACE_O_TRACESYSGOOD) < 0) - panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, " - "errno = %d\n", errno); - - return pid; -} - -/* - * This is used only, if stub pages are needed, while proc_mm is - * availabl. Opening /proc/mm creates a new mm_context, which lacks - * the stub-pages. Thus, we map them using /proc/mm-fd - */ -void map_stub_pages(int fd, unsigned long code, - unsigned long data, unsigned long stack) -{ - struct proc_mm_op mmop; - int n; - - mmop = ((struct proc_mm_op) { .op = MM_MMAP, - .u = - { .mmap = - { .addr = code, - .len = PAGE_SIZE, - .prot = PROT_EXEC, - .flags = MAP_FIXED | MAP_PRIVATE, - .fd = stub_code_fd, - .offset = stub_code_offset - } } }); - n = os_write_file(fd, &mmop, sizeof(mmop)); - if(n != sizeof(mmop)) - panic("map_stub_pages : /proc/mm map for code failed, " - "err = %d\n", -n); - - if ( stack ) { - __u64 map_offset; - int map_fd = phys_mapping(to_phys((void *)stack), &map_offset); - mmop = ((struct proc_mm_op) - { .op = MM_MMAP, - .u = - { .mmap = - { .addr = data, - .len = PAGE_SIZE, - .prot = PROT_READ | PROT_WRITE, - .flags = MAP_FIXED | MAP_SHARED, - .fd = map_fd, - .offset = map_offset - } } }); - n = os_write_file(fd, &mmop, sizeof(mmop)); - if(n != sizeof(mmop)) - panic("map_stub_pages : /proc/mm map for data failed, " - "err = %d\n", -n); - } -} - -void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, - void (*handler)(int)) -{ - unsigned long flags; - sigjmp_buf switch_buf, fork_buf; - - *switch_buf_ptr = &switch_buf; - *fork_buf_ptr = &fork_buf; - - /* Somewhat subtle - siglongjmp restores the signal mask before doing - * the longjmp. This means that when jumping from one stack to another - * when the target stack has interrupts enabled, an interrupt may occur - * on the source stack. This is bad when starting up a process because - * it's not supposed to get timer ticks until it has been scheduled. - * So, we disable interrupts around the sigsetjmp to ensure that - * they can't happen until we get back here where they are safe. - */ - flags = get_signals(); block_signals(); - if(sigsetjmp(fork_buf, 1) == 0) - new_thread_proc(stack, handler); - - remove_sigstack(); - - set_signals(flags); -} - -void thread_wait(void *sw, void *fb) -{ - sigjmp_buf buf, **switch_buf = sw, *fork_buf; - - *switch_buf = &buf; - fork_buf = fb; - if(sigsetjmp(buf, 1) == 0) - siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK); -} + pid = os_getpid(); -void switch_threads(void *me, void *next) -{ - sigjmp_buf my_buf, **me_ptr = me, *next_buf = next; - - *me_ptr = &my_buf; - if(sigsetjmp(my_buf, 1) == 0) - siglongjmp(*next_buf, 1); + cpu_tasks[0].pid = pid; + cpu_tasks[0].task = current; +#ifdef CONFIG_SMP + init_cpu_online(get_cpu_mask(0)); +#endif + start_kernel(); + return 0; } -static sigjmp_buf initial_jmpbuf; +extern int userspace_pid[]; -/* XXX Make these percpu */ -static void (*cb_proc)(void *arg); -static void *cb_arg; -static sigjmp_buf *cb_back; +extern char cpu0_irqstack[]; -int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) +int __init start_uml(void) { - sigjmp_buf **switch_buf = switch_buf_ptr; - int n; - - set_handler(SIGWINCH, (__sighandler_t) sig_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, - SIGVTALRM, -1); - - *fork_buf_ptr = &initial_jmpbuf; - n = sigsetjmp(initial_jmpbuf, 1); - switch(n){ - case INIT_JMP_NEW_THREAD: - new_thread_proc((void *) stack, new_thread_handler); - break; - case INIT_JMP_REMOVE_SIGSTACK: - remove_sigstack(); - break; - case INIT_JMP_CALLBACK: - (*cb_proc)(cb_arg); - siglongjmp(*cb_back, 1); - break; - case INIT_JMP_HALT: - kmalloc_ok = 0; - return(0); - case INIT_JMP_REBOOT: - kmalloc_ok = 0; - return(1); - default: - panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); + stack_protections((unsigned long) &cpu0_irqstack); + set_sigstack(cpu0_irqstack, THREAD_SIZE); + if (proc_mm) { + userspace_pid[0] = start_userspace(0); + if (userspace_pid[0] < 0) { + printf("start_uml - start_userspace returned %d\n", + userspace_pid[0]); + exit(1); + } } - siglongjmp(**switch_buf, 1); -} -void remove_sigstack(void) -{ - stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE, - .ss_sp = NULL, - .ss_size = 0 }); + init_new_thread_signals(); - if(sigaltstack(&stack, NULL) != 0) - panic("disabling signal stack failed, errno = %d\n", errno); + init_task.thread.request.u.thread.proc = start_kernel_proc; + init_task.thread.request.u.thread.arg = NULL; + return start_idle_thread(task_stack_page(&init_task), + &init_task.thread.switch_buf); } -void initial_thread_cb_skas(void (*proc)(void *), void *arg) +unsigned long current_stub_stack(void) { - sigjmp_buf here; + if (current->mm == NULL) + return 0; - cb_proc = proc; - cb_arg = arg; - cb_back = &here; - - block_signals(); - if(sigsetjmp(here, 1) == 0) - siglongjmp(initial_jmpbuf, INIT_JMP_CALLBACK); - unblock_signals(); - - cb_proc = NULL; - cb_arg = NULL; - cb_back = NULL; + return current->mm->context.id.stack; } - -void halt_skas(void) -{ - block_signals(); - siglongjmp(initial_jmpbuf, INIT_JMP_HALT); -} - -void reboot_skas(void) -{ - block_signals(); - siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT); -} - -void switch_mm_skas(struct mm_id *mm_idp) -{ - int err; - -#warning need cpu pid in switch_mm_skas - if(proc_mm){ - err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, - mm_idp->u.mm_fd); - if(err) - panic("switch_mm_skas - PTRACE_SWITCH_MM failed, " - "errno = %d\n", errno); - } - else userspace_pid[0] = mm_idp->u.pid; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c deleted file mode 100644 index 9c990253966..00000000000 --- a/arch/um/kernel/skas/process_kern.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "linux/slab.h" -#include "linux/ptrace.h" -#include "linux/proc_fs.h" -#include "linux/file.h" -#include "linux/errno.h" -#include "linux/init.h" -#include "asm/uaccess.h" -#include "asm/atomic.h" -#include "kern_util.h" -#include "time_user.h" -#include "signal_user.h" -#include "skas.h" -#include "os.h" -#include "user_util.h" -#include "tlb.h" -#include "kern.h" -#include "mode.h" -#include "proc_mm.h" -#include "registers.h" - -void switch_to_skas(void *prev, void *next) -{ - struct task_struct *from, *to; - - from = prev; - to = next; - - /* XXX need to check runqueues[cpu].idle */ - if(current->pid == 0) - switch_timers(0); - - switch_threads(&from->thread.mode.skas.switch_buf, - to->thread.mode.skas.switch_buf); - - if(current->pid == 0) - switch_timers(1); -} - -extern void schedule_tail(struct task_struct *prev); - -void new_thread_handler(int sig) -{ - int (*fn)(void *), n; - void *arg; - - fn = current->thread.request.u.thread.proc; - arg = current->thread.request.u.thread.arg; - change_sig(SIGUSR1, 1); - thread_wait(¤t->thread.mode.skas.switch_buf, - current->thread.mode.skas.fork_buf); - - if(current->thread.prev_sched != NULL) - schedule_tail(current->thread.prev_sched); - current->thread.prev_sched = NULL; - - /* The return value is 1 if the kernel thread execs a process, - * 0 if it just exits - */ - n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); - if(n == 1){ - /* Handle any immediate reschedules or signals */ - interrupt_end(); - userspace(¤t->thread.regs.regs); - } - else do_exit(0); -} - -void new_thread_proc(void *stack, void (*handler)(int sig)) -{ - init_new_thread_stack(stack, handler); - os_usr1_process(os_getpid()); -} - -void release_thread_skas(struct task_struct *task) -{ -} - -void fork_handler(int sig) -{ - change_sig(SIGUSR1, 1); - thread_wait(¤t->thread.mode.skas.switch_buf, - current->thread.mode.skas.fork_buf); - - force_flush_all(); - if(current->thread.prev_sched == NULL) - panic("blech"); - - schedule_tail(current->thread.prev_sched); - current->thread.prev_sched = NULL; - - /* Handle any immediate reschedules or signals */ - interrupt_end(); - userspace(¤t->thread.regs.regs); -} - -int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, - unsigned long stack_top, struct task_struct * p, - struct pt_regs *regs) -{ - void (*handler)(int); - - if(current->thread.forking){ - memcpy(&p->thread.regs.regs.skas, ®s->regs.skas, - sizeof(p->thread.regs.regs.skas)); - REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0); - if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp; - - handler = fork_handler; - } - else { - init_thread_registers(&p->thread.regs.regs); - p->thread.request.u.thread = current->thread.request.u.thread; - handler = new_thread_handler; - } - - new_thread(p->thread_info, &p->thread.mode.skas.switch_buf, - &p->thread.mode.skas.fork_buf, handler); - return(0); -} - -extern void map_stub_pages(int fd, unsigned long code, - unsigned long data, unsigned long stack); -int new_mm(int from, unsigned long stack) -{ - struct proc_mm_op copy; - int n, fd; - - fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); - if(fd < 0) - return(fd); - - if(from != -1){ - copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, - .u = - { .copy_segments = from } } ); - n = os_write_file(fd, ©, sizeof(copy)); - if(n != sizeof(copy)) - printk("new_mm : /proc/mm copy_segments failed, " - "err = %d\n", -n); - } - - if(skas_needs_stub) - map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack); - - return(fd); -} - -void init_idle_skas(void) -{ - cpu_tasks[current_thread->cpu].pid = os_getpid(); - default_idle(); -} - -extern void start_kernel(void); - -static int start_kernel_proc(void *unused) -{ - int pid; - - block_signals(); - pid = os_getpid(); - - cpu_tasks[0].pid = pid; - cpu_tasks[0].task = current; -#ifdef CONFIG_SMP - cpu_online_map = cpumask_of_cpu(0); -#endif - start_kernel(); - return(0); -} - -extern int userspace_pid[]; - -int start_uml_skas(void) -{ - if(proc_mm) - userspace_pid[0] = start_userspace(0); - - init_new_thread_signals(1); - - init_task.thread.request.u.thread.proc = start_kernel_proc; - init_task.thread.request.u.thread.arg = NULL; - return(start_idle_thread(init_task.thread_info, - &init_task.thread.mode.skas.switch_buf, - &init_task.thread.mode.skas.fork_buf)); -} - -int external_pid_skas(struct task_struct *task) -{ -#warning Need to look up userspace_pid by cpu - return(userspace_pid[0]); -} - -int thread_pid_skas(struct task_struct *task) -{ -#warning Need to look up userspace_pid by cpu - return(userspace_pid[0]); -} - -void kill_off_processes_skas(void) -{ - if(proc_mm) -#warning need to loop over userspace_pids in kill_off_processes_skas - os_kill_ptraced_process(userspace_pid[0], 1); - else { - struct task_struct *p; - int pid, me; - - me = os_getpid(); - for_each_process(p){ - if(p->mm == NULL) - continue; - - pid = p->mm->context.skas.id.u.pid; - os_kill_ptraced_process(pid, 1); - } - } -} - -unsigned long current_stub_stack(void) -{ - if(current->mm == NULL) - return(0); - - return(current->mm->context.skas.id.stack); -} diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index 51fb94076fc..c0681e09743 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -1,34 +1,27 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/sys.h" -#include "linux/ptrace.h" -#include "asm/errno.h" -#include "asm/unistd.h" -#include "asm/ptrace.h" -#include "asm/current.h" -#include "sysdep/syscalls.h" -#include "kern_util.h" -#include "syscall.h" +#include <linux/kernel.h> +#include <linux/ptrace.h> +#include <kern_util.h> +#include <sysdep/ptrace.h> +#include <sysdep/syscalls.h> -void handle_syscall(union uml_pt_regs *r) +extern int syscall_table_size; +#define NR_SYSCALLS (syscall_table_size / sizeof(void *)) + +void handle_syscall(struct uml_pt_regs *r) { struct pt_regs *regs = container_of(r, struct pt_regs, regs); long result; int syscall; -#ifdef UML_CONFIG_SYSCALL_DEBUG - int index; - - index = record_syscall_start(UPT_SYSCALL_NR(r)); -#endif - syscall_trace(r, 0); - current->thread.nsyscalls++; - nsyscalls++; + syscall_trace_enter(regs); - /* This should go in the declaration of syscall, but when I do that, + /* + * This should go in the declaration of syscall, but when I do that, * strace -f -c bash -c 'ls ; ls' breaks, sometimes not tracing * children at all, sometimes hanging when bash doesn't see the first * ls exit. @@ -37,14 +30,11 @@ void handle_syscall(union uml_pt_regs *r) * in case it's a compiler bug. */ syscall = UPT_SYSCALL_NR(r); - if((syscall >= NR_syscalls) || (syscall < 0)) + if ((syscall >= NR_SYSCALLS) || (syscall < 0)) result = -ENOSYS; else result = EXECUTE_SYSCALL(syscall, regs); - REGS_SET_SYSCALL_RETURN(r->skas.regs, result); + PT_REGS_SET_SYSCALL_RETURN(regs, result); - syscall_trace(r, 1); -#ifdef UML_CONFIG_SYSCALL_DEBUG - record_syscall_end(index, result); -#endif + syscall_trace_leave(regs); } diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c deleted file mode 100644 index 6e84963dfc2..00000000000 --- a/arch/um/kernel/skas/tlb.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Copyright 2003 PathScale, Inc. - * Licensed under the GPL - */ - -#include "linux/stddef.h" -#include "linux/sched.h" -#include "linux/config.h" -#include "linux/mm.h" -#include "asm/page.h" -#include "asm/pgtable.h" -#include "asm/mmu.h" -#include "user_util.h" -#include "mem_user.h" -#include "mem.h" -#include "skas.h" -#include "os.h" -#include "tlb.h" - -static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last, - int finished, void **flush) -{ - struct host_vm_op *op; - int i, ret = 0; - - for(i = 0; i <= last && !ret; i++){ - op = &ops[i]; - switch(op->type){ - case MMAP: - ret = map(&mmu->skas.id, op->u.mmap.addr, - op->u.mmap.len, op->u.mmap.r, op->u.mmap.w, - op->u.mmap.x, op->u.mmap.fd, - op->u.mmap.offset, finished, flush); - break; - case MUNMAP: - ret = unmap(&mmu->skas.id, - (void *) op->u.munmap.addr, - op->u.munmap.len, finished, flush); - break; - case MPROTECT: - ret = protect(&mmu->skas.id, op->u.mprotect.addr, - op->u.mprotect.len, op->u.mprotect.r, - op->u.mprotect.w, op->u.mprotect.x, - finished, flush); - break; - default: - printk("Unknown op type %d in do_ops\n", op->type); - break; - } - } - - return ret; -} - -extern int proc_mm; - -static void fix_range(struct mm_struct *mm, unsigned long start_addr, - unsigned long end_addr, int force) -{ - if(!proc_mm && (end_addr > CONFIG_STUB_START)) - end_addr = CONFIG_STUB_START; - - fix_range_common(mm, start_addr, end_addr, force, do_ops); -} - -void __flush_tlb_one_skas(unsigned long addr) -{ - flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE); -} - -void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start, - unsigned long end) -{ - if(vma->vm_mm == NULL) - flush_tlb_kernel_range_common(start, end); - else fix_range(vma->vm_mm, start, end, 0); -} - -void flush_tlb_mm_skas(struct mm_struct *mm) -{ - unsigned long end; - - /* Don't bother flushing if this address space is about to be - * destroyed. - */ - if(atomic_read(&mm->mm_users) == 0) - return; - - end = proc_mm ? task_size : CONFIG_STUB_START; - fix_range(mm, 0, end, 0); -} - -void force_flush_all_skas(void) -{ - unsigned long end = proc_mm ? task_size : CONFIG_STUB_START; - fix_range(current->mm, 0, end, 1); -} diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c deleted file mode 100644 index 9950a6716fe..00000000000 --- a/arch/um/kernel/skas/trap_user.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include <signal.h> -#include <errno.h> -#include "signal_user.h" -#include "user_util.h" -#include "kern_util.h" -#include "task.h" -#include "sigcontext.h" -#include "skas.h" -#include "ptrace_user.h" -#include "sysdep/ptrace.h" -#include "sysdep/ptrace_user.h" - -void sig_handler_common_skas(int sig, void *sc_ptr) -{ - struct sigcontext *sc = sc_ptr; - struct skas_regs *r; - struct signal_info *info; - int save_errno = errno; - int save_user; - - /* This is done because to allow SIGSEGV to be delivered inside a SEGV - * handler. This can happen in copy_user, and if SEGV is disabled, - * the process will die. - * XXX Figure out why this is better than SA_NODEFER - */ - if(sig == SIGSEGV) - change_sig(SIGSEGV, 1); - - r = &TASK_REGS(get_current())->skas; - save_user = r->is_user; - r->is_user = 0; - if ( sig == SIGFPE || sig == SIGSEGV || - sig == SIGBUS || sig == SIGILL || - sig == SIGTRAP ) { - GET_FAULTINFO_FROM_SC(r->faultinfo, sc); - } - - change_sig(SIGUSR1, 1); - info = &sig_info[sig]; - if(!info->is_irq) unblock_signals(); - - (*info->handler)(sig, (union uml_pt_regs *) r); - - errno = save_errno; - r->is_user = save_user; -} - -extern int ptrace_faultinfo; - -void user_signal(int sig, union uml_pt_regs *regs, int pid) -{ - struct signal_info *info; - int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) || - (sig == SIGILL) || (sig == SIGTRAP)); - - if (segv) - get_skas_faultinfo(pid, ®s->skas.faultinfo); - info = &sig_info[sig]; - (*info->handler)(sig, regs); - - unblock_signals(); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 75195281081..4ffb644d6c0 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -1,130 +1,133 @@ /* - * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/compiler.h" -#include "linux/stddef.h" -#include "linux/kernel.h" -#include "linux/string.h" -#include "linux/fs.h" -#include "linux/highmem.h" -#include "asm/page.h" -#include "asm/pgtable.h" -#include "asm/uaccess.h" -#include "kern_util.h" -#include "user_util.h" - -extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, - pte_t *pte_out); - -static unsigned long maybe_map(unsigned long virt, int is_write) +#include <linux/err.h> +#include <linux/highmem.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <asm/current.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <kern_util.h> +#include <os.h> + +pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr) { - pte_t pte; - int err; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; - void *phys = um_virt_to_phys(current, virt, &pte); - int dummy_code; + if (mm == NULL) + return NULL; - if(IS_ERR(phys) || (is_write && !pte_write(pte))){ + pgd = pgd_offset(mm, addr); + if (!pgd_present(*pgd)) + return NULL; + + pud = pud_offset(pgd, addr); + if (!pud_present(*pud)) + return NULL; + + pmd = pmd_offset(pud, addr); + if (!pmd_present(*pmd)) + return NULL; + + return pte_offset_kernel(pmd, addr); +} + +static pte_t *maybe_map(unsigned long virt, int is_write) +{ + pte_t *pte = virt_to_pte(current->mm, virt); + int err, dummy_code; + + if ((pte == NULL) || !pte_present(*pte) || + (is_write && !pte_write(*pte))) { err = handle_page_fault(virt, 0, is_write, 1, &dummy_code); - if(err) - return(-1UL); - phys = um_virt_to_phys(current, virt, NULL); + if (err) + return NULL; + pte = virt_to_pte(current->mm, virt); } - if(IS_ERR(phys)) - phys = (void *) -1; + if (!pte_present(*pte)) + pte = NULL; - return((unsigned long) phys); + return pte; } -static int do_op(unsigned long addr, int len, int is_write, +static int do_op_one_page(unsigned long addr, int len, int is_write, int (*op)(unsigned long addr, int len, void *arg), void *arg) { + jmp_buf buf; struct page *page; - int n; + pte_t *pte; + int n, faulted; + + pte = maybe_map(addr, is_write); + if (pte == NULL) + return -1; - addr = maybe_map(addr, is_write); - if(addr == -1UL) - return(-1); + page = pte_page(*pte); + addr = (unsigned long) kmap_atomic(page) + + (addr & ~PAGE_MASK); - page = phys_to_page(addr); - addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK); - n = (*op)(addr, len, arg); - kunmap(page); + current->thread.fault_catcher = &buf; - return(n); + faulted = UML_SETJMP(&buf); + if (faulted == 0) + n = (*op)(addr, len, arg); + else + n = -1; + + current->thread.fault_catcher = NULL; + + kunmap_atomic((void *)addr); + + return n; } -static void do_buffer_op(void *jmpbuf, void *arg_ptr) +static int buffer_op(unsigned long addr, int len, int is_write, + int (*op)(unsigned long, int, void *), void *arg) { - va_list args; - unsigned long addr; - int len, is_write, size, remain, n; - int (*op)(unsigned long, int, void *); - void *arg; - int *res; - - va_copy(args, *(va_list *)arg_ptr); - addr = va_arg(args, unsigned long); - len = va_arg(args, int); - is_write = va_arg(args, int); - op = va_arg(args, void *); - arg = va_arg(args, void *); - res = va_arg(args, int *); - va_end(args); + int size, remain, n; + size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); remain = len; - current->thread.fault_catcher = jmpbuf; - n = do_op(addr, size, is_write, op, arg); - if(n != 0){ - *res = (n < 0 ? remain : 0); + n = do_op_one_page(addr, size, is_write, op, arg); + if (n != 0) { + remain = (n < 0 ? remain : 0); goto out; } addr += size; remain -= size; - if(remain == 0){ - *res = 0; + if (remain == 0) goto out; - } - while(addr < ((addr + remain) & PAGE_MASK)){ - n = do_op(addr, PAGE_SIZE, is_write, op, arg); - if(n != 0){ - *res = (n < 0 ? remain : 0); + while (addr < ((addr + remain) & PAGE_MASK)) { + n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg); + if (n != 0) { + remain = (n < 0 ? remain : 0); goto out; } addr += PAGE_SIZE; remain -= PAGE_SIZE; } - if(remain == 0){ - *res = 0; + if (remain == 0) + goto out; + + n = do_op_one_page(addr, remain, is_write, op, arg); + if (n != 0) { + remain = (n < 0 ? remain : 0); goto out; } - n = do_op(addr, remain, is_write, op, arg); - if(n != 0) - *res = (n < 0 ? remain : 0); - else *res = 0; + return 0; out: - current->thread.fault_catcher = NULL; -} - -static int buffer_op(unsigned long addr, int len, int is_write, - int (*op)(unsigned long addr, int len, void *arg), - void *arg) -{ - int faulted, res; - - faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg, - &res); - if(!faulted) - return(res); - - return(addr + len - (unsigned long) current->thread.fault_addr); + return remain; } static int copy_chunk_from_user(unsigned long from, int len, void *arg) @@ -133,20 +136,21 @@ static int copy_chunk_from_user(unsigned long from, int len, void *arg) memcpy((void *) to, (void *) from, len); *to_ptr += len; - return(0); + return 0; } -int copy_from_user_skas(void *to, const void __user *from, int n) +int copy_from_user(void *to, const void __user *from, int n) { - if(segment_eq(get_fs(), KERNEL_DS)){ + if (segment_eq(get_fs(), KERNEL_DS)) { memcpy(to, (__force void*)from, n); - return(0); + return 0; } - return(access_ok_skas(VERIFY_READ, from, n) ? + return access_ok(VERIFY_READ, from, n) ? buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to): - n); + n; } +EXPORT_SYMBOL(copy_from_user); static int copy_chunk_to_user(unsigned long to, int len, void *arg) { @@ -154,20 +158,21 @@ static int copy_chunk_to_user(unsigned long to, int len, void *arg) memcpy((void *) to, (void *) from, len); *from_ptr += len; - return(0); + return 0; } -int copy_to_user_skas(void __user *to, const void *from, int n) +int copy_to_user(void __user *to, const void *from, int n) { - if(segment_eq(get_fs(), KERNEL_DS)){ - memcpy((__force void*)to, from, n); - return(0); + if (segment_eq(get_fs(), KERNEL_DS)) { + memcpy((__force void *) to, from, n); + return 0; } - return(access_ok_skas(VERIFY_WRITE, to, n) ? + return access_ok(VERIFY_WRITE, to, n) ? buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) : - n); + n; } +EXPORT_SYMBOL(copy_to_user); static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) { @@ -178,52 +183,54 @@ static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) n = strnlen(to, len); *to_ptr += n; - if(n < len) - return(1); - return(0); + if (n < len) + return 1; + return 0; } -int strncpy_from_user_skas(char *dst, const char __user *src, int count) +int strncpy_from_user(char *dst, const char __user *src, int count) { int n; char *ptr = dst; - if(segment_eq(get_fs(), KERNEL_DS)){ - strncpy(dst, (__force void*)src, count); - return(strnlen(dst, count)); + if (segment_eq(get_fs(), KERNEL_DS)) { + strncpy(dst, (__force void *) src, count); + return strnlen(dst, count); } - if(!access_ok_skas(VERIFY_READ, src, 1)) - return(-EFAULT); + if (!access_ok(VERIFY_READ, src, 1)) + return -EFAULT; n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user, &ptr); - if(n != 0) - return(-EFAULT); - return(strnlen(dst, count)); + if (n != 0) + return -EFAULT; + return strnlen(dst, count); } +EXPORT_SYMBOL(strncpy_from_user); static int clear_chunk(unsigned long addr, int len, void *unused) { memset((void *) addr, 0, len); - return(0); + return 0; } -int __clear_user_skas(void __user *mem, int len) +int __clear_user(void __user *mem, int len) { - return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL)); + return buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL); } -int clear_user_skas(void __user *mem, int len) +int clear_user(void __user *mem, int len) { - if(segment_eq(get_fs(), KERNEL_DS)){ + if (segment_eq(get_fs(), KERNEL_DS)) { memset((__force void*)mem, 0, len); - return(0); + return 0; } - return(access_ok_skas(VERIFY_WRITE, mem, len) ? - buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len); + return access_ok(VERIFY_WRITE, mem, len) ? + buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len; } +EXPORT_SYMBOL(clear_user); static int strnlen_chunk(unsigned long str, int len, void *arg) { @@ -232,31 +239,21 @@ static int strnlen_chunk(unsigned long str, int len, void *arg) n = strnlen((void *) str, len); *len_ptr += n; - if(n < len) - return(1); - return(0); + if (n < len) + return 1; + return 0; } -int strnlen_user_skas(const void __user *str, int len) +int strnlen_user(const void __user *str, int len) { int count = 0, n; - if(segment_eq(get_fs(), KERNEL_DS)) - return(strnlen((__force char*)str, len) + 1); + if (segment_eq(get_fs(), KERNEL_DS)) + return strnlen((__force char*)str, len) + 1; n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count); - if(n == 0) - return(count + 1); - return(-EFAULT); + if (n == 0) + return count + 1; + return 0; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +EXPORT_SYMBOL(strnlen_user); diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index 72113b0a96e..5c8c3ea7db7 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -1,39 +1,26 @@ -/* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/percpu.h" -#include "asm/pgalloc.h" -#include "asm/tlb.h" - -/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */ -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); +#include <linux/percpu.h> +#include <asm/pgalloc.h> +#include <asm/tlb.h> #ifdef CONFIG_SMP -#include "linux/sched.h" -#include "linux/module.h" -#include "linux/threads.h" -#include "linux/interrupt.h" -#include "linux/err.h" -#include "linux/hardirq.h" -#include "asm/smp.h" -#include "asm/processor.h" -#include "asm/spinlock.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" -#include "irq_user.h" -#include "os.h" - -/* CPU online map, set by smp_boot_cpus */ -cpumask_t cpu_online_map = CPU_MASK_NONE; -cpumask_t cpu_possible_map = CPU_MASK_NONE; - -EXPORT_SYMBOL(cpu_online_map); -EXPORT_SYMBOL(cpu_possible_map); +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/threads.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/hardirq.h> +#include <asm/smp.h> +#include <asm/processor.h> +#include <asm/spinlock.h> +#include <kern.h> +#include <irq_user.h> +#include <os.h> /* Per CPU bogomips and other parameters * The only piece used here is the ipi pipe, which is set before SMP is @@ -58,12 +45,12 @@ void smp_send_stop(void) int i; printk(KERN_INFO "Stopping all CPUs..."); - for(i = 0; i < num_online_cpus(); i++){ - if(i == current_thread->cpu) + for (i = 0; i < num_online_cpus(); i++) { + if (i == current_thread->cpu) continue; os_write_file(cpu_data[i].ipi_pipe[1], "S", 1); } - printk("done\n"); + printk(KERN_CONT "done\n"); } static cpumask_t smp_commenced_mask = CPU_MASK_NONE; @@ -74,46 +61,43 @@ static int idle_proc(void *cpup) int cpu = (int) cpup, err; err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1); - if(err < 0) + if (err < 0) panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err); - activate_ipi(cpu_data[cpu].ipi_pipe[0], - current->thread.mode.tt.extern_pid); - + os_set_fd_async(cpu_data[cpu].ipi_pipe[0]); + wmb(); if (cpu_test_and_set(cpu, cpu_callin_map)) { - printk("huh, CPU#%d already present??\n", cpu); + printk(KERN_ERR "huh, CPU#%d already present??\n", cpu); BUG(); } while (!cpu_isset(cpu, smp_commenced_mask)) cpu_relax(); - cpu_set(cpu, cpu_online_map); + notify_cpu_starting(cpu); + set_cpu_online(cpu, true); default_idle(); - return(0); + return 0; } static struct task_struct *idle_thread(int cpu) { struct task_struct *new_task; - unsigned char c; - current->thread.request.u.thread.proc = idle_proc; - current->thread.request.u.thread.arg = (void *) cpu; + current->thread.request.u.thread.proc = idle_proc; + current->thread.request.u.thread.arg = (void *) cpu; new_task = fork_idle(cpu); - if(IS_ERR(new_task)) + if (IS_ERR(new_task)) panic("copy_process failed in idle_thread, error = %ld", PTR_ERR(new_task)); - cpu_tasks[cpu] = ((struct cpu_task) + cpu_tasks[cpu] = ((struct cpu_task) { .pid = new_task->thread.mode.tt.extern_pid, .task = new_task } ); idle_threads[cpu] = new_task; - CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c, - sizeof(c)), - ({ panic("skas mode doesn't support SMP"); })); - return(new_task); + panic("skas mode doesn't support SMP"); + return new_task; } void smp_prepare_cpus(unsigned int maxcpus) @@ -124,54 +108,50 @@ void smp_prepare_cpus(unsigned int maxcpus) int i; for (i = 0; i < ncpus; ++i) - cpu_set(i, cpu_possible_map); + set_cpu_possible(i, true); - cpu_clear(me, cpu_online_map); - cpu_set(me, cpu_online_map); + set_cpu_online(me, true); cpu_set(me, cpu_callin_map); err = os_pipe(cpu_data[me].ipi_pipe, 1, 1); - if(err < 0) + if (err < 0) panic("CPU#0 failed to create IPI pipe, errno = %d", -err); - activate_ipi(cpu_data[me].ipi_pipe[0], - current->thread.mode.tt.extern_pid); + os_set_fd_async(cpu_data[me].ipi_pipe[0]); + + for (cpu = 1; cpu < ncpus; cpu++) { + printk(KERN_INFO "Booting processor %d...\n", cpu); - for(cpu = 1; cpu < ncpus; cpu++){ - printk("Booting processor %d...\n", cpu); - idle = idle_thread(cpu); init_idle(idle, cpu); - unhash_process(idle); waittime = 200000000; while (waittime-- && !cpu_isset(cpu, cpu_callin_map)) cpu_relax(); - if (cpu_isset(cpu, cpu_callin_map)) - printk("done\n"); - else printk("failed\n"); + printk(KERN_INFO "%s\n", + cpu_isset(cpu, cpu_calling_map) ? "done" : "failed"); } } void smp_prepare_boot_cpu(void) { - cpu_set(smp_processor_id(), cpu_online_map); + set_cpu_online(smp_processor_id(), true); } -int __cpu_up(unsigned int cpu) +int __cpu_up(unsigned int cpu, struct task_struct *tidle) { cpu_set(cpu, smp_commenced_mask); - while (!cpu_isset(cpu, cpu_online_map)) + while (!cpu_online(cpu)) mb(); - return(0); + return 0; } int setup_profiling_timer(unsigned int multiplier) { printk(KERN_INFO "setup_profiling_timer\n"); - return(0); + return 0; } void smp_call_function_slave(int cpu); @@ -189,17 +169,18 @@ void IPI_handler(int cpu) break; case 'R': - set_tsk_need_resched(current); + scheduler_ipi(); break; case 'S': - printk("CPU#%d stopping\n", cpu); - while(1) + printk(KERN_INFO "CPU#%d stopping\n", cpu); + while (1) pause(); break; default: - printk("CPU#%d received unknown IPI [%c]!\n", cpu, c); + printk(KERN_ERR "CPU#%d received unknown IPI [%c]!\n", + cpu, c); break; } } @@ -207,7 +188,7 @@ void IPI_handler(int cpu) int hard_smp_processor_id(void) { - return(pid_to_processor_id(os_getpid())); + return pid_to_processor_id(os_getpid()); } static DEFINE_SPINLOCK(call_lock); @@ -223,8 +204,7 @@ void smp_call_function_slave(int cpu) atomic_inc(&scf_finished); } -int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, - int wait) +int smp_call_function(void (*_func)(void *info), void *_info, int wait) { int cpus = num_online_cpus() - 1; int i; @@ -256,14 +236,3 @@ int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, } #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index 1429c131879..c1d0ae069b5 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -1,36 +1,28 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "kern_util.h" -#include "syscall.h" -#include "os.h" +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/utsname.h> +#include <linux/syscalls.h> +#include <asm/current.h> +#include <asm/mman.h> +#include <asm/uaccess.h> +#include <asm/unistd.h> -struct { - int syscall; - int pid; - long result; - unsigned long long start; - unsigned long long end; -} syscall_record[1024]; - -int record_syscall_start(int syscall) +long old_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long offset) { - int max, index; - - max = sizeof(syscall_record)/sizeof(syscall_record[0]); - index = next_syscall_index(max); + long err = -EINVAL; + if (offset & ~PAGE_MASK) + goto out; - syscall_record[index].syscall = syscall; - syscall_record[index].pid = current_pid(); - syscall_record[index].result = 0xdeadbeef; - syscall_record[index].start = os_usecs(); - return(index); -} - -void record_syscall_end(int index, long result) -{ - syscall_record[index].result = result; - syscall_record[index].end = os_usecs(); + err = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + out: + return err; } diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c deleted file mode 100644 index 8e1a3501ff4..00000000000 --- a/arch/um/kernel/syscall_kern.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "linux/file.h" -#include "linux/smp_lock.h" -#include "linux/mm.h" -#include "linux/utsname.h" -#include "linux/msg.h" -#include "linux/shm.h" -#include "linux/sys.h" -#include "linux/syscalls.h" -#include "linux/unistd.h" -#include "linux/slab.h" -#include "linux/utime.h" -#include "asm/mman.h" -#include "asm/uaccess.h" -#include "kern_util.h" -#include "user_util.h" -#include "sysdep/syscalls.h" -#include "mode_kern.h" -#include "choose-mode.h" - -/* Unlocked, I don't care if this is a bit off */ -int nsyscalls = 0; - -long sys_fork(void) -{ - long ret; - - current->thread.forking = 1; - ret = do_fork(SIGCHLD, UPT_SP(¤t->thread.regs.regs), - ¤t->thread.regs, 0, NULL, NULL); - current->thread.forking = 0; - return(ret); -} - -long sys_vfork(void) -{ - long ret; - - current->thread.forking = 1; - ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, - UPT_SP(¤t->thread.regs.regs), - ¤t->thread.regs, 0, NULL, NULL); - current->thread.forking = 0; - return(ret); -} - -/* common code for old and new mmaps */ -long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - long error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); - out: - return error; -} - -long old_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long offset) -{ - long err = -EINVAL; - if (offset & ~PAGE_MASK) - goto out; - - err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); - out: - return err; -} -/* - * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way unix traditionally does this, though. - */ -long sys_pipe(unsigned long __user * fildes) -{ - int fd[2]; - long error; - - error = do_pipe(fd); - if (!error) { - if (copy_to_user(fildes, fd, sizeof(fd))) - error = -EFAULT; - } - return error; -} - - -long sys_uname(struct old_utsname * name) -{ - long err; - if (!name) - return -EFAULT; - down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); - up_read(&uts_sem); - return err?-EFAULT:0; -} - -long sys_olduname(struct oldold_utsname * name) -{ - long error; - - if (!name) - return -EFAULT; - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) - return -EFAULT; - - down_read(&uts_sem); - - error = __copy_to_user(&name->sysname,&system_utsname.sysname, - __OLD_UTS_LEN); - error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename, - __OLD_UTS_LEN); - error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release, - __OLD_UTS_LEN); - error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version, - __OLD_UTS_LEN); - error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine, - __OLD_UTS_LEN); - error |= __put_user(0,name->machine+__OLD_UTS_LEN); - - up_read(&uts_sem); - - error = error ? -EFAULT : 0; - - return error; -} - -DEFINE_SPINLOCK(syscall_lock); - -static int syscall_index = 0; - -int next_syscall_index(int limit) -{ - int ret; - - spin_lock(&syscall_lock); - ret = syscall_index; - if(++syscall_index == limit) - syscall_index = 0; - spin_unlock(&syscall_lock); - return(ret); -} diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index b331e970002..799d7e413bf 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -1,82 +1,98 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2013 Richard Weinberger <richrd@nod.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ -#include "linux/config.h" -#include "linux/sched.h" -#include "linux/kernel.h" -#include "linux/module.h" -#include "linux/kallsyms.h" -#include "asm/page.h" -#include "asm/processor.h" -#include "sysrq.h" -#include "user_util.h" +#include <linux/kallsyms.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <asm/sysrq.h> +#include <os.h> -/* Catch non-i386 SUBARCH's. */ -#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT) -void show_trace(struct task_struct *task, unsigned long * stack) -{ - unsigned long addr; +struct stack_frame { + struct stack_frame *next_frame; + unsigned long return_address; +}; - if (!stack) { - stack = (unsigned long*) &stack; - WARN_ON(1); - } +static void do_stack_trace(unsigned long *sp, unsigned long bp) +{ + int reliable; + unsigned long addr; + struct stack_frame *frame = (struct stack_frame *)bp; - printk("Call Trace: \n"); - while (((long) stack & (THREAD_SIZE-1)) != 0) { - addr = *stack; + printk(KERN_INFO "Call Trace:\n"); + while (((long) sp & (THREAD_SIZE-1)) != 0) { + addr = *sp; if (__kernel_text_address(addr)) { - printk("%08lx: [<%08lx>]", (unsigned long) stack, addr); - print_symbol(" %s", addr); - printk("\n"); - } - stack++; - } - printk("\n"); + reliable = 0; + if ((unsigned long) sp == bp + sizeof(long)) { + frame = frame ? frame->next_frame : NULL; + bp = (unsigned long)frame; + reliable = 1; + } + + printk(KERN_INFO " [<%08lx>]", addr); + printk(KERN_CONT " %s", reliable ? "" : "? "); + print_symbol(KERN_CONT "%s", addr); + printk(KERN_CONT "\n"); + } + sp++; + } + printk(KERN_INFO "\n"); } -#endif -/* - * stack dumps generator - this is used by arch-independent code. - * And this is identical to i386 currently. - */ -void dump_stack(void) +static unsigned long get_frame_pointer(struct task_struct *task, + struct pt_regs *segv_regs) { - unsigned long stack; - - show_trace(current, &stack); + if (!task || task == current) + return segv_regs ? PT_REGS_BP(segv_regs) : current_bp(); + else + return KSTK_EBP(task); } -EXPORT_SYMBOL(dump_stack); -/*Stolen from arch/i386/kernel/traps.c */ -static int kstack_depth_to_print = 24; +static unsigned long *get_stack_pointer(struct task_struct *task, + struct pt_regs *segv_regs) +{ + if (!task || task == current) + return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp(); + else + return (unsigned long *)KSTK_ESP(task); +} -/* This recently started being used in arch-independent code too, as in - * kernel/sched.c.*/ -void show_stack(struct task_struct *task, unsigned long *esp) +void show_stack(struct task_struct *task, unsigned long *stack) { - unsigned long *stack; + unsigned long *sp = stack, bp = 0; + struct pt_regs *segv_regs = current->thread.segv_regs; int i; - if (esp == NULL) { - if (task != current && task != NULL) { - esp = (unsigned long *) KSTK_ESP(task); - } else { - esp = (unsigned long *) &esp; - } + if (!segv_regs && os_is_signal_stack()) { + printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler," + " aborting stack trace!\n"); + return; } - stack = esp; - for(i = 0; i < kstack_depth_to_print; i++) { +#ifdef CONFIG_FRAME_POINTER + bp = get_frame_pointer(task, segv_regs); +#endif + + if (!stack) + sp = get_stack_pointer(task, segv_regs); + + printk(KERN_INFO "Stack:\n"); + stack = sp; + for (i = 0; i < 3 * STACKSLOTS_PER_LINE; i++) { if (kstack_end(stack)) break; - if (i && ((i % 8) == 0)) - printk("\n "); - printk("%08lx ", *stack++); + if (i && ((i % STACKSLOTS_PER_LINE) == 0)) + printk(KERN_CONT "\n"); + printk(KERN_CONT " %08lx", *stack++); } + printk(KERN_CONT "\n"); - printk("Call Trace: \n"); - show_trace(task, esp); + do_stack_trace(sp, bp); } diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index c40b611e3d9..117568d4f64 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -1,171 +1,115 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <time.h> -#include <sys/time.h> -#include <signal.h> -#include <errno.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "process.h" -#include "signal_user.h" -#include "time_user.h" -#include "kern_constants.h" - -/* XXX This really needs to be declared and initialized in a kernel file since - * it's in <linux/time.h> - */ -extern struct timespec wall_to_monotonic; - -extern struct timeval xtime; - -struct timeval local_offset = { 0, 0 }; - -void timer(void) -{ - gettimeofday(&xtime, NULL); - timeradd(&xtime, &local_offset, &xtime); -} - -static void set_interval(int timer_type) -{ - int usec = 1000000/hz(); - struct itimerval interval = ((struct itimerval) { { 0, usec }, - { 0, usec } }); - - if(setitimer(timer_type, &interval, NULL) == -1) - panic("setitimer failed - errno = %d\n", errno); -} - -void enable_timer(void) -{ - set_interval(ITIMER_VIRTUAL); -} - -void prepare_timer(void * ptr) +#include <linux/clockchips.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/threads.h> +#include <asm/irq.h> +#include <asm/param.h> +#include <kern_util.h> +#include <os.h> + +void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) { - int usec = 1000000/hz(); - *(struct itimerval *)ptr = ((struct itimerval) { { 0, usec }, - { 0, usec }}); -} + unsigned long flags; -void disable_timer(void) -{ - struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); - if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) || - (setitimer(ITIMER_REAL, &disable, NULL) < 0)) - printk("disnable_timer - setitimer failed, errno = %d\n", - errno); - /* If there are signals already queued, after unblocking ignore them */ - set_handler(SIGALRM, SIG_IGN, 0, -1); - set_handler(SIGVTALRM, SIG_IGN, 0, -1); + local_irq_save(flags); + do_IRQ(TIMER_IRQ, regs); + local_irq_restore(flags); } -void switch_timers(int to_real) +static void itimer_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) { - struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); - struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() }, - { 0, 1000000/hz() }}); - int old, new; - - if(to_real){ - old = ITIMER_VIRTUAL; - new = ITIMER_REAL; - } - else { - old = ITIMER_REAL; - new = ITIMER_VIRTUAL; + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + set_interval(); + break; + + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_ONESHOT: + disable_timer(); + break; + + case CLOCK_EVT_MODE_RESUME: + break; } - - if((setitimer(old, &disable, NULL) < 0) || - (setitimer(new, &enable, NULL))) - printk("switch_timers - setitimer failed, errno = %d\n", - errno); } -void uml_idle_timer(void) +static int itimer_next_event(unsigned long delta, + struct clock_event_device *evt) { - if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) - panic("Couldn't unset SIGVTALRM handler"); - - set_handler(SIGALRM, (__sighandler_t) alarm_handler, - SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_interval(ITIMER_REAL); + return timer_one_shot(delta + 1); } -extern int do_posix_clock_monotonic_gettime(struct timespec *tp); - -void time_init(void) +static struct clock_event_device itimer_clockevent = { + .name = "itimer", + .rating = 250, + .cpumask = cpu_all_mask, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = itimer_set_mode, + .set_next_event = itimer_next_event, + .shift = 32, + .irq = 0, +}; + +static irqreturn_t um_timer(int irq, void *dev) { - struct timespec now; + (*itimer_clockevent.event_handler)(&itimer_clockevent); - if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) - panic("Couldn't set SIGVTALRM handler"); - set_interval(ITIMER_VIRTUAL); - - do_posix_clock_monotonic_gettime(&now); - wall_to_monotonic.tv_sec = -now.tv_sec; - wall_to_monotonic.tv_nsec = -now.tv_nsec; + return IRQ_HANDLED; } -/* Declared in linux/time.h, which can't be included here */ -extern void clock_was_set(void); - -void do_gettimeofday(struct timeval *tv) +static cycle_t itimer_read(struct clocksource *cs) { - unsigned long flags; - - flags = time_lock(); - gettimeofday(tv, NULL); - timeradd(tv, &local_offset, tv); - time_unlock(flags); - clock_was_set(); + return os_nsecs() / 1000; } -int do_settimeofday(struct timespec *tv) -{ - struct timeval now; - unsigned long flags; - struct timeval tv_in; - - if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC) - return -EINVAL; - - tv_in.tv_sec = tv->tv_sec; - tv_in.tv_usec = tv->tv_nsec / 1000; +static struct clocksource itimer_clocksource = { + .name = "itimer", + .rating = 300, + .read = itimer_read, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; - flags = time_lock(); - gettimeofday(&now, NULL); - timersub(&tv_in, &now, &local_offset); - time_unlock(flags); - - return(0); +static void __init setup_itimer(void) +{ + int err; + + err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL); + if (err != 0) + printk(KERN_ERR "register_timer : request_irq failed - " + "errno = %d\n", -err); + + itimer_clockevent.mult = div_sc(HZ, NSEC_PER_SEC, 32); + itimer_clockevent.max_delta_ns = + clockevent_delta2ns(60 * HZ, &itimer_clockevent); + itimer_clockevent.min_delta_ns = + clockevent_delta2ns(1, &itimer_clockevent); + err = clocksource_register_hz(&itimer_clocksource, USEC_PER_SEC); + if (err) { + printk(KERN_ERR "clocksource_register_hz returned %d\n", err); + return; + } + clockevents_register_device(&itimer_clockevent); } -void idle_sleep(int secs) +void read_persistent_clock(struct timespec *ts) { - struct timespec ts; + long long nsecs = os_nsecs(); - ts.tv_sec = secs; - ts.tv_nsec = 0; - nanosleep(&ts, NULL); + set_normalized_timespec(ts, nsecs / NSEC_PER_SEC, + nsecs % NSEC_PER_SEC); } -/* XXX This partly duplicates init_irq_signals */ - -void user_time_init(void) +void __init time_init(void) { - set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, - SIGALRM, SIGUSR2, -1); - set_handler(SIGALRM, (__sighandler_t) alarm_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, - SIGVTALRM, SIGUSR2, -1); - set_interval(ITIMER_VIRTUAL); + timer_init(); + late_time_init = setup_itimer; } diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c deleted file mode 100644 index 020ca79b8d3..00000000000 --- a/arch/um/kernel/time_kern.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/kernel.h" -#include "linux/module.h" -#include "linux/unistd.h" -#include "linux/stddef.h" -#include "linux/spinlock.h" -#include "linux/time.h" -#include "linux/sched.h" -#include "linux/interrupt.h" -#include "linux/init.h" -#include "linux/delay.h" -#include "asm/irq.h" -#include "asm/param.h" -#include "asm/current.h" -#include "kern_util.h" -#include "user_util.h" -#include "time_user.h" -#include "mode.h" -#include "os.h" - -int hz(void) -{ - return(HZ); -} - -/* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies_64 * (1000000000 / HZ); -} - -/* Changed at early boot */ -int timer_irq_inited = 0; - -static int first_tick; -static unsigned long long prev_usecs; -#ifdef CONFIG_UML_REAL_TIME_CLOCK -static long long delta; /* Deviation per interval */ -#endif - -void timer_irq(union uml_pt_regs *regs) -{ - unsigned long long ticks = 0; - - if(!timer_irq_inited){ - /* This is to ensure that ticks don't pile up when - * the timer handler is suspended */ - first_tick = 0; - return; - } - - if(first_tick){ -#ifdef CONFIG_UML_REAL_TIME_CLOCK - /* We've had 1 tick */ - unsigned long long usecs = os_usecs(); - - delta += usecs - prev_usecs; - prev_usecs = usecs; - - /* Protect against the host clock being set backwards */ - if(delta < 0) - delta = 0; - - ticks += (delta * HZ) / MILLION; - delta -= (ticks * MILLION) / HZ; -#else - ticks = 1; -#endif - } - else { - prev_usecs = os_usecs(); - first_tick = 1; - } - - while(ticks > 0){ - do_IRQ(TIMER_IRQ, regs); - ticks--; - } -} - -void boot_timer_handler(int sig) -{ - struct pt_regs regs; - - CHOOSE_MODE((void) - (UPT_SC(®s.regs) = (struct sigcontext *) (&sig + 1)), - (void) (regs.regs.skas.is_user = 0)); - do_timer(®s); -} - -irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) -{ - unsigned long flags; - - do_timer(regs); - write_seqlock_irqsave(&xtime_lock, flags); - timer(); - write_sequnlock_irqrestore(&xtime_lock, flags); - return(IRQ_HANDLED); -} - -long um_time(int __user *tloc) -{ - struct timeval now; - - do_gettimeofday(&now); - if (tloc) { - if (put_user(now.tv_sec, tloc)) - now.tv_sec = -EFAULT; - } - return now.tv_sec; -} - -long um_stime(int __user *tptr) -{ - int value; - struct timespec new; - - if (get_user(value, tptr)) - return -EFAULT; - new.tv_sec = value; - new.tv_nsec = 0; - do_settimeofday(&new); - return 0; -} - -void timer_handler(int sig, union uml_pt_regs *regs) -{ - local_irq_disable(); - irq_enter(); - update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)), - (regs)->skas.is_user)); - irq_exit(); - local_irq_enable(); - if(current_thread->cpu == 0) - timer_irq(regs); -} - -static DEFINE_SPINLOCK(timer_spinlock); - -unsigned long time_lock(void) -{ - unsigned long flags; - - spin_lock_irqsave(&timer_spinlock, flags); - return(flags); -} - -void time_unlock(unsigned long flags) -{ - spin_unlock_irqrestore(&timer_spinlock, flags); -} - -int __init timer_init(void) -{ - int err; - - user_time_init(); - err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL); - if(err != 0) - printk(KERN_ERR "timer_init : request_irq failed - " - "errno = %d\n", -err); - timer_irq_inited = 1; - return(0); -} - -__initcall(timer_init); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index f5b0636f9ad..f1b3eb14b85 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -1,390 +1,544 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/mm.h" -#include "asm/page.h" -#include "asm/pgalloc.h" -#include "asm/tlbflush.h" -#include "choose-mode.h" -#include "mode_kern.h" -#include "user_util.h" -#include "tlb.h" -#include "mem.h" -#include "mem_user.h" -#include "os.h" +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <asm/pgtable.h> +#include <asm/tlbflush.h> +#include <as-layout.h> +#include <mem_user.h> +#include <os.h> +#include <skas.h> +#include <kern_util.h> + +struct host_vm_change { + struct host_vm_op { + enum { NONE, MMAP, MUNMAP, MPROTECT } type; + union { + struct { + unsigned long addr; + unsigned long len; + unsigned int prot; + int fd; + __u64 offset; + } mmap; + struct { + unsigned long addr; + unsigned long len; + } munmap; + struct { + unsigned long addr; + unsigned long len; + unsigned int prot; + } mprotect; + } u; + } ops[1]; + int index; + struct mm_id *id; + void *data; + int force; +}; + +#define INIT_HVC(mm, force) \ + ((struct host_vm_change) \ + { .ops = { { .type = NONE } }, \ + .id = &mm->context.id, \ + .data = NULL, \ + .index = 0, \ + .force = force }) + +static int do_ops(struct host_vm_change *hvc, int end, + int finished) +{ + struct host_vm_op *op; + int i, ret = 0; + + for (i = 0; i < end && !ret; i++) { + op = &hvc->ops[i]; + switch (op->type) { + case MMAP: + ret = map(hvc->id, op->u.mmap.addr, op->u.mmap.len, + op->u.mmap.prot, op->u.mmap.fd, + op->u.mmap.offset, finished, &hvc->data); + break; + case MUNMAP: + ret = unmap(hvc->id, op->u.munmap.addr, + op->u.munmap.len, finished, &hvc->data); + break; + case MPROTECT: + ret = protect(hvc->id, op->u.mprotect.addr, + op->u.mprotect.len, op->u.mprotect.prot, + finished, &hvc->data); + break; + default: + printk(KERN_ERR "Unknown op type %d in do_ops\n", + op->type); + BUG(); + break; + } + } + + return ret; +} static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x, struct host_vm_op *ops, int *index, - int last_filled, union mm_context *mmu, void **flush, - int (*do_ops)(union mm_context *, struct host_vm_op *, - int, int, void **)) + unsigned int prot, struct host_vm_change *hvc) { - __u64 offset; + __u64 offset; struct host_vm_op *last; int fd, ret = 0; fd = phys_mapping(phys, &offset); - if(*index != -1){ - last = &ops[*index]; - if((last->type == MMAP) && + if (hvc->index != 0) { + last = &hvc->ops[hvc->index - 1]; + if ((last->type == MMAP) && (last->u.mmap.addr + last->u.mmap.len == virt) && - (last->u.mmap.r == r) && (last->u.mmap.w == w) && - (last->u.mmap.x == x) && (last->u.mmap.fd == fd) && - (last->u.mmap.offset + last->u.mmap.len == offset)){ + (last->u.mmap.prot == prot) && (last->u.mmap.fd == fd) && + (last->u.mmap.offset + last->u.mmap.len == offset)) { last->u.mmap.len += len; return 0; } } - if(*index == last_filled){ - ret = (*do_ops)(mmu, ops, last_filled, 0, flush); - *index = -1; + if (hvc->index == ARRAY_SIZE(hvc->ops)) { + ret = do_ops(hvc, ARRAY_SIZE(hvc->ops), 0); + hvc->index = 0; } - ops[++*index] = ((struct host_vm_op) { .type = MMAP, - .u = { .mmap = { - .addr = virt, - .len = len, - .r = r, - .w = w, - .x = x, - .fd = fd, - .offset = offset } + hvc->ops[hvc->index++] = ((struct host_vm_op) + { .type = MMAP, + .u = { .mmap = { .addr = virt, + .len = len, + .prot = prot, + .fd = fd, + .offset = offset } } }); return ret; } static int add_munmap(unsigned long addr, unsigned long len, - struct host_vm_op *ops, int *index, int last_filled, - union mm_context *mmu, void **flush, - int (*do_ops)(union mm_context *, struct host_vm_op *, - int, int, void **)) + struct host_vm_change *hvc) { struct host_vm_op *last; int ret = 0; - if(*index != -1){ - last = &ops[*index]; - if((last->type == MUNMAP) && - (last->u.munmap.addr + last->u.mmap.len == addr)){ + if ((addr >= STUB_START) && (addr < STUB_END)) + return -EINVAL; + + if (hvc->index != 0) { + last = &hvc->ops[hvc->index - 1]; + if ((last->type == MUNMAP) && + (last->u.munmap.addr + last->u.mmap.len == addr)) { last->u.munmap.len += len; return 0; } } - if(*index == last_filled){ - ret = (*do_ops)(mmu, ops, last_filled, 0, flush); - *index = -1; + if (hvc->index == ARRAY_SIZE(hvc->ops)) { + ret = do_ops(hvc, ARRAY_SIZE(hvc->ops), 0); + hvc->index = 0; } - ops[++*index] = ((struct host_vm_op) { .type = MUNMAP, - .u = { .munmap = { - .addr = addr, - .len = len } } }); + hvc->ops[hvc->index++] = ((struct host_vm_op) + { .type = MUNMAP, + .u = { .munmap = { .addr = addr, + .len = len } } }); return ret; } -static int add_mprotect(unsigned long addr, unsigned long len, int r, int w, - int x, struct host_vm_op *ops, int *index, - int last_filled, union mm_context *mmu, void **flush, - int (*do_ops)(union mm_context *, struct host_vm_op *, - int, int, void **)) +static int add_mprotect(unsigned long addr, unsigned long len, + unsigned int prot, struct host_vm_change *hvc) { struct host_vm_op *last; int ret = 0; - if(*index != -1){ - last = &ops[*index]; - if((last->type == MPROTECT) && + if (hvc->index != 0) { + last = &hvc->ops[hvc->index - 1]; + if ((last->type == MPROTECT) && (last->u.mprotect.addr + last->u.mprotect.len == addr) && - (last->u.mprotect.r == r) && (last->u.mprotect.w == w) && - (last->u.mprotect.x == x)){ + (last->u.mprotect.prot == prot)) { last->u.mprotect.len += len; return 0; } } - if(*index == last_filled){ - ret = (*do_ops)(mmu, ops, last_filled, 0, flush); - *index = -1; + if (hvc->index == ARRAY_SIZE(hvc->ops)) { + ret = do_ops(hvc, ARRAY_SIZE(hvc->ops), 0); + hvc->index = 0; } - ops[++*index] = ((struct host_vm_op) { .type = MPROTECT, - .u = { .mprotect = { - .addr = addr, - .len = len, - .r = r, - .w = w, - .x = x } } }); + hvc->ops[hvc->index++] = ((struct host_vm_op) + { .type = MPROTECT, + .u = { .mprotect = { .addr = addr, + .len = len, + .prot = prot } } }); return ret; } #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) -void fix_range_common(struct mm_struct *mm, unsigned long start_addr, - unsigned long end_addr, int force, - int (*do_ops)(union mm_context *, struct host_vm_op *, - int, int, void **)) +static inline int update_pte_range(pmd_t *pmd, unsigned long addr, + unsigned long end, + struct host_vm_change *hvc) { - pgd_t *npgd; - pud_t *npud; - pmd_t *npmd; - pte_t *npte; - union mm_context *mmu = &mm->context; - unsigned long addr, end; - int r, w, x; - struct host_vm_op ops[1]; - void *flush = NULL; - int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1; - int ret = 0; - - if(mm == NULL) return; - - ops[0].type = NONE; - for(addr = start_addr; addr < end_addr && !ret;){ - npgd = pgd_offset(mm, addr); - if(!pgd_present(*npgd)){ - end = ADD_ROUND(addr, PGDIR_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pgd_newpage(*npgd)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pgd_mkuptodate(*npgd); - } - addr = end; - continue; - } - - npud = pud_offset(npgd, addr); - if(!pud_present(*npud)){ - end = ADD_ROUND(addr, PUD_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pud_newpage(*npud)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pud_mkuptodate(*npud); - } - addr = end; - continue; - } - - npmd = pmd_offset(npud, addr); - if(!pmd_present(*npmd)){ - end = ADD_ROUND(addr, PMD_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pmd_newpage(*npmd)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pmd_mkuptodate(*npmd); - } - addr = end; - continue; - } - - npte = pte_offset_kernel(npmd, addr); - r = pte_read(*npte); - w = pte_write(*npte); - x = pte_exec(*npte); - if (!pte_young(*npte)) { + pte_t *pte; + int r, w, x, prot, ret = 0; + + pte = pte_offset_kernel(pmd, addr); + do { + if ((addr >= STUB_START) && (addr < STUB_END)) + continue; + + r = pte_read(*pte); + w = pte_write(*pte); + x = pte_exec(*pte); + if (!pte_young(*pte)) { r = 0; w = 0; - } else if (!pte_dirty(*npte)) { + } else if (!pte_dirty(*pte)) w = 0; + + prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | + (x ? UM_PROT_EXEC : 0)); + if (hvc->force || pte_newpage(*pte)) { + if (pte_present(*pte)) + ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, prot, hvc); + else + ret = add_munmap(addr, PAGE_SIZE, hvc); + } else if (pte_newprot(*pte)) + ret = add_mprotect(addr, PAGE_SIZE, prot, hvc); + *pte = pte_mkuptodate(*pte); + } while (pte++, addr += PAGE_SIZE, ((addr < end) && !ret)); + return ret; +} + +static inline int update_pmd_range(pud_t *pud, unsigned long addr, + unsigned long end, + struct host_vm_change *hvc) +{ + pmd_t *pmd; + unsigned long next; + int ret = 0; + + pmd = pmd_offset(pud, addr); + do { + next = pmd_addr_end(addr, end); + if (!pmd_present(*pmd)) { + if (hvc->force || pmd_newpage(*pmd)) { + ret = add_munmap(addr, next - addr, hvc); + pmd_mkuptodate(*pmd); + } + } + else ret = update_pte_range(pmd, addr, next, hvc); + } while (pmd++, addr = next, ((addr < end) && !ret)); + return ret; +} + +static inline int update_pud_range(pgd_t *pgd, unsigned long addr, + unsigned long end, + struct host_vm_change *hvc) +{ + pud_t *pud; + unsigned long next; + int ret = 0; + + pud = pud_offset(pgd, addr); + do { + next = pud_addr_end(addr, end); + if (!pud_present(*pud)) { + if (hvc->force || pud_newpage(*pud)) { + ret = add_munmap(addr, next - addr, hvc); + pud_mkuptodate(*pud); + } } - if(force || pte_newpage(*npte)){ - if(pte_present(*npte)) - ret = add_mmap(addr, - pte_val(*npte) & PAGE_MASK, - PAGE_SIZE, r, w, x, ops, - &op_index, last_op, mmu, - &flush, do_ops); - else ret = add_munmap(addr, PAGE_SIZE, ops, - &op_index, last_op, mmu, - &flush, do_ops); - } - else if(pte_newprot(*npte)) - ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops, - &op_index, last_op, mmu, - &flush, do_ops); - - *npte = pte_mkuptodate(*npte); - addr += PAGE_SIZE; - } - - if(!ret) - ret = (*do_ops)(mmu, ops, op_index, 1, &flush); + else ret = update_pmd_range(pud, addr, next, hvc); + } while (pud++, addr = next, ((addr < end) && !ret)); + return ret; +} + +void fix_range_common(struct mm_struct *mm, unsigned long start_addr, + unsigned long end_addr, int force) +{ + pgd_t *pgd; + struct host_vm_change hvc; + unsigned long addr = start_addr, next; + int ret = 0; + + hvc = INIT_HVC(mm, force); + pgd = pgd_offset(mm, addr); + do { + next = pgd_addr_end(addr, end_addr); + if (!pgd_present(*pgd)) { + if (force || pgd_newpage(*pgd)) { + ret = add_munmap(addr, next - addr, &hvc); + pgd_mkuptodate(*pgd); + } + } + else ret = update_pud_range(pgd, addr, next, &hvc); + } while (pgd++, addr = next, ((addr < end_addr) && !ret)); + + if (!ret) + ret = do_ops(&hvc, hvc.index, 1); /* This is not an else because ret is modified above */ - if(ret) { - printk("fix_range_common: failed, killing current process\n"); + if (ret) { + printk(KERN_ERR "fix_range_common: failed, killing current " + "process: %d\n", task_tgid_vnr(current)); + /* We are under mmap_sem, release it such that current can terminate */ + up_write(¤t->mm->mmap_sem); force_sig(SIGKILL, current); + do_signal(); } } -int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) +static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) { - struct mm_struct *mm; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - unsigned long addr, last; - int updated = 0, err; - - mm = &init_mm; - for(addr = start; addr < end;){ - pgd = pgd_offset(mm, addr); - if(!pgd_present(*pgd)){ - last = ADD_ROUND(addr, PGDIR_SIZE); - if(last > end) - last = end; - if(pgd_newpage(*pgd)){ - updated = 1; - err = os_unmap_memory((void *) addr, - last - addr); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr = last; - continue; - } - - pud = pud_offset(pgd, addr); - if(!pud_present(*pud)){ - last = ADD_ROUND(addr, PUD_SIZE); - if(last > end) - last = end; - if(pud_newpage(*pud)){ - updated = 1; - err = os_unmap_memory((void *) addr, - last - addr); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr = last; - continue; - } - - pmd = pmd_offset(pud, addr); - if(!pmd_present(*pmd)){ - last = ADD_ROUND(addr, PMD_SIZE); - if(last > end) - last = end; - if(pmd_newpage(*pmd)){ - updated = 1; - err = os_unmap_memory((void *) addr, - last - addr); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr = last; - continue; - } - - pte = pte_offset_kernel(pmd, addr); - if(!pte_present(*pte) || pte_newpage(*pte)){ - updated = 1; - err = os_unmap_memory((void *) addr, - PAGE_SIZE); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - if(pte_present(*pte)) - map_memory(addr, - pte_val(*pte) & PAGE_MASK, - PAGE_SIZE, 1, 1, 1); - } - else if(pte_newprot(*pte)){ - updated = 1; - os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1); - } - addr += PAGE_SIZE; - } - return(updated); + struct mm_struct *mm; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + unsigned long addr, last; + int updated = 0, err; + + mm = &init_mm; + for (addr = start; addr < end;) { + pgd = pgd_offset(mm, addr); + if (!pgd_present(*pgd)) { + last = ADD_ROUND(addr, PGDIR_SIZE); + if (last > end) + last = end; + if (pgd_newpage(*pgd)) { + updated = 1; + err = os_unmap_memory((void *) addr, + last - addr); + if (err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr = last; + continue; + } + + pud = pud_offset(pgd, addr); + if (!pud_present(*pud)) { + last = ADD_ROUND(addr, PUD_SIZE); + if (last > end) + last = end; + if (pud_newpage(*pud)) { + updated = 1; + err = os_unmap_memory((void *) addr, + last - addr); + if (err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr = last; + continue; + } + + pmd = pmd_offset(pud, addr); + if (!pmd_present(*pmd)) { + last = ADD_ROUND(addr, PMD_SIZE); + if (last > end) + last = end; + if (pmd_newpage(*pmd)) { + updated = 1; + err = os_unmap_memory((void *) addr, + last - addr); + if (err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr = last; + continue; + } + + pte = pte_offset_kernel(pmd, addr); + if (!pte_present(*pte) || pte_newpage(*pte)) { + updated = 1; + err = os_unmap_memory((void *) addr, + PAGE_SIZE); + if (err < 0) + panic("munmap failed, errno = %d\n", + -err); + if (pte_present(*pte)) + map_memory(addr, + pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, 1, 1, 1); + } + else if (pte_newprot(*pte)) { + updated = 1; + os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1); + } + addr += PAGE_SIZE; + } + return updated; +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + struct mm_struct *mm = vma->vm_mm; + void *flush = NULL; + int r, w, x, prot, err = 0; + struct mm_id *mm_id; + + address &= PAGE_MASK; + pgd = pgd_offset(mm, address); + if (!pgd_present(*pgd)) + goto kill; + + pud = pud_offset(pgd, address); + if (!pud_present(*pud)) + goto kill; + + pmd = pmd_offset(pud, address); + if (!pmd_present(*pmd)) + goto kill; + + pte = pte_offset_kernel(pmd, address); + + r = pte_read(*pte); + w = pte_write(*pte); + x = pte_exec(*pte); + if (!pte_young(*pte)) { + r = 0; + w = 0; + } else if (!pte_dirty(*pte)) { + w = 0; + } + + mm_id = &mm->context.id; + prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | + (x ? UM_PROT_EXEC : 0)); + if (pte_newpage(*pte)) { + if (pte_present(*pte)) { + unsigned long long offset; + int fd; + + fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset); + err = map(mm_id, address, PAGE_SIZE, prot, fd, offset, + 1, &flush); + } + else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush); + } + else if (pte_newprot(*pte)) + err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush); + + if (err) + goto kill; + + *pte = pte_mkuptodate(*pte); + + return; + +kill: + printk(KERN_ERR "Failed to flush page for address 0x%lx\n", address); + force_sig(SIGKILL, current); } pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) { - return(pgd_offset(mm, address)); + return pgd_offset(mm, address); } pud_t *pud_offset_proc(pgd_t *pgd, unsigned long address) { - return(pud_offset(pgd, address)); + return pud_offset(pgd, address); } pmd_t *pmd_offset_proc(pud_t *pud, unsigned long address) { - return(pmd_offset(pud, address)); + return pmd_offset(pud, address); } pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address) { - return(pte_offset_kernel(pmd, address)); + return pte_offset_kernel(pmd, address); } pte_t *addr_pte(struct task_struct *task, unsigned long addr) { - pgd_t *pgd = pgd_offset(task->mm, addr); - pud_t *pud = pud_offset(pgd, addr); - pmd_t *pmd = pmd_offset(pud, addr); - - return(pte_offset_map(pmd, addr)); -} + pgd_t *pgd = pgd_offset(task->mm, addr); + pud_t *pud = pud_offset(pgd, addr); + pmd_t *pmd = pmd_offset(pud, addr); -void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) -{ - address &= PAGE_MASK; - flush_tlb_range(vma, address, address + PAGE_SIZE); + return pte_offset_map(pmd, addr); } void flush_tlb_all(void) { - flush_tlb_mm(current->mm); + flush_tlb_mm(current->mm); } void flush_tlb_kernel_range(unsigned long start, unsigned long end) { - CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt, - flush_tlb_kernel_range_common, start, end); + flush_tlb_kernel_range_common(start, end); } void flush_tlb_kernel_vm(void) { - CHOOSE_MODE(flush_tlb_kernel_vm_tt(), - flush_tlb_kernel_range_common(start_vm, end_vm)); + flush_tlb_kernel_range_common(start_vm, end_vm); } void __flush_tlb_one(unsigned long addr) { - CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); + flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE); +} + +static void fix_range(struct mm_struct *mm, unsigned long start_addr, + unsigned long end_addr, int force) +{ + fix_range_common(mm, start_addr, end_addr, force); } void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start, - end); + if (vma->vm_mm == NULL) + flush_tlb_kernel_range_common(start, end); + else fix_range(vma->vm_mm, start, end, 0); +} +EXPORT_SYMBOL(flush_tlb_range); + +void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + /* + * Don't bother flushing if this address space is about to be + * destroyed. + */ + if (atomic_read(&mm->mm_users) == 0) + return; + + fix_range(mm, start, end, 0); } void flush_tlb_mm(struct mm_struct *mm) { - CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); + struct vm_area_struct *vma = mm->mmap; + + while (vma != NULL) { + fix_range(mm, vma->vm_start, vma->vm_end, 0); + vma = vma->vm_next; + } } void force_flush_all(void) { - CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); -} + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma = mm->mmap; + while (vma != NULL) { + fix_range(mm, vma->vm_start, vma->vm_end, 1); + vma = vma->vm_next; + } +} diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c new file mode 100644 index 00000000000..5678c3571e7 --- /dev/null +++ b/arch/um/kernel/trap.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/hardirq.h> +#include <linux/module.h> +#include <asm/current.h> +#include <asm/pgtable.h> +#include <asm/tlbflush.h> +#include <arch.h> +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> +#include <skas.h> + +/* + * Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by + * segv(). + */ +int handle_page_fault(unsigned long address, unsigned long ip, + int is_write, int is_user, int *code_out) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + int err = -EFAULT; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; + + *code_out = SEGV_MAPERR; + + /* + * If the fault was during atomic operation, don't take the fault, just + * fail. + */ + if (in_atomic()) + goto out_nosemaphore; + + if (is_user) + flags |= FAULT_FLAG_USER; +retry: + down_read(&mm->mmap_sem); + vma = find_vma(mm, address); + if (!vma) + goto out; + else if (vma->vm_start <= address) + goto good_area; + else if (!(vma->vm_flags & VM_GROWSDOWN)) + goto out; + else if (is_user && !ARCH_IS_STACKGROW(address)) + goto out; + else if (expand_stack(vma, address)) + goto out; + +good_area: + *code_out = SEGV_ACCERR; + if (is_write) { + if (!(vma->vm_flags & VM_WRITE)) + goto out; + flags |= FAULT_FLAG_WRITE; + } else { + /* Don't require VM_READ|VM_EXEC for write faults! */ + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto out; + } + + do { + int fault; + + fault = handle_mm_fault(mm, vma, address, flags); + + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + goto out_nosemaphore; + + if (unlikely(fault & VM_FAULT_ERROR)) { + if (fault & VM_FAULT_OOM) { + goto out_of_memory; + } else if (fault & VM_FAULT_SIGBUS) { + err = -EACCES; + goto out; + } + BUG(); + } + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) + current->maj_flt++; + else + current->min_flt++; + if (fault & VM_FAULT_RETRY) { + flags &= ~FAULT_FLAG_ALLOW_RETRY; + flags |= FAULT_FLAG_TRIED; + + goto retry; + } + } + + pgd = pgd_offset(mm, address); + pud = pud_offset(pgd, address); + pmd = pmd_offset(pud, address); + pte = pte_offset_kernel(pmd, address); + } while (!pte_present(*pte)); + err = 0; + /* + * The below warning was added in place of + * pte_mkyoung(); if (is_write) pte_mkdirty(); + * If it's triggered, we'd see normally a hang here (a clean pte is + * marked read-only to emulate the dirty bit). + * However, the generic code can mark a PTE writable but clean on a + * concurrent read fault, triggering this harmlessly. So comment it out. + */ +#if 0 + WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte))); +#endif + flush_tlb_page(vma, address); +out: + up_read(&mm->mmap_sem); +out_nosemaphore: + return err; + +out_of_memory: + /* + * We ran out of memory, call the OOM killer, and return the userspace + * (which will retry the fault, or kill us if we got oom-killed). + */ + up_read(&mm->mmap_sem); + if (!is_user) + goto out_nosemaphore; + pagefault_out_of_memory(); + return 0; +} +EXPORT_SYMBOL(handle_page_fault); + +static void show_segv_info(struct uml_pt_regs *regs) +{ + struct task_struct *tsk = current; + struct faultinfo *fi = UPT_FAULTINFO(regs); + + if (!unhandled_signal(tsk, SIGSEGV)) + return; + + if (!printk_ratelimit()) + return; + + printk("%s%s[%d]: segfault at %lx ip %p sp %p error %x", + task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, + tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi), + (void *)UPT_IP(regs), (void *)UPT_SP(regs), + fi->error_code); + + print_vma_addr(KERN_CONT " in ", UPT_IP(regs)); + printk(KERN_CONT "\n"); +} + +static void bad_segv(struct faultinfo fi, unsigned long ip) +{ + struct siginfo si; + + si.si_signo = SIGSEGV; + si.si_code = SEGV_ACCERR; + si.si_addr = (void __user *) FAULT_ADDRESS(fi); + current->thread.arch.faultinfo = fi; + force_sig_info(SIGSEGV, &si, current); +} + +void fatal_sigsegv(void) +{ + force_sigsegv(SIGSEGV, current); + do_signal(); + /* + * This is to tell gcc that we're not returning - do_signal + * can, in general, return, but in this case, it's not, since + * we just got a fatal SIGSEGV queued. + */ + os_dump_core(); +} + +void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) +{ + struct faultinfo * fi = UPT_FAULTINFO(regs); + + if (UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)) { + show_segv_info(regs); + bad_segv(*fi, UPT_IP(regs)); + return; + } + segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); +} + +/* + * We give a *copy* of the faultinfo in the regs to segv. + * This must be done, since nesting SEGVs could overwrite + * the info in the regs. A pointer to the info then would + * give us bad data! + */ +unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, + struct uml_pt_regs *regs) +{ + struct siginfo si; + jmp_buf *catcher; + int err; + int is_write = FAULT_WRITE(fi); + unsigned long address = FAULT_ADDRESS(fi); + + if (!is_user && regs) + current->thread.segv_regs = container_of(regs, struct pt_regs, regs); + + if (!is_user && (address >= start_vm) && (address < end_vm)) { + flush_tlb_kernel_vm(); + goto out; + } + else if (current->mm == NULL) { + show_regs(container_of(regs, struct pt_regs, regs)); + panic("Segfault with no mm"); + } + + if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi)) + err = handle_page_fault(address, ip, is_write, is_user, + &si.si_code); + else { + err = -EFAULT; + /* + * A thread accessed NULL, we get a fault, but CR2 is invalid. + * This code is used in __do_copy_from_user() of TT mode. + * XXX tt mode is gone, so maybe this isn't needed any more + */ + address = 0; + } + + catcher = current->thread.fault_catcher; + if (!err) + goto out; + else if (catcher != NULL) { + current->thread.fault_addr = (void *) address; + UML_LONGJMP(catcher, 1); + } + else if (current->thread.fault_addr != NULL) + panic("fault_addr set but no fault catcher"); + else if (!is_user && arch_fixup(ip, regs)) + goto out; + + if (!is_user) { + show_regs(container_of(regs, struct pt_regs, regs)); + panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", + address, ip); + } + + show_segv_info(regs); + + if (err == -EACCES) { + si.si_signo = SIGBUS; + si.si_errno = 0; + si.si_code = BUS_ADRERR; + si.si_addr = (void __user *)address; + current->thread.arch.faultinfo = fi; + force_sig_info(SIGBUS, &si, current); + } else { + BUG_ON(err != -EFAULT); + si.si_signo = SIGSEGV; + si.si_addr = (void __user *) address; + current->thread.arch.faultinfo = fi; + force_sig_info(SIGSEGV, &si, current); + } + +out: + if (regs) + current->thread.segv_regs = NULL; + + return 0; +} + +void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs) +{ + struct faultinfo *fi; + struct siginfo clean_si; + + if (!UPT_IS_USER(regs)) { + if (sig == SIGBUS) + printk(KERN_ERR "Bus error - the host /dev/shm or /tmp " + "mount likely just ran out of space\n"); + panic("Kernel mode signal %d", sig); + } + + arch_examine_signal(sig, regs); + + memset(&clean_si, 0, sizeof(clean_si)); + clean_si.si_signo = si->si_signo; + clean_si.si_errno = si->si_errno; + clean_si.si_code = si->si_code; + switch (sig) { + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGTRAP: + fi = UPT_FAULTINFO(regs); + clean_si.si_addr = (void __user *) FAULT_ADDRESS(*fi); + current->thread.arch.faultinfo = *fi; +#ifdef __ARCH_SI_TRAPNO + clean_si.si_trapno = si->si_trapno; +#endif + break; + default: + printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d)\n", + sig, si->si_code); + } + + force_sig_info(sig, &clean_si, current); +} + +void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs) +{ + if (current->thread.fault_catcher != NULL) + UML_LONGJMP(current->thread.fault_catcher, 1); + else + relay_signal(sig, si, regs); +} + +void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) +{ + do_IRQ(WINCH_IRQ, regs); +} + +void trap_init(void) +{ +} diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c deleted file mode 100644 index 95c8f8733ba..00000000000 --- a/arch/um/kernel/trap_kern.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/kernel.h" -#include "asm/errno.h" -#include "linux/sched.h" -#include "linux/mm.h" -#include "linux/spinlock.h" -#include "linux/config.h" -#include "linux/init.h" -#include "linux/ptrace.h" -#include "asm/semaphore.h" -#include "asm/pgtable.h" -#include "asm/pgalloc.h" -#include "asm/tlbflush.h" -#include "asm/a.out.h" -#include "asm/current.h" -#include "asm/irq.h" -#include "sysdep/sigcontext.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" -#include "chan_kern.h" -#include "mconsole_kern.h" -#include "mem.h" -#include "mem_kern.h" -#ifdef CONFIG_MODE_SKAS -#include "skas.h" -#endif - -/* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */ -int handle_page_fault(unsigned long address, unsigned long ip, - int is_write, int is_user, int *code_out) -{ - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - int err = -EFAULT; - - *code_out = SEGV_MAPERR; - - /* If the fault was during atomic operation, don't take the fault, just - * fail. */ - if (in_atomic()) - goto out_nosemaphore; - - down_read(&mm->mmap_sem); - vma = find_vma(mm, address); - if(!vma) - goto out; - else if(vma->vm_start <= address) - goto good_area; - else if(!(vma->vm_flags & VM_GROWSDOWN)) - goto out; - else if(is_user && !ARCH_IS_STACKGROW(address)) - goto out; - else if(expand_stack(vma, address)) - goto out; - -good_area: - *code_out = SEGV_ACCERR; - if(is_write && !(vma->vm_flags & VM_WRITE)) - goto out; - - /* Don't require VM_READ|VM_EXEC for write faults! */ - if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC))) - goto out; - - do { -survive: - switch (handle_mm_fault(mm, vma, address, is_write)){ - case VM_FAULT_MINOR: - current->min_flt++; - break; - case VM_FAULT_MAJOR: - current->maj_flt++; - break; - case VM_FAULT_SIGBUS: - err = -EACCES; - goto out; - case VM_FAULT_OOM: - err = -ENOMEM; - goto out_of_memory; - default: - BUG(); - } - pgd = pgd_offset(mm, address); - pud = pud_offset(pgd, address); - pmd = pmd_offset(pud, address); - pte = pte_offset_kernel(pmd, address); - } while(!pte_present(*pte)); - err = 0; - WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte))); - flush_tlb_page(vma, address); -out: - up_read(&mm->mmap_sem); -out_nosemaphore: - return(err); - -/* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ -out_of_memory: - if (current->pid == 1) { - up_read(&mm->mmap_sem); - yield(); - down_read(&mm->mmap_sem); - goto survive; - } - goto out; -} - -/* - * We give a *copy* of the faultinfo in the regs to segv. - * This must be done, since nesting SEGVs could overwrite - * the info in the regs. A pointer to the info then would - * give us bad data! - */ -unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) -{ - struct siginfo si; - void *catcher; - int err; - int is_write = FAULT_WRITE(fi); - unsigned long address = FAULT_ADDRESS(fi); - - if(!is_user && (address >= start_vm) && (address < end_vm)){ - flush_tlb_kernel_vm(); - return(0); - } - else if(current->mm == NULL) - panic("Segfault with no mm"); - - if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi)) - err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); - else { - err = -EFAULT; - /* A thread accessed NULL, we get a fault, but CR2 is invalid. - * This code is used in __do_copy_from_user() of TT mode. */ - address = 0; - } - - catcher = current->thread.fault_catcher; - if(!err) - return(0); - else if(catcher != NULL){ - current->thread.fault_addr = (void *) address; - do_longjmp(catcher, 1); - } - else if(current->thread.fault_addr != NULL) - panic("fault_addr set but no fault catcher"); - else if(!is_user && arch_fixup(ip, sc)) - return(0); - - if(!is_user) - panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", - address, ip); - - if (err == -EACCES) { - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRERR; - si.si_addr = (void *)address; - current->thread.arch.faultinfo = fi; - force_sig_info(SIGBUS, &si, current); - } else if (err == -ENOMEM) { - printk("VM: killing process %s\n", current->comm); - do_exit(SIGKILL); - } else { - BUG_ON(err != -EFAULT); - si.si_signo = SIGSEGV; - si.si_addr = (void *) address; - current->thread.arch.faultinfo = fi; - force_sig_info(SIGSEGV, &si, current); - } - return(0); -} - -void bad_segv(struct faultinfo fi, unsigned long ip) -{ - struct siginfo si; - - si.si_signo = SIGSEGV; - si.si_code = SEGV_ACCERR; - si.si_addr = (void *) FAULT_ADDRESS(fi); - current->thread.arch.faultinfo = fi; - force_sig_info(SIGSEGV, &si, current); -} - -void relay_signal(int sig, union uml_pt_regs *regs) -{ - if(arch_handle_signal(sig, regs)) return; - if(!UPT_IS_USER(regs)) - panic("Kernel mode signal %d", sig); - current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); - force_sig(sig, current); -} - -void bus_handler(int sig, union uml_pt_regs *regs) -{ - if(current->thread.fault_catcher != NULL) - do_longjmp(current->thread.fault_catcher, 1); - else relay_signal(sig, regs); -} - -void winch(int sig, union uml_pt_regs *regs) -{ - do_IRQ(WINCH_IRQ, regs); -} - -void trap_init(void) -{ -} diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c deleted file mode 100644 index e9ccd6b8d3c..00000000000 --- a/arch/um/kernel/trap_user.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdlib.h> -#include <errno.h> -#include <setjmp.h> -#include <signal.h> -#include <sys/time.h> -#include <sys/wait.h> -#include <asm/page.h> -#include <asm/unistd.h> -#include <asm/ptrace.h> -#include "init.h" -#include "sysdep/ptrace.h" -#include "sigcontext.h" -#include "sysdep/sigcontext.h" -#include "irq_user.h" -#include "signal_user.h" -#include "time_user.h" -#include "task.h" -#include "mode.h" -#include "choose-mode.h" -#include "kern_util.h" -#include "user_util.h" -#include "os.h" - -void kill_child_dead(int pid) -{ - kill(pid, SIGKILL); - kill(pid, SIGCONT); - do { - int n; - CATCH_EINTR(n = waitpid(pid, NULL, 0)); - if (n > 0) - kill(pid, SIGCONT); - else - break; - } while(1); -} - -void segv_handler(int sig, union uml_pt_regs *regs) -{ - struct faultinfo * fi = UPT_FAULTINFO(regs); - - if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){ - bad_segv(*fi, UPT_IP(regs)); - return; - } - segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); -} - -void usr2_handler(int sig, union uml_pt_regs *regs) -{ - CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); -} - -struct signal_info sig_info[] = { - [ SIGTRAP ] { .handler = relay_signal, - .is_irq = 0 }, - [ SIGFPE ] { .handler = relay_signal, - .is_irq = 0 }, - [ SIGILL ] { .handler = relay_signal, - .is_irq = 0 }, - [ SIGWINCH ] { .handler = winch, - .is_irq = 1 }, - [ SIGBUS ] { .handler = bus_handler, - .is_irq = 0 }, - [ SIGSEGV] { .handler = segv_handler, - .is_irq = 0 }, - [ SIGIO ] { .handler = sigio_handler, - .is_irq = 1 }, - [ SIGVTALRM ] { .handler = timer_handler, - .is_irq = 1 }, - [ SIGALRM ] { .handler = timer_handler, - .is_irq = 1 }, - [ SIGUSR2 ] { .handler = usr2_handler, - .is_irq = 0 }, -}; - -void do_longjmp(void *b, int val) -{ - sigjmp_buf *buf = b; - - siglongjmp(*buf, val); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile deleted file mode 100644 index 6939e5af847..00000000000 --- a/arch/um/kernel/tt/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) -# Licensed under the GPL -# - -obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \ - syscall_kern.o syscall_user.o tlb.o tracer.o trap_user.o \ - uaccess.o uaccess_user.o - -obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/ - -USER_OBJS := gdb.o tracer.o - -include arch/um/scripts/Makefile.rules diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c deleted file mode 100644 index 065b504a653..00000000000 --- a/arch/um/kernel/tt/exec_kern.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/kernel.h" -#include "linux/mm.h" -#include "asm/signal.h" -#include "asm/ptrace.h" -#include "asm/uaccess.h" -#include "asm/pgalloc.h" -#include "asm/tlbflush.h" -#include "user_util.h" -#include "kern_util.h" -#include "irq_user.h" -#include "time_user.h" -#include "signal_user.h" -#include "mem_user.h" -#include "os.h" -#include "tlb.h" -#include "mode.h" - -static int exec_tramp(void *sig_stack) -{ - init_new_thread_stack(sig_stack, NULL); - init_new_thread_signals(1); - os_stop_process(os_getpid()); - return(0); -} - -void flush_thread_tt(void) -{ - unsigned long stack; - int new_pid; - - stack = alloc_stack(0, 0); - if(stack == 0){ - printk(KERN_ERR - "flush_thread : failed to allocate temporary stack\n"); - do_exit(SIGKILL); - } - - new_pid = start_fork_tramp(current->thread_info, stack, 0, exec_tramp); - if(new_pid < 0){ - printk(KERN_ERR - "flush_thread : new thread failed, errno = %d\n", - -new_pid); - do_exit(SIGKILL); - } - - if(current_thread->cpu == 0) - forward_interrupts(new_pid); - current->thread.request.op = OP_EXEC; - current->thread.request.u.exec.pid = new_pid; - unprotect_stack((unsigned long) current_thread); - os_usr1_process(os_getpid()); - change_sig(SIGUSR1, 1); - - change_sig(SIGUSR1, 0); - enable_timer(); - free_page(stack); - protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current_thread); - force_flush_all(); - unblock_signals(); -} - -void start_thread_tt(struct pt_regs *regs, unsigned long eip, - unsigned long esp) -{ - set_fs(USER_DS); - flush_tlb_mm(current->mm); - PT_REGS_IP(regs) = eip; - PT_REGS_SP(regs) = esp; - PT_FIX_EXEC_STACK(esp); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c deleted file mode 100644 index a92c02ff2ce..00000000000 --- a/arch/um/kernel/tt/exec_user.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <sched.h> -#include <errno.h> -#include <sys/wait.h> -#include <signal.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "ptrace_user.h" -#include "os.h" - -void do_exec(int old_pid, int new_pid) -{ - unsigned long regs[FRAME_SIZE]; - int err; - - if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || - (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0)) - tracer_panic("do_exec failed to attach proc - errno = %d", - errno); - - CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED)); - if (err < 0) - tracer_panic("do_exec failed to attach proc in waitpid - errno = %d", - errno); - - if(ptrace_getregs(old_pid, regs) < 0) - tracer_panic("do_exec failed to get registers - errno = %d", - errno); - - os_kill_ptraced_process(old_pid, 0); - - if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) - tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno); - - if(ptrace_setregs(new_pid, regs) < 0) - tracer_panic("do_exec failed to start new proc - errno = %d", - errno); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c deleted file mode 100644 index 37e22d71a0d..00000000000 --- a/arch/um/kernel/tt/gdb.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include <sys/types.h> -#include "ptrace_user.h" -#include "uml-config.h" -#include "kern_constants.h" -#include "chan_user.h" -#include "init.h" -#include "user.h" -#include "debug.h" -#include "kern_util.h" -#include "user_util.h" -#include "tt.h" -#include "sysdep/thread.h" - -extern int debugger_pid; -extern int debugger_fd; -extern int debugger_parent; - -int detach(int pid, int sig) -{ - return(ptrace(PTRACE_DETACH, pid, 0, sig)); -} - -int attach(int pid) -{ - int err; - - err = ptrace(PTRACE_ATTACH, pid, 0, 0); - if(err < 0) return(-errno); - else return(err); -} - -int cont(int pid) -{ - return(ptrace(PTRACE_CONT, pid, 0, 0)); -} - -#ifdef UML_CONFIG_PT_PROXY - -int debugger_signal(int status, pid_t pid) -{ - return(debugger_proxy(status, pid)); -} - -void child_signal(pid_t pid, int status) -{ - child_proxy(pid, status); -} - -static void gdb_announce(char *dev_name, int dev) -{ - printf("gdb assigned device '%s'\n", dev_name); -} - -static struct chan_opts opts = { - .announce = gdb_announce, - .xterm_title = "UML kernel debugger", - .raw = 0, - .tramp_stack = 0, - .in_kernel = 0, -}; - -/* Accessed by the tracing thread, which automatically serializes access */ -static void *xterm_data; -static int xterm_fd; - -extern void *xterm_init(char *, int, struct chan_opts *); -extern int xterm_open(int, int, int, void *, char **); -extern void xterm_close(int, void *); - -int open_gdb_chan(void) -{ - char stack[UM_KERN_PAGE_SIZE], *dummy; - - opts.tramp_stack = (unsigned long) stack; - xterm_data = xterm_init("", 0, &opts); - xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy); - return(xterm_fd); -} - -static void exit_debugger_cb(void *unused) -{ - if(debugger_pid != -1){ - if(gdb_pid != -1){ - fake_child_exit(); - gdb_pid = -1; - } - else kill_child_dead(debugger_pid); - debugger_pid = -1; - if(debugger_parent != -1) - detach(debugger_parent, SIGINT); - } - if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data); -} - -static void exit_debugger(void) -{ - initial_thread_cb(exit_debugger_cb, NULL); -} - -__uml_exitcall(exit_debugger); - -struct gdb_data { - char *str; - int err; -}; - -static void config_gdb_cb(void *arg) -{ - struct gdb_data *data = arg; - void *task; - int pid; - - data->err = -1; - if(debugger_pid != -1) exit_debugger_cb(NULL); - if(!strncmp(data->str, "pid,", strlen("pid,"))){ - data->str += strlen("pid,"); - pid = strtoul(data->str, NULL, 0); - task = cpu_tasks[0].task; - debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0); - if(debugger_pid != -1){ - data->err = 0; - gdb_pid = pid; - } - return; - } - data->err = 0; - debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); - init_proxy(debugger_pid, 0, 0); -} - -int gdb_config(char *str) -{ - struct gdb_data data; - - if(*str++ != '=') return(-1); - data.str = str; - initial_thread_cb(config_gdb_cb, &data); - return(data.err); -} - -void remove_gdb_cb(void *unused) -{ - exit_debugger_cb(NULL); -} - -int gdb_remove(int unused) -{ - initial_thread_cb(remove_gdb_cb, NULL); - return 0; -} - -void signal_usr1(int sig) -{ - if(debugger_pid != -1){ - printf("The debugger is already running\n"); - return; - } - debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); - init_proxy(debugger_pid, 0, 0); -} - -int init_ptrace_proxy(int idle_pid, int startup, int stop) -{ - int pid, status; - - pid = start_debugger(linux_prog, startup, stop, &debugger_fd); - status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); - if(pid < 0){ - cont(idle_pid); - return(-1); - } - init_proxy(pid, 1, status); - return(pid); -} - -int attach_debugger(int idle_pid, int pid, int stop) -{ - int status = 0, err; - - err = attach(pid); - if(err < 0){ - printf("Failed to attach pid %d, errno = %d\n", pid, -err); - return(-1); - } - if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); - init_proxy(pid, 1, status); - return(pid); -} - -#ifdef notdef /* Put this back in when it does something useful */ -static int __init uml_gdb_init_setup(char *line, int *add) -{ - gdb_init = uml_strdup(line); - return 0; -} - -__uml_setup("gdb=", uml_gdb_init_setup, -"gdb=<channel description>\n\n" -); -#endif - -static int __init uml_gdb_pid_setup(char *line, int *add) -{ - gdb_pid = strtoul(line, NULL, 0); - *add = 0; - return 0; -} - -__uml_setup("gdb-pid=", uml_gdb_pid_setup, -"gdb-pid=<pid>\n" -" gdb-pid is used to attach an external debugger to UML. This may be\n" -" an already-running gdb or a debugger-like process like strace.\n\n" -); - -#else - -int debugger_signal(int status, pid_t pid){ return(0); } -void child_signal(pid_t pid, int status){ } -int init_ptrace_proxy(int idle_pid, int startup, int stop) -{ - printf("debug requested when CONFIG_PT_PROXY is off\n"); - kill_child_dead(idle_pid); - exit(1); -} - -void signal_usr1(int sig) -{ - printf("debug requested when CONFIG_PT_PROXY is off\n"); -} - -int attach_debugger(int idle_pid, int pid, int stop) -{ - printf("attach_debugger called when CONFIG_PT_PROXY " - "is off\n"); - return(-1); -} - -int config_gdb(char *str) -{ - return(-1); -} - -int remove_gdb(void) -{ - return(-1); -} - -int init_parent_proxy(int pid) -{ - return(-1); -} - -void debugger_parent_signal(int status, int pid) -{ -} - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c deleted file mode 100644 index 26506388a6a..00000000000 --- a/arch/um/kernel/tt/gdb_kern.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/init.h" -#include "linux/config.h" -#include "mconsole_kern.h" - -#ifdef CONFIG_MCONSOLE - -extern int gdb_config(char *str); -extern int gdb_remove(int n); - -static struct mc_device gdb_mc = { - .name = "gdb", - .config = gdb_config, - .remove = gdb_remove, -}; - -int gdb_mc_init(void) -{ - mconsole_register_dev(&gdb_mc); - return(0); -} - -__initcall(gdb_mc_init); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h deleted file mode 100644 index 738435461e1..00000000000 --- a/arch/um/kernel/tt/include/debug.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and - * Lars Brinkhoff. - * Licensed under the GPL - */ - -#ifndef __UML_TT_DEBUG_H -#define __UML_TT_DEBUG_H - -extern int debugger_proxy(int status, pid_t pid); -extern void child_proxy(pid_t pid, int status); -extern void init_proxy (pid_t pid, int waiting, int status); -extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); -extern void fake_child_exit(void); -extern int gdb_config(char *str); -extern int gdb_remove(int unused); - -#endif diff --git a/arch/um/kernel/tt/include/mmu-tt.h b/arch/um/kernel/tt/include/mmu-tt.h deleted file mode 100644 index 0440510ab3f..00000000000 --- a/arch/um/kernel/tt/include/mmu-tt.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __TT_MMU_H -#define __TT_MMU_H - -struct mmu_context_tt { -}; - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/include/mode-tt.h b/arch/um/kernel/tt/include/mode-tt.h deleted file mode 100644 index e171e15fead..00000000000 --- a/arch/um/kernel/tt/include/mode-tt.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __MODE_TT_H__ -#define __MODE_TT_H__ - -#include "sysdep/ptrace.h" - -enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; - -extern int tracing_pid; - -extern int tracer(int (*init_proc)(void *), void *sp); -extern void sig_handler_common_tt(int sig, void *sc); -extern void syscall_handler_tt(int sig, union uml_pt_regs *regs); -extern void reboot_tt(void); -extern void halt_tt(void); -extern int is_tracer_winch(int pid, int fd, void *data); -extern void kill_off_processes_tt(void); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h deleted file mode 100644 index 2a35b15c5fe..00000000000 --- a/arch/um/kernel/tt/include/mode_kern-tt.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __TT_MODE_KERN_H__ -#define __TT_MODE_KERN_H__ - -#include "linux/sched.h" -#include "asm/page.h" -#include "asm/ptrace.h" -#include "asm/uaccess.h" - -extern void switch_to_tt(void *prev, void *next); -extern void flush_thread_tt(void); -extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, - unsigned long esp); -extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, - unsigned long stack_top, struct task_struct *p, - struct pt_regs *regs); -extern void release_thread_tt(struct task_struct *task); -extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); -extern void init_idle_tt(void); -extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end); -extern void flush_tlb_kernel_vm_tt(void); -extern void __flush_tlb_one_tt(unsigned long addr); -extern void flush_tlb_range_tt(struct vm_area_struct *vma, - unsigned long start, unsigned long end); -extern void flush_tlb_mm_tt(struct mm_struct *mm); -extern void force_flush_all_tt(void); -extern long execute_syscall_tt(void *r); -extern void before_mem_tt(unsigned long brk_start); -extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, - unsigned long *task_size_out); -extern int start_uml_tt(void); -extern int external_pid_tt(struct task_struct *task); -extern int thread_pid_tt(struct task_struct *task); - -#define kmem_end_tt (host_task_size - ABOVE_KMEM) - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/include/tt.h b/arch/um/kernel/tt/include/tt.h deleted file mode 100644 index c667b67af40..00000000000 --- a/arch/um/kernel/tt/include/tt.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __TT_H__ -#define __TT_H__ - -#include "sysdep/ptrace.h" - -extern int gdb_pid; -extern int debug; -extern int debug_stop; -extern int debug_trace; - -extern int honeypot; - -extern int fork_tramp(void *sig_stack); -extern int do_proc_op(void *t, int proc_id); -extern int tracer(int (*init_proc)(void *), void *sp); -extern void attach_process(int pid); -extern void tracer_panic(char *format, ...); -extern void set_init_pid(int pid); -extern int set_user_mode(void *task); -extern void set_tracing(void *t, int tracing); -extern int is_tracing(void *task); -extern void syscall_handler(int sig, union uml_pt_regs *regs); -extern void exit_kernel(int pid, void *task); -extern void do_syscall(void *task, int pid, int local_using_sysemu); -extern void do_sigtrap(void *task); -extern int is_valid_pid(int pid); -extern void remap_data(void *segment_start, void *segment_end, int w); -extern long execute_syscall_tt(void *r); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h deleted file mode 100644 index dc2ebfa8c54..00000000000 --- a/arch/um/kernel/tt/include/uaccess-tt.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#ifndef __TT_UACCESS_H -#define __TT_UACCESS_H - -#include "linux/string.h" -#include "linux/sched.h" -#include "asm/processor.h" -#include "asm/errno.h" -#include "asm/current.h" -#include "asm/a.out.h" -#include "uml_uaccess.h" - -#define ABOVE_KMEM (16 * 1024 * 1024) - -extern unsigned long end_vm; -extern unsigned long uml_physmem; - -#define under_task_size(addr, size) \ - (((unsigned long) (addr) < TASK_SIZE) && \ - (((unsigned long) (addr) + (size)) < TASK_SIZE)) - -#define is_stack(addr, size) \ - (((unsigned long) (addr) < STACK_TOP) && \ - ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \ - (((unsigned long) (addr) + (size)) <= STACK_TOP)) - -#define access_ok_tt(type, addr, size) \ - ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \ - (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ - (under_task_size(addr, size) || is_stack(addr, size)))) - -extern unsigned long get_fault_addr(void); - -extern int __do_copy_from_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher); -extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, - void **fault_addr, void **fault_catcher); -extern int __do_clear_user(void *mem, size_t len, void **fault_addr, - void **fault_catcher); -extern int __do_strnlen_user(const char *str, unsigned long n, - void **fault_addr, void **fault_catcher); - -extern int copy_from_user_tt(void *to, const void __user *from, int n); -extern int copy_to_user_tt(void __user *to, const void *from, int n); -extern int strncpy_from_user_tt(char *dst, const char __user *src, int count); -extern int __clear_user_tt(void __user *mem, int len); -extern int clear_user_tt(void __user *mem, int len); -extern int strnlen_user_tt(const void __user *str, int len); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c deleted file mode 100644 index 84a9385a8fe..00000000000 --- a/arch/um/kernel/tt/ksyms.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/module.h" -#include "asm/uaccess.h" -#include "mode.h" - -EXPORT_SYMBOL(__do_copy_from_user); -EXPORT_SYMBOL(__do_copy_to_user); -EXPORT_SYMBOL(__do_strncpy_from_user); -EXPORT_SYMBOL(__do_strnlen_user); -EXPORT_SYMBOL(__do_clear_user); -EXPORT_SYMBOL(clear_user_tt); - -EXPORT_SYMBOL(tracing_pid); -EXPORT_SYMBOL(honeypot); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c deleted file mode 100644 index bcb8796c3cb..00000000000 --- a/arch/um/kernel/tt/mem.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/stddef.h" -#include "linux/config.h" -#include "linux/mm.h" -#include "asm/uaccess.h" -#include "mem_user.h" -#include "kern_util.h" -#include "user_util.h" -#include "kern.h" -#include "tt.h" - -void before_mem_tt(unsigned long brk_start) -{ - if(debug) - remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1); - remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1); - remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1); -} - -#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) -#define START (CONFIG_TOP_ADDR - SIZE) - -unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, - unsigned long *task_size_out) -{ - /* Round up to the nearest 4M */ - *host_size_out = ROUND_4M((unsigned long) &arg); - *task_size_out = START; - return(START); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c deleted file mode 100644 index 03e58989538..00000000000 --- a/arch/um/kernel/tt/mem_user.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <sys/mman.h> -#include "tt.h" -#include "mem_user.h" -#include "user_util.h" -#include "os.h" - -void remap_data(void *segment_start, void *segment_end, int w) -{ - void *addr; - unsigned long size; - int data, prot; - - if(w) prot = PROT_WRITE; - else prot = 0; - prot |= PROT_READ | PROT_EXEC; - size = (unsigned long) segment_end - - (unsigned long) segment_start; - data = create_mem_file(size); - addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0); - if(addr == MAP_FAILED){ - perror("mapping new data segment"); - exit(1); - } - memcpy(addr, segment_start, size); - if(switcheroo(data, prot, addr, segment_start, size) < 0){ - printf("switcheroo failed\n"); - exit(1); - } -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c deleted file mode 100644 index cfaa373a6e7..00000000000 --- a/arch/um/kernel/tt/process_kern.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "linux/signal.h" -#include "linux/kernel.h" -#include "linux/interrupt.h" -#include "linux/ptrace.h" -#include "asm/system.h" -#include "asm/pgalloc.h" -#include "asm/ptrace.h" -#include "asm/tlbflush.h" -#include "irq_user.h" -#include "signal_user.h" -#include "kern_util.h" -#include "user_util.h" -#include "os.h" -#include "kern.h" -#include "sigcontext.h" -#include "time_user.h" -#include "mem_user.h" -#include "tlb.h" -#include "mode.h" -#include "mode_kern.h" -#include "init.h" -#include "tt.h" - -void switch_to_tt(void *prev, void *next) -{ - struct task_struct *from, *to, *prev_sched; - unsigned long flags; - int err, vtalrm, alrm, prof, cpu; - char c; - - from = prev; - to = next; - - cpu = from->thread_info->cpu; - if(cpu == 0) - forward_interrupts(to->thread.mode.tt.extern_pid); -#ifdef CONFIG_SMP - forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid); -#endif - local_irq_save(flags); - - vtalrm = change_sig(SIGVTALRM, 0); - alrm = change_sig(SIGALRM, 0); - prof = change_sig(SIGPROF, 0); - - forward_pending_sigio(to->thread.mode.tt.extern_pid); - - c = 0; - - err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); - if(err != sizeof(c)) - panic("write of switch_pipe failed, err = %d", -err); - - if(from->thread.mode.tt.switch_pipe[0] == -1) - os_kill_process(os_getpid(), 0); - - err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); - if(err != sizeof(c)) - panic("read of switch_pipe failed, errno = %d", -err); - - /* If the process that we have just scheduled away from has exited, - * then it needs to be killed here. The reason is that, even though - * it will kill itself when it next runs, that may be too late. Its - * stack will be freed, possibly before then, and if that happens, - * we have a use-after-free situation. So, it gets killed here - * in case it has not already killed itself. - */ - prev_sched = current->thread.prev_sched; - if(prev_sched->thread.mode.tt.switch_pipe[0] == -1) - os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); - - change_sig(SIGVTALRM, vtalrm); - change_sig(SIGALRM, alrm); - change_sig(SIGPROF, prof); - - arch_switch(); - - flush_tlb_all(); - local_irq_restore(flags); -} - -void release_thread_tt(struct task_struct *task) -{ - int pid = task->thread.mode.tt.extern_pid; - - /* - * We first have to kill the other process, before - * closing its switch_pipe. Else it might wake up - * and receive "EOF" before we could kill it. - */ - if(os_getpid() != pid) - os_kill_process(pid, 0); - - os_close_file(task->thread.mode.tt.switch_pipe[0]); - os_close_file(task->thread.mode.tt.switch_pipe[1]); - /* use switch_pipe as flag: thread is released */ - task->thread.mode.tt.switch_pipe[0] = -1; -} - -void suspend_new_thread(int fd) -{ - int err; - char c; - - os_stop_process(os_getpid()); - err = os_read_file(fd, &c, sizeof(c)); - if(err != sizeof(c)) - panic("read failed in suspend_new_thread, err = %d", -err); -} - -void schedule_tail(task_t *prev); - -static void new_thread_handler(int sig) -{ - unsigned long disable; - int (*fn)(void *); - void *arg; - - fn = current->thread.request.u.thread.proc; - arg = current->thread.request.u.thread.arg; - - UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); - disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) | - (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1)); - SC_SIGMASK(UPT_SC(¤t->thread.regs.regs)) &= ~disable; - - suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); - - force_flush_all(); - if(current->thread.prev_sched != NULL) - schedule_tail(current->thread.prev_sched); - current->thread.prev_sched = NULL; - - init_new_thread_signals(1); - enable_timer(); - free_page(current->thread.temp_stack); - set_cmdline("(kernel thread)"); - - change_sig(SIGUSR1, 1); - change_sig(SIGVTALRM, 1); - change_sig(SIGPROF, 1); - local_irq_enable(); - if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) - do_exit(0); - - /* XXX No set_user_mode here because a newly execed process will - * immediately segfault on its non-existent IP, coming straight back - * to the signal handler, which will call set_user_mode on its way - * out. This should probably change since it's confusing. - */ -} - -static int new_thread_proc(void *stack) -{ - /* local_irq_disable is needed to block out signals until this thread is - * properly scheduled. Otherwise, the tracing thread will get mighty - * upset about any signals that arrive before that. - * This has the complication that it sets the saved signal mask in - * the sigcontext to block signals. This gets restored when this - * thread (or a descendant, since they get a copy of this sigcontext) - * returns to userspace. - * So, this is compensated for elsewhere. - * XXX There is still a small window until local_irq_disable() actually - * finishes where signals are possible - shouldn't be a problem in - * practice since SIGIO hasn't been forwarded here yet, and the - * local_irq_disable should finish before a SIGVTALRM has time to be - * delivered. - */ - - local_irq_disable(); - init_new_thread_stack(stack, new_thread_handler); - os_usr1_process(os_getpid()); - change_sig(SIGUSR1, 1); - return(0); -} - -/* Signal masking - signals are blocked at the start of fork_tramp. They - * are re-enabled when finish_fork_handler is entered by fork_tramp hitting - * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off, - * so it is blocked before it's called. They are re-enabled on sigreturn - * despite the fact that they were blocked when the SIGUSR1 was issued because - * copy_thread copies the parent's sigcontext, including the signal mask - * onto the signal frame. - */ - -void finish_fork_handler(int sig) -{ - UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); - suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); - - force_flush_all(); - if(current->thread.prev_sched != NULL) - schedule_tail(current->thread.prev_sched); - current->thread.prev_sched = NULL; - - enable_timer(); - change_sig(SIGVTALRM, 1); - local_irq_enable(); - if(current->mm != current->parent->mm) - protect_memory(uml_reserved, high_physmem - uml_reserved, 1, - 1, 0, 1); - task_protections((unsigned long) current_thread); - - free_page(current->thread.temp_stack); - local_irq_disable(); - change_sig(SIGUSR1, 0); - set_user_mode(current); -} - -int fork_tramp(void *stack) -{ - local_irq_disable(); - arch_init_thread(); - init_new_thread_stack(stack, finish_fork_handler); - - os_usr1_process(os_getpid()); - change_sig(SIGUSR1, 1); - return(0); -} - -int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, - unsigned long stack_top, struct task_struct * p, - struct pt_regs *regs) -{ - int (*tramp)(void *); - int new_pid, err; - unsigned long stack; - - if(current->thread.forking) - tramp = fork_tramp; - else { - tramp = new_thread_proc; - p->thread.request.u.thread = current->thread.request.u.thread; - } - - err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1); - if(err < 0){ - printk("copy_thread : pipe failed, err = %d\n", -err); - return(err); - } - - stack = alloc_stack(0, 0); - if(stack == 0){ - printk(KERN_ERR "copy_thread : failed to allocate " - "temporary stack\n"); - return(-ENOMEM); - } - - clone_flags &= CLONE_VM; - p->thread.temp_stack = stack; - new_pid = start_fork_tramp(p->thread_info, stack, clone_flags, tramp); - if(new_pid < 0){ - printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", - -new_pid); - return(new_pid); - } - - if(current->thread.forking){ - sc_to_sc(UPT_SC(&p->thread.regs.regs), UPT_SC(®s->regs)); - SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0); - if(sp != 0) - SC_SP(UPT_SC(&p->thread.regs.regs)) = sp; - } - p->thread.mode.tt.extern_pid = new_pid; - - current->thread.request.op = OP_FORK; - current->thread.request.u.fork.pid = new_pid; - os_usr1_process(os_getpid()); - - /* Enable the signal and then disable it to ensure that it is handled - * here, and nowhere else. - */ - change_sig(SIGUSR1, 1); - - change_sig(SIGUSR1, 0); - err = 0; - return(err); -} - -void reboot_tt(void) -{ - current->thread.request.op = OP_REBOOT; - os_usr1_process(os_getpid()); - change_sig(SIGUSR1, 1); -} - -void halt_tt(void) -{ - current->thread.request.op = OP_HALT; - os_usr1_process(os_getpid()); - change_sig(SIGUSR1, 1); -} - -void kill_off_processes_tt(void) -{ - struct task_struct *p; - int me; - - me = os_getpid(); - for_each_process(p){ - if(p->thread.mode.tt.extern_pid != me) - os_kill_process(p->thread.mode.tt.extern_pid, 0); - } - if(init_task.thread.mode.tt.extern_pid != me) - os_kill_process(init_task.thread.mode.tt.extern_pid, 0); -} - -void initial_thread_cb_tt(void (*proc)(void *), void *arg) -{ - if(os_getpid() == tracing_pid){ - (*proc)(arg); - } - else { - current->thread.request.op = OP_CB; - current->thread.request.u.cb.proc = proc; - current->thread.request.u.cb.arg = arg; - os_usr1_process(os_getpid()); - change_sig(SIGUSR1, 1); - - change_sig(SIGUSR1, 0); - } -} - -int do_proc_op(void *t, int proc_id) -{ - struct task_struct *task; - struct thread_struct *thread; - int op, pid; - - task = t; - thread = &task->thread; - op = thread->request.op; - switch(op){ - case OP_NONE: - case OP_TRACE_ON: - break; - case OP_EXEC: - pid = thread->request.u.exec.pid; - do_exec(thread->mode.tt.extern_pid, pid); - thread->mode.tt.extern_pid = pid; - cpu_tasks[task->thread_info->cpu].pid = pid; - break; - case OP_FORK: - attach_process(thread->request.u.fork.pid); - break; - case OP_CB: - (*thread->request.u.cb.proc)(thread->request.u.cb.arg); - break; - case OP_REBOOT: - case OP_HALT: - break; - default: - tracer_panic("Bad op in do_proc_op"); - break; - } - thread->request.op = OP_NONE; - return(op); -} - -void init_idle_tt(void) -{ - default_idle(); -} - -extern void start_kernel(void); - -static int start_kernel_proc(void *unused) -{ - int pid; - - block_signals(); - pid = os_getpid(); - - cpu_tasks[0].pid = pid; - cpu_tasks[0].task = current; -#ifdef CONFIG_SMP - cpu_online_map = cpumask_of_cpu(0); -#endif - if(debug) os_stop_process(pid); - start_kernel(); - return(0); -} - -void set_tracing(void *task, int tracing) -{ - ((struct task_struct *) task)->thread.mode.tt.tracing = tracing; -} - -int is_tracing(void *t) -{ - return (((struct task_struct *) t)->thread.mode.tt.tracing); -} - -int set_user_mode(void *t) -{ - struct task_struct *task; - - task = t ? t : current; - if(task->thread.mode.tt.tracing) - return(1); - task->thread.request.op = OP_TRACE_ON; - os_usr1_process(os_getpid()); - return(0); -} - -void set_init_pid(int pid) -{ - int err; - - init_task.thread.mode.tt.extern_pid = pid; - err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1); - if(err) - panic("Can't create switch pipe for init_task, errno = %d", - -err); -} - -int start_uml_tt(void) -{ - void *sp; - int pages; - - pages = (1 << CONFIG_KERNEL_STACK_ORDER); - sp = (void *) ((unsigned long) init_task.thread_info) + - pages * PAGE_SIZE - sizeof(unsigned long); - return(tracer(start_kernel_proc, sp)); -} - -int external_pid_tt(struct task_struct *task) -{ - return(task->thread.mode.tt.extern_pid); -} - -int thread_pid_tt(struct task_struct *task) -{ - return(task->thread.mode.tt.extern_pid); -} - -int is_valid_pid(int pid) -{ - struct task_struct *task; - - read_lock(&tasklist_lock); - for_each_process(task){ - if(task->thread.mode.tt.extern_pid == pid){ - read_unlock(&tasklist_lock); - return(1); - } - } - read_unlock(&tasklist_lock); - return(0); -} diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile deleted file mode 100644 index 3ad5b774de5..00000000000 --- a/arch/um/kernel/tt/ptproxy/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) -# Licensed under the GPL -# - -obj-y = proxy.o ptrace.o sysdep.o wait.o - -USER_OBJS := $(obj-y) - -include arch/um/scripts/Makefile.rules diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c deleted file mode 100644 index 58800c50b10..00000000000 --- a/arch/um/kernel/tt/ptproxy/proxy.c +++ /dev/null @@ -1,377 +0,0 @@ -/********************************************************************** -proxy.c - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. - -Jeff Dike (jdike@karaya.com) : Modified for integration into uml -**********************************************************************/ - -/* XXX This file shouldn't refer to CONFIG_* */ - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <signal.h> -#include <string.h> -#include <termios.h> -#include <sys/wait.h> -#include <sys/types.h> -#include <sys/ioctl.h> -#include <asm/unistd.h> -#include "ptrace_user.h" - -#include "ptproxy.h" -#include "sysdep.h" -#include "wait.h" - -#include "user_util.h" -#include "user.h" -#include "os.h" -#include "tempfile.h" - -static int debugger_wait(debugger_state *debugger, int *status, int options, - int (*syscall)(debugger_state *debugger, pid_t child), - int (*normal_return)(debugger_state *debugger, - pid_t unused), - int (*wait_return)(debugger_state *debugger, - pid_t unused)) -{ - if(debugger->real_wait){ - debugger->handle_trace = normal_return; - syscall_continue(debugger->pid); - debugger->real_wait = 0; - return(1); - } - debugger->wait_status_ptr = status; - debugger->wait_options = options; - if((debugger->debugee != NULL) && debugger->debugee->event){ - syscall_continue(debugger->pid); - wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL, - NULL); - (*wait_return)(debugger, -1); - return(0); - } - else if(debugger->wait_options & WNOHANG){ - syscall_cancel(debugger->pid, 0); - debugger->handle_trace = syscall; - return(0); - } - else { - syscall_pause(debugger->pid); - debugger->handle_trace = wait_return; - debugger->waiting = 1; - } - return(1); -} - -/* - * Handle debugger trap, i.e. syscall. - */ - -int debugger_syscall(debugger_state *debugger, pid_t child) -{ - long arg1, arg2, arg3, arg4, arg5, result; - int syscall, ret = 0; - - syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4, - &arg5); - - switch(syscall){ - case __NR_execve: - /* execve never returns */ - debugger->handle_trace = debugger_syscall; - break; - - case __NR_ptrace: - if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid; - if(!debugger->debugee->in_context) - child = debugger->debugee->pid; - result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child, - &ret); - syscall_cancel(debugger->pid, result); - debugger->handle_trace = debugger_syscall; - return(ret); - -#ifdef __NR_waitpid - case __NR_waitpid: -#endif - case __NR_wait4: - if(!debugger_wait(debugger, (int *) arg2, arg3, - debugger_syscall, debugger_normal_return, - proxy_wait_return)) - return(0); - break; - - case __NR_kill: - if(!debugger->debugee->in_context) - child = debugger->debugee->pid; - if(arg1 == debugger->debugee->pid){ - result = kill(child, arg2); - syscall_cancel(debugger->pid, result); - debugger->handle_trace = debugger_syscall; - return(0); - } - else debugger->handle_trace = debugger_normal_return; - break; - - default: - debugger->handle_trace = debugger_normal_return; - } - - syscall_continue(debugger->pid); - return(0); -} - -/* Used by the tracing thread */ -static debugger_state parent; -static int parent_syscall(debugger_state *debugger, int pid); - -int init_parent_proxy(int pid) -{ - parent = ((debugger_state) { .pid = pid, - .wait_options = 0, - .wait_status_ptr = NULL, - .waiting = 0, - .real_wait = 0, - .expecting_child = 0, - .handle_trace = parent_syscall, - .debugee = NULL } ); - return(0); -} - -int parent_normal_return(debugger_state *debugger, pid_t unused) -{ - debugger->handle_trace = parent_syscall; - syscall_continue(debugger->pid); - return(0); -} - -static int parent_syscall(debugger_state *debugger, int pid) -{ - long arg1, arg2, arg3, arg4, arg5; - int syscall; - - syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5); - - if((syscall == __NR_wait4) -#ifdef __NR_waitpid - || (syscall == __NR_waitpid) -#endif - ){ - debugger_wait(&parent, (int *) arg2, arg3, parent_syscall, - parent_normal_return, parent_wait_return); - } - else ptrace(PTRACE_SYSCALL, pid, 0, 0); - return(0); -} - -int debugger_normal_return(debugger_state *debugger, pid_t unused) -{ - debugger->handle_trace = debugger_syscall; - syscall_continue(debugger->pid); - return(0); -} - -void debugger_cancelled_return(debugger_state *debugger, int result) -{ - debugger->handle_trace = debugger_syscall; - syscall_set_result(debugger->pid, result); - syscall_continue(debugger->pid); -} - -/* Used by the tracing thread */ -static debugger_state debugger; -static debugee_state debugee; - -void init_proxy (pid_t debugger_pid, int stopped, int status) -{ - debugger.pid = debugger_pid; - debugger.handle_trace = debugger_syscall; - debugger.debugee = &debugee; - debugger.waiting = 0; - debugger.real_wait = 0; - debugger.expecting_child = 0; - - debugee.pid = 0; - debugee.traced = 0; - debugee.stopped = stopped; - debugee.event = 0; - debugee.zombie = 0; - debugee.died = 0; - debugee.wait_status = status; - debugee.in_context = 1; -} - -int debugger_proxy(int status, int pid) -{ - int ret = 0, sig; - - if(WIFSTOPPED(status)){ - sig = WSTOPSIG(status); - if (sig == SIGTRAP) - ret = (*debugger.handle_trace)(&debugger, pid); - - else if(sig == SIGCHLD){ - if(debugger.expecting_child){ - ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); - debugger.expecting_child = 0; - } - else if(debugger.waiting) - real_wait_return(&debugger); - else { - ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); - debugger.real_wait = 1; - } - } - else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); - } - else if(WIFEXITED(status)){ - tracer_panic("debugger (pid %d) exited with status %d", - debugger.pid, WEXITSTATUS(status)); - } - else if(WIFSIGNALED(status)){ - tracer_panic("debugger (pid %d) exited with signal %d", - debugger.pid, WTERMSIG(status)); - } - else { - tracer_panic("proxy got unknown status (0x%x) on debugger " - "(pid %d)", status, debugger.pid); - } - return(ret); -} - -void child_proxy(pid_t pid, int status) -{ - debugee.event = 1; - debugee.wait_status = status; - - if(WIFSTOPPED(status)){ - debugee.stopped = 1; - debugger.expecting_child = 1; - kill(debugger.pid, SIGCHLD); - } - else if(WIFEXITED(status) || WIFSIGNALED(status)){ - debugee.zombie = 1; - debugger.expecting_child = 1; - kill(debugger.pid, SIGCHLD); - } - else panic("proxy got unknown status (0x%x) on child (pid %d)", - status, pid); -} - -void debugger_parent_signal(int status, int pid) -{ - int sig; - - if(WIFSTOPPED(status)){ - sig = WSTOPSIG(status); - if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid); - else ptrace(PTRACE_SYSCALL, pid, 0, sig); - } -} - -void fake_child_exit(void) -{ - int status, pid; - - child_proxy(1, W_EXITCODE(0, 0)); - while(debugger.waiting == 1){ - CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); - if(pid != debugger.pid){ - printk("fake_child_exit - waitpid failed, " - "errno = %d\n", errno); - return; - } - debugger_proxy(status, debugger.pid); - } - CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); - if(pid != debugger.pid){ - printk("fake_child_exit - waitpid failed, " - "errno = %d\n", errno); - return; - } - if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0) - printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n", - errno); -} - -char gdb_init_string[] = -"att 1 \n\ -b panic \n\ -b stop \n\ -handle SIGWINCH nostop noprint pass \n\ -"; - -int start_debugger(char *prog, int startup, int stop, int *fd_out) -{ - int slave, child; - - slave = open_gdb_chan(); - child = fork(); - if(child == 0){ - char *tempname = NULL; - int fd; - - if(setsid() < 0) perror("setsid"); - if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) || - (dup2(slave, 2) < 0)){ - printk("start_debugger : dup2 failed, errno = %d\n", - errno); - exit(1); - } - if(ioctl(0, TIOCSCTTY, 0) < 0){ - printk("start_debugger : TIOCSCTTY failed, " - "errno = %d\n", errno); - exit(1); - } - if(tcsetpgrp (1, os_getpid()) < 0){ - printk("start_debugger : tcsetpgrp failed, " - "errno = %d\n", errno); -#ifdef notdef - exit(1); -#endif - } - fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0); - if(fd < 0){ - printk("start_debugger : make_tempfile failed," - "err = %d\n", -fd); - exit(1); - } - os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1); - if(startup){ - if(stop){ - os_write_file(fd, "b start_kernel\n", - strlen("b start_kernel\n")); - } - os_write_file(fd, "c\n", strlen("c\n")); - } - if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ - printk("start_debugger : PTRACE_TRACEME failed, " - "errno = %d\n", errno); - exit(1); - } - execlp("gdb", "gdb", "--command", tempname, prog, NULL); - printk("start_debugger : exec of gdb failed, errno = %d\n", - errno); - } - if(child < 0){ - printk("start_debugger : fork for gdb failed, errno = %d\n", - errno); - return(-1); - } - *fd_out = slave; - return(child); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/ptproxy/ptproxy.h b/arch/um/kernel/tt/ptproxy/ptproxy.h deleted file mode 100644 index 5eb0285b196..00000000000 --- a/arch/um/kernel/tt/ptproxy/ptproxy.h +++ /dev/null @@ -1,61 +0,0 @@ -/********************************************************************** -ptproxy.h - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. -**********************************************************************/ - -#ifndef __PTPROXY_H -#define __PTPROXY_H - -#include <sys/types.h> - -typedef struct debugger debugger_state; -typedef struct debugee debugee_state; - -struct debugger -{ - pid_t pid; - int wait_options; - int *wait_status_ptr; - unsigned int waiting : 1; - unsigned int real_wait : 1; - unsigned int expecting_child : 1; - int (*handle_trace) (debugger_state *, pid_t); - - debugee_state *debugee; -}; - -struct debugee -{ - pid_t pid; - int wait_status; - unsigned int died : 1; - unsigned int event : 1; - unsigned int stopped : 1; - unsigned int trace_singlestep : 1; - unsigned int trace_syscall : 1; - unsigned int traced : 1; - unsigned int zombie : 1; - unsigned int in_context : 1; -}; - -extern int debugger_syscall(debugger_state *debugger, pid_t pid); -extern int debugger_normal_return (debugger_state *debugger, pid_t unused); - -extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t, - int *strace_out); -extern void debugger_cancelled_return(debugger_state *debugger, int result); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c deleted file mode 100644 index 528a5fc8d88..00000000000 --- a/arch/um/kernel/tt/ptproxy/ptrace.c +++ /dev/null @@ -1,237 +0,0 @@ -/********************************************************************** -ptrace.c - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. - -Jeff Dike (jdike@karaya.com) : Modified for integration into uml -**********************************************************************/ - -#include <errno.h> -#include <unistd.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/time.h> -#include <sys/wait.h> - -#include "ptproxy.h" -#include "debug.h" -#include "user_util.h" -#include "kern_util.h" -#include "ptrace_user.h" -#include "tt.h" - -long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2, - long arg3, long arg4, pid_t child, int *ret) -{ - sigset_t relay; - long result; - int status; - - *ret = 0; - if(debugger->debugee->died) return(-ESRCH); - - switch(arg1){ - case PTRACE_ATTACH: - if(debugger->debugee->traced) return(-EPERM); - - debugger->debugee->pid = arg2; - debugger->debugee->traced = 1; - - if(is_valid_pid(arg2) && (arg2 != child)){ - debugger->debugee->in_context = 0; - kill(arg2, SIGSTOP); - debugger->debugee->event = 1; - debugger->debugee->wait_status = W_STOPCODE(SIGSTOP); - } - else { - debugger->debugee->in_context = 1; - if(debugger->debugee->stopped) - child_proxy(child, W_STOPCODE(SIGSTOP)); - else kill(child, SIGSTOP); - } - - return(0); - - case PTRACE_DETACH: - if(!debugger->debugee->traced) return(-EPERM); - - debugger->debugee->traced = 0; - debugger->debugee->pid = 0; - if(!debugger->debugee->in_context) - kill(child, SIGCONT); - - return(0); - - case PTRACE_CONT: - if(!debugger->debugee->in_context) return(-EPERM); - *ret = PTRACE_CONT; - return(ptrace(PTRACE_CONT, child, arg3, arg4)); - -#ifdef UM_HAVE_GETFPREGS - case PTRACE_GETFPREGS: - { - long regs[FP_FRAME_SIZE]; - int i, result; - - result = ptrace(PTRACE_GETFPREGS, child, 0, regs); - if(result == -1) return(-errno); - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, - regs[i]); - return(result); - } -#endif - -#ifdef UM_HAVE_GETFPXREGS - case PTRACE_GETFPXREGS: - { - long regs[FPX_FRAME_SIZE]; - int i, result; - - result = ptrace(PTRACE_GETFPXREGS, child, 0, regs); - if(result == -1) return(-errno); - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, - regs[i]); - return(result); - } -#endif - -#ifdef UM_HAVE_GETREGS - case PTRACE_GETREGS: - { - long regs[FRAME_SIZE]; - int i, result; - - result = ptrace(PTRACE_GETREGS, child, 0, regs); - if(result == -1) return(-errno); - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - ptrace (PTRACE_POKEDATA, debugger->pid, - arg4 + 4 * i, regs[i]); - return(result); - } - break; -#endif - - case PTRACE_KILL: - result = ptrace(PTRACE_KILL, child, arg3, arg4); - if(result == -1) return(-errno); - - return(result); - - case PTRACE_PEEKDATA: - case PTRACE_PEEKTEXT: - case PTRACE_PEEKUSR: - /* The value being read out could be -1, so we have to - * check errno to see if there's an error, and zero it - * beforehand so we're not faked out by an old error - */ - - errno = 0; - result = ptrace(arg1, child, arg3, 0); - if((result == -1) && (errno != 0)) return(-errno); - - result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result); - if(result == -1) return(-errno); - - return(result); - - case PTRACE_POKEDATA: - case PTRACE_POKETEXT: - case PTRACE_POKEUSR: - result = ptrace(arg1, child, arg3, arg4); - if(result == -1) return(-errno); - - if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4); - return(result); - -#ifdef UM_HAVE_SETFPREGS - case PTRACE_SETFPREGS: - { - long regs[FP_FRAME_SIZE]; - int i; - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, - arg4 + 4 * i, 0); - result = ptrace(PTRACE_SETFPREGS, child, 0, regs); - if(result == -1) return(-errno); - - return(result); - } -#endif - -#ifdef UM_HAVE_SETFPXREGS - case PTRACE_SETFPXREGS: - { - long regs[FPX_FRAME_SIZE]; - int i; - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, - arg4 + 4 * i, 0); - result = ptrace(PTRACE_SETFPXREGS, child, 0, regs); - if(result == -1) return(-errno); - - return(result); - } -#endif - -#ifdef UM_HAVE_SETREGS - case PTRACE_SETREGS: - { - long regs[FRAME_SIZE]; - int i; - - for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) - regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid, - arg4 + 4 * i, 0); - result = ptrace(PTRACE_SETREGS, child, 0, regs); - if(result == -1) return(-errno); - - return(result); - } -#endif - - case PTRACE_SINGLESTEP: - if(!debugger->debugee->in_context) return(-EPERM); - sigemptyset(&relay); - sigaddset(&relay, SIGSEGV); - sigaddset(&relay, SIGILL); - sigaddset(&relay, SIGBUS); - result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4); - if(result == -1) return(-errno); - - status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP, - &relay); - child_proxy(child, status); - return(result); - - case PTRACE_SYSCALL: - if(!debugger->debugee->in_context) return(-EPERM); - result = ptrace(PTRACE_SYSCALL, child, arg3, arg4); - if(result == -1) return(-errno); - - *ret = PTRACE_SYSCALL; - return(result); - - case PTRACE_TRACEME: - default: - return(-EINVAL); - } -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c deleted file mode 100644 index a5f0e01e214..00000000000 --- a/arch/um/kernel/tt/ptproxy/sysdep.c +++ /dev/null @@ -1,70 +0,0 @@ -/********************************************************************** -sysdep.c - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. -**********************************************************************/ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <signal.h> -#include <errno.h> -#include <sys/types.h> -#include <linux/unistd.h> -#include "ptrace_user.h" -#include "user_util.h" -#include "user.h" - -int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, - long *arg5) -{ - *arg1 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG1_OFFSET, 0); - *arg2 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG2_OFFSET, 0); - *arg3 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG3_OFFSET, 0); - *arg4 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG4_OFFSET, 0); - *arg5 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG5_OFFSET, 0); - return(ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0)); -} - -void syscall_cancel(pid_t pid, int result) -{ - if((ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, - __NR_getpid) < 0) || - (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) || - (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) || - (ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result) < 0) || - (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)) - printk("ptproxy: couldn't cancel syscall: errno = %d\n", - errno); -} - -void syscall_set_result(pid_t pid, long result) -{ - ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result); -} - -void syscall_continue(pid_t pid) -{ - ptrace(PTRACE_SYSCALL, pid, 0, 0); -} - -int syscall_pause(pid_t pid) -{ - if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){ - printk("syscall_change - ptrace failed, errno = %d\n", errno); - return(-1); - } - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/ptproxy/sysdep.h b/arch/um/kernel/tt/ptproxy/sysdep.h deleted file mode 100644 index 735f488049a..00000000000 --- a/arch/um/kernel/tt/ptproxy/sysdep.h +++ /dev/null @@ -1,25 +0,0 @@ -/********************************************************************** -sysdep.h - -Copyright (C) 1999 Lars Brinkhoff. -Copyright (C) 2001 Jeff Dike (jdike@karaya.com) -See the file COPYING for licensing terms and conditions. -**********************************************************************/ - -extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, - long *arg4, long *arg5); -extern void syscall_cancel (pid_t pid, long result); -extern void syscall_set_result (pid_t pid, long result); -extern void syscall_continue (pid_t pid); -extern int syscall_pause(pid_t pid); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c deleted file mode 100644 index 12f6319d8d7..00000000000 --- a/arch/um/kernel/tt/ptproxy/wait.c +++ /dev/null @@ -1,86 +0,0 @@ -/********************************************************************** -wait.c - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. - -**********************************************************************/ - -#include <errno.h> -#include <signal.h> -#include <sys/wait.h> - -#include "ptproxy.h" -#include "sysdep.h" -#include "wait.h" -#include "user_util.h" -#include "ptrace_user.h" -#include "sysdep/ptrace.h" -#include "sysdep/sigcontext.h" - -int proxy_wait_return(struct debugger *debugger, pid_t unused) -{ - debugger->waiting = 0; - - if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){ - debugger_cancelled_return(debugger, -ECHILD); - return(0); - } - - if(debugger->debugee->zombie && debugger->debugee->event) - debugger->debugee->died = 1; - - if(debugger->debugee->event){ - debugger->debugee->event = 0; - ptrace(PTRACE_POKEDATA, debugger->pid, - debugger->wait_status_ptr, - debugger->debugee->wait_status); - /* if (wait4) - ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */ - debugger_cancelled_return(debugger, debugger->debugee->pid); - return(0); - } - - /* pause will return -EINTR, which happens to be right for wait */ - debugger_normal_return(debugger, -1); - return(0); -} - -int parent_wait_return(struct debugger *debugger, pid_t unused) -{ - return(debugger_normal_return(debugger, -1)); -} - -int real_wait_return(struct debugger *debugger) -{ - unsigned long ip; - int pid; - - pid = debugger->pid; - - ip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0); - IP_RESTART_SYSCALL(ip); - - if(ptrace(PTRACE_POKEUSR, pid, PT_IP_OFFSET, ip) < 0) - tracer_panic("real_wait_return : Failed to restart system " - "call, errno = %d\n", errno); - - if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) || - (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || - (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || - debugger_normal_return(debugger, -1)) - tracer_panic("real_wait_return : gdb failed to wait, " - "errno = %d\n", errno); - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/ptproxy/wait.h b/arch/um/kernel/tt/ptproxy/wait.h deleted file mode 100644 index 542e73ee2ce..00000000000 --- a/arch/um/kernel/tt/ptproxy/wait.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************** -wait.h - -Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing -terms and conditions. -**********************************************************************/ - -#ifndef __PTPROXY_WAIT_H -#define __PTPROXY_WAIT_H - -extern int proxy_wait_return(struct debugger *debugger, pid_t unused); -extern int real_wait_return(struct debugger *debugger); -extern int parent_wait_return(struct debugger *debugger, pid_t unused); - -#endif diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c deleted file mode 100644 index 3d29c90514c..00000000000 --- a/arch/um/kernel/tt/syscall_kern.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/types.h" -#include "linux/utime.h" -#include "linux/sys.h" -#include "linux/ptrace.h" -#include "asm/unistd.h" -#include "asm/ptrace.h" -#include "asm/uaccess.h" -#include "asm/stat.h" -#include "sysdep/syscalls.h" -#include "sysdep/sigcontext.h" -#include "kern_util.h" -#include "syscall.h" - -void syscall_handler_tt(int sig, struct pt_regs *regs) -{ - void *sc; - long result; - int syscall; -#ifdef CONFIG_SYSCALL_DEBUG - int index; - index = record_syscall_start(syscall); -#endif - sc = UPT_SC(®s->regs); - SC_START_SYSCALL(sc); - - syscall_trace(®s->regs, 0); - - current->thread.nsyscalls++; - nsyscalls++; - syscall = UPT_SYSCALL_NR(®s->regs); - - if((syscall >= NR_syscalls) || (syscall < 0)) - result = -ENOSYS; - else result = EXECUTE_SYSCALL(syscall, regs); - - /* regs->sc may have changed while the system call ran (there may - * have been an interrupt or segfault), so it needs to be refreshed. - */ - UPT_SC(®s->regs) = sc; - - SC_SET_SYSCALL_RETURN(sc, result); - - syscall_trace(®s->regs, 1); -#ifdef CONFIG_SYSCALL_DEBUG - record_syscall_end(index, result); -#endif -} diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c deleted file mode 100644 index 902987bf379..00000000000 --- a/arch/um/kernel/tt/syscall_user.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <unistd.h> -#include <signal.h> -#include <errno.h> -#include <asm/unistd.h> -#include "sysdep/ptrace.h" -#include "sigcontext.h" -#include "ptrace_user.h" -#include "task.h" -#include "user_util.h" -#include "kern_util.h" -#include "syscall.h" -#include "tt.h" - -void do_sigtrap(void *task) -{ - UPT_SYSCALL_NR(TASK_REGS(task)) = -1; -} - -void do_syscall(void *task, int pid, int local_using_sysemu) -{ - unsigned long proc_regs[FRAME_SIZE]; - - if(ptrace_getregs(pid, proc_regs) < 0) - tracer_panic("Couldn't read registers"); - - UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs); - -#ifdef UPT_ORIGGPR2 - UPT_ORIGGPR2(TASK_REGS(task)) = REGS_ORIGGPR2(proc_regs); -#endif - - if(((unsigned long *) PT_IP(proc_regs) >= &_stext) && - ((unsigned long *) PT_IP(proc_regs) <= &_etext)) - tracer_panic("I'm tracing myself and I can't get out"); - - /* advanced sysemu mode set syscall number to -1 automatically */ - if (local_using_sysemu==2) - return; - - /* syscall number -1 in sysemu skips syscall restarting in host */ - if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, - local_using_sysemu ? -1 : __NR_getpid) < 0) - tracer_panic("do_syscall : Nullifying syscall failed, " - "errno = %d", errno); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c deleted file mode 100644 index ae6217c8613..00000000000 --- a/arch/um/kernel/tt/tlb.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Copyright 2003 PathScale, Inc. - * Licensed under the GPL - */ - -#include "linux/stddef.h" -#include "linux/kernel.h" -#include "linux/sched.h" -#include "linux/mm.h" -#include "asm/page.h" -#include "asm/pgtable.h" -#include "asm/uaccess.h" -#include "asm/tlbflush.h" -#include "user_util.h" -#include "mem_user.h" -#include "os.h" -#include "tlb.h" - -static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last, - int finished, void **flush) -{ - struct host_vm_op *op; - int i, ret=0; - - for(i = 0; i <= last && !ret; i++){ - op = &ops[i]; - switch(op->type){ - case MMAP: - ret = os_map_memory((void *) op->u.mmap.addr, - op->u.mmap.fd, op->u.mmap.offset, - op->u.mmap.len, op->u.mmap.r, - op->u.mmap.w, op->u.mmap.x); - break; - case MUNMAP: - ret = os_unmap_memory((void *) op->u.munmap.addr, - op->u.munmap.len); - break; - case MPROTECT: - ret = protect_memory(op->u.mprotect.addr, - op->u.munmap.len, - op->u.mprotect.r, - op->u.mprotect.w, - op->u.mprotect.x, 1); - protect_memory(op->u.mprotect.addr, op->u.munmap.len, - op->u.mprotect.r, op->u.mprotect.w, - op->u.mprotect.x, 1); - break; - default: - printk("Unknown op type %d in do_ops\n", op->type); - break; - } - } - - return ret; -} - -static void fix_range(struct mm_struct *mm, unsigned long start_addr, - unsigned long end_addr, int force) -{ - if((current->thread.mode.tt.extern_pid != -1) && - (current->thread.mode.tt.extern_pid != os_getpid())) - panic("fix_range fixing wrong address space, current = 0x%p", - current); - - fix_range_common(mm, start_addr, end_addr, force, do_ops); -} - -atomic_t vmchange_seq = ATOMIC_INIT(1); - -void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end) -{ - if(flush_tlb_kernel_range_common(start, end)) - atomic_inc(&vmchange_seq); -} - -void flush_tlb_kernel_vm_tt(void) -{ - flush_tlb_kernel_range(start_vm, end_vm); -} - -void __flush_tlb_one_tt(unsigned long addr) -{ - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); -} - -void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start, - unsigned long end) -{ - if(vma->vm_mm != current->mm) return; - - /* Assumes that the range start ... end is entirely within - * either process memory or kernel vm - */ - if((start >= start_vm) && (start < end_vm)){ - if(flush_tlb_kernel_range_common(start, end)) - atomic_inc(&vmchange_seq); - } - else fix_range(vma->vm_mm, start, end, 0); -} - -void flush_tlb_mm_tt(struct mm_struct *mm) -{ - unsigned long seq; - - if(mm != current->mm) return; - - fix_range(mm, 0, STACK_TOP, 0); - - seq = atomic_read(&vmchange_seq); - if(current->thread.mode.tt.vm_seq == seq) - return; - current->thread.mode.tt.vm_seq = seq; - flush_tlb_kernel_range_common(start_vm, end_vm); -} - -void force_flush_all_tt(void) -{ - fix_range(current->mm, 0, STACK_TOP, 1); - flush_tlb_kernel_range_common(start_vm, end_vm); -} diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c deleted file mode 100644 index d11e7399d7a..00000000000 --- a/arch/um/kernel/tt/tracer.c +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <unistd.h> -#include <signal.h> -#include <errno.h> -#include <sched.h> -#include <string.h> -#include <sys/mman.h> -#include <sys/time.h> -#include <sys/wait.h> -#include "user.h" -#include "sysdep/ptrace.h" -#include "sigcontext.h" -#include "sysdep/sigcontext.h" -#include "os.h" -#include "signal_user.h" -#include "user_util.h" -#include "mem_user.h" -#include "process.h" -#include "kern_util.h" -#include "chan_user.h" -#include "ptrace_user.h" -#include "irq_user.h" -#include "mode.h" -#include "tt.h" - -static int tracer_winch[2]; - -int is_tracer_winch(int pid, int fd, void *data) -{ - if(pid != os_getpgrp()) - return(0); - - register_winch_irq(tracer_winch[0], fd, -1, data); - return(1); -} - -static void tracer_winch_handler(int sig) -{ - int n; - char c = 1; - - n = os_write_file(tracer_winch[1], &c, sizeof(c)); - if(n != sizeof(c)) - printk("tracer_winch_handler - write failed, err = %d\n", -n); -} - -/* Called only by the tracing thread during initialization */ - -static void setup_tracer_winch(void) -{ - int err; - - err = os_pipe(tracer_winch, 1, 1); - if(err < 0){ - printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err); - return; - } - signal(SIGWINCH, tracer_winch_handler); -} - -void attach_process(int pid) -{ - if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) || - (ptrace(PTRACE_CONT, pid, 0, 0) < 0)) - tracer_panic("OP_FORK failed to attach pid"); - wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); - if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) - tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno); - if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) - tracer_panic("OP_FORK failed to continue process"); -} - -void tracer_panic(char *format, ...) -{ - va_list ap; - - va_start(ap, format); - vprintf(format, ap); - va_end(ap); - printf("\n"); - while(1) pause(); -} - -static void tracer_segv(int sig, struct sigcontext sc) -{ - struct faultinfo fi; - GET_FAULTINFO_FROM_SC(fi, &sc); - printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n", - FAULT_ADDRESS(fi), SC_IP(&sc)); - while(1) - pause(); -} - -/* Changed early in boot, and then only read */ -int debug = 0; -int debug_stop = 1; -int debug_parent = 0; -int honeypot = 0; - -static int signal_tramp(void *arg) -{ - int (*proc)(void *); - - if(honeypot && munmap((void *) (host_task_size - 0x10000000), - 0x10000000)) - panic("Unmapping stack failed"); - if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) - panic("ptrace PTRACE_TRACEME failed"); - os_stop_process(os_getpid()); - change_sig(SIGWINCH, 0); - signal(SIGUSR1, SIG_IGN); - change_sig(SIGCHLD, 0); - signal(SIGSEGV, (__sighandler_t) sig_handler); - set_cmdline("(idle thread)"); - set_init_pid(os_getpid()); - init_irq_signals(0); - proc = arg; - return((*proc)(NULL)); -} - -static void sleeping_process_signal(int pid, int sig) -{ - switch(sig){ - /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is - * right because the process must be in the kernel already. - */ - case SIGCONT: - case SIGTSTP: - if(ptrace(PTRACE_CONT, pid, 0, sig) < 0) - tracer_panic("sleeping_process_signal : Failed to " - "continue pid %d, signal = %d, " - "errno = %d\n", pid, sig, errno); - break; - - /* This happens when the debugger (e.g. strace) is doing system call - * tracing on the kernel. During a context switch, the current task - * will be set to the incoming process and the outgoing process will - * hop into write and then read. Since it's not the current process - * any more, the trace of those will land here. So, we need to just - * PTRACE_SYSCALL it. - */ - case (SIGTRAP + 0x80): - if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) - tracer_panic("sleeping_process_signal : Failed to " - "PTRACE_SYSCALL pid %d, errno = %d\n", - pid, errno); - break; - case SIGSTOP: - break; - default: - tracer_panic("sleeping process %d got unexpected " - "signal : %d\n", pid, sig); - break; - } -} - -/* Accessed only by the tracing thread */ -int debugger_pid = -1; -int debugger_parent = -1; -int debugger_fd = -1; -int gdb_pid = -1; - -struct { - int pid; - int signal; - unsigned long addr; - struct timeval time; -} signal_record[1024][32]; - -int signal_index[32]; -int nsignals = 0; -int debug_trace = 0; -extern int io_nsignals, io_count, intr_count; - -extern void signal_usr1(int sig); - -int tracing_pid = -1; - -int tracer(int (*init_proc)(void *), void *sp) -{ - void *task = NULL; - int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; - int proc_id = 0, n, err, old_tracing = 0, strace = 0; - int local_using_sysemu = 0; -#ifdef UML_CONFIG_SYSCALL_DEBUG - unsigned long eip = 0; - int last_index; -#endif - signal(SIGPIPE, SIG_IGN); - setup_tracer_winch(); - tracing_pid = os_getpid(); - printf("tracing thread pid = %d\n", tracing_pid); - - pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); - CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); - if(n < 0){ - printf("waitpid on idle thread failed, errno = %d\n", errno); - exit(1); - } - if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) { - printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno); - exit(1); - } - if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){ - printf("Failed to continue idle thread, errno = %d\n", errno); - exit(1); - } - - signal(SIGSEGV, (sighandler_t) tracer_segv); - signal(SIGUSR1, signal_usr1); - if(debug_trace){ - printf("Tracing thread pausing to be attached\n"); - stop(); - } - if(debug){ - if(gdb_pid != -1) - debugger_pid = attach_debugger(pid, gdb_pid, 1); - else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop); - if(debug_parent){ - debugger_parent = os_process_parent(debugger_pid); - init_parent_proxy(debugger_parent); - err = attach(debugger_parent); - if(err){ - printf("Failed to attach debugger parent %d, " - "errno = %d\n", debugger_parent, -err); - debugger_parent = -1; - } - else { - if(ptrace(PTRACE_SYSCALL, debugger_parent, - 0, 0) < 0){ - printf("Failed to continue debugger " - "parent, errno = %d\n", errno); - debugger_parent = -1; - } - } - } - } - set_cmdline("(tracing thread)"); - while(1){ - CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED)); - if(pid <= 0){ - if(errno != ECHILD){ - printf("wait failed - errno = %d\n", errno); - } - continue; - } - if(pid == debugger_pid){ - int cont = 0; - - if(WIFEXITED(status) || WIFSIGNALED(status)) - debugger_pid = -1; - /* XXX Figure out how to deal with gdb and SMP */ - else cont = debugger_signal(status, cpu_tasks[0].pid); - if(cont == PTRACE_SYSCALL) strace = 1; - continue; - } - else if(pid == debugger_parent){ - debugger_parent_signal(status, pid); - continue; - } - nsignals++; - if(WIFEXITED(status)) ; -#ifdef notdef - { - printf("Child %d exited with status %d\n", pid, - WEXITSTATUS(status)); - } -#endif - else if(WIFSIGNALED(status)){ - sig = WTERMSIG(status); - if(sig != 9){ - printf("Child %d exited with signal %d\n", pid, - sig); - } - } - else if(WIFSTOPPED(status)){ - proc_id = pid_to_processor_id(pid); - sig = WSTOPSIG(status); -#ifdef UML_CONFIG_SYSCALL_DEBUG - if(signal_index[proc_id] == 1024){ - signal_index[proc_id] = 0; - last_index = 1023; - } - else last_index = signal_index[proc_id] - 1; - if(((sig == SIGPROF) || (sig == SIGVTALRM) || - (sig == SIGALRM)) && - (signal_record[proc_id][last_index].signal == sig)&& - (signal_record[proc_id][last_index].pid == pid)) - signal_index[proc_id] = last_index; - signal_record[proc_id][signal_index[proc_id]].pid = pid; - gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL); - eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0); - signal_record[proc_id][signal_index[proc_id]].addr = eip; - signal_record[proc_id][signal_index[proc_id]++].signal = sig; -#endif - if(proc_id == -1){ - sleeping_process_signal(pid, sig); - continue; - } - - task = cpu_tasks[proc_id].task; - tracing = is_tracing(task); - old_tracing = tracing; - - /* Assume: no syscall, when coming from user */ - if ( tracing ) - do_sigtrap(task); - - switch(sig){ - case SIGUSR1: - sig = 0; - op = do_proc_op(task, proc_id); - switch(op){ - /* - * This is called when entering user mode; after - * this, we start intercepting syscalls. - * - * In fact, a process is started in kernel mode, - * so with is_tracing() == 0 (and that is reset - * when executing syscalls, since UML kernel has - * the right to do syscalls); - */ - case OP_TRACE_ON: - arch_leave_kernel(task, pid); - tracing = 1; - break; - case OP_REBOOT: - case OP_HALT: - unmap_physmem(); - kmalloc_ok = 0; - os_kill_ptraced_process(pid, 0); - /* Now let's reap remaining zombies */ - errno = 0; - do { - waitpid(-1, &status, - WUNTRACED); - } while (errno != ECHILD); - return(op == OP_REBOOT); - case OP_NONE: - printf("Detaching pid %d\n", pid); - detach(pid, SIGSTOP); - continue; - default: - break; - } - /* OP_EXEC switches host processes on us, - * we want to continue the new one. - */ - pid = cpu_tasks[proc_id].pid; - break; - case (SIGTRAP + 0x80): - if(!tracing && (debugger_pid != -1)){ - child_signal(pid, status & 0x7fff); - continue; - } - tracing = 0; - /* local_using_sysemu has been already set - * below, since if we are here, is_tracing() on - * the traced task was 1, i.e. the process had - * already run through one iteration of the - * loop which executed a OP_TRACE_ON request.*/ - do_syscall(task, pid, local_using_sysemu); - sig = SIGUSR2; - break; - case SIGTRAP: - if(!tracing && (debugger_pid != -1)){ - child_signal(pid, status); - continue; - } - tracing = 0; - break; - case SIGPROF: - if(tracing) sig = 0; - break; - case SIGCHLD: - case SIGHUP: - sig = 0; - break; - case SIGSEGV: - case SIGIO: - case SIGALRM: - case SIGVTALRM: - case SIGFPE: - case SIGBUS: - case SIGILL: - case SIGWINCH: - - default: - tracing = 0; - break; - } - set_tracing(task, tracing); - - if(!tracing && old_tracing) - arch_enter_kernel(task, pid); - - if(!tracing && (debugger_pid != -1) && (sig != 0) && - (sig != SIGALRM) && (sig != SIGVTALRM) && - (sig != SIGSEGV) && (sig != SIGTRAP) && - (sig != SIGUSR2) && (sig != SIGIO) && - (sig != SIGFPE)){ - child_signal(pid, status); - continue; - } - - local_using_sysemu = get_using_sysemu(); - - if(tracing) - cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu, - singlestepping(task)); - else if((debugger_pid != -1) && strace) - cont_type = PTRACE_SYSCALL; - else - cont_type = PTRACE_CONT; - - if(ptrace(cont_type, pid, 0, sig) != 0){ - tracer_panic("ptrace failed to continue " - "process - errno = %d\n", - errno); - } - } - } - return(0); -} - -static int __init uml_debug_setup(char *line, int *add) -{ - char *next; - - debug = 1; - *add = 0; - if(*line != '=') return(0); - line++; - - while(line != NULL){ - next = strchr(line, ','); - if(next) *next++ = '\0'; - - if(!strcmp(line, "go")) debug_stop = 0; - else if(!strcmp(line, "parent")) debug_parent = 1; - else printf("Unknown debug option : '%s'\n", line); - - line = next; - } - return(0); -} - -__uml_setup("debug", uml_debug_setup, -"debug\n" -" Starts up the kernel under the control of gdb. See the \n" -" kernel debugging tutorial and the debugging session pages\n" -" at http://user-mode-linux.sourceforge.net/ for more information.\n\n" -); - -static int __init uml_debugtrace_setup(char *line, int *add) -{ - debug_trace = 1; - return 0; -} -__uml_setup("debugtrace", uml_debugtrace_setup, -"debugtrace\n" -" Causes the tracing thread to pause until it is attached by a\n" -" debugger and continued. This is mostly for debugging crashes\n" -" early during boot, and should be pretty much obsoleted by\n" -" the debug switch.\n\n" -); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c deleted file mode 100644 index fc108615bea..00000000000 --- a/arch/um/kernel/tt/trap_user.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdlib.h> -#include <errno.h> -#include <signal.h> -#include "sysdep/ptrace.h" -#include "sysdep/sigcontext.h" -#include "signal_user.h" -#include "user_util.h" -#include "kern_util.h" -#include "task.h" -#include "tt.h" - -void sig_handler_common_tt(int sig, void *sc_ptr) -{ - struct sigcontext *sc = sc_ptr; - struct tt_regs save_regs, *r; - struct signal_info *info; - int save_errno = errno, is_user; - - /* This is done because to allow SIGSEGV to be delivered inside a SEGV - * handler. This can happen in copy_user, and if SEGV is disabled, - * the process will die. - */ - if(sig == SIGSEGV) - change_sig(SIGSEGV, 1); - - r = &TASK_REGS(get_current())->tt; - if ( sig == SIGFPE || sig == SIGSEGV || - sig == SIGBUS || sig == SIGILL || - sig == SIGTRAP ) { - GET_FAULTINFO_FROM_SC(r->faultinfo, sc); - } - save_regs = *r; - is_user = user_context(SC_SP(sc)); - r->sc = sc; - if(sig != SIGUSR2) - r->syscall = -1; - - info = &sig_info[sig]; - if(!info->is_irq) unblock_signals(); - - (*info->handler)(sig, (union uml_pt_regs *) r); - - if(is_user){ - interrupt_end(); - block_signals(); - set_user_mode(NULL); - } - *r = save_regs; - errno = save_errno; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c deleted file mode 100644 index a72aa632972..00000000000 --- a/arch/um/kernel/tt/uaccess.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "asm/uaccess.h" - -int copy_from_user_tt(void *to, const void __user *from, int n) -{ - if(!access_ok_tt(VERIFY_READ, from, n)) - return(n); - - return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -int copy_to_user_tt(void __user *to, const void *from, int n) -{ - if(!access_ok_tt(VERIFY_WRITE, to, n)) - return(n); - - return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -int strncpy_from_user_tt(char *dst, const char __user *src, int count) -{ - int n; - - if(!access_ok_tt(VERIFY_READ, src, 1)) - return(-EFAULT); - - n = __do_strncpy_from_user(dst, src, count, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher); - if(n < 0) return(-EFAULT); - return(n); -} - -int __clear_user_tt(void __user *mem, int len) -{ - return(__do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -int clear_user_tt(void __user *mem, int len) -{ - if(!access_ok_tt(VERIFY_WRITE, mem, len)) - return(len); - - return(__do_clear_user(mem, len, ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -int strnlen_user_tt(const void __user *str, int len) -{ - return(__do_strnlen_user(str, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c deleted file mode 100644 index 6c92bbccb49..00000000000 --- a/arch/um/kernel/tt/uaccess_user.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <setjmp.h> -#include <string.h> -#include "user_util.h" -#include "uml_uaccess.h" -#include "task.h" -#include "kern_util.h" -#include "os.h" - -int __do_copy_from_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher) -{ - struct tt_regs save = TASK_REGS(get_current())->tt; - unsigned long fault; - int faulted; - - fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, - __do_copy, &faulted); - TASK_REGS(get_current())->tt = save; - - if(!faulted) - return 0; - else if (fault) - return n - (fault - (unsigned long) from); - else - /* In case of a general protection fault, we don't have the - * fault address, so NULL is used instead. Pretend we didn't - * copy anything. */ - return n; -} - -static void __do_strncpy(void *dst, const void *src, int count) -{ - strncpy(dst, src, count); -} - -int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, - void **fault_addr, void **fault_catcher) -{ - struct tt_regs save = TASK_REGS(get_current())->tt; - unsigned long fault; - int faulted; - - fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, - __do_strncpy, &faulted); - TASK_REGS(get_current())->tt = save; - - if(!faulted) return(strlen(dst)); - else return(-1); -} - -static void __do_clear(void *to, const void *from, int n) -{ - memset(to, 0, n); -} - -int __do_clear_user(void *mem, unsigned long len, - void **fault_addr, void **fault_catcher) -{ - struct tt_regs save = TASK_REGS(get_current())->tt; - unsigned long fault; - int faulted; - - fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, - __do_clear, &faulted); - TASK_REGS(get_current())->tt = save; - - if(!faulted) return(0); - else return(len - (fault - (unsigned long) mem)); -} - -int __do_strnlen_user(const char *str, unsigned long n, - void **fault_addr, void **fault_catcher) -{ - struct tt_regs save = TASK_REGS(get_current())->tt; - int ret; - unsigned long *faddrp = (unsigned long *)fault_addr; - sigjmp_buf jbuf; - - *fault_catcher = &jbuf; - if(sigsetjmp(jbuf, 1) == 0) - ret = strlen(str) + 1; - else ret = *faddrp - (unsigned long) str; - - *fault_addr = NULL; - *fault_catcher = NULL; - - TASK_REGS(get_current())->tt = save; - return ret; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c deleted file mode 100644 index 9ada656f68c..00000000000 --- a/arch/um/kernel/tty_log.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and - * geoffrey hing <ghing@net.ohio-state.edu> - * Licensed under the GPL - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/time.h> -#include "init.h" -#include "user.h" -#include "kern_util.h" -#include "os.h" - -#define TTY_LOG_DIR "./" - -/* Set early in boot and then unchanged */ -static char *tty_log_dir = TTY_LOG_DIR; -static int tty_log_fd = -1; - -#define TTY_LOG_OPEN 1 -#define TTY_LOG_CLOSE 2 -#define TTY_LOG_WRITE 3 -#define TTY_LOG_EXEC 4 - -#define TTY_READ 1 -#define TTY_WRITE 2 - -struct tty_log_buf { - int what; - unsigned long tty; - int len; - int direction; - unsigned long sec; - unsigned long usec; -}; - -int open_tty_log(void *tty, void *current_tty) -{ - struct timeval tv; - struct tty_log_buf data; - char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; - int fd; - - gettimeofday(&tv, NULL); - if(tty_log_fd != -1){ - data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, - .tty = (unsigned long) tty, - .len = sizeof(current_tty), - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); - os_write_file(tty_log_fd, ¤t_tty, data.len); - return(tty_log_fd); - } - - sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, - (unsigned int) tv.tv_usec); - - fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))), - 0644); - if(fd < 0){ - printk("open_tty_log : couldn't open '%s', errno = %d\n", - buf, -fd); - } - return(fd); -} - -void close_tty_log(int fd, void *tty) -{ - struct tty_log_buf data; - struct timeval tv; - - if(tty_log_fd != -1){ - gettimeofday(&tv, NULL); - data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE, - .tty = (unsigned long) tty, - .len = 0, - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); - return; - } - os_close_file(fd); -} - -static int log_chunk(int fd, const char *buf, int len) -{ - int total = 0, try, missed, n; - char chunk[64]; - - while(len > 0){ - try = (len > sizeof(chunk)) ? sizeof(chunk) : len; - missed = copy_from_user_proc(chunk, (char *) buf, try); - try -= missed; - n = os_write_file(fd, chunk, try); - if(n != try) { - if(n < 0) - return(n); - return(-EIO); - } - if(missed != 0) - return(-EFAULT); - - len -= try; - total += try; - buf += try; - } - - return(total); -} - -int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) -{ - struct timeval tv; - struct tty_log_buf data; - int direction; - - if(fd == tty_log_fd){ - gettimeofday(&tv, NULL); - direction = is_read ? TTY_READ : TTY_WRITE; - data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE, - .tty = (unsigned long) tty, - .len = len, - .direction = direction, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); - } - - return(log_chunk(fd, buf, len)); -} - -void log_exec(char **argv, void *tty) -{ - struct timeval tv; - struct tty_log_buf data; - char **ptr,*arg; - int len; - - if(tty_log_fd == -1) return; - - gettimeofday(&tv, NULL); - - len = 0; - for(ptr = argv; ; ptr++){ - if(copy_from_user_proc(&arg, ptr, sizeof(arg))) - return; - if(arg == NULL) break; - len += strlen_user_proc(arg); - } - - data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC, - .tty = (unsigned long) tty, - .len = len, - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); - - for(ptr = argv; ; ptr++){ - if(copy_from_user_proc(&arg, ptr, sizeof(arg))) - return; - if(arg == NULL) break; - log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); - } -} - -extern void register_tty_logger(int (*opener)(void *, void *), - int (*writer)(int, const char *, int, - void *, int), - void (*closer)(int, void *)); - -static int register_logger(void) -{ - register_tty_logger(open_tty_log, write_tty_log, close_tty_log); - return(0); -} - -__uml_initcall(register_logger); - -static int __init set_tty_log_dir(char *name, int *add) -{ - tty_log_dir = name; - return 0; -} - -__uml_setup("tty_log_dir=", set_tty_log_dir, -"tty_log_dir=<directory>\n" -" This is used to specify the directory where the logs of all pty\n" -" data from this UML machine will be written.\n\n" -); - -static int __init set_tty_log_fd(char *name, int *add) -{ - char *end; - - tty_log_fd = strtoul(name, &end, 0); - if((*end != '\0') || (end == name)){ - printf("set_tty_log_fd - strtoul failed on '%s'\n", name); - tty_log_fd = -1; - } - - *add = 0; - return 0; -} - -__uml_setup("tty_log_fd=", set_tty_log_fd, -"tty_log_fd=<fd>\n" -" This is used to specify a preconfigured file descriptor to which all\n" -" tty data will be written. Preconfigure the descriptor with something\n" -" like '10>tty_log tty_log_fd=10'.\n\n" -); - - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/uaccess.c b/arch/um/kernel/uaccess.c deleted file mode 100644 index 054e3de0784..00000000000 --- a/arch/um/kernel/uaccess.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -/* These are here rather than tt/uaccess.c because skas mode needs them in - * order to do SIGBUS recovery when a tmpfs mount runs out of room. - */ - -#include <linux/string.h> -#include "os.h" - -void __do_copy(void *to, const void *from, int n) -{ - memcpy(to, from, n); -} - - -int __do_copy_to_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, - __do_copy, &faulted); - if(!faulted) return(0); - else return(n - (fault - (unsigned long) to)); -} diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 142a9493912..016adf0985d 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -1,74 +1,67 @@ -/* - * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/kernel.h" -#include "linux/sched.h" -#include "linux/notifier.h" -#include "linux/mm.h" -#include "linux/types.h" -#include "linux/tty.h" -#include "linux/init.h" -#include "linux/bootmem.h" -#include "linux/spinlock.h" -#include "linux/utsname.h" -#include "linux/sysrq.h" -#include "linux/seq_file.h" -#include "linux/delay.h" -#include "linux/module.h" -#include "asm/page.h" -#include "asm/pgtable.h" -#include "asm/ptrace.h" -#include "asm/elf.h" -#include "asm/user.h" -#include "asm/setup.h" -#include "ubd_user.h" -#include "asm/current.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" -#include "mem_user.h" -#include "mem.h" -#include "umid.h" -#include "initrd.h" -#include "init.h" -#include "os.h" -#include "choose-mode.h" -#include "mode_kern.h" -#include "mode.h" -#ifdef UML_CONFIG_MODE_SKAS -#include "skas.h" -#endif +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/seq_file.h> +#include <linux/string.h> +#include <linux/utsname.h> +#include <linux/sched.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/sections.h> +#include <asm/setup.h> +#include <as-layout.h> +#include <arch.h> +#include <init.h> +#include <kern.h> +#include <kern_util.h> +#include <mem_user.h> +#include <os.h> #define DEFAULT_COMMAND_LINE "root=98:0" -/* Changed in linux_main and setup_arch, which run before SMP is started */ -static char command_line[COMMAND_LINE_SIZE] = { 0 }; +/* Changed in add_arg and setup_arch, which run before SMP is started */ +static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 }; -static void add_arg(char *arg) +static void __init add_arg(char *arg) { if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { printf("add_arg: Too many command line arguments!\n"); exit(1); } - if(strlen(command_line) > 0) + if (strlen(command_line) > 0) strcat(command_line, " "); strcat(command_line, arg); } -struct cpuinfo_um boot_cpu_data = { +/* + * These fields are initialized at boot time and not changed. + * XXX This structure is used only in the non-SMP case. Maybe this + * should be moved to smp.c. + */ +struct cpuinfo_um boot_cpu_data = { .loops_per_jiffy = 0, .ipi_pipe = { -1, -1 } }; +union thread_union cpu0_irqstack + __attribute__((__section__(".data..init_irqstack"))) = + { INIT_THREAD_INFO(init_task) }; + unsigned long thread_saved_pc(struct task_struct *task) { - return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, - task))); + /* FIXME: Need to look up userspace_pid by cpu */ + return os_process_pc(userspace_pid[0]); } +/* Changed in setup_arch, which is called in early boot */ +static char host_info[(__NEW_UTS_LEN + 1) * 5]; + static int show_cpuinfo(struct seq_file *m, void *v) { int index = 0; @@ -82,13 +75,13 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "processor\t: %d\n", index); seq_printf(m, "vendor_id\t: User Mode Linux\n"); seq_printf(m, "model name\t: UML\n"); - seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas")); + seq_printf(m, "mode\t\t: skas\n"); seq_printf(m, "host\t\t: %s\n", host_info); seq_printf(m, "bogomips\t: %lu.%02lu\n\n", loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ)) % 100); - return(0); + return 0; } static void *c_start(struct seq_file *m, loff_t *pos) @@ -106,7 +99,7 @@ static void c_stop(struct seq_file *m, void *v) { } -struct seq_operations cpuinfo_op = { +const struct seq_operations cpuinfo_op = { .start = c_start, .next = c_next, .stop = c_stop, @@ -114,60 +107,29 @@ struct seq_operations cpuinfo_op = { }; /* Set in linux_main */ -unsigned long host_task_size; -unsigned long task_size; - -unsigned long uml_start; - -/* Set in early boot */ unsigned long uml_physmem; -unsigned long uml_reserved; +EXPORT_SYMBOL(uml_physmem); + +unsigned long uml_reserved; /* Also modified in mem_init */ unsigned long start_vm; unsigned long end_vm; -int ncpus = 1; -#ifdef CONFIG_CMDLINE_ON_HOST -/* Pointer set in linux_main, the array itself is private to each thread, - * and changed at address space creation time so this poses no concurrency - * problems. - */ -static char *argv1_begin = NULL; -static char *argv1_end = NULL; -#endif +/* Set in uml_ncpus_setup */ +int ncpus = 1; /* Set in early boot */ static int have_root __initdata = 0; -long long physmem_size = 32 * 1024 * 1024; - -void set_cmdline(char *cmd) -{ -#ifdef CONFIG_CMDLINE_ON_HOST - char *umid, *ptr; - - if(CHOOSE_MODE(honeypot, 0)) return; - umid = get_umid(1); - if(umid != NULL){ - snprintf(argv1_begin, - (argv1_end - argv1_begin) * sizeof(*ptr), - "(%s) ", umid); - ptr = &argv1_begin[strlen(argv1_begin)]; - } - else ptr = argv1_begin; - - snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd); - memset(argv1_begin + strlen(argv1_begin), '\0', - argv1_end - argv1_begin - strlen(argv1_begin)); -#endif -} +/* Set in uml_mem_setup and modified in linux_main */ +long long physmem_size = 32 * 1024 * 1024; -static char *usage_string = +static const char *usage_string = "User Mode Linux v%s\n" " available at http://user-mode-linux.sourceforge.net/\n\n"; static int __init uml_version_setup(char *line, int *add) { - printf("%s\n", system_utsname.release); + printf("%s\n", init_utsname()->release); exit(0); return 0; @@ -193,85 +155,47 @@ __uml_setup("root=", uml_root_setup, " root=/dev/ubd5\n\n" ); -#ifdef CONFIG_SMP -static int __init uml_ncpus_setup(char *line, int *add) +static int __init no_skas_debug_setup(char *line, int *add) { - if (!sscanf(line, "%d", &ncpus)) { - printf("Couldn't parse [%s]\n", line); - return -1; - } + printf("'debug' is not necessary to gdb UML in skas mode - run \n"); + printf("'gdb linux'\n"); - return 0; + return 0; } -__uml_setup("ncpus=", uml_ncpus_setup, -"ncpus=<# of desired CPUs>\n" -" This tells an SMP kernel how many virtual processors to start.\n\n" +__uml_setup("debug", no_skas_debug_setup, +"debug\n" +" this flag is not needed to run gdb on UML in skas mode\n\n" ); -#endif - -static int force_tt = 0; - -#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) -#define DEFAULT_TT 0 - -static int __init mode_tt_setup(char *line, int *add) -{ - force_tt = 1; - return(0); -} - -#else -#ifdef CONFIG_MODE_SKAS - -#define DEFAULT_TT 0 -static int __init mode_tt_setup(char *line, int *add) +#ifdef CONFIG_SMP +static int __init uml_ncpus_setup(char *line, int *add) { - printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); - return(0); -} - -#else -#ifdef CONFIG_MODE_TT - -#define DEFAULT_TT 1 + if (!sscanf(line, "%d", &ncpus)) { + printf("Couldn't parse [%s]\n", line); + return -1; + } -static int __init mode_tt_setup(char *line, int *add) -{ - printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); - return(0); + return 0; } -#else - -#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled - -#endif -#endif -#endif - -__uml_setup("mode=tt", mode_tt_setup, -"mode=tt\n" -" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n" -" forces UML to run in tt (tracing thread) mode. It is not the default\n" -" because it's slower and less secure than skas mode.\n\n" +__uml_setup("ncpus=", uml_ncpus_setup, +"ncpus=<# of desired CPUs>\n" +" This tells an SMP kernel how many virtual processors to start.\n\n" ); - -int mode_tt = DEFAULT_TT; +#endif static int __init Usage(char *line, int *add) { - const char **p; - - printf(usage_string, system_utsname.release); - p = &__uml_help_start; - while (p < &__uml_help_end) { - printf("%s", *p); - p++; - } - exit(0); + const char **p; + printf(usage_string, init_utsname()->release); + p = &__uml_help_start; + while (p < &__uml_help_end) { + printf("%s", *p); + p++; + } + exit(0); return 0; } @@ -280,21 +204,19 @@ __uml_setup("--help", Usage, " Prints this message.\n\n" ); -static int __init uml_checksetup(char *line, int *add) +static void __init uml_checksetup(char *line, int *add) { struct uml_param *p; p = &__uml_setup_start; - while(p < &__uml_setup_end) { - int n; + while (p < &__uml_setup_end) { + size_t n; n = strlen(p->str); - if(!strncmp(line, p->str, n)){ - if (p->setup_func(line + n, add)) return 1; - } + if (!strncmp(line, p->str, n) && p->setup_func(line + n, add)) + return; p++; } - return 0; } static void __init uml_postsetup(void) @@ -302,107 +224,120 @@ static void __init uml_postsetup(void) initcall_t *p; p = &__uml_postsetup_start; - while(p < &__uml_postsetup_end){ + while (p < &__uml_postsetup_end) { (*p)(); p++; } return; } +static int panic_exit(struct notifier_block *self, unsigned long unused1, + void *unused2) +{ + bust_spinlocks(1); + bust_spinlocks(0); + uml_exitcode = 1; + os_dump_core(); + return 0; +} + +static struct notifier_block panic_exit_notifier = { + .notifier_call = panic_exit, + .next = NULL, + .priority = 0 +}; + /* Set during early boot */ +unsigned long task_size; +EXPORT_SYMBOL(task_size); + +unsigned long host_task_size; + unsigned long brk_start; unsigned long end_iomem; EXPORT_SYMBOL(end_iomem); #define MIN_VMALLOC (32 * 1024 * 1024) -int linux_main(int argc, char **argv) +extern char __binary_start; + +int __init linux_main(int argc, char **argv) { unsigned long avail, diff; unsigned long virtmem_size, max_physmem; - unsigned int i, add; + unsigned long stack; + unsigned int i; + int add; char * mode; - for (i = 1; i < argc; i++){ - if((i == 1) && (argv[i][0] == ' ')) continue; + for (i = 1; i < argc; i++) { + if ((i == 1) && (argv[i][0] == ' ')) + continue; add = 1; uml_checksetup(argv[i], &add); if (add) add_arg(argv[i]); } - if(have_root == 0) + if (have_root == 0) add_arg(DEFAULT_COMMAND_LINE); + host_task_size = os_get_top_address(); + /* + * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps + * out + */ + task_size = host_task_size & PGDIR_MASK; + + /* OS sanity checks that need to happen before the kernel runs */ os_early_checks(); - if (force_tt) - clear_can_do_skas(); - mode_tt = force_tt ? 1 : !can_do_skas(); -#ifndef CONFIG_MODE_TT - if (mode_tt) { - /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So, - * can_do_skas() returned 0, and the message is correct. */ - printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n"); - exit(1); - } -#endif -#ifndef CONFIG_MODE_SKAS - mode = "TT"; -#else - /* Show to the user the result of selection */ - if (mode_tt) - mode = "TT"; - else if (proc_mm && ptrace_faultinfo) + can_do_skas(); + + if (proc_mm && ptrace_faultinfo) mode = "SKAS3"; else mode = "SKAS0"; -#endif printf("UML running in %s mode\n", mode); - uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, - &host_task_size, &task_size); - brk_start = (unsigned long) sbrk(0); - CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); - /* Increase physical memory size for exec-shield users - so they actually get what they asked for. This should - add zero for non-exec shield users */ + + /* + * Increase physical memory size for exec-shield users + * so they actually get what they asked for. This should + * add zero for non-exec shield users + */ diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); - if(diff > 1024 * 1024){ + if (diff > 1024 * 1024) { printf("Adding %ld bytes to physical memory to account for " "exec-shield gap\n", diff); physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); } - uml_physmem = uml_start; + uml_physmem = (unsigned long) &__binary_start & PAGE_MASK; /* Reserve up to 4M after the current brk */ uml_reserved = ROUND_4M(brk_start) + (1 << 22); - setup_machinename(system_utsname.machine); + setup_machinename(init_utsname()->machine); -#ifdef CONFIG_CMDLINE_ON_HOST - argv1_begin = argv[1]; - argv1_end = &argv[1][strlen(argv[1])]; -#endif - highmem = 0; iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; - max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; + max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC; - /* Zones have to begin on a 1 << MAX_ORDER page boundary, + /* + * Zones have to begin on a 1 << MAX_ORDER page boundary, * so this makes sure that's true for highmem */ max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); - if(physmem_size + iomem_size > max_physmem){ + if (physmem_size + iomem_size > max_physmem) { highmem = physmem_size + iomem_size - max_physmem; physmem_size -= highmem; #ifndef CONFIG_HIGHMEM highmem = 0; printf("CONFIG_HIGHMEM not enabled - physical memory shrunk " - "to %lu bytes\n", physmem_size); + "to %Lu bytes\n", physmem_size); #endif } @@ -413,65 +348,62 @@ int linux_main(int argc, char **argv) start_vm = VMALLOC_START; setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); - if(init_maps(physmem_size, iomem_size, highmem)){ - printf("Failed to allocate mem_map for %lu bytes of physical " - "memory and %lu bytes of highmem\n", physmem_size, + if (init_maps(physmem_size, iomem_size, highmem)) { + printf("Failed to allocate mem_map for %Lu bytes of physical " + "memory and %Lu bytes of highmem\n", physmem_size, highmem); exit(1); } virtmem_size = physmem_size; - avail = get_kmem_end() - start_vm; - if(physmem_size > avail) virtmem_size = avail; + stack = (unsigned long) argv; + stack &= ~(1024 * 1024 - 1); + avail = stack - start_vm; + if (physmem_size > avail) + virtmem_size = avail; end_vm = start_vm + virtmem_size; - if(virtmem_size < physmem_size) + if (virtmem_size < physmem_size) printf("Kernel virtual memory size shrunk to %lu bytes\n", virtmem_size); - uml_postsetup(); + atomic_notifier_chain_register(&panic_notifier_list, + &panic_exit_notifier); - task_protections((unsigned long) &init_thread_info); - os_flush_stdout(); - - return(CHOOSE_MODE(start_uml_tt(), start_uml_skas())); -} + uml_postsetup(); -extern int uml_exitcode; + stack_protections((unsigned long) &init_thread_info); + os_flush_stdout(); -static int panic_exit(struct notifier_block *self, unsigned long unused1, - void *unused2) -{ - bust_spinlocks(1); - show_regs(&(current->thread.regs)); - bust_spinlocks(0); - uml_exitcode = 1; - machine_halt(); - return(0); + return start_uml(); } -static struct notifier_block panic_exit_notifier = { - .notifier_call = panic_exit, - .next = NULL, - .priority = 0 -}; - void __init setup_arch(char **cmdline_p) { - notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); paging_init(); - strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); - *cmdline_p = command_line; - setup_hostinfo(); + strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + *cmdline_p = command_line; + setup_hostinfo(host_info, sizeof host_info); } void __init check_bugs(void) { arch_check_bugs(); - check_sigio(); - check_devanon(); + os_check_bugs(); +} + +void apply_alternatives(struct alt_instr *start, struct alt_instr *end) +{ } -void apply_alternatives(void *start, void *end) +#ifdef CONFIG_SMP +void alternatives_smp_module_add(struct module *mod, char *name, + void *locks, void *locks_end, + void *text, void *text_end) { } + +void alternatives_smp_module_del(struct module *mod) +{ +} +#endif diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c index 0b21d59ba0c..f6cc3bd6178 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -1,330 +1,38 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stdio.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> -#include <dirent.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/param.h> -#include "user.h" -#include "umid.h" -#include "init.h" -#include "os.h" -#include "user_util.h" -#include "choose-mode.h" - -#define UMID_LEN 64 -#define UML_DIR "~/.uml/" - -/* Changed by set_umid and make_umid, which are run early in boot */ -static char umid[UMID_LEN] = { 0 }; +#include <asm/errno.h> +#include <init.h> +#include <kern.h> +#include <os.h> -/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */ -static char *uml_dir = UML_DIR; - -/* Changed by set_umid */ -static int umid_is_random = 1; +/* Changed by set_umid_arg */ static int umid_inited = 0; -/* Have we created the files? Should we remove them? */ -static int umid_owned = 0; - -static int make_umid(int (*printer)(const char *fmt, ...)); -static int __init set_umid(char *name, int is_random, - int (*printer)(const char *fmt, ...)) +static int __init set_umid_arg(char *name, int *add) { - if(umid_inited){ - (*printer)("Unique machine name can't be set twice\n"); - return(-1); + int err; + + if (umid_inited) { + printf("umid already set\n"); + return 0; } - if(strlen(name) > UMID_LEN - 1) - (*printer)("Unique machine name is being truncated to %d " - "characters\n", UMID_LEN); - strlcpy(umid, name, sizeof(umid)); + *add = 0; + err = set_umid(name); + if (err == -EEXIST) + printf("umid '%s' already in use\n", name); + else if (!err) + umid_inited = 1; - umid_is_random = is_random; - umid_inited = 1; return 0; } -static int __init set_umid_arg(char *name, int *add) -{ - *add = 0; - return(set_umid(name, 0, printf)); -} - __uml_setup("umid=", set_umid_arg, "umid=<name>\n" " This is used to assign a unique identity to this UML machine and\n" " is used for naming the pid file and management console socket.\n\n" ); -int __init umid_file_name(char *name, char *buf, int len) -{ - int n; - - if(!umid_inited && make_umid(printk)) return(-1); - - n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1; - if(n > len){ - printk("umid_file_name : buffer too short\n"); - return(-1); - } - - sprintf(buf, "%s%s/%s", uml_dir, umid, name); - return(0); -} - -extern int tracing_pid; - -static void __init create_pid_file(void) -{ - char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; - char pid[sizeof("nnnnn\0")]; - int fd, n; - - if(umid_file_name("pid", file, sizeof(file))) - return; - - fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), - 0644); - if(fd < 0){ - printf("Open of machine pid file \"%s\" failed: %s\n", - file, strerror(-fd)); - return; - } - - sprintf(pid, "%d\n", os_getpid()); - n = os_write_file(fd, pid, strlen(pid)); - if(n != strlen(pid)) - printf("Write of pid file failed - err = %d\n", -n); - os_close_file(fd); -} - -static int actually_do_remove(char *dir) -{ - DIR *directory; - struct dirent *ent; - int len; - char file[256]; - - directory = opendir(dir); - if(directory == NULL){ - printk("actually_do_remove : couldn't open directory '%s', " - "errno = %d\n", dir, errno); - return(1); - } - while((ent = readdir(directory)) != NULL){ - if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) - continue; - len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1; - if(len > sizeof(file)){ - printk("Not deleting '%s' from '%s' - name too long\n", - ent->d_name, dir); - continue; - } - sprintf(file, "%s/%s", dir, ent->d_name); - if(unlink(file) < 0){ - printk("actually_do_remove : couldn't remove '%s' " - "from '%s', errno = %d\n", ent->d_name, dir, - errno); - return(1); - } - } - if(rmdir(dir) < 0){ - printk("actually_do_remove : couldn't rmdir '%s', " - "errno = %d\n", dir, errno); - return(1); - } - return(0); -} - -void remove_umid_dir(void) -{ - char dir[strlen(uml_dir) + UMID_LEN + 1]; - if (!umid_owned) - return; - - sprintf(dir, "%s%s", uml_dir, umid); - actually_do_remove(dir); -} - -char *get_umid(int only_if_set) -{ - if(only_if_set && umid_is_random) - return NULL; - return umid; -} - -static int not_dead_yet(char *dir) -{ - char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; - char pid[sizeof("nnnnn\0")], *end; - int dead, fd, p, n; - - sprintf(file, "%s/pid", dir); - dead = 0; - fd = os_open_file(file, of_read(OPENFLAGS()), 0); - if(fd < 0){ - if(fd != -ENOENT){ - printk("not_dead_yet : couldn't open pid file '%s', " - "err = %d\n", file, -fd); - return(1); - } - dead = 1; - } - if(fd > 0){ - n = os_read_file(fd, pid, sizeof(pid)); - if(n < 0){ - printk("not_dead_yet : couldn't read pid file '%s', " - "err = %d\n", file, -n); - return(1); - } - p = strtoul(pid, &end, 0); - if(end == pid){ - printk("not_dead_yet : couldn't parse pid file '%s', " - "errno = %d\n", file, errno); - dead = 1; - } - if(((kill(p, 0) < 0) && (errno == ESRCH)) || - (p == CHOOSE_MODE(tracing_pid, os_getpid()))) - dead = 1; - } - if(!dead) - return(1); - return(actually_do_remove(dir)); -} - -static int __init set_uml_dir(char *name, int *add) -{ - if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){ - uml_dir = malloc(strlen(name) + 2); - if(uml_dir == NULL){ - printf("Failed to malloc uml_dir - error = %d\n", - errno); - uml_dir = name; - /* Return 0 here because do_initcalls doesn't look at - * the return value. - */ - return(0); - } - sprintf(uml_dir, "%s/", name); - } - else uml_dir = name; - return(0); -} - -static int __init make_uml_dir(void) -{ - char dir[MAXPATHLEN + 1] = { '\0' }; - int len; - - if(*uml_dir == '~'){ - char *home = getenv("HOME"); - - if(home == NULL){ - printf("make_uml_dir : no value in environment for " - "$HOME\n"); - exit(1); - } - strlcpy(dir, home, sizeof(dir)); - uml_dir++; - } - strlcat(dir, uml_dir, sizeof(dir)); - len = strlen(dir); - if (len > 0 && dir[len - 1] != '/') - strlcat(dir, "/", sizeof(dir)); - - uml_dir = malloc(strlen(dir) + 1); - if (uml_dir == NULL) { - printf("make_uml_dir : malloc failed, errno = %d\n", errno); - exit(1); - } - strcpy(uml_dir, dir); - - if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){ - printf("Failed to mkdir %s: %s\n", uml_dir, strerror(errno)); - return(-1); - } - return 0; -} - -static int __init make_umid(int (*printer)(const char *fmt, ...)) -{ - int fd, err; - char tmp[strlen(uml_dir) + UMID_LEN + 1]; - - strlcpy(tmp, uml_dir, sizeof(tmp)); - - if(!umid_inited){ - strcat(tmp, "XXXXXX"); - fd = mkstemp(tmp); - if(fd < 0){ - (*printer)("make_umid - mkstemp(%s) failed: %s\n", - tmp,strerror(errno)); - return(1); - } - - os_close_file(fd); - /* There's a nice tiny little race between this unlink and - * the mkdir below. It'd be nice if there were a mkstemp - * for directories. - */ - unlink(tmp); - set_umid(&tmp[strlen(uml_dir)], 1, printer); - } - - sprintf(tmp, "%s%s", uml_dir, umid); - - err = mkdir(tmp, 0777); - if(err < 0){ - if(errno == EEXIST){ - if(not_dead_yet(tmp)){ - (*printer)("umid '%s' is in use\n", umid); - umid_owned = 0; - return(-1); - } - err = mkdir(tmp, 0777); - } - } - if(err < 0){ - (*printer)("Failed to create %s - errno = %d\n", umid, errno); - return(-1); - } - - umid_owned = 1; - return 0; -} - -__uml_setup("uml_dir=", set_uml_dir, -"uml_dir=<directory>\n" -" The location to place the pid and umid files.\n\n" -); - -static int __init make_umid_setup(void) -{ - /* one function with the ordering we need ... */ - make_uml_dir(); - make_umid(printf); - create_pid_file(); - return 0; -} -__uml_postsetup(make_umid_setup); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index af11915ce0a..6899195602b 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -1,4 +1,5 @@ #include <asm-generic/vmlinux.lds.h> +#include <asm/page.h> OUTPUT_FORMAT(ELF_FORMAT) OUTPUT_ARCH(ELF_ARCH) @@ -7,55 +8,69 @@ jiffies = jiffies_64; SECTIONS { - /*This must contain the right address - not quite the default ELF one.*/ + /* This must contain the right address - not quite the default ELF one.*/ PROVIDE (__executable_start = START); - . = START + SIZEOF_HEADERS; - - /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start - * is remapped.*/ - __binary_start = .; + /* Static binaries stick stuff here, like the sigreturn trampoline, + * invisibly to objdump. So, just make __binary_start equal to the very + * beginning of the executable, and if there are unmapped pages after this, + * they are forever unusable. + */ + __binary_start = START; -#ifdef MODE_TT - .remap_data : { UNMAP_PATH (.data .bss) } - .remap : { UNMAP_PATH (.text) } + . = START + SIZEOF_HEADERS; - . = ALIGN(4096); /* Init code and data */ -#endif - - _stext = .; - __init_begin = .; - .init.text : { - _sinittext = .; - *(.init.text) - _einittext = .; - } - . = ALIGN(4096); + _text = .; + INIT_TEXT_SECTION(0) + . = ALIGN(PAGE_SIZE); .text : { - *(.text) + _stext = .; + TEXT_TEXT SCHED_TEXT LOCK_TEXT *(.fixup) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) *(.gnu.linkonce.t*) + } - . = ALIGN(4096); - __syscall_stub_start = .; - *(.__syscall_stub*) - __syscall_stub_end = .; - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); + .syscall_stub : { + __syscall_stub_start = .; + *(.__syscall_stub*) + __syscall_stub_end = .; } - #include "asm/common.lds.S" + /* + * These are needed even in a static link, even if they wind up being empty. + * Newer glibc needs these __rel{,a}_iplt_{start,end} symbols. + */ + .rel.plt : { + *(.rel.plt) + PROVIDE_HIDDEN(__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN(__rel_iplt_end = .); + } + .rela.plt : { + *(.rela.plt) + PROVIDE_HIDDEN(__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN(__rela_iplt_end = .); + } + + #include <asm/common.lds.S> + + __init_begin = .; + init.data : { INIT_DATA } + __init_end = .; - init.data : { *(init.data) } .data : { - . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ - *(.data.init_task) - *(.data) + INIT_TASK_DATA(KERNEL_STACK_SIZE) + . = ALIGN(KERNEL_STACK_SIZE); + *(.data..init_irqstack) + DATA_DATA *(.gnu.linkonce.d*) CONSTRUCTORS } @@ -79,24 +94,18 @@ SECTIONS .sdata : { *(.sdata) } _edata = .; PROVIDE (edata = .); - . = ALIGN(0x1000); - .sbss : - { - __bss_start = .; - PROVIDE(_bss_start = .); - *(.sbss) - *(.scommon) - } - .bss : - { - *(.dynbss) - *(.bss) - *(COMMON) - } + . = ALIGN(PAGE_SIZE); + __bss_start = .; + PROVIDE(_bss_start = .); + SBSS(0) + BSS(0) + __bss_stop = .; _end = .; PROVIDE (end = .); STABS_DEBUG DWARF_DEBUG + + DISCARDS } diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c deleted file mode 100644 index 4c231161f25..00000000000 --- a/arch/um/kernel/user_util.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <limits.h> -#include <setjmp.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/utsname.h> -#include <sys/param.h> -#include <sys/time.h> -#include "asm/types.h" -#include <ctype.h> -#include <signal.h> -#include <wait.h> -#include <errno.h> -#include <stdarg.h> -#include <sched.h> -#include <termios.h> -#include <string.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "mem_user.h" -#include "init.h" -#include "ptrace_user.h" -#include "uml-config.h" - -void stop(void) -{ - while(1) sleep(1000000); -} - -void stack_protections(unsigned long address) -{ - int prot = PROT_READ | PROT_WRITE | PROT_EXEC; - - if(mprotect((void *) address, page_size(), prot) < 0) - panic("protecting stack failed, errno = %d", errno); -} - -void task_protections(unsigned long address) -{ - unsigned long guard = address + page_size(); - unsigned long stack = guard + page_size(); - int prot = 0, pages; - -#ifdef notdef - if(mprotect((void *) stack, page_size(), prot) < 0) - panic("protecting guard page failed, errno = %d", errno); -#endif - pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2; - prot = PROT_READ | PROT_WRITE | PROT_EXEC; - if(mprotect((void *) stack, pages * page_size(), prot) < 0) - panic("protecting stack failed, errno = %d", errno); -} - -int wait_for_stop(int pid, int sig, int cont_type, void *relay) -{ - sigset_t *relay_signals = relay; - int status, ret; - - while(1){ - CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED)); - if((ret < 0) || - !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ - if(ret < 0){ - printk("wait failed, errno = %d\n", - errno); - } - else if(WIFEXITED(status)) - printk("process %d exited with status %d\n", - pid, WEXITSTATUS(status)); - else if(WIFSIGNALED(status)) - printk("process %d exited with signal %d\n", - pid, WTERMSIG(status)); - else if((WSTOPSIG(status) == SIGVTALRM) || - (WSTOPSIG(status) == SIGALRM) || - (WSTOPSIG(status) == SIGIO) || - (WSTOPSIG(status) == SIGPROF) || - (WSTOPSIG(status) == SIGCHLD) || - (WSTOPSIG(status) == SIGWINCH) || - (WSTOPSIG(status) == SIGINT)){ - ptrace(cont_type, pid, 0, WSTOPSIG(status)); - continue; - } - else if((relay_signals != NULL) && - sigismember(relay_signals, WSTOPSIG(status))){ - ptrace(cont_type, pid, 0, WSTOPSIG(status)); - continue; - } - else printk("process %d stopped with signal %d\n", - pid, WSTOPSIG(status)); - panic("wait_for_stop failed to wait for %d to stop " - "with %d\n", pid, sig); - } - return(status); - } -} - -int raw(int fd) -{ - struct termios tt; - int err; - - CATCH_EINTR(err = tcgetattr(fd, &tt)); - if(err < 0) - return -errno; - - cfmakeraw(&tt); - - CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); - if(err < 0) - return -errno; - - /* XXX tcsetattr could have applied only some changes - * (and cfmakeraw() is a set of changes) */ - return(0); -} - -void setup_machinename(char *machine_out) -{ - struct utsname host; - - uname(&host); -#if defined(UML_CONFIG_UML_X86) && !defined(UML_CONFIG_64BIT) - if (!strcmp(host.machine, "x86_64")) { - strcpy(machine_out, "i686"); - return; - } -#endif - strcpy(machine_out, host.machine); -} - -char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1]; - -void setup_hostinfo(void) -{ - struct utsname host; - - uname(&host); - sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename, - host.release, host.version, host.machine); -} - -int setjmp_wrapper(void (*proc)(void *, void *), ...) -{ - va_list args; - sigjmp_buf buf; - int n; - - n = sigsetjmp(buf, 1); - if(n == 0){ - va_start(args, proc); - (*proc)(&buf, &args); - } - va_end(args); - return(n); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/vmlinux.lds.S b/arch/um/kernel/vmlinux.lds.S index 1660a769674..16e49bfa2b4 100644 --- a/arch/um/kernel/vmlinux.lds.S +++ b/arch/um/kernel/vmlinux.lds.S @@ -1,4 +1,6 @@ -#include <linux/config.h> + +KERNEL_STACK_SIZE = 4096 * (1 << CONFIG_KERNEL_STACK_ORDER); + #ifdef CONFIG_LD_SCRIPT_STATIC #include "uml.lds.S" #else diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index b83ac8e21c3..08ff5094fcd 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -1,19 +1,17 @@ # -# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) +# Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) # Licensed under the GPL # -obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ - start_up.o time.o tt.o tty.o uaccess.o user_syms.o drivers/ \ - sys-$(SUBARCH)/ +obj-y = aio.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ + registers.o sigio.o signal.o start_up.o time.o tty.o \ + umid.o user_syms.o util.o drivers/ skas/ -USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ - start_up.o time.o tt.o tty.o uaccess.o +obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) += elf_aux.o -elf_aux.o: $(ARCH_DIR)/kernel-offsets.h -CFLAGS_elf_aux.o += -I$(objtree)/arch/um - -CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) +USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \ + main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \ + tty.o umid.o util.o HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \ echo -DHAVE_AIO_ABI ) diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index ffa759addd3..014eb35fd13 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c @@ -1,36 +1,33 @@ /* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stdlib.h> #include <unistd.h> +#include <sched.h> #include <signal.h> #include <errno.h> -#include <sched.h> -#include <sys/syscall.h> -#include "os.h" -#include "aio.h" -#include "init.h" -#include "user.h" -#include "mode.h" +#include <sys/time.h> +#include <asm/unistd.h> +#include <aio.h> +#include <init.h> +#include <kern_util.h> +#include <os.h> struct aio_thread_req { - enum aio_type type; - int io_fd; - unsigned long long offset; - char *buf; - int len; - struct aio_context *aio; + enum aio_type type; + int io_fd; + unsigned long long offset; + char *buf; + int len; + struct aio_context *aio; }; -static int aio_req_fd_r = -1; -static int aio_req_fd_w = -1; - #if defined(HAVE_AIO_ABI) #include <linux/aio_abi.h> -/* If we have the headers, we are going to build with AIO enabled. +/* + * If we have the headers, we are going to build with AIO enabled. * If we don't have aio in libc, we define the necessary stubs here. */ @@ -38,23 +35,24 @@ static int aio_req_fd_w = -1; static long io_setup(int n, aio_context_t *ctxp) { - return syscall(__NR_io_setup, n, ctxp); + return syscall(__NR_io_setup, n, ctxp); } static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) { - return syscall(__NR_io_submit, ctx, nr, iocbpp); + return syscall(__NR_io_submit, ctx, nr, iocbpp); } static long io_getevents(aio_context_t ctx_id, long min_nr, long nr, - struct io_event *events, struct timespec *timeout) + struct io_event *events, struct timespec *timeout) { - return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout); + return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout); } #endif -/* The AIO_MMAP cases force the mmapped page into memory here +/* + * The AIO_MMAP cases force the mmapped page into memory here * rather than in whatever place first touches the data. I used * to do this by touching the page, but that's delicate because * gcc is prone to optimizing that away. So, what's done here @@ -66,252 +64,247 @@ static long io_getevents(aio_context_t ctx_id, long min_nr, long nr, */ static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf, - int len, unsigned long long offset, struct aio_context *aio) + int len, unsigned long long offset, struct aio_context *aio) { - struct iocb iocb, *iocbp = &iocb; - char c; - int err; - - iocb = ((struct iocb) { .aio_data = (unsigned long) aio, - .aio_reqprio = 0, - .aio_fildes = fd, - .aio_buf = (unsigned long) buf, - .aio_nbytes = len, - .aio_offset = offset, - .aio_reserved1 = 0, - .aio_reserved2 = 0, - .aio_reserved3 = 0 }); - - switch(type){ - case AIO_READ: - iocb.aio_lio_opcode = IOCB_CMD_PREAD; - err = io_submit(ctx, 1, &iocbp); - break; - case AIO_WRITE: - iocb.aio_lio_opcode = IOCB_CMD_PWRITE; - err = io_submit(ctx, 1, &iocbp); - break; - case AIO_MMAP: - iocb.aio_lio_opcode = IOCB_CMD_PREAD; - iocb.aio_buf = (unsigned long) &c; - iocb.aio_nbytes = sizeof(c); - err = io_submit(ctx, 1, &iocbp); - break; - default: - printk("Bogus op in do_aio - %d\n", type); - err = -EINVAL; - break; - } - - if(err > 0) - err = 0; - else - err = -errno; - - return err; + struct iocb *iocbp = & ((struct iocb) { + .aio_data = (unsigned long) aio, + .aio_fildes = fd, + .aio_buf = (unsigned long) buf, + .aio_nbytes = len, + .aio_offset = offset + }); + char c; + + switch (type) { + case AIO_READ: + iocbp->aio_lio_opcode = IOCB_CMD_PREAD; + break; + case AIO_WRITE: + iocbp->aio_lio_opcode = IOCB_CMD_PWRITE; + break; + case AIO_MMAP: + iocbp->aio_lio_opcode = IOCB_CMD_PREAD; + iocbp->aio_buf = (unsigned long) &c; + iocbp->aio_nbytes = sizeof(c); + break; + default: + printk(UM_KERN_ERR "Bogus op in do_aio - %d\n", type); + return -EINVAL; + } + + return (io_submit(ctx, 1, &iocbp) > 0) ? 0 : -errno; } +/* Initialized in an initcall and unchanged thereafter */ static aio_context_t ctx = 0; static int aio_thread(void *arg) { - struct aio_thread_reply reply; - struct io_event event; - int err, n, reply_fd; - - signal(SIGWINCH, SIG_IGN); - - while(1){ - n = io_getevents(ctx, 1, 1, &event, NULL); - if(n < 0){ - if(errno == EINTR) - continue; - printk("aio_thread - io_getevents failed, " - "errno = %d\n", errno); - } - else { - reply = ((struct aio_thread_reply) - { .data = (void *) (long) event.data, - .err = event.res }); + struct aio_thread_reply reply; + struct io_event event; + int err, n, reply_fd; + + os_fix_helper_signals(); + while (1) { + n = io_getevents(ctx, 1, 1, &event, NULL); + if (n < 0) { + if (errno == EINTR) + continue; + printk(UM_KERN_ERR "aio_thread - io_getevents failed, " + "errno = %d\n", errno); + } + else { + reply = ((struct aio_thread_reply) + { .data = (void *) (long) event.data, + .err = event.res }); reply_fd = ((struct aio_context *) reply.data)->reply_fd; - err = os_write_file(reply_fd, &reply, sizeof(reply)); - if(err != sizeof(reply)) - printk("aio_thread - write failed, fd = %d, " - "err = %d\n", aio_req_fd_r, -err); - } - } - return 0; + err = write(reply_fd, &reply, sizeof(reply)); + if (err != sizeof(reply)) + printk(UM_KERN_ERR "aio_thread - write failed, " + "fd = %d, err = %d\n", reply_fd, errno); + } + } + return 0; } #endif static int do_not_aio(struct aio_thread_req *req) { - char c; - int err; - - switch(req->type){ - case AIO_READ: - err = os_seek_file(req->io_fd, req->offset); - if(err) - goto out; - - err = os_read_file(req->io_fd, req->buf, req->len); - break; - case AIO_WRITE: - err = os_seek_file(req->io_fd, req->offset); - if(err) - goto out; - - err = os_write_file(req->io_fd, req->buf, req->len); - break; - case AIO_MMAP: - err = os_seek_file(req->io_fd, req->offset); - if(err) - goto out; - - err = os_read_file(req->io_fd, &c, sizeof(c)); - break; - default: - printk("do_not_aio - bad request type : %d\n", req->type); - err = -EINVAL; - break; - } - - out: - return err; + char c; + unsigned long long actual; + int n; + + actual = lseek64(req->io_fd, req->offset, SEEK_SET); + if (actual != req->offset) + return -errno; + + switch (req->type) { + case AIO_READ: + n = read(req->io_fd, req->buf, req->len); + break; + case AIO_WRITE: + n = write(req->io_fd, req->buf, req->len); + break; + case AIO_MMAP: + n = read(req->io_fd, &c, sizeof(c)); + break; + default: + printk(UM_KERN_ERR "do_not_aio - bad request type : %d\n", + req->type); + return -EINVAL; + } + + if (n < 0) + return -errno; + return 0; } +/* These are initialized in initcalls and not changed */ +static int aio_req_fd_r = -1; +static int aio_req_fd_w = -1; +static int aio_pid = -1; +static unsigned long aio_stack; + static int not_aio_thread(void *arg) { - struct aio_thread_req req; - struct aio_thread_reply reply; - int err; - - signal(SIGWINCH, SIG_IGN); - while(1){ - err = os_read_file(aio_req_fd_r, &req, sizeof(req)); - if(err != sizeof(req)){ - if(err < 0) - printk("not_aio_thread - read failed, " - "fd = %d, err = %d\n", aio_req_fd_r, - -err); - else { - printk("not_aio_thread - short read, fd = %d, " - "length = %d\n", aio_req_fd_r, err); - } - continue; - } - err = do_not_aio(&req); - reply = ((struct aio_thread_reply) { .data = req.aio, - .err = err }); - err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply)); - if(err != sizeof(reply)) - printk("not_aio_thread - write failed, fd = %d, " - "err = %d\n", aio_req_fd_r, -err); - } + struct aio_thread_req req; + struct aio_thread_reply reply; + int err; + + os_fix_helper_signals(); + while (1) { + err = read(aio_req_fd_r, &req, sizeof(req)); + if (err != sizeof(req)) { + if (err < 0) + printk(UM_KERN_ERR "not_aio_thread - " + "read failed, fd = %d, err = %d\n", + aio_req_fd_r, + errno); + else { + printk(UM_KERN_ERR "not_aio_thread - short " + "read, fd = %d, length = %d\n", + aio_req_fd_r, err); + } + continue; + } + err = do_not_aio(&req); + reply = ((struct aio_thread_reply) { .data = req.aio, + .err = err }); + err = write(req.aio->reply_fd, &reply, sizeof(reply)); + if (err != sizeof(reply)) + printk(UM_KERN_ERR "not_aio_thread - write failed, " + "fd = %d, err = %d\n", req.aio->reply_fd, errno); + } + + return 0; } -static int aio_pid = -1; - static int init_aio_24(void) { - unsigned long stack; - int fds[2], err; - - err = os_pipe(fds, 1, 1); - if(err) - goto out; - - aio_req_fd_w = fds[0]; - aio_req_fd_r = fds[1]; - err = run_helper_thread(not_aio_thread, NULL, - CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0); - if(err < 0) - goto out_close_pipe; - - aio_pid = err; - goto out; - - out_close_pipe: - os_close_file(fds[0]); - os_close_file(fds[1]); - aio_req_fd_w = -1; - aio_req_fd_r = -1; - out: + int fds[2], err; + + err = os_pipe(fds, 1, 1); + if (err) + goto out; + + aio_req_fd_w = fds[0]; + aio_req_fd_r = fds[1]; + + err = os_set_fd_block(aio_req_fd_w, 0); + if (err) + goto out_close_pipe; + + err = run_helper_thread(not_aio_thread, NULL, + CLONE_FILES | CLONE_VM, &aio_stack); + if (err < 0) + goto out_close_pipe; + + aio_pid = err; + goto out; + +out_close_pipe: + close(fds[0]); + close(fds[1]); + aio_req_fd_w = -1; + aio_req_fd_r = -1; +out: #ifndef HAVE_AIO_ABI - printk("/usr/include/linux/aio_abi.h not present during build\n"); + printk(UM_KERN_INFO "/usr/include/linux/aio_abi.h not present during " + "build\n"); #endif - printk("2.6 host AIO support not used - falling back to I/O " - "thread\n"); - return 0; + printk(UM_KERN_INFO "2.6 host AIO support not used - falling back to " + "I/O thread\n"); + return 0; } #ifdef HAVE_AIO_ABI #define DEFAULT_24_AIO 0 static int init_aio_26(void) { - unsigned long stack; - int err; + int err; - if(io_setup(256, &ctx)){ + if (io_setup(256, &ctx)) { err = -errno; - printk("aio_thread failed to initialize context, err = %d\n", - errno); - return err; - } + printk(UM_KERN_ERR "aio_thread failed to initialize context, " + "err = %d\n", errno); + return err; + } - err = run_helper_thread(aio_thread, NULL, - CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0); - if(err < 0) - return err; + err = run_helper_thread(aio_thread, NULL, + CLONE_FILES | CLONE_VM, &aio_stack); + if (err < 0) + return err; - aio_pid = err; + aio_pid = err; - printk("Using 2.6 host AIO\n"); - return 0; + printk(UM_KERN_INFO "Using 2.6 host AIO\n"); + return 0; } static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, unsigned long long offset, struct aio_context *aio) { - struct aio_thread_reply reply; - int err; - - err = do_aio(ctx, type, io_fd, buf, len, offset, aio); - if(err){ - reply = ((struct aio_thread_reply) { .data = aio, - .err = err }); - err = os_write_file(aio->reply_fd, &reply, sizeof(reply)); - if(err != sizeof(reply)) - printk("submit_aio_26 - write failed, " - "fd = %d, err = %d\n", aio->reply_fd, -err); - else err = 0; - } - - return err; + struct aio_thread_reply reply; + int err; + + err = do_aio(ctx, type, io_fd, buf, len, offset, aio); + if (err) { + reply = ((struct aio_thread_reply) { .data = aio, + .err = err }); + err = write(aio->reply_fd, &reply, sizeof(reply)); + if (err != sizeof(reply)) { + err = -errno; + printk(UM_KERN_ERR "submit_aio_26 - write failed, " + "fd = %d, err = %d\n", aio->reply_fd, -err); + } + else err = 0; + } + + return err; } #else #define DEFAULT_24_AIO 1 static int init_aio_26(void) { - return -ENOSYS; + return -ENOSYS; } static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, unsigned long long offset, struct aio_context *aio) { - return -ENOSYS; + return -ENOSYS; } #endif +/* Initialized in an initcall and unchanged thereafter */ static int aio_24 = DEFAULT_24_AIO; static int __init set_aio_24(char *name, int *add) { - aio_24 = 1; - return 0; + aio_24 = 1; + return 0; } __uml_setup("aio=2.4", set_aio_24, @@ -328,31 +321,26 @@ __uml_setup("aio=2.4", set_aio_24, static int init_aio(void) { - int err; - - CHOOSE_MODE(({ - if(!aio_24){ - printk("Disabling 2.6 AIO in tt mode\n"); - aio_24 = 1; - } }), (void) 0); - - if(!aio_24){ - err = init_aio_26(); - if(err && (errno == ENOSYS)){ - printk("2.6 AIO not supported on the host - " - "reverting to 2.4 AIO\n"); - aio_24 = 1; - } - else return err; - } - - if(aio_24) - return init_aio_24(); - - return 0; + int err; + + if (!aio_24) { + err = init_aio_26(); + if (err && (errno == ENOSYS)) { + printk(UM_KERN_INFO "2.6 AIO not supported on the " + "host - reverting to 2.4 AIO\n"); + aio_24 = 1; + } + else return err; + } + + if (aio_24) + return init_aio_24(); + + return 0; } -/* The reason for the __initcall/__uml_exitcall asymmetry is that init_aio +/* + * The reason for the __initcall/__uml_exitcall asymmetry is that init_aio * needs to be called when the kernel is running because it calls run_helper, * which needs get_free_page. exit_aio is a __uml_exitcall because the generic * kernel does not run __exitcalls on shutdown, and can't because many of them @@ -362,8 +350,10 @@ __initcall(init_aio); static void exit_aio(void) { - if(aio_pid != -1) - os_kill_process(aio_pid, 1); + if (aio_pid != -1) { + os_kill_process(aio_pid, 1); + free_stack(aio_stack, 0); + } } __uml_exitcall(exit_aio); @@ -371,30 +361,30 @@ __uml_exitcall(exit_aio); static int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len, unsigned long long offset, struct aio_context *aio) { - struct aio_thread_req req = { .type = type, - .io_fd = io_fd, - .offset = offset, - .buf = buf, - .len = len, - .aio = aio, - }; - int err; - - err = os_write_file(aio_req_fd_w, &req, sizeof(req)); - if(err == sizeof(req)) - err = 0; - - return err; + struct aio_thread_req req = { .type = type, + .io_fd = io_fd, + .offset = offset, + .buf = buf, + .len = len, + .aio = aio, + }; + int err; + + err = write(aio_req_fd_w, &req, sizeof(req)); + if (err == sizeof(req)) + err = 0; + else err = -errno; + + return err; } int submit_aio(enum aio_type type, int io_fd, char *buf, int len, - unsigned long long offset, int reply_fd, - struct aio_context *aio) + unsigned long long offset, int reply_fd, + struct aio_context *aio) { - aio->reply_fd = reply_fd; - if(aio_24) - return submit_aio_24(type, io_fd, buf, len, offset, aio); - else { - return submit_aio_26(type, io_fd, buf, len, offset, aio); - } + aio->reply_fd = reply_fd; + if (aio_24) + return submit_aio_24(type, io_fd, buf, len, offset, aio); + else + return submit_aio_26(type, io_fd, buf, len, offset, aio); } diff --git a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h index b84f6c4740f..54183a679fd 100644 --- a/arch/um/os-Linux/drivers/etap.h +++ b/arch/um/os-Linux/drivers/etap.h @@ -1,9 +1,12 @@ /* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "net_user.h" +#ifndef __DRIVERS_ETAP_H +#define __DRIVERS_ETAP_H + +#include <net_user.h> struct ethertap_data { char *dev_name; @@ -13,15 +16,6 @@ struct ethertap_data { void *dev; }; -extern struct net_user_info ethertap_user_info; +extern const struct net_user_info ethertap_user_info; -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +#endif diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c index 6ae4b19d9f5..f424600a583 100644 --- a/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/arch/um/os-Linux/drivers/ethertap_kern.c @@ -1,16 +1,15 @@ /* - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Copyright (C) 2001 by various other people who didn't put their name here. * Licensed under the GPL. */ -#include "linux/init.h" -#include "linux/netdevice.h" -#include "linux/etherdevice.h" -#include "net_kern.h" -#include "net_user.h" +#include <linux/init.h> +#include <linux/netdevice.h> #include "etap.h" +#include <net_kern.h> struct ethertap_init { char *dev_name; @@ -23,7 +22,7 @@ static void etap_init(struct net_device *dev, void *data) struct ethertap_data *epri; struct ethertap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); epri = (struct ethertap_data *) pri->user; epri->dev_name = init->dev_name; epri->gate_addr = init->gate_addr; @@ -31,41 +30,33 @@ static void etap_init(struct net_device *dev, void *data) epri->control_fd = -1; epri->dev = dev; - printk("ethertap backend - %s", epri->dev_name); + printk(KERN_INFO "ethertap backend - %s", epri->dev_name); if (epri->gate_addr != NULL) - printk(", IP = %s", epri->gate_addr); - printk("\n"); + printk(KERN_CONT ", IP = %s", epri->gate_addr); + printk(KERN_CONT "\n"); } -static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) +static int etap_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) { int len; - *skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP); - if(*skb == NULL) return(-ENOMEM); - len = net_recvfrom(fd, (*skb)->mac.raw, - (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP); - if(len <= 0) return(len); - skb_pull(*skb, 2); + len = net_recvfrom(fd, skb_mac_header(skb), + skb->dev->mtu + 2 + ETH_HEADER_ETHERTAP); + if (len <= 0) + return(len); + + skb_pull(skb, 2); len -= 2; - return(len); + return len; } -static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp) +static int etap_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - if(skb_headroom(*skb) < 2){ - struct sk_buff *skb2; - - skb2 = skb_realloc_headroom(*skb, 2); - dev_kfree_skb(*skb); - if (skb2 == NULL) return(-ENOMEM); - *skb = skb2; - } - skb_push(*skb, 2); - return(net_send(fd, (*skb)->data, (*skb)->len)); + skb_push(skb, 2); + return net_send(fd, skb->data, skb->len); } -struct net_kern_info ethertap_kern_info = { +const struct net_kern_info ethertap_kern_info = { .init = etap_init, .protocol = eth_protocol, .read = etap_read, @@ -79,15 +70,15 @@ int ethertap_setup(char *str, char **mac_out, void *data) *init = ((struct ethertap_init) { .dev_name = NULL, .gate_addr = NULL }); - if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out, + if (tap_setup_common(str, "ethertap", &init->dev_name, mac_out, &init->gate_addr)) - return(0); - if(init->dev_name == NULL){ - printk("ethertap_setup : Missing tap device name\n"); - return(0); + return 0; + if (init->dev_name == NULL) { + printk(KERN_ERR "ethertap_setup : Missing tap device name\n"); + return 0; } - return(1); + return 1; } static struct transport ethertap_transport = { @@ -97,23 +88,13 @@ static struct transport ethertap_transport = { .user = ðertap_user_info, .kern = ðertap_kern_info, .private_size = sizeof(struct ethertap_data), + .setup_size = sizeof(struct ethertap_init), }; static int register_ethertap(void) { register_transport(ðertap_transport); - return(1); + return 0; } -__initcall(register_ethertap); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +late_initcall(register_ethertap); diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index 901b85e8a1c..b39b6696ac5 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and * James Leu (jleu@mindspring.net). * Copyright (C) 2001 by various other people who didn't put their name here. * Licensed under the GPL. @@ -7,27 +8,23 @@ #include <stdio.h> #include <unistd.h> -#include <stddef.h> -#include <stdlib.h> -#include <sys/errno.h> +#include <errno.h> +#include <string.h> #include <sys/socket.h> #include <sys/wait.h> -#include <sys/un.h> -#include <net/if.h> -#include "user.h" -#include "kern_util.h" -#include "user_util.h" -#include "net_user.h" #include "etap.h" -#include "os.h" +#include <os.h> +#include <net_user.h> +#include <um_malloc.h> #define MAX_PACKET ETH_MAX_PACKET -void etap_user_init(void *data, void *dev) +static int etap_user_init(void *data, void *dev) { struct ethertap_data *pri = data; pri->dev = dev; + return 0; } struct addr_change { @@ -40,20 +37,25 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask, int fd) { struct addr_change change; - void *output; + char *output; int n; change.what = op; memcpy(change.addr, addr, sizeof(change.addr)); memcpy(change.netmask, netmask, sizeof(change.netmask)); - n = os_write_file(fd, &change, sizeof(change)); - if(n != sizeof(change)) - printk("etap_change - request failed, err = %d\n", -n); - output = um_kmalloc(page_size()); - if(output == NULL) - printk("etap_change : Failed to allocate output buffer\n"); - read_output(fd, output, page_size()); - if(output != NULL){ + CATCH_EINTR(n = write(fd, &change, sizeof(change))); + if (n != sizeof(change)) { + printk(UM_KERN_ERR "etap_change - request failed, err = %d\n", + errno); + return; + } + + output = uml_kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL); + if (output == NULL) + printk(UM_KERN_ERR "etap_change : Failed to allocate output " + "buffer\n"); + read_output(fd, output, UM_KERN_PAGE_SIZE); + if (output != NULL) { printk("%s", output); kfree(output); } @@ -82,27 +84,27 @@ static void etap_pre_exec(void *arg) struct etap_pre_exec_data *data = arg; dup2(data->control_remote, 1); - os_close_file(data->data_me); - os_close_file(data->control_me); + close(data->data_me); + close(data->control_me); } -static int etap_tramp(char *dev, char *gate, int control_me, +static int etap_tramp(char *dev, char *gate, int control_me, int control_remote, int data_me, int data_remote) { struct etap_pre_exec_data pe_data; - int pid, status, err, n; + int pid, err, n; char version_buf[sizeof("nnnnn\0")]; char data_fd_buf[sizeof("nnnnnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; char *setup_args[] = { "uml_net", version_buf, "ethertap", dev, data_fd_buf, gate_buf, NULL }; - char *nosetup_args[] = { "uml_net", version_buf, "ethertap", + char *nosetup_args[] = { "uml_net", version_buf, "ethertap", dev, data_fd_buf, NULL }; char **args, c; sprintf(data_fd_buf, "%d", data_remote); sprintf(version_buf, "%d", UML_NET_VERSION); - if(gate != NULL){ + if (gate != NULL) { strcpy(gate_buf, gate); args = setup_args; } @@ -112,26 +114,24 @@ static int etap_tramp(char *dev, char *gate, int control_me, pe_data.control_remote = control_remote; pe_data.control_me = control_me; pe_data.data_me = data_me; - pid = run_helper(etap_pre_exec, &pe_data, args, NULL); - - if(pid < 0) err = pid; - os_close_file(data_remote); - os_close_file(control_remote); - n = os_read_file(control_me, &c, sizeof(c)); - if(n != sizeof(c)){ - printk("etap_tramp : read of status failed, err = %d\n", -n); - return(-EINVAL); + pid = run_helper(etap_pre_exec, &pe_data, args); + + if (pid < 0) + err = pid; + close(data_remote); + close(control_remote); + CATCH_EINTR(n = read(control_me, &c, sizeof(c))); + if (n != sizeof(c)) { + err = -errno; + printk(UM_KERN_ERR "etap_tramp : read of status failed, " + "err = %d\n", -err); + return err; } - if(c != 1){ - printk("etap_tramp : uml_net failed\n"); - err = -EINVAL; - CATCH_EINTR(n = waitpid(pid, &status, 0)); - if(n < 0) - err = -errno; - else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) - printk("uml_net didn't exit with status 1\n"); + if (c != 1) { + printk(UM_KERN_ERR "etap_tramp : uml_net failed\n"); + err = helper_wait(pid); } - return(err); + return err; } static int etap_open(void *data) @@ -141,42 +141,56 @@ static int etap_open(void *data) int data_fds[2], control_fds[2], err, output_len; err = tap_open_common(pri->dev, pri->gate_addr); - if(err) return(err); - - err = os_pipe(data_fds, 0, 0); - if(err < 0){ - printk("data os_pipe failed - err = %d\n", -err); - return(err); + if (err) + return err; + + err = socketpair(AF_UNIX, SOCK_DGRAM, 0, data_fds); + if (err) { + err = -errno; + printk(UM_KERN_ERR "etap_open - data socketpair failed - " + "err = %d\n", errno); + return err; } - err = os_pipe(control_fds, 1, 0); - if(err < 0){ - printk("control os_pipe failed - err = %d\n", -err); - return(err); + err = socketpair(AF_UNIX, SOCK_STREAM, 0, control_fds); + if (err) { + err = -errno; + printk(UM_KERN_ERR "etap_open - control socketpair failed - " + "err = %d\n", errno); + goto out_close_data; } - - err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], + + err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], control_fds[1], data_fds[0], data_fds[1]); - output_len = page_size(); - output = um_kmalloc(output_len); + output_len = UM_KERN_PAGE_SIZE; + output = uml_kmalloc(output_len, UM_GFP_KERNEL); read_output(control_fds[0], output, output_len); - if(output == NULL) - printk("etap_open : failed to allocate output buffer\n"); + if (output == NULL) + printk(UM_KERN_ERR "etap_open : failed to allocate output " + "buffer\n"); else { printk("%s", output); kfree(output); } - if(err < 0){ - printk("etap_tramp failed - err = %d\n", -err); - return(err); + if (err < 0) { + printk(UM_KERN_ERR "etap_tramp failed - err = %d\n", -err); + goto out_close_control; } pri->data_fd = data_fds[0]; pri->control_fd = control_fds[0]; iter_addresses(pri->dev, etap_open_addr, &pri->control_fd); - return(data_fds[0]); + return data_fds[0]; + +out_close_control: + close(control_fds[0]); + close(control_fds[1]); +out_close_data: + close(data_fds[0]); + close(data_fds[1]); + return err; } static void etap_close(int fd, void *data) @@ -184,56 +198,51 @@ static void etap_close(int fd, void *data) struct ethertap_data *pri = data; iter_addresses(pri->dev, etap_close_addr, &pri->control_fd); - os_close_file(fd); - os_shutdown_socket(pri->data_fd, 1, 1); - os_close_file(pri->data_fd); + close(fd); + + if (shutdown(pri->data_fd, SHUT_RDWR) < 0) + printk(UM_KERN_ERR "etap_close - shutdown data socket failed, " + "errno = %d\n", errno); + + if (shutdown(pri->control_fd, SHUT_RDWR) < 0) + printk(UM_KERN_ERR "etap_close - shutdown control socket " + "failed, errno = %d\n", errno); + + close(pri->data_fd); pri->data_fd = -1; - os_close_file(pri->control_fd); + close(pri->control_fd); pri->control_fd = -1; } -static int etap_set_mtu(int mtu, void *data) -{ - return(mtu); -} - static void etap_add_addr(unsigned char *addr, unsigned char *netmask, void *data) { struct ethertap_data *pri = data; tap_check_ips(pri->gate_addr, addr); - if(pri->control_fd == -1) return; + if (pri->control_fd == -1) + return; etap_open_addr(addr, netmask, &pri->control_fd); } -static void etap_del_addr(unsigned char *addr, unsigned char *netmask, +static void etap_del_addr(unsigned char *addr, unsigned char *netmask, void *data) { struct ethertap_data *pri = data; - if(pri->control_fd == -1) return; + if (pri->control_fd == -1) + return; + etap_close_addr(addr, netmask, &pri->control_fd); } -struct net_user_info ethertap_user_info = { +const struct net_user_info ethertap_user_info = { .init = etap_user_init, .open = etap_open, .close = etap_close, .remove = NULL, - .set_mtu = etap_set_mtu, .add_address = etap_add_addr, .delete_address = etap_del_addr, - .max_packet = MAX_PACKET - ETH_HEADER_ETHERTAP + .mtu = ETH_MAX_PACKET, + .max_packet = ETH_MAX_PACKET + ETH_HEADER_ETHERTAP, }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h index 25d4a286881..7367354ac8d 100644 --- a/arch/um/os-Linux/drivers/tuntap.h +++ b/arch/um/os-Linux/drivers/tuntap.h @@ -1,12 +1,12 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #ifndef __UM_TUNTAP_H #define __UM_TUNTAP_H -#include "net_user.h" +#include <net_user.h> struct tuntap_data { char *dev_name; @@ -16,17 +16,6 @@ struct tuntap_data { void *dev; }; -extern struct net_user_info tuntap_user_info; +extern const struct net_user_info tuntap_user_info; #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index 4202b9ebad4..d9d56e5810f 100644 --- a/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/arch/um/os-Linux/drivers/tuntap_kern.c @@ -1,16 +1,13 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/stddef.h" -#include "linux/netdevice.h" -#include "linux/etherdevice.h" -#include "linux/skbuff.h" -#include "linux/init.h" -#include "asm/errno.h" -#include "net_kern.h" -#include "net_user.h" +#include <linux/netdevice.h> +#include <linux/init.h> +#include <linux/skbuff.h> +#include <asm/errno.h> +#include <net_kern.h> #include "tuntap.h" struct tuntap_init { @@ -24,7 +21,7 @@ static void tuntap_init(struct net_device *dev, void *data) struct tuntap_data *tpri; struct tuntap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); tpri = (struct tuntap_data *) pri->user; tpri->dev_name = init->dev_name; tpri->fixed_config = (init->dev_name != NULL); @@ -32,28 +29,24 @@ static void tuntap_init(struct net_device *dev, void *data) tpri->fd = -1; tpri->dev = dev; - printk("TUN/TAP backend - "); + printk(KERN_INFO "TUN/TAP backend - "); if (tpri->gate_addr != NULL) - printk("IP = %s", tpri->gate_addr); - printk("\n"); + printk(KERN_CONT "IP = %s", tpri->gate_addr); + printk(KERN_CONT "\n"); } -static int tuntap_read(int fd, struct sk_buff **skb, - struct uml_net_private *lp) +static int tuntap_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); - if(*skb == NULL) return(-ENOMEM); - return(net_read(fd, (*skb)->mac.raw, - (*skb)->dev->mtu + ETH_HEADER_OTHER)); + return net_read(fd, skb_mac_header(skb), + skb->dev->mtu + ETH_HEADER_OTHER); } -static int tuntap_write(int fd, struct sk_buff **skb, - struct uml_net_private *lp) +static int tuntap_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) { - return(net_write(fd, (*skb)->data, (*skb)->len)); + return net_write(fd, skb->data, skb->len); } -struct net_kern_info tuntap_kern_info = { +const struct net_kern_info tuntap_kern_info = { .init = tuntap_init, .protocol = eth_protocol, .read = tuntap_read, @@ -67,11 +60,11 @@ int tuntap_setup(char *str, char **mac_out, void *data) *init = ((struct tuntap_init) { .dev_name = NULL, .gate_addr = NULL }); - if(tap_setup_common(str, "tuntap", &init->dev_name, mac_out, + if (tap_setup_common(str, "tuntap", &init->dev_name, mac_out, &init->gate_addr)) - return(0); + return 0; - return(1); + return 1; } static struct transport tuntap_transport = { @@ -87,18 +80,7 @@ static struct transport tuntap_transport = { static int register_tuntap(void) { register_transport(&tuntap_transport); - return(1); + return 0; } -__initcall(register_tuntap); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +late_initcall(register_tuntap); diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index 52945338b64..14126d9176a 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -1,34 +1,28 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #include <stdio.h> -#include <stddef.h> -#include <stdlib.h> #include <unistd.h> #include <errno.h> -#include <sys/wait.h> +#include <string.h> +#include <linux/if_tun.h> +#include <net/if.h> +#include <sys/ioctl.h> #include <sys/socket.h> -#include <sys/un.h> +#include <sys/wait.h> #include <sys/uio.h> -#include <sys/ioctl.h> -#include <net/if.h> -#include <linux/if_tun.h> -#include "net_user.h" +#include <kern_util.h> +#include <os.h> #include "tuntap.h" -#include "kern_util.h" -#include "user_util.h" -#include "user.h" -#include "os.h" -#define MAX_PACKET ETH_MAX_PACKET - -void tuntap_user_init(void *data, void *dev) +static int tuntap_user_init(void *data, void *dev) { struct tuntap_data *pri = data; pri->dev = dev; + return 0; } static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask, @@ -37,7 +31,8 @@ static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask, struct tuntap_data *pri = data; tap_check_ips(pri->gate_addr, addr); - if((pri->fd == -1) || pri->fixed_config) return; + if ((pri->fd == -1) || pri->fixed_config) + return; open_addr(addr, netmask, pri->dev_name); } @@ -46,7 +41,8 @@ static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask, { struct tuntap_data *pri = data; - if((pri->fd == -1) || pri->fixed_config) return; + if ((pri->fd == -1) || pri->fixed_config) + return; close_addr(addr, netmask, pri->dev_name); } @@ -58,9 +54,9 @@ struct tuntap_pre_exec_data { static void tuntap_pre_exec(void *arg) { struct tuntap_pre_exec_data *data = arg; - + dup2(data->stdout, 1); - os_close_file(data->close_me); + close(data->close_me); } static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, @@ -81,15 +77,16 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, data.stdout = remote; data.close_me = me; - pid = run_helper(tuntap_pre_exec, &data, argv, NULL); + pid = run_helper(tuntap_pre_exec, &data, argv); - if(pid < 0) return(-pid); + if (pid < 0) + return -pid; - os_close_file(remote); + close(remote); msg.msg_name = NULL; msg.msg_namelen = 0; - if(buffer != NULL){ + if (buffer != NULL) { iov = ((struct iovec) { buffer, buffer_len }); msg.msg_iov = &iov; msg.msg_iovlen = 1; @@ -103,26 +100,29 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, msg.msg_flags = 0; n = recvmsg(me, &msg, 0); *used_out = n; - if(n < 0){ + if (n < 0) { err = -errno; - printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", - errno); + printk(UM_KERN_ERR "tuntap_open_tramp : recvmsg failed - " + "errno = %d\n", errno); return err; } - CATCH_EINTR(waitpid(pid, NULL, 0)); + helper_wait(pid); cmsg = CMSG_FIRSTHDR(&msg); - if(cmsg == NULL){ - printk("tuntap_open_tramp : didn't receive a message\n"); - return(-EINVAL); + if (cmsg == NULL) { + printk(UM_KERN_ERR "tuntap_open_tramp : didn't receive a " + "message\n"); + return -EINVAL; } - if((cmsg->cmsg_level != SOL_SOCKET) || - (cmsg->cmsg_type != SCM_RIGHTS)){ - printk("tuntap_open_tramp : didn't receive a descriptor\n"); - return(-EINVAL); + if ((cmsg->cmsg_level != SOL_SOCKET) || + (cmsg->cmsg_type != SCM_RIGHTS)) { + printk(UM_KERN_ERR "tuntap_open_tramp : didn't receive a " + "descriptor\n"); + return -EINVAL; } *fd_out = ((int *) CMSG_DATA(cmsg))[0]; - return(0); + os_set_exec_close(*fd_out); + return 0; } static int tuntap_open(void *data) @@ -133,47 +133,52 @@ static int tuntap_open(void *data) int err, fds[2], len, used; err = tap_open_common(pri->dev, pri->gate_addr); - if(err < 0) - return(err); - - if(pri->fixed_config){ - pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0); - if(pri->fd < 0){ - printk("Failed to open /dev/net/tun, err = %d\n", - -pri->fd); - return(pri->fd); + if (err < 0) + return err; + + if (pri->fixed_config) { + pri->fd = os_open_file("/dev/net/tun", + of_cloexec(of_rdwr(OPENFLAGS())), 0); + if (pri->fd < 0) { + printk(UM_KERN_ERR "Failed to open /dev/net/tun, " + "err = %d\n", -pri->fd); + return pri->fd; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); - if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){ + if (ioctl(pri->fd, TUNSETIFF, &ifr) < 0) { err = -errno; - printk("TUNSETIFF failed, errno = %d\n", errno); - os_close_file(pri->fd); + printk(UM_KERN_ERR "TUNSETIFF failed, errno = %d\n", + errno); + close(pri->fd); return err; } } else { - err = os_pipe(fds, 0, 0); - if(err < 0){ - printk("tuntap_open : os_pipe failed - err = %d\n", - -err); - return(err); + err = socketpair(AF_UNIX, SOCK_DGRAM, 0, fds); + if (err) { + err = -errno; + printk(UM_KERN_ERR "tuntap_open : socketpair failed - " + "errno = %d\n", errno); + return err; } buffer = get_output_buffer(&len); - if(buffer != NULL) len--; + if (buffer != NULL) + len--; used = 0; err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0], fds[1], buffer, len, &used); output = buffer; - if(err < 0) { + if (err < 0) { printk("%s", output); free_output_buffer(buffer); - printk("tuntap_open_tramp failed - err = %d\n", -err); - return(err); + printk(UM_KERN_ERR "tuntap_open_tramp failed - " + "err = %d\n", -err); + return err; } pri->dev_name = uml_strdup(buffer); @@ -181,46 +186,30 @@ static int tuntap_open(void *data) printk("%s", output); free_output_buffer(buffer); - os_close_file(fds[0]); + close(fds[0]); iter_addresses(pri->dev, open_addr, pri->dev_name); } - return(pri->fd); + return pri->fd; } static void tuntap_close(int fd, void *data) { struct tuntap_data *pri = data; - if(!pri->fixed_config) + if (!pri->fixed_config) iter_addresses(pri->dev, close_addr, pri->dev_name); - os_close_file(fd); + close(fd); pri->fd = -1; } -static int tuntap_set_mtu(int mtu, void *data) -{ - return(mtu); -} - -struct net_user_info tuntap_user_info = { +const struct net_user_info tuntap_user_info = { .init = tuntap_user_init, .open = tuntap_open, .close = tuntap_close, .remove = NULL, - .set_mtu = tuntap_set_mtu, .add_address = tuntap_add_addr, .delete_address = tuntap_del_addr, - .max_packet = MAX_PACKET + .mtu = ETH_MAX_PACKET, + .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 5a99dd3fbed..1a365ddc4d0 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c @@ -9,24 +9,17 @@ */ #include <elf.h> #include <stddef.h> -#include "init.h" -#include "elf_user.h" -#include "mem_user.h" -#include <kern_constants.h> +#include <init.h> +#include <elf_user.h> +#include <mem_user.h> -/* Use the one from the kernel - the host may miss it, if having old headers. */ -#if UM_ELF_CLASS == UM_ELFCLASS32 typedef Elf32_auxv_t elf_auxv_t; -#else -typedef Elf64_auxv_t elf_auxv_t; -#endif +/* These are initialized very early in boot and never changed */ char * elf_aux_platform; -long elf_aux_hwcap; - +extern long elf_aux_hwcap; unsigned long vsyscall_ehdr; unsigned long vsyscall_end; - unsigned long __kernel_vsyscall; __init void scan_elf_aux( char **envp) @@ -40,6 +33,9 @@ __init void scan_elf_aux( char **envp) switch ( auxv->a_type ) { case AT_SYSINFO: __kernel_vsyscall = auxv->a_un.a_val; + /* See if the page is under TASK_SIZE */ + if (__kernel_vsyscall < (unsigned long) envp) + __kernel_vsyscall = 0; break; case AT_SYSINFO_EHDR: vsyscall_ehdr = auxv->a_un.a_val; diff --git a/arch/um/os-Linux/execvp.c b/arch/um/os-Linux/execvp.c new file mode 100644 index 00000000000..8fb25ca07c4 --- /dev/null +++ b/arch/um/os-Linux/execvp.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2006 by Paolo Giarrusso - modified from glibc' execvp.c. + Original copyright notice follows: + + Copyright (C) 1991,92,1995-99,2002,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ +#include <unistd.h> + +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <limits.h> + +#ifndef TEST +#include <um_malloc.h> +#else +#include <stdio.h> +#define um_kmalloc malloc +#endif +#include <os.h> + +/* Execute FILE, searching in the `PATH' environment variable if it contains + no slashes, with arguments ARGV and environment from `environ'. */ +int execvp_noalloc(char *buf, const char *file, char *const argv[]) +{ + if (*file == '\0') { + return -ENOENT; + } + + if (strchr (file, '/') != NULL) { + /* Don't search when it contains a slash. */ + execv(file, argv); + } else { + int got_eacces; + size_t len, pathlen; + char *name, *p; + char *path = getenv("PATH"); + if (path == NULL) + path = ":/bin:/usr/bin"; + + len = strlen(file) + 1; + pathlen = strlen(path); + /* Copy the file name at the top. */ + name = memcpy(buf + pathlen + 1, file, len); + /* And add the slash. */ + *--name = '/'; + + got_eacces = 0; + p = path; + do { + char *startp; + + path = p; + //Let's avoid this GNU extension. + //p = strchrnul (path, ':'); + p = strchr(path, ':'); + if (!p) + p = strchr(path, '\0'); + + if (p == path) + /* Two adjacent colons, or a colon at the beginning or the end + of `PATH' means to search the current directory. */ + startp = name + 1; + else + startp = memcpy(name - (p - path), path, p - path); + + /* Try to execute this name. If it works, execv will not return. */ + execv(startp, argv); + + /* + if (errno == ENOEXEC) { + } + */ + + switch (errno) { + case EACCES: + /* Record the we got a `Permission denied' error. If we end + up finding no executable we can use, we want to diagnose + that we did find one but were denied access. */ + got_eacces = 1; + case ENOENT: + case ESTALE: + case ENOTDIR: + /* Those errors indicate the file is missing or not executable + by us, in which case we want to just try the next path + directory. */ + case ENODEV: + case ETIMEDOUT: + /* Some strange filesystems like AFS return even + stranger error numbers. They cannot reasonably mean + anything else so ignore those, too. */ + case ENOEXEC: + /* We won't go searching for the shell + * if it is not executable - the Linux + * kernel already handles this enough, + * for us. */ + break; + + default: + /* Some other error means we found an executable file, but + something went wrong executing it; return the error to our + caller. */ + return -errno; + } + } while (*p++ != '\0'); + + /* We tried every element and none of them worked. */ + if (got_eacces) + /* At least one failure was due to permissions, so report that + error. */ + return -EACCES; + } + + /* Return the error from the last attempt (probably ENOENT). */ + return -errno; +} +#ifdef TEST +int main(int argc, char**argv) +{ + char buf[PATH_MAX]; + int ret; + argc--; + if (!argc) { + fprintf(stderr, "Not enough arguments\n"); + return 1; + } + argv++; + if (ret = execvp_noalloc(buf, argv[0], argv)) { + errno = -ret; + perror("execvp_noalloc"); + } + return 0; +} +#endif diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index f55773c819e..08d90fba952 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -8,18 +8,14 @@ #include <errno.h> #include <fcntl.h> #include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/un.h> #include <sys/ioctl.h> #include <sys/mount.h> -#include <sys/uio.h> -#include "os.h" -#include "user.h" -#include "kern_util.h" +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> +#include <os.h> -static void copy_stat(struct uml_stat *dst, struct stat64 *src) +static void copy_stat(struct uml_stat *dst, const struct stat64 *src) { *dst = ((struct uml_stat) { .ust_dev = src->st_dev, /* device */ @@ -42,16 +38,13 @@ int os_stat_fd(const int fd, struct uml_stat *ubuf) struct stat64 sbuf; int err; - do { - err = fstat64(fd, &sbuf); - } while((err < 0) && (errno == EINTR)) ; - - if(err < 0) - return(-errno); + CATCH_EINTR(err = fstat64(fd, &sbuf)); + if (err < 0) + return -errno; - if(ubuf != NULL) + if (ubuf != NULL) copy_stat(ubuf, &sbuf); - return(err); + return err; } int os_stat_file(const char *file_name, struct uml_stat *ubuf) @@ -59,37 +52,29 @@ int os_stat_file(const char *file_name, struct uml_stat *ubuf) struct stat64 sbuf; int err; - do { - err = stat64(file_name, &sbuf); - } while((err < 0) && (errno == EINTR)) ; - - if(err < 0) - return(-errno); + CATCH_EINTR(err = stat64(file_name, &sbuf)); + if (err < 0) + return -errno; - if(ubuf != NULL) + if (ubuf != NULL) copy_stat(ubuf, &sbuf); - return(err); + return err; } -int os_access(const char* file, int mode) +int os_access(const char *file, int mode) { int amode, err; - amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) | - (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ; + amode = (mode & OS_ACC_R_OK ? R_OK : 0) | + (mode & OS_ACC_W_OK ? W_OK : 0) | + (mode & OS_ACC_X_OK ? X_OK : 0) | + (mode & OS_ACC_F_OK ? F_OK : 0); err = access(file, amode); - if(err < 0) - return(-errno); - - return(0); -} - -void os_print_error(int error, const char* str) -{ - errno = error < 0 ? -error : error; + if (err < 0) + return -errno; - perror(str); + return 0; } /* FIXME? required only by hostaudio (because it passes ioctls verbatim) */ @@ -98,43 +83,19 @@ int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg) int err; err = ioctl(fd, cmd, arg); - if(err < 0) - return(-errno); - - return(err); -} - -int os_window_size(int fd, int *rows, int *cols) -{ - struct winsize size; - - if(ioctl(fd, TIOCGWINSZ, &size) < 0) - return(-errno); - - *rows = size.ws_row; - *cols = size.ws_col; - - return(0); -} - -int os_new_tty_pgrp(int fd, int pid) -{ - if(ioctl(fd, TIOCSCTTY, 0) < 0) + if (err < 0) return -errno; - if(tcsetpgrp(fd, pid) < 0) - return -errno; - - return(0); + return err; } /* FIXME: ensure namebuf in os_get_if_name is big enough */ int os_get_ifname(int fd, char* namebuf) { - if(ioctl(fd, SIOCGIFNAME, namebuf) < 0) - return(-errno); + if (ioctl(fd, SIOCGIFNAME, namebuf) < 0) + return -errno; - return(0); + return 0; } int os_set_slip(int fd) @@ -142,59 +103,25 @@ int os_set_slip(int fd) int disc, sencap; disc = N_SLIP; - if(ioctl(fd, TIOCSETD, &disc) < 0) + if (ioctl(fd, TIOCSETD, &disc) < 0) return -errno; sencap = 0; - if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0) - return -errno; - - return(0); -} - -int os_set_owner(int fd, int pid) -{ - if(fcntl(fd, F_SETOWN, pid) < 0){ - int save_errno = errno; - - if(fcntl(fd, F_GETOWN, 0) != pid) - return(-save_errno); - } - - return(0); -} - -/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */ -int os_sigio_async(int master, int slave) -{ - int flags; - - flags = fcntl(master, F_GETFL); - if(flags < 0) - return errno; - - if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || - (fcntl(master, F_SETOWN, os_getpid()) < 0)) - return -errno; - - if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) + if (ioctl(fd, SIOCSIFENCAP, &sencap) < 0) return -errno; - return(0); + return 0; } int os_mode_fd(int fd, int mode) { int err; - do { - err = fchmod(fd, mode); - } while((err < 0) && (errno==EINTR)) ; - - if(err < 0) - return(-errno); + CATCH_EINTR(err = fchmod(fd, mode)); + if (err < 0) + return -errno; - return(0); + return 0; } int os_file_type(char *file) @@ -203,67 +130,82 @@ int os_file_type(char *file) int err; err = os_stat_file(file, &buf); - if(err < 0) - return(err); + if (err < 0) + return err; - if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR); - else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK); - else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV); - else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV); - else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO); - else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK); - else return(OS_TYPE_FILE); + if (S_ISDIR(buf.ust_mode)) + return OS_TYPE_DIR; + else if (S_ISLNK(buf.ust_mode)) + return OS_TYPE_SYMLINK; + else if (S_ISCHR(buf.ust_mode)) + return OS_TYPE_CHARDEV; + else if (S_ISBLK(buf.ust_mode)) + return OS_TYPE_BLOCKDEV; + else if (S_ISFIFO(buf.ust_mode)) + return OS_TYPE_FIFO; + else if (S_ISSOCK(buf.ust_mode)) + return OS_TYPE_SOCK; + else return OS_TYPE_FILE; } -int os_file_mode(char *file, struct openflags *mode_out) +int os_file_mode(const char *file, struct openflags *mode_out) { int err; *mode_out = OPENFLAGS(); - err = os_access(file, OS_ACC_W_OK); - if((err < 0) && (err != -EACCES)) - return(err); - - *mode_out = of_write(*mode_out); - - err = os_access(file, OS_ACC_R_OK); - if((err < 0) && (err != -EACCES)) - return(err); + err = access(file, W_OK); + if (err && (errno != EACCES)) + return -errno; + else if (!err) + *mode_out = of_write(*mode_out); - *mode_out = of_read(*mode_out); + err = access(file, R_OK); + if (err && (errno != EACCES)) + return -errno; + else if (!err) + *mode_out = of_read(*mode_out); - return(0); + return err; } -int os_open_file(char *file, struct openflags flags, int mode) +int os_open_file(const char *file, struct openflags flags, int mode) { int fd, err, f = 0; - if(flags.r && flags.w) f = O_RDWR; - else if(flags.r) f = O_RDONLY; - else if(flags.w) f = O_WRONLY; + if (flags.r && flags.w) + f = O_RDWR; + else if (flags.r) + f = O_RDONLY; + else if (flags.w) + f = O_WRONLY; else f = 0; - if(flags.s) f |= O_SYNC; - if(flags.c) f |= O_CREAT; - if(flags.t) f |= O_TRUNC; - if(flags.e) f |= O_EXCL; + if (flags.s) + f |= O_SYNC; + if (flags.c) + f |= O_CREAT; + if (flags.t) + f |= O_TRUNC; + if (flags.e) + f |= O_EXCL; + if (flags.a) + f |= O_APPEND; fd = open64(file, f, mode); - if(fd < 0) - return(-errno); + if (fd < 0) + return -errno; - if(flags.cl && fcntl(fd, F_SETFD, 1)){ + if (flags.cl && fcntl(fd, F_SETFD, 1)) { err = -errno; - os_close_file(fd); + close(fd); return err; } - return(fd); + return fd; } -int os_connect_socket(char *name) +int os_connect_socket(const char *name) { struct sockaddr_un sock; int fd, err; @@ -272,159 +214,136 @@ int os_connect_socket(char *name) snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name); fd = socket(AF_UNIX, SOCK_STREAM, 0); - if(fd < 0) - return(fd); + if (fd < 0) { + err = -errno; + goto out; + } err = connect(fd, (struct sockaddr *) &sock, sizeof(sock)); - if(err) - return(-errno); + if (err) { + err = -errno; + goto out_close; + } + + return fd; - return(fd); +out_close: + close(fd); +out: + return err; } void os_close_file(int fd) { close(fd); } +int os_fsync_file(int fd) +{ + if (fsync(fd) < 0) + return -errno; + return 0; +} -int os_seek_file(int fd, __u64 offset) +int os_seek_file(int fd, unsigned long long offset) { - __u64 actual; + unsigned long long actual; actual = lseek64(fd, offset, SEEK_SET); - if(actual != offset) - return(-errno); - return(0); + if (actual != offset) + return -errno; + return 0; } -static int fault_buffer(void *start, int len, - int (*copy_proc)(void *addr, void *buf, int len)) +int os_read_file(int fd, void *buf, int len) { - int page = getpagesize(), i; - char c; + int n = read(fd, buf, len); - for(i = 0; i < len; i += page){ - if((*copy_proc)(start + i, &c, sizeof(c))) - return(-EFAULT); - } - if((len % page) != 0){ - if((*copy_proc)(start + len - 1, &c, sizeof(c))) - return(-EFAULT); - } - return(0); + if (n < 0) + return -errno; + return n; } -static int file_io(int fd, void *buf, int len, - int (*io_proc)(int fd, void *buf, int len), - int (*copy_user_proc)(void *addr, void *buf, int len)) +int os_write_file(int fd, const void *buf, int len) { - int n, err; + int n = write(fd, (void *) buf, len); - do { - n = (*io_proc)(fd, buf, len); - if((n < 0) && (errno == EFAULT)){ - err = fault_buffer(buf, len, copy_user_proc); - if(err) - return(err); - n = (*io_proc)(fd, buf, len); - } - } while((n < 0) && (errno == EINTR)); - - if(n < 0) - return(-errno); - return(n); + if (n < 0) + return -errno; + return n; } -int os_read_file(int fd, void *buf, int len) +int os_sync_file(int fd) { - return(file_io(fd, buf, len, (int (*)(int, void *, int)) read, - copy_from_user_proc)); -} + int n = fsync(fd); -int os_write_file(int fd, const void *buf, int len) -{ - return(file_io(fd, (void *) buf, len, - (int (*)(int, void *, int)) write, copy_to_user_proc)); + if (n < 0) + return -errno; + return n; } -int os_file_size(char *file, unsigned long long *size_out) +int os_file_size(const char *file, unsigned long long *size_out) { struct uml_stat buf; int err; err = os_stat_file(file, &buf); - if(err < 0){ - printk("Couldn't stat \"%s\" : err = %d\n", file, -err); - return(err); + if (err < 0) { + printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file, + -err); + return err; } - if(S_ISBLK(buf.ust_mode)){ - int fd, blocks; + if (S_ISBLK(buf.ust_mode)) { + int fd; + long blocks; - fd = os_open_file(file, of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Couldn't open \"%s\", errno = %d\n", file, -fd); - return(fd); - } - if(ioctl(fd, BLKGETSIZE, &blocks) < 0){ + fd = open(file, O_RDONLY, 0); + if (fd < 0) { err = -errno; - printk("Couldn't get the block size of \"%s\", " + printk(UM_KERN_ERR "Couldn't open \"%s\", " "errno = %d\n", file, errno); - os_close_file(fd); - return(err); + return err; + } + if (ioctl(fd, BLKGETSIZE, &blocks) < 0) { + err = -errno; + printk(UM_KERN_ERR "Couldn't get the block size of " + "\"%s\", errno = %d\n", file, errno); + close(fd); + return err; } *size_out = ((long long) blocks) * 512; - os_close_file(fd); - return(0); + close(fd); } - *size_out = buf.ust_size; - return(0); + else *size_out = buf.ust_size; + + return 0; } -int os_file_modtime(char *file, unsigned long *modtime) +int os_file_modtime(const char *file, unsigned long *modtime) { struct uml_stat buf; int err; err = os_stat_file(file, &buf); - if(err < 0){ - printk("Couldn't stat \"%s\" : err = %d\n", file, -err); - return(err); + if (err < 0) { + printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file, + -err); + return err; } *modtime = buf.ust_mtime; - return(0); + return 0; } -int os_get_exec_close(int fd, int* close_on_exec) +int os_set_exec_close(int fd) { - int ret; - - do { - ret = fcntl(fd, F_GETFD); - } while((ret < 0) && (errno == EINTR)) ; - - if(ret < 0) - return(-errno); - - *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0; - return(ret); -} - -int os_set_exec_close(int fd, int close_on_exec) -{ - int flag, err; - - if(close_on_exec) flag = FD_CLOEXEC; - else flag = 0; + int err; - do { - err = fcntl(fd, F_SETFD, flag); - } while((err < 0) && (errno == EINTR)) ; + CATCH_EINTR(err = fcntl(fd, F_SETFD, FD_CLOEXEC)); - if(err < 0) - return(-errno); - return(err); + if (err < 0) + return -errno; + return err; } int os_pipe(int *fds, int stream, int close_on_exec) @@ -432,67 +351,69 @@ int os_pipe(int *fds, int stream, int close_on_exec) int err, type = stream ? SOCK_STREAM : SOCK_DGRAM; err = socketpair(AF_UNIX, type, 0, fds); - if(err < 0) - return(-errno); + if (err < 0) + return -errno; - if(!close_on_exec) - return(0); + if (!close_on_exec) + return 0; - err = os_set_exec_close(fds[0], 1); - if(err < 0) + err = os_set_exec_close(fds[0]); + if (err < 0) goto error; - err = os_set_exec_close(fds[1], 1); - if(err < 0) + err = os_set_exec_close(fds[1]); + if (err < 0) goto error; - return(0); + return 0; error: - printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err); - os_close_file(fds[1]); - os_close_file(fds[0]); - return(err); + printk(UM_KERN_ERR "os_pipe : Setting FD_CLOEXEC failed, err = %d\n", + -err); + close(fds[1]); + close(fds[0]); + return err; } -int os_set_fd_async(int fd, int owner) +int os_set_fd_async(int fd) { - int err; + int err, flags; + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -errno; - /* XXX This should do F_GETFL first */ - if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){ + flags |= O_ASYNC | O_NONBLOCK; + if (fcntl(fd, F_SETFL, flags) < 0) { err = -errno; - printk("os_set_fd_async : failed to set O_ASYNC and " - "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno); + printk(UM_KERN_ERR "os_set_fd_async : failed to set O_ASYNC " + "and O_NONBLOCK on fd # %d, errno = %d\n", fd, errno); return err; } -#ifdef notdef - if(fcntl(fd, F_SETFD, 1) < 0){ - printk("os_set_fd_async : Setting FD_CLOEXEC failed, " - "errno = %d\n", errno); - } -#endif - if((fcntl(fd, F_SETSIG, SIGIO) < 0) || - (fcntl(fd, F_SETOWN, owner) < 0)){ + if ((fcntl(fd, F_SETSIG, SIGIO) < 0) || + (fcntl(fd, F_SETOWN, os_getpid()) < 0)) { err = -errno; - printk("os_set_fd_async : Failed to fcntl F_SETOWN " - "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd, - owner, errno); + printk(UM_KERN_ERR "os_set_fd_async : Failed to fcntl F_SETOWN " + "(or F_SETSIG) fd %d, errno = %d\n", fd, errno); return err; } - return(0); + return 0; } int os_clear_fd_async(int fd) { - int flags = fcntl(fd, F_GETFL); + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -errno; flags &= ~(O_ASYNC | O_NONBLOCK); - if(fcntl(fd, F_SETFL, flags) < 0) - return(-errno); - return(0); + if (fcntl(fd, F_SETFL, flags) < 0) + return -errno; + return 0; } int os_set_fd_block(int fd, int blocking) @@ -500,14 +421,18 @@ int os_set_fd_block(int fd, int blocking) int flags; flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -errno; - if(blocking) flags &= ~O_NONBLOCK; - else flags |= O_NONBLOCK; + if (blocking) + flags &= ~O_NONBLOCK; + else + flags |= O_NONBLOCK; - if(fcntl(fd, F_SETFL, flags) < 0) + if (fcntl(fd, F_SETFL, flags) < 0) return -errno; - return(0); + return 0; } int os_accept_connection(int fd) @@ -515,9 +440,9 @@ int os_accept_connection(int fd) int new; new = accept(fd, NULL, 0); - if(new < 0) - return(-errno); - return(new); + if (new < 0) + return -errno; + return new; } #ifndef SHUT_RD @@ -536,17 +461,19 @@ int os_shutdown_socket(int fd, int r, int w) { int what, err; - if(r && w) what = SHUT_RDWR; - else if(r) what = SHUT_RD; - else if(w) what = SHUT_WR; - else { - printk("os_shutdown_socket : neither r or w was set\n"); - return(-EINVAL); - } + if (r && w) + what = SHUT_RDWR; + else if (r) + what = SHUT_RD; + else if (w) + what = SHUT_WR; + else + return -EINVAL; + err = shutdown(fd, what); - if(err < 0) - return(-errno); - return(0); + if (err < 0) + return -errno; + return 0; } int os_rcv_fd(int fd, int *helper_pid_out) @@ -568,53 +495,52 @@ int os_rcv_fd(int fd, int *helper_pid_out) msg.msg_flags = 0; n = recvmsg(fd, &msg, 0); - if(n < 0) - return(-errno); - - else if(n != sizeof(iov.iov_len)) + if (n < 0) + return -errno; + else if (n != iov.iov_len) *helper_pid_out = -1; cmsg = CMSG_FIRSTHDR(&msg); - if(cmsg == NULL){ - printk("rcv_fd didn't receive anything, error = %d\n", errno); - return(-1); + if (cmsg == NULL) { + printk(UM_KERN_ERR "rcv_fd didn't receive anything, " + "error = %d\n", errno); + return -1; } - if((cmsg->cmsg_level != SOL_SOCKET) || - (cmsg->cmsg_type != SCM_RIGHTS)){ - printk("rcv_fd didn't receive a descriptor\n"); - return(-1); + if ((cmsg->cmsg_level != SOL_SOCKET) || + (cmsg->cmsg_type != SCM_RIGHTS)) { + printk(UM_KERN_ERR "rcv_fd didn't receive a descriptor\n"); + return -1; } new = ((int *) CMSG_DATA(cmsg))[0]; - return(new); + return new; } -int os_create_unix_socket(char *file, int len, int close_on_exec) +int os_create_unix_socket(const char *file, int len, int close_on_exec) { struct sockaddr_un addr; int sock, err; sock = socket(PF_UNIX, SOCK_DGRAM, 0); - if(sock < 0) + if (sock < 0) return -errno; - if(close_on_exec) { - err = os_set_exec_close(sock, 1); - if(err < 0) - printk("create_unix_socket : close_on_exec failed, " - "err = %d", -err); + if (close_on_exec) { + err = os_set_exec_close(sock); + if (err < 0) + printk(UM_KERN_ERR "create_unix_socket : " + "close_on_exec failed, err = %d", -err); } addr.sun_family = AF_UNIX; - /* XXX Be more careful about overflow */ snprintf(addr.sun_path, len, "%s", file); err = bind(sock, (struct sockaddr *) &addr, sizeof(addr)); - if(err < 0) + if (err < 0) return -errno; - return(sock); + return sock; } void os_flush_stdout(void) @@ -632,29 +558,34 @@ int os_lock_file(int fd, int excl) int err, save; err = fcntl(fd, F_SETLK, &lock); - if(!err) + if (!err) goto out; save = -errno; err = fcntl(fd, F_GETLK, &lock); - if(err){ + if (err) { err = -errno; goto out; } - printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid); + printk(UM_KERN_ERR "F_SETLK failed, file already locked by pid %d\n", + lock.l_pid); err = save; out: - return(err); + return err; } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +unsigned os_major(unsigned long long dev) +{ + return major(dev); +} + +unsigned os_minor(unsigned long long dev) +{ + return minor(dev); +} + +unsigned long long os_makedev(unsigned major, unsigned minor) +{ + return makedev(major, minor); +} diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 36cc8475bcd..e3ee4a51ef6 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -1,165 +1,164 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sched.h> -#include <sys/signal.h> +#include <linux/limits.h> +#include <sys/socket.h> #include <sys/wait.h> -#include "user.h" -#include "kern_util.h" -#include "user_util.h" -#include "os.h" +#include <kern_util.h> +#include <os.h> +#include <um_malloc.h> struct helper_data { void (*pre_exec)(void*); void *pre_data; char **argv; int fd; + char *buf; }; -/* Debugging aid, changed only from gdb */ -int helper_pause = 0; - -static void helper_hup(int sig) -{ -} - static int helper_child(void *arg) { struct helper_data *data = arg; char **argv = data->argv; - int errval; + int err, ret; - if(helper_pause){ - signal(SIGHUP, helper_hup); - pause(); - } - if(data->pre_exec != NULL) + if (data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); - execvp(argv[0], argv); - errval = errno; - printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); - os_write_file(data->fd, &errval, sizeof(errval)); - kill(os_getpid(), SIGKILL); - return(0); + err = execvp_noalloc(data->buf, argv[0], argv); + + /* If the exec succeeds, we don't get here */ + CATCH_EINTR(ret = write(data->fd, &err, sizeof(err))); + + return 0; } -/* Returns either the pid of the child process we run or -E* on failure. - * XXX The alloc_stack here breaks if this is called in the tracing thread */ -int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, - unsigned long *stack_out) +/* Returns either the pid of the child process we run or -E* on failure. */ +int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) { struct helper_data data; unsigned long stack, sp; int pid, fds[2], ret, n; - if((stack_out != NULL) && (*stack_out != 0)) - stack = *stack_out; - else stack = alloc_stack(0, um_in_interrupt()); - if(stack == 0) - return(-ENOMEM); + stack = alloc_stack(0, __cant_sleep()); + if (stack == 0) + return -ENOMEM; - ret = os_pipe(fds, 1, 0); - if(ret < 0){ - printk("run_helper : pipe failed, ret = %d\n", -ret); + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); + if (ret < 0) { + ret = -errno; + printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n", + errno); goto out_free; } - ret = os_set_exec_close(fds[1], 1); - if(ret < 0){ - printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n", - -ret); + ret = os_set_exec_close(fds[1]); + if (ret < 0) { + printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, " + "ret = %d\n", -ret); goto out_close; } - sp = stack + page_size() - sizeof(void *); + sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); data.pre_exec = pre_exec; data.pre_data = pre_data; data.argv = argv; data.fd = fds[1]; - pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); - if(pid < 0){ + data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) : + uml_kmalloc(PATH_MAX, UM_GFP_KERNEL); + pid = clone(helper_child, (void *) sp, CLONE_VM, &data); + if (pid < 0) { ret = -errno; - printk("run_helper : clone failed, errno = %d\n", errno); - goto out_close; + printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n", + errno); + goto out_free2; } close(fds[1]); fds[1] = -1; - /*Read the errno value from the child.*/ - n = os_read_file(fds[0], &ret, sizeof(ret)); - if(n < 0){ - printk("run_helper : read on pipe failed, ret = %d\n", -n); - ret = n; - kill(pid, SIGKILL); - CATCH_EINTR(waitpid(pid, NULL, 0)); - } - else if(n != 0){ - CATCH_EINTR(n = waitpid(pid, NULL, 0)); - ret = -errno; - } else { + /* + * Read the errno value from the child, if the exec failed, or get 0 if + * the exec succeeded because the pipe fd was set as close-on-exec. + */ + n = read(fds[0], &ret, sizeof(ret)); + if (n == 0) { ret = pid; + } else { + if (n < 0) { + n = -errno; + printk(UM_KERN_ERR "run_helper : read on pipe failed, " + "ret = %d\n", -n); + ret = n; + } + CATCH_EINTR(waitpid(pid, NULL, __WCLONE)); } +out_free2: + kfree(data.buf); out_close: if (fds[1] != -1) close(fds[1]); close(fds[0]); out_free: - if(stack_out == NULL) - free_stack(stack, 0); - else *stack_out = stack; - return(ret); + free_stack(stack, 0); + return ret; } int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, - unsigned long *stack_out, int stack_order) + unsigned long *stack_out) { unsigned long stack, sp; int pid, status, err; - stack = alloc_stack(stack_order, um_in_interrupt()); - if(stack == 0) return(-ENOMEM); + stack = alloc_stack(0, __cant_sleep()); + if (stack == 0) + return -ENOMEM; - sp = stack + (page_size() << stack_order) - sizeof(void *); - pid = clone(proc, (void *) sp, flags | SIGCHLD, arg); - if(pid < 0){ + sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); + pid = clone(proc, (void *) sp, flags, arg); + if (pid < 0) { err = -errno; - printk("run_helper_thread : clone failed, errno = %d\n", - errno); + printk(UM_KERN_ERR "run_helper_thread : clone failed, " + "errno = %d\n", errno); return err; } - if(stack_out == NULL){ - CATCH_EINTR(pid = waitpid(pid, &status, 0)); - if(pid < 0){ + if (stack_out == NULL) { + CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE)); + if (pid < 0) { err = -errno; - printk("run_helper_thread - wait failed, errno = %d\n", - errno); + printk(UM_KERN_ERR "run_helper_thread - wait failed, " + "errno = %d\n", errno); pid = err; } - if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) - printk("run_helper_thread - thread returned status " - "0x%x\n", status); - free_stack(stack, stack_order); - } - else *stack_out = stack; - return(pid); + if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) + printk(UM_KERN_ERR "run_helper_thread - thread " + "returned status 0x%x\n", status); + free_stack(stack, 0); + } else + *stack_out = stack; + return pid; } int helper_wait(int pid) { - int ret; - - CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG)); - if(ret < 0){ - ret = -errno; - printk("helper_wait : waitpid failed, errno = %d\n", errno); - } - return(ret); + int ret, status; + int wflags = __WCLONE; + + CATCH_EINTR(ret = waitpid(pid, &status, wflags)); + if (ret < 0) { + printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, " + "errno = %d\n", pid, errno); + return -errno; + } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + printk(UM_KERN_ERR "helper_wait : process %d exited with " + "status 0x%x\n", pid, status); + return -ECHILD; + } else + return 0; } diff --git a/arch/um/os-Linux/include/file.h b/arch/um/os-Linux/include/file.h deleted file mode 100644 index d82711efacf..00000000000 --- a/arch/um/os-Linux/include/file.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __OS_FILE_H__ -#define __OS_FILE_H__ - -#define DEV_NULL "/dev/null" - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h new file mode 100644 index 00000000000..0dc2c9f135f --- /dev/null +++ b/arch/um/os-Linux/internal.h @@ -0,0 +1 @@ +void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc); diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c new file mode 100644 index 00000000000..b9afb74b79a --- /dev/null +++ b/arch/um/os-Linux/irq.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <errno.h> +#include <poll.h> +#include <signal.h> +#include <string.h> +#include <irq_user.h> +#include <os.h> +#include <um_malloc.h> + +/* + * Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd + * and os_free_irq_by_cb, which are called under irq_lock. + */ +static struct pollfd *pollfds = NULL; +static int pollfds_num = 0; +static int pollfds_size = 0; + +int os_waiting_for_events(struct irq_fd *active_fds) +{ + struct irq_fd *irq_fd; + int i, n, err; + + n = poll(pollfds, pollfds_num, 0); + if (n < 0) { + err = -errno; + if (errno != EINTR) + printk(UM_KERN_ERR "os_waiting_for_events:" + " poll returned %d, errno = %d\n", n, errno); + return err; + } + + if (n == 0) + return 0; + + irq_fd = active_fds; + + for (i = 0; i < pollfds_num; i++) { + if (pollfds[i].revents != 0) { + irq_fd->current_events = pollfds[i].revents; + pollfds[i].fd = -1; + } + irq_fd = irq_fd->next; + } + return n; +} + +int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds) +{ + if (pollfds_num == pollfds_size) { + if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) { + /* return min size needed for new pollfds area */ + return (pollfds_size + 1) * sizeof(pollfds[0]); + } + + if (pollfds != NULL) { + memcpy(tmp_pfd, pollfds, + sizeof(pollfds[0]) * pollfds_size); + /* remove old pollfds */ + kfree(pollfds); + } + pollfds = tmp_pfd; + pollfds_size++; + } else + kfree(tmp_pfd); /* remove not used tmp_pfd */ + + pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, + .events = events, + .revents = 0 }); + pollfds_num++; + + return 0; +} + +void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, + struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2) +{ + struct irq_fd **prev; + int i = 0; + + prev = &active_fds; + while (*prev != NULL) { + if ((*test)(*prev, arg)) { + struct irq_fd *old_fd = *prev; + if ((pollfds[i].fd != -1) && + (pollfds[i].fd != (*prev)->fd)) { + printk(UM_KERN_ERR "os_free_irq_by_cb - " + "mismatch between active_fds and " + "pollfds, fd %d vs %d\n", + (*prev)->fd, pollfds[i].fd); + goto out; + } + + pollfds_num--; + + /* + * This moves the *whole* array after pollfds[i] + * (though it doesn't spot as such)! + */ + memmove(&pollfds[i], &pollfds[i + 1], + (pollfds_num - i) * sizeof(pollfds[0])); + if (*last_irq_ptr2 == &old_fd->next) + *last_irq_ptr2 = prev; + + *prev = (*prev)->next; + if (old_fd->type == IRQ_WRITE) + ignore_sigio_fd(old_fd->fd); + kfree(old_fd); + continue; + } + prev = &(*prev)->next; + i++; + } + out: + return; +} + +int os_get_pollfd(int i) +{ + return pollfds[i].fd; +} + +void os_set_pollfd(int i, int fd) +{ + pollfds[i].fd = fd; +} + +void os_set_ioignore(void) +{ + signal(SIGIO, SIG_IGN); +} diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index 23da27d2256..df9191acd92 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -1,59 +1,42 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <unistd.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <signal.h> +#include <unistd.h> #include <errno.h> +#include <signal.h> +#include <string.h> #include <sys/resource.h> -#include <sys/mman.h> -#include <sys/user.h> -#include <asm/page.h> -#include "user_util.h" -#include "kern_util.h" -#include "mem_user.h" -#include "signal_user.h" -#include "time_user.h" -#include "irq_user.h" -#include "user.h" -#include "init.h" -#include "mode.h" -#include "choose-mode.h" -#include "uml-config.h" -#include "os.h" - -/* Set in set_stklim, which is called from main and __wrap_malloc. - * __wrap_malloc only calls it if main hasn't started. - */ -unsigned long stacksizelim; - -/* Set in main */ -char *linux_prog; +#include <as-layout.h> +#include <init.h> +#include <kern_util.h> +#include <os.h> +#include <um_malloc.h> #define PGD_BOUND (4 * 1024 * 1024) #define STACKSIZE (8 * 1024 * 1024) #define THREAD_NAME_LEN (256) +long elf_aux_hwcap; + static void set_stklim(void) { struct rlimit lim; - if(getrlimit(RLIMIT_STACK, &lim) < 0){ + if (getrlimit(RLIMIT_STACK, &lim) < 0) { perror("getrlimit"); exit(1); } - if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){ + if ((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)) { lim.rlim_cur = STACKSIZE; - if(setrlimit(RLIMIT_STACK, &lim) < 0){ + if (setrlimit(RLIMIT_STACK, &lim) < 0) { perror("setrlimit"); exit(1); } } - stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1); } static __init void do_uml_initcalls(void) @@ -61,7 +44,7 @@ static __init void do_uml_initcalls(void) initcall_t *call; call = &__uml_initcall_start; - while (call < &__uml_initcall_end){; + while (call < &__uml_initcall_end) { (*call)(); call++; } @@ -69,156 +52,179 @@ static __init void do_uml_initcalls(void) static void last_ditch_exit(int sig) { - signal(SIGINT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); uml_cleanup(); exit(1); } -extern int uml_exitcode; - -extern void scan_elf_aux( char **envp); - -int main(int argc, char **argv, char **envp) +static void install_fatal_handler(int sig) { - char **new_argv; - sigset_t mask; - int ret, i, err; + struct sigaction action; - /* Enable all signals except SIGIO - in some environments, we can - * enter with some signals blocked - */ + /* All signals are enabled in this handler ... */ + sigemptyset(&action.sa_mask); - sigemptyset(&mask); - sigaddset(&mask, SIGIO); - if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){ - perror("sigprocmask"); + /* + * ... including the signal being handled, plus we want the + * handler reset to the default behavior, so that if an exit + * handler is hanging for some reason, the UML will just die + * after this signal is sent a second time. + */ + action.sa_flags = SA_RESETHAND | SA_NODEFER; + action.sa_restorer = NULL; + action.sa_handler = last_ditch_exit; + if (sigaction(sig, &action, NULL) < 0) { + printf("failed to install handler for signal %d - errno = %d\n", + sig, errno); exit(1); } +} -#ifdef UML_CONFIG_CMDLINE_ON_HOST - /* Allocate memory for thread command lines */ - if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){ +#define UML_LIB_PATH ":" OS_LIB_PATH "/uml" - char padding[THREAD_NAME_LEN] = { - [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0' - }; +static void setup_env_path(void) +{ + char *new_path = NULL; + char *old_path = NULL; + int path_len = 0; + + old_path = getenv("PATH"); + /* + * if no PATH variable is set or it has an empty value + * just use the default + /usr/lib/uml + */ + if (!old_path || (path_len = strlen(old_path)) == 0) { + if (putenv("PATH=:/bin:/usr/bin/" UML_LIB_PATH)) + perror("couldn't putenv"); + return; + } - new_argv = malloc((argc + 2) * sizeof(char*)); - if(!new_argv) { - perror("Allocating extended argv"); - exit(1); - } + /* append /usr/lib/uml to the existing path */ + path_len += strlen("PATH=" UML_LIB_PATH) + 1; + new_path = malloc(path_len); + if (!new_path) { + perror("couldn't malloc to set a new PATH"); + return; + } + snprintf(new_path, path_len, "PATH=%s" UML_LIB_PATH, old_path); + if (putenv(new_path)) { + perror("couldn't putenv to set a new PATH"); + free(new_path); + } +} - new_argv[0] = argv[0]; - new_argv[1] = padding; +extern void scan_elf_aux( char **envp); - for(i = 2; i <= argc; i++) - new_argv[i] = argv[i - 1]; - new_argv[argc + 1] = NULL; +int __init main(int argc, char **argv, char **envp) +{ + char **new_argv; + int ret, i, err; - execvp(new_argv[0], new_argv); - perror("execing with extended args"); - exit(1); - } -#endif + set_stklim(); - linux_prog = argv[0]; + setup_env_path(); - set_stklim(); + setsid(); new_argv = malloc((argc + 1) * sizeof(char *)); - if(new_argv == NULL){ + if (new_argv == NULL) { perror("Mallocing argv"); exit(1); } - for(i=0;i<argc;i++){ + for (i = 0; i < argc; i++) { new_argv[i] = strdup(argv[i]); - if(new_argv[i] == NULL){ + if (new_argv[i] == NULL) { perror("Mallocing an arg"); exit(1); } } new_argv[argc] = NULL; - set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); - set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); - set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); + /* + * Allow these signals to bring down a UML if all other + * methods of control fail. + */ + install_fatal_handler(SIGINT); + install_fatal_handler(SIGTERM); - scan_elf_aux( envp); +#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA + scan_elf_aux(envp); +#endif do_uml_initcalls(); + change_sig(SIGPIPE, 0); ret = linux_main(argc, argv); - /* Disable SIGPROF - I have no idea why libc doesn't do this or turn + /* + * Disable SIGPROF - I have no idea why libc doesn't do this or turn * off the profiling time, but UML dies with a SIGPROF just before * exiting when profiling is active. */ change_sig(SIGPROF, 0); - /* This signal stuff used to be in the reboot case. However, + /* + * This signal stuff used to be in the reboot case. However, * sometimes a SIGVTALRM can come in when we're halting (reproducably * when writing out gcov information, presumably because that takes * some time) and cause a segfault. */ - /* stop timers and set SIG*ALRM to be ignored */ + /* stop timers and set SIGVTALRM to be ignored */ disable_timer(); /* disable SIGIO for the fds and set SIGIO to be ignored */ err = deactivate_all_fds(); - if(err) + if (err) printf("deactivate_all_fds failed, errno = %d\n", -err); - /* Let any pending signals fire now. This ensures + /* + * Let any pending signals fire now. This ensures * that they won't be delivered after the exec, when * they are definitely not expected. */ unblock_signals(); /* Reboot */ - if(ret){ + if (ret) { printf("\n"); execvp(new_argv[0], new_argv); perror("Failed to exec kernel"); ret = 1; } printf("\n"); - return(uml_exitcode); + return uml_exitcode; } -#define CAN_KMALLOC() \ - (kmalloc_ok && CHOOSE_MODE((os_getpid() != tracing_pid), 1)) - extern void *__real_malloc(int); void *__wrap_malloc(int size) { void *ret; - if(!CAN_KMALLOC()) - return(__real_malloc(size)); - else if(size <= PAGE_SIZE) /* finding contiguos pages can be hard*/ - ret = um_kmalloc(size); - else ret = um_vmalloc(size); + if (!kmalloc_ok) + return __real_malloc(size); + else if (size <= UM_KERN_PAGE_SIZE) + /* finding contiguous pages can be hard*/ + ret = uml_kmalloc(size, UM_GFP_KERNEL); + else ret = vmalloc(size); - /* glibc people insist that if malloc fails, errno should be + /* + * glibc people insist that if malloc fails, errno should be * set by malloc as well. So we do. */ - if(ret == NULL) + if (ret == NULL) errno = ENOMEM; - return(ret); + return ret; } void *__wrap_calloc(int n, int size) { void *ptr = __wrap_malloc(n * size); - if(ptr == NULL) return(NULL); + if (ptr == NULL) + return NULL; memset(ptr, 0, n * size); - return(ptr); + return ptr; } extern void __real_free(void *); @@ -229,7 +235,8 @@ void __wrap_free(void *ptr) { unsigned long addr = (unsigned long) ptr; - /* We need to know how the allocation happened, so it can be correctly + /* + * We need to know how the allocation happened, so it can be correctly * freed. This is done by seeing what region of memory the pointer is * in - * physical memory - kmalloc/kfree @@ -247,12 +254,12 @@ void __wrap_free(void *ptr) * there is a possibility for memory leaks. */ - if((addr >= uml_physmem) && (addr < high_physmem)){ - if(CAN_KMALLOC()) + if ((addr >= uml_physmem) && (addr < high_physmem)) { + if (kmalloc_ok) kfree(ptr); } - else if((addr >= start_vm) && (addr < end_vm)){ - if(CAN_KMALLOC()) + else if ((addr >= start_vm) && (addr < end_vm)) { + if (kmalloc_ok) vfree(ptr); } else __real_free(ptr); diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 9d7d69a523b..897e9ad0c10 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -1,161 +1,205 @@ +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + #include <stdio.h> -#include <stdlib.h> #include <stddef.h> -#include <stdarg.h> +#include <stdlib.h> #include <unistd.h> #include <errno.h> -#include <string.h> #include <fcntl.h> -#include <sys/types.h> +#include <string.h> +#include <sys/stat.h> #include <sys/mman.h> -#include "kern_util.h" -#include "user.h" -#include "user_util.h" -#include "mem_user.h" -#include "init.h" -#include "os.h" -#include "tempfile.h" -#include "kern_constants.h" - -#include <sys/param.h> +#include <sys/vfs.h> +#include <linux/magic.h> +#include <init.h> +#include <os.h> +/* Set by make_tempfile() during early boot. */ static char *tempdir = NULL; -static void __init find_tempdir(void) +/* Check if dir is on tmpfs. Return 0 if yes, -1 if no or error. */ +static int __init check_tmpfs(const char *dir) { - char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; - int i; - char *dir = NULL; + struct statfs st; + + printf("Checking if %s is on tmpfs...", dir); + if (statfs(dir, &st) < 0) { + printf("%s\n", strerror(errno)); + } else if (st.f_type != TMPFS_MAGIC) { + printf("no\n"); + } else { + printf("OK\n"); + return 0; + } + return -1; +} - if(tempdir != NULL) return; /* We've already been called */ - for(i = 0; dirs[i]; i++){ - dir = getenv(dirs[i]); - if((dir != NULL) && (*dir != '\0')) - break; +/* + * Choose the tempdir to use. We want something on tmpfs so that our memory is + * not subject to the host's vm.dirty_ratio. If a tempdir is specified in the + * environment, we use that even if it's not on tmpfs, but we warn the user. + * Otherwise, we try common tmpfs locations, and if no tmpfs directory is found + * then we fall back to /tmp. + */ +static char * __init choose_tempdir(void) +{ + static const char * const vars[] = { + "TMPDIR", + "TMP", + "TEMP", + NULL + }; + static const char fallback_dir[] = "/tmp"; + static const char * const tmpfs_dirs[] = { + "/dev/shm", + fallback_dir, + NULL + }; + int i; + const char *dir; + + printf("Checking environment variables for a tempdir..."); + for (i = 0; vars[i]; i++) { + dir = getenv(vars[i]); + if ((dir != NULL) && (*dir != '\0')) { + printf("%s\n", dir); + if (check_tmpfs(dir) >= 0) + goto done; + else + goto warn; + } } - if((dir == NULL) || (*dir == '\0')) - dir = "/tmp"; - - tempdir = malloc(strlen(dir) + 2); - if(tempdir == NULL){ - fprintf(stderr, "Failed to malloc tempdir, " - "errno = %d\n", errno); - return; + printf("none found\n"); + + for (i = 0; tmpfs_dirs[i]; i++) { + dir = tmpfs_dirs[i]; + if (check_tmpfs(dir) >= 0) + goto done; } - strcpy(tempdir, dir); - strcat(tempdir, "/"); + + dir = fallback_dir; +warn: + printf("Warning: tempdir %s is not on tmpfs\n", dir); +done: + /* Make a copy since getenv results may not remain valid forever. */ + return strdup(dir); } /* - * This proc still used in tt-mode - * (file: kernel/tt/ptproxy/proxy.c, proc: start_debugger). - * So it isn't 'static' yet. + * Create an unlinked tempfile in a suitable tempdir. template must be the + * basename part of the template with a leading '/'. */ -int make_tempfile(const char *template, char **out_tempname, int do_unlink) +static int __init make_tempfile(const char *template) { - char tempname[MAXPATHLEN]; + char *tempname; int fd; - find_tempdir(); - if (*template != '/') - strcpy(tempname, tempdir); - else - *tempname = 0; + if (tempdir == NULL) { + tempdir = choose_tempdir(); + if (tempdir == NULL) { + fprintf(stderr, "Failed to choose tempdir: %s\n", + strerror(errno)); + return -1; + } + } + + tempname = malloc(strlen(tempdir) + strlen(template) + 1); + if (tempname == NULL) + return -1; + + strcpy(tempname, tempdir); strcat(tempname, template); fd = mkstemp(tempname); - if(fd < 0){ + if (fd < 0) { fprintf(stderr, "open - cannot create %s: %s\n", tempname, strerror(errno)); - return -1; + goto out; } - if(do_unlink && (unlink(tempname) < 0)){ + if (unlink(tempname) < 0) { perror("unlink"); - return -1; + goto close; } - if(out_tempname){ - *out_tempname = strdup(tempname); - if(*out_tempname == NULL){ - perror("strdup"); - return -1; - } - } - return(fd); + free(tempname); + return fd; +close: + close(fd); +out: + free(tempname); + return -1; } -#define TEMPNAME_TEMPLATE "vm_file-XXXXXX" +#define TEMPNAME_TEMPLATE "/vm_file-XXXXXX" -/* - * This proc is used in start_up.c - * So it isn't 'static'. - */ -int create_tmp_file(unsigned long long len) +static int __init create_tmp_file(unsigned long long len) { int fd, err; char zero; - fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); - if(fd < 0) { + fd = make_tempfile(TEMPNAME_TEMPLATE); + if (fd < 0) exit(1); - } err = fchmod(fd, 0777); - if(err < 0){ - perror("os_mode_fd"); + if (err < 0) { + perror("fchmod"); exit(1); } - if (lseek64(fd, len, SEEK_SET) < 0) { - perror("os_seek_file"); + /* + * Seek to len - 1 because writing a character there will + * increase the file size by one byte, to the desired length. + */ + if (lseek64(fd, len - 1, SEEK_SET) < 0) { + perror("lseek64"); exit(1); } zero = 0; - err = os_write_file(fd, &zero, 1); - if(err != 1){ - errno = -err; - perror("os_write_file"); + err = write(fd, &zero, 1); + if (err != 1) { + perror("write"); exit(1); } - return(fd); + return fd; } -static int create_anon_file(unsigned long long len) +int __init create_mem_file(unsigned long long len) { - void *addr; - int fd; + int err, fd; - fd = open("/dev/anon", O_RDWR); - if(fd < 0) { - perror("opening /dev/anon"); - exit(1); - } + fd = create_tmp_file(len); - addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if(addr == MAP_FAILED){ - perror("mapping physmem file"); - exit(1); + err = os_set_exec_close(fd); + if (err < 0) { + errno = -err; + perror("exec_close"); } - munmap(addr, len); - - return(fd); + return fd; } -extern int have_devanon; - -int create_mem_file(unsigned long long len) +void __init check_tmpexec(void) { - int err, fd; - - if(have_devanon) - fd = create_anon_file(len); - else fd = create_tmp_file(len); - - err = os_set_exec_close(fd, 1); - if(err < 0){ - errno = -err; - perror("exec_close"); + void *addr; + int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE); + + addr = mmap(NULL, UM_KERN_PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); + printf("Checking PROT_EXEC mmap in %s...", tempdir); + if (addr == MAP_FAILED) { + err = errno; + printf("%s\n", strerror(err)); + close(fd); + if (err == EPERM) + printf("%s must be not mounted noexec\n", tempdir); + exit(1); } - return(fd); + printf("OK\n"); + munmap(addr, UM_KERN_PAGE_SIZE); + + close(fd); } diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index d9c52387c4a..33496fe2bb5 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -1,24 +1,22 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@addtoit.com) +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <unistd.h> #include <stdio.h> +#include <stdlib.h> +#include <unistd.h> #include <errno.h> #include <signal.h> -#include <setjmp.h> -#include <linux/unistd.h> +#include <fcntl.h> #include <sys/mman.h> +#include <sys/ptrace.h> #include <sys/wait.h> -#include "ptrace_user.h" -#include "os.h" -#include "user.h" -#include "user_util.h" -#include "signal_user.h" -#include "process.h" -#include "irq_user.h" -#include "kern_util.h" +#include <asm/unistd.h> +#include <init.h> +#include <longjmp.h> +#include <os.h> +#include <skas_ptrace.h> #define ARBITRARY_ADDR -1 #define FAILURE_PID -1 @@ -29,62 +27,67 @@ unsigned long os_process_pc(int pid) { char proc_stat[STAT_PATH_LEN], buf[256]; - unsigned long pc; + unsigned long pc = ARBITRARY_ADDR; int fd, err; sprintf(proc_stat, "/proc/%d/stat", pid); - fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("os_process_pc - couldn't open '%s', err = %d\n", - proc_stat, -fd); - return(ARBITRARY_ADDR); + fd = open(proc_stat, O_RDONLY, 0); + if (fd < 0) { + printk(UM_KERN_ERR "os_process_pc - couldn't open '%s', " + "errno = %d\n", proc_stat, errno); + goto out; } - err = os_read_file(fd, buf, sizeof(buf)); - if(err < 0){ - printk("os_process_pc - couldn't read '%s', err = %d\n", - proc_stat, -err); - os_close_file(fd); - return(ARBITRARY_ADDR); + CATCH_EINTR(err = read(fd, buf, sizeof(buf))); + if (err < 0) { + printk(UM_KERN_ERR "os_process_pc - couldn't read '%s', " + "err = %d\n", proc_stat, errno); + goto out_close; } os_close_file(fd); pc = ARBITRARY_ADDR; - if(sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %*d %lu", &pc) != 1){ - printk("os_process_pc - couldn't find pc in '%s'\n", buf); - } - return(pc); + if (sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d " + "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " + "%*d %*d %*d %*d %*d %lu", &pc) != 1) + printk(UM_KERN_ERR "os_process_pc - couldn't find pc in '%s'\n", + buf); + out_close: + close(fd); + out: + return pc; } int os_process_parent(int pid) { char stat[STAT_PATH_LEN]; char data[256]; - int parent, n, fd; + int parent = FAILURE_PID, n, fd; - if(pid == -1) return(-1); + if (pid == -1) + return parent; snprintf(stat, sizeof(stat), "/proc/%d/stat", pid); - fd = os_open_file(stat, of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Couldn't open '%s', err = %d\n", stat, -fd); - return(FAILURE_PID); + fd = open(stat, O_RDONLY, 0); + if (fd < 0) { + printk(UM_KERN_ERR "Couldn't open '%s', errno = %d\n", stat, + errno); + return parent; } - n = os_read_file(fd, data, sizeof(data)); - os_close_file(fd); + CATCH_EINTR(n = read(fd, data, sizeof(data))); + close(fd); - if(n < 0){ - printk("Couldn't read '%s', err = %d\n", stat, -n); - return(FAILURE_PID); + if (n < 0) { + printk(UM_KERN_ERR "Couldn't read '%s', errno = %d\n", stat, + errno); + return parent; } parent = FAILURE_PID; n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent); - if(n != 1) - printk("Failed to scan '%s'\n", data); + if (n != 1) + printk(UM_KERN_ERR "Failed to scan '%s'\n", data); - return(parent); + return parent; } void os_stop_process(int pid) @@ -95,9 +98,23 @@ void os_stop_process(int pid) void os_kill_process(int pid, int reap_child) { kill(pid, SIGKILL); - if(reap_child) - CATCH_EINTR(waitpid(pid, NULL, 0)); - + if (reap_child) + CATCH_EINTR(waitpid(pid, NULL, __WALL)); +} + +/* This is here uniquely to have access to the userspace errno, i.e. the one + * used by ptrace in case of error. + */ + +long os_ptrace_ldt(long pid, long addr, long data) +{ + int ret; + + ret = ptrace(PTRACE_LDT, pid, addr, data); + + if (ret < 0) + return -errno; + return ret; } /* Kill off a ptraced child by all means available. kill it normally first, @@ -110,24 +127,17 @@ void os_kill_ptraced_process(int pid, int reap_child) kill(pid, SIGKILL); ptrace(PTRACE_KILL, pid); ptrace(PTRACE_CONT, pid); - if(reap_child) - CATCH_EINTR(waitpid(pid, NULL, 0)); -} - -void os_usr1_process(int pid) -{ - kill(pid, SIGUSR1); + if (reap_child) + CATCH_EINTR(waitpid(pid, NULL, __WALL)); } /* Don't use the glibc version, which caches the result in TLS. It misses some * syscalls, and also breaks with clone(), which does not unshare the TLS. */ -inline _syscall0(pid_t, getpid) - int os_getpid(void) { - return(getpid()); + return syscall(__NR_getpid); } int os_getpgrp(void) @@ -141,89 +151,147 @@ int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, void *loc; int prot; - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0); loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, fd, off); - if(loc == MAP_FAILED) - return(-errno); - return(0); + if (loc == MAP_FAILED) + return -errno; + return 0; } int os_protect_memory(void *addr, unsigned long len, int r, int w, int x) { - int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0)); - if(mprotect(addr, len, prot) < 0) - return(-errno); - return(0); + if (mprotect(addr, len, prot) < 0) + return -errno; + + return 0; } int os_unmap_memory(void *addr, int len) { - int err; + int err; - err = munmap(addr, len); - if(err < 0) - return(-errno); - return(0); + err = munmap(addr, len); + if (err < 0) + return -errno; + return 0; } -void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) +#ifndef MADV_REMOVE +#define MADV_REMOVE KERNEL_MADV_REMOVE +#endif + +int os_drop_memory(void *addr, int length) { - int flags = 0, pages; + int err; - if(sig_stack != NULL){ - pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER); - set_sigstack(sig_stack, pages * page_size()); - flags = SA_ONSTACK; - } - if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); + err = madvise(addr, length, MADV_REMOVE); + if (err < 0) + err = -errno; + return err; } -void init_new_thread_signals(int altstack) +int __init can_drop_memory(void) { - int flags = altstack ? SA_ONSTACK : 0; + void *addr; + int fd, ok = 0; + + printk(UM_KERN_INFO "Checking host MADV_REMOVE support..."); + fd = create_mem_file(UM_KERN_PAGE_SIZE); + if (fd < 0) { + printk(UM_KERN_ERR "Creating test memory file failed, " + "err = %d\n", -fd); + goto out; + } - set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - set_handler(SIGILL, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - set_handler(SIGUSR2, (__sighandler_t) sig_handler, - flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - signal(SIGHUP, SIG_IGN); + addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + printk(UM_KERN_ERR "Mapping test memory file failed, " + "err = %d\n", -errno); + goto out_close; + } + + if (madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0) { + printk(UM_KERN_ERR "MADV_REMOVE failed, err = %d\n", -errno); + goto out_unmap; + } - init_irq_signals(altstack); + printk(UM_KERN_CONT "OK\n"); + ok = 1; + +out_unmap: + munmap(addr, UM_KERN_PAGE_SIZE); +out_close: + close(fd); +out: + return ok; } -int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) +static int os_page_mincore(void *addr) { - sigjmp_buf buf; - int n; + char vec[2]; + int ret; + + ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); + if (ret < 0) { + if (errno == ENOMEM || errno == EINVAL) + return 0; + else + return -errno; + } - *jmp_ptr = &buf; - n = sigsetjmp(buf, 1); - if(n != 0) - return(n); - (*fn)(arg); - return(0); + return vec[0] & 1; } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +int os_mincore(void *addr, unsigned long len) +{ + char *vec; + int ret, i; + + if (len <= UM_KERN_PAGE_SIZE) + return os_page_mincore(addr); + + vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); + if (!vec) + return -ENOMEM; + + ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); + if (ret < 0) { + if (errno == ENOMEM || errno == EINVAL) + ret = 0; + else + ret = -errno; + + goto out; + } + + for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) { + if (!(vec[i] & 1)) { + ret = 0; + goto out; + } + } + + ret = 1; +out: + free(vec); + return ret; +} + +void init_new_thread_signals(void) +{ + set_handler(SIGSEGV); + set_handler(SIGTRAP); + set_handler(SIGFPE); + set_handler(SIGILL); + set_handler(SIGBUS); + signal(SIGHUP, SIG_IGN); + set_handler(SIGIO); + signal(SIGWINCH, SIG_IGN); +} diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c new file mode 100644 index 00000000000..2ff8d4fe83c --- /dev/null +++ b/arch/um/os-Linux/registers.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004 PathScale, Inc + * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <errno.h> +#include <string.h> +#include <sys/ptrace.h> +#include <sysdep/ptrace.h> +#include <sysdep/ptrace_user.h> +#include <registers.h> + +int save_registers(int pid, struct uml_pt_regs *regs) +{ + int err; + + err = ptrace(PTRACE_GETREGS, pid, 0, regs->gp); + if (err < 0) + return -errno; + return 0; +} + +int restore_registers(int pid, struct uml_pt_regs *regs) +{ + int err; + + err = ptrace(PTRACE_SETREGS, pid, 0, regs->gp); + if (err < 0) + return -errno; + return 0; +} + +/* This is set once at boot time and not changed thereafter */ + +static unsigned long exec_regs[MAX_REG_NR]; +static unsigned long exec_fp_regs[FP_SIZE]; + +int init_registers(int pid) +{ + int err; + + err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs); + if (err < 0) + return -errno; + + arch_init_registers(pid); + get_fp_registers(pid, exec_fp_regs); + return 0; +} + +void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) +{ + memcpy(regs, exec_regs, sizeof(exec_regs)); + + if (fp_regs) + memcpy(fp_regs, exec_fp_regs, sizeof(exec_fp_regs)); +} diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c new file mode 100644 index 00000000000..46e762f926e --- /dev/null +++ b/arch/um/os-Linux/sigio.c @@ -0,0 +1,546 @@ +/* + * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <poll.h> +#include <pty.h> +#include <sched.h> +#include <signal.h> +#include <string.h> +#include <kern_util.h> +#include <init.h> +#include <os.h> +#include <sigio.h> +#include <um_malloc.h> + +/* + * Protected by sigio_lock(), also used by sigio_cleanup, which is an + * exitcall. + */ +static int write_sigio_pid = -1; +static unsigned long write_sigio_stack; + +/* + * These arrays are initialized before the sigio thread is started, and + * the descriptors closed after it is killed. So, it can't see them change. + * On the UML side, they are changed under the sigio_lock. + */ +#define SIGIO_FDS_INIT {-1, -1} + +static int write_sigio_fds[2] = SIGIO_FDS_INIT; +static int sigio_private[2] = SIGIO_FDS_INIT; + +struct pollfds { + struct pollfd *poll; + int size; + int used; +}; + +/* + * Protected by sigio_lock(). Used by the sigio thread, but the UML thread + * synchronizes with it. + */ +static struct pollfds current_poll; +static struct pollfds next_poll; +static struct pollfds all_sigio_fds; + +static int write_sigio_thread(void *unused) +{ + struct pollfds *fds, tmp; + struct pollfd *p; + int i, n, respond_fd; + char c; + + os_fix_helper_signals(); + fds = ¤t_poll; + while (1) { + n = poll(fds->poll, fds->used, -1); + if (n < 0) { + if (errno == EINTR) + continue; + printk(UM_KERN_ERR "write_sigio_thread : poll returned " + "%d, errno = %d\n", n, errno); + } + for (i = 0; i < fds->used; i++) { + p = &fds->poll[i]; + if (p->revents == 0) + continue; + if (p->fd == sigio_private[1]) { + CATCH_EINTR(n = read(sigio_private[1], &c, + sizeof(c))); + if (n != sizeof(c)) + printk(UM_KERN_ERR + "write_sigio_thread : " + "read on socket failed, " + "err = %d\n", errno); + tmp = current_poll; + current_poll = next_poll; + next_poll = tmp; + respond_fd = sigio_private[1]; + } + else { + respond_fd = write_sigio_fds[1]; + fds->used--; + memmove(&fds->poll[i], &fds->poll[i + 1], + (fds->used - i) * sizeof(*fds->poll)); + } + + CATCH_EINTR(n = write(respond_fd, &c, sizeof(c))); + if (n != sizeof(c)) + printk(UM_KERN_ERR "write_sigio_thread : " + "write on socket failed, err = %d\n", + errno); + } + } + + return 0; +} + +static int need_poll(struct pollfds *polls, int n) +{ + struct pollfd *new; + + if (n <= polls->size) + return 0; + + new = uml_kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); + if (new == NULL) { + printk(UM_KERN_ERR "need_poll : failed to allocate new " + "pollfds\n"); + return -ENOMEM; + } + + memcpy(new, polls->poll, polls->used * sizeof(struct pollfd)); + kfree(polls->poll); + + polls->poll = new; + polls->size = n; + return 0; +} + +/* + * Must be called with sigio_lock held, because it's needed by the marked + * critical section. + */ +static void update_thread(void) +{ + unsigned long flags; + int n; + char c; + + flags = set_signals(0); + CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c))); + if (n != sizeof(c)) { + printk(UM_KERN_ERR "update_thread : write failed, err = %d\n", + errno); + goto fail; + } + + CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c))); + if (n != sizeof(c)) { + printk(UM_KERN_ERR "update_thread : read failed, err = %d\n", + errno); + goto fail; + } + + set_signals(flags); + return; + fail: + /* Critical section start */ + if (write_sigio_pid != -1) { + os_kill_process(write_sigio_pid, 1); + free_stack(write_sigio_stack, 0); + } + write_sigio_pid = -1; + close(sigio_private[0]); + close(sigio_private[1]); + close(write_sigio_fds[0]); + close(write_sigio_fds[1]); + /* Critical section end */ + set_signals(flags); +} + +int add_sigio_fd(int fd) +{ + struct pollfd *p; + int err = 0, i, n; + + sigio_lock(); + for (i = 0; i < all_sigio_fds.used; i++) { + if (all_sigio_fds.poll[i].fd == fd) + break; + } + if (i == all_sigio_fds.used) + goto out; + + p = &all_sigio_fds.poll[i]; + + for (i = 0; i < current_poll.used; i++) { + if (current_poll.poll[i].fd == fd) + goto out; + } + + n = current_poll.used; + err = need_poll(&next_poll, n + 1); + if (err) + goto out; + + memcpy(next_poll.poll, current_poll.poll, + current_poll.used * sizeof(struct pollfd)); + next_poll.poll[n] = *p; + next_poll.used = n + 1; + update_thread(); + out: + sigio_unlock(); + return err; +} + +int ignore_sigio_fd(int fd) +{ + struct pollfd *p; + int err = 0, i, n = 0; + + /* + * This is called from exitcalls elsewhere in UML - if + * sigio_cleanup has already run, then update_thread will hang + * or fail because the thread is no longer running. + */ + if (write_sigio_pid == -1) + return -EIO; + + sigio_lock(); + for (i = 0; i < current_poll.used; i++) { + if (current_poll.poll[i].fd == fd) + break; + } + if (i == current_poll.used) + goto out; + + err = need_poll(&next_poll, current_poll.used - 1); + if (err) + goto out; + + for (i = 0; i < current_poll.used; i++) { + p = ¤t_poll.poll[i]; + if (p->fd != fd) + next_poll.poll[n++] = *p; + } + next_poll.used = current_poll.used - 1; + + update_thread(); + out: + sigio_unlock(); + return err; +} + +static struct pollfd *setup_initial_poll(int fd) +{ + struct pollfd *p; + + p = uml_kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); + if (p == NULL) { + printk(UM_KERN_ERR "setup_initial_poll : failed to allocate " + "poll\n"); + return NULL; + } + *p = ((struct pollfd) { .fd = fd, + .events = POLLIN, + .revents = 0 }); + return p; +} + +static void write_sigio_workaround(void) +{ + struct pollfd *p; + int err; + int l_write_sigio_fds[2]; + int l_sigio_private[2]; + int l_write_sigio_pid; + + /* We call this *tons* of times - and most ones we must just fail. */ + sigio_lock(); + l_write_sigio_pid = write_sigio_pid; + sigio_unlock(); + + if (l_write_sigio_pid != -1) + return; + + err = os_pipe(l_write_sigio_fds, 1, 1); + if (err < 0) { + printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 1 failed, " + "err = %d\n", -err); + return; + } + err = os_pipe(l_sigio_private, 1, 1); + if (err < 0) { + printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 2 failed, " + "err = %d\n", -err); + goto out_close1; + } + + p = setup_initial_poll(l_sigio_private[1]); + if (!p) + goto out_close2; + + sigio_lock(); + + /* + * Did we race? Don't try to optimize this, please, it's not so likely + * to happen, and no more than once at the boot. + */ + if (write_sigio_pid != -1) + goto out_free; + + current_poll = ((struct pollfds) { .poll = p, + .used = 1, + .size = 1 }); + + if (write_sigio_irq(l_write_sigio_fds[0])) + goto out_clear_poll; + + memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); + memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); + + write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, + CLONE_FILES | CLONE_VM, + &write_sigio_stack); + + if (write_sigio_pid < 0) + goto out_clear; + + sigio_unlock(); + return; + +out_clear: + write_sigio_pid = -1; + write_sigio_fds[0] = -1; + write_sigio_fds[1] = -1; + sigio_private[0] = -1; + sigio_private[1] = -1; +out_clear_poll: + current_poll = ((struct pollfds) { .poll = NULL, + .size = 0, + .used = 0 }); +out_free: + sigio_unlock(); + kfree(p); +out_close2: + close(l_sigio_private[0]); + close(l_sigio_private[1]); +out_close1: + close(l_write_sigio_fds[0]); + close(l_write_sigio_fds[1]); +} + +void sigio_broken(int fd, int read) +{ + int err; + + write_sigio_workaround(); + + sigio_lock(); + err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); + if (err) { + printk(UM_KERN_ERR "maybe_sigio_broken - failed to add pollfd " + "for descriptor %d\n", fd); + goto out; + } + + all_sigio_fds.poll[all_sigio_fds.used++] = + ((struct pollfd) { .fd = fd, + .events = read ? POLLIN : POLLOUT, + .revents = 0 }); +out: + sigio_unlock(); +} + +/* Changed during early boot */ +static int pty_output_sigio; +static int pty_close_sigio; + +void maybe_sigio_broken(int fd, int read) +{ + if (!isatty(fd)) + return; + + if ((read || pty_output_sigio) && (!read || pty_close_sigio)) + return; + + sigio_broken(fd, read); +} + +static void sigio_cleanup(void) +{ + if (write_sigio_pid == -1) + return; + + os_kill_process(write_sigio_pid, 1); + free_stack(write_sigio_stack, 0); + write_sigio_pid = -1; +} + +__uml_exitcall(sigio_cleanup); + +/* Used as a flag during SIGIO testing early in boot */ +static int got_sigio; + +static void __init handler(int sig) +{ + got_sigio = 1; +} + +struct openpty_arg { + int master; + int slave; + int err; +}; + +static void openpty_cb(void *arg) +{ + struct openpty_arg *info = arg; + + info->err = 0; + if (openpty(&info->master, &info->slave, NULL, NULL, NULL)) + info->err = -errno; +} + +static int async_pty(int master, int slave) +{ + int flags; + + flags = fcntl(master, F_GETFL); + if (flags < 0) + return -errno; + + if ((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || + (fcntl(master, F_SETOWN, os_getpid()) < 0)) + return -errno; + + if ((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) + return -errno; + + return 0; +} + +static void __init check_one_sigio(void (*proc)(int, int)) +{ + struct sigaction old, new; + struct openpty_arg pty = { .master = -1, .slave = -1 }; + int master, slave, err; + + initial_thread_cb(openpty_cb, &pty); + if (pty.err) { + printk(UM_KERN_ERR "check_one_sigio failed, errno = %d\n", + -pty.err); + return; + } + + master = pty.master; + slave = pty.slave; + + if ((master == -1) || (slave == -1)) { + printk(UM_KERN_ERR "check_one_sigio failed to allocate a " + "pty\n"); + return; + } + + /* Not now, but complain so we now where we failed. */ + err = raw(master); + if (err < 0) { + printk(UM_KERN_ERR "check_one_sigio : raw failed, errno = %d\n", + -err); + return; + } + + err = async_pty(master, slave); + if (err < 0) { + printk(UM_KERN_ERR "check_one_sigio : sigio_async failed, " + "err = %d\n", -err); + return; + } + + if (sigaction(SIGIO, NULL, &old) < 0) { + printk(UM_KERN_ERR "check_one_sigio : sigaction 1 failed, " + "errno = %d\n", errno); + return; + } + + new = old; + new.sa_handler = handler; + if (sigaction(SIGIO, &new, NULL) < 0) { + printk(UM_KERN_ERR "check_one_sigio : sigaction 2 failed, " + "errno = %d\n", errno); + return; + } + + got_sigio = 0; + (*proc)(master, slave); + + close(master); + close(slave); + + if (sigaction(SIGIO, &old, NULL) < 0) + printk(UM_KERN_ERR "check_one_sigio : sigaction 3 failed, " + "errno = %d\n", errno); +} + +static void tty_output(int master, int slave) +{ + int n; + char buf[512]; + + printk(UM_KERN_INFO "Checking that host ptys support output SIGIO..."); + + memset(buf, 0, sizeof(buf)); + + while (write(master, buf, sizeof(buf)) > 0) ; + if (errno != EAGAIN) + printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n", + errno); + while (((n = read(slave, buf, sizeof(buf))) > 0) && + !({ barrier(); got_sigio; })) + ; + + if (got_sigio) { + printk(UM_KERN_CONT "Yes\n"); + pty_output_sigio = 1; + } else if (n == -EAGAIN) + printk(UM_KERN_CONT "No, enabling workaround\n"); + else + printk(UM_KERN_CONT "tty_output : read failed, err = %d\n", n); +} + +static void tty_close(int master, int slave) +{ + printk(UM_KERN_INFO "Checking that host ptys support SIGIO on " + "close..."); + + close(slave); + if (got_sigio) { + printk(UM_KERN_CONT "Yes\n"); + pty_close_sigio = 1; + } else + printk(UM_KERN_CONT "No, enabling workaround\n"); +} + +static void __init check_sigio(void) +{ + if ((access("/dev/ptmx", R_OK) < 0) && + (access("/dev/ptyp0", R_OK) < 0)) { + printk(UM_KERN_WARNING "No pseudo-terminals available - " + "skipping pty SIGIO check\n"); + return; + } + check_one_sigio(tty_output); + check_one_sigio(tty_close); +} + +/* Here because it only does the SIGIO testing for now */ +void __init os_check_bugs(void) +{ + check_sigio(); +} diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index c7bfd5ee392..7b605e4dfff 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -1,48 +1,314 @@ /* * Copyright (C) 2004 PathScale, Inc + * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ +#include <stdlib.h> +#include <stdarg.h> +#include <errno.h> #include <signal.h> -#include "time_user.h" -#include "mode.h" -#include "sysdep/signal.h" +#include <strings.h> +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> +#include <sysdep/mcontext.h> +#include "internal.h" -void sig_handler(ARCH_SIGHDLR_PARAM) +void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { + [SIGTRAP] = relay_signal, + [SIGFPE] = relay_signal, + [SIGILL] = relay_signal, + [SIGWINCH] = winch, + [SIGBUS] = bus_handler, + [SIGSEGV] = segv_handler, + [SIGIO] = sigio_handler, + [SIGVTALRM] = timer_handler }; + +static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) { - struct sigcontext *sc; + struct uml_pt_regs r; + int save_errno = errno; + + r.is_user = 0; + if (sig == SIGSEGV) { + /* For segfaults, we want the data from the sigcontext. */ + get_regs_from_mc(&r, mc); + GET_FAULTINFO_FROM_MC(r.faultinfo, mc); + } + + /* enable signals if sig isn't IRQ signal */ + if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) + unblock_signals(); - ARCH_GET_SIGCONTEXT(sc, sig); - CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, - sig, sc); + (*sig_info[sig])(sig, si, &r); + + errno = save_errno; } -extern int timer_irq_inited; +/* + * These are the asynchronous signals. SIGPROF is excluded because we want to + * be able to profile all of UML, not just the non-critical sections. If + * profiling is not thread-safe, then that is not my problem. We can disable + * profiling when SMP is enabled in that case. + */ +#define SIGIO_BIT 0 +#define SIGIO_MASK (1 << SIGIO_BIT) + +#define SIGVTALRM_BIT 1 +#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT) + +static int signals_enabled; +static unsigned int signals_pending; -void alarm_handler(ARCH_SIGHDLR_PARAM) +void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) { - struct sigcontext *sc; + int enabled; - ARCH_GET_SIGCONTEXT(sc, sig); - if(!timer_irq_inited) return; + enabled = signals_enabled; + if (!enabled && (sig == SIGIO)) { + signals_pending |= SIGIO_MASK; + return; + } - if(sig == SIGALRM) - switch_timers(0); + block_signals(); - CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, - sig, sc); + sig_handler_common(sig, si, mc); - if(sig == SIGALRM) - switch_timers(1); + set_signals(enabled); } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +static void real_alarm_handler(mcontext_t *mc) +{ + struct uml_pt_regs regs; + + if (mc != NULL) + get_regs_from_mc(®s, mc); + regs.is_user = 0; + unblock_signals(); + timer_handler(SIGVTALRM, NULL, ®s); +} + +void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) +{ + int enabled; + + enabled = signals_enabled; + if (!signals_enabled) { + signals_pending |= SIGVTALRM_MASK; + return; + } + + block_signals(); + + real_alarm_handler(mc); + set_signals(enabled); +} + +void timer_init(void) +{ + set_handler(SIGVTALRM); +} + +void set_sigstack(void *sig_stack, int size) +{ + stack_t stack = ((stack_t) { .ss_flags = 0, + .ss_sp = (__ptr_t) sig_stack, + .ss_size = size - sizeof(void *) }); + + if (sigaltstack(&stack, NULL) != 0) + panic("enabling signal stack failed, errno = %d\n", errno); +} + +static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { + [SIGSEGV] = sig_handler, + [SIGBUS] = sig_handler, + [SIGILL] = sig_handler, + [SIGFPE] = sig_handler, + [SIGTRAP] = sig_handler, + + [SIGIO] = sig_handler, + [SIGWINCH] = sig_handler, + [SIGVTALRM] = alarm_handler +}; + + +static void hard_handler(int sig, siginfo_t *si, void *p) +{ + struct ucontext *uc = p; + mcontext_t *mc = &uc->uc_mcontext; + unsigned long pending = 1UL << sig; + + do { + int nested, bail; + + /* + * pending comes back with one bit set for each + * interrupt that arrived while setting up the stack, + * plus a bit for this interrupt, plus the zero bit is + * set if this is a nested interrupt. + * If bail is true, then we interrupted another + * handler setting up the stack. In this case, we + * have to return, and the upper handler will deal + * with this interrupt. + */ + bail = to_irq_stack(&pending); + if (bail) + return; + + nested = pending & 1; + pending &= ~1; + + while ((sig = ffs(pending)) != 0){ + sig--; + pending &= ~(1 << sig); + (*handlers[sig])(sig, (struct siginfo *)si, mc); + } + + /* + * Again, pending comes back with a mask of signals + * that arrived while tearing down the stack. If this + * is non-zero, we just go back, set up the stack + * again, and handle the new interrupts. + */ + if (!nested) + pending = from_irq_stack(nested); + } while (pending); +} + +void set_handler(int sig) +{ + struct sigaction action; + int flags = SA_SIGINFO | SA_ONSTACK; + sigset_t sig_mask; + + action.sa_sigaction = hard_handler; + + /* block irq ones */ + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGVTALRM); + sigaddset(&action.sa_mask, SIGIO); + sigaddset(&action.sa_mask, SIGWINCH); + + if (sig == SIGSEGV) + flags |= SA_NODEFER; + + if (sigismember(&action.sa_mask, sig)) + flags |= SA_RESTART; /* if it's an irq signal */ + + action.sa_flags = flags; + action.sa_restorer = NULL; + if (sigaction(sig, &action, NULL) < 0) + panic("sigaction failed - errno = %d\n", errno); + + sigemptyset(&sig_mask); + sigaddset(&sig_mask, sig); + if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0) + panic("sigprocmask failed - errno = %d\n", errno); +} + +int change_sig(int signal, int on) +{ + sigset_t sigset; + + sigemptyset(&sigset); + sigaddset(&sigset, signal); + if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0) + return -errno; + + return 0; +} + +void block_signals(void) +{ + signals_enabled = 0; + /* + * This must return with signals disabled, so this barrier + * ensures that writes are flushed out before the return. + * This might matter if gcc figures out how to inline this and + * decides to shuffle this code into the caller. + */ + barrier(); +} + +void unblock_signals(void) +{ + int save_pending; + + if (signals_enabled == 1) + return; + + /* + * We loop because the IRQ handler returns with interrupts off. So, + * interrupts may have arrived and we need to re-enable them and + * recheck signals_pending. + */ + while (1) { + /* + * Save and reset save_pending after enabling signals. This + * way, signals_pending won't be changed while we're reading it. + */ + signals_enabled = 1; + + /* + * Setting signals_enabled and reading signals_pending must + * happen in this order. + */ + barrier(); + + save_pending = signals_pending; + if (save_pending == 0) + return; + + signals_pending = 0; + + /* + * We have pending interrupts, so disable signals, as the + * handlers expect them off when they are called. They will + * be enabled again above. + */ + + signals_enabled = 0; + + /* + * Deal with SIGIO first because the alarm handler might + * schedule, leaving the pending SIGIO stranded until we come + * back here. + * + * SIGIO's handler doesn't use siginfo or mcontext, + * so they can be NULL. + */ + if (save_pending & SIGIO_MASK) + sig_handler_common(SIGIO, NULL, NULL); + + if (save_pending & SIGVTALRM_MASK) + real_alarm_handler(NULL); + } +} + +int get_signals(void) +{ + return signals_enabled; +} + +int set_signals(int enable) +{ + int ret; + if (signals_enabled == enable) + return enable; + + ret = signals_enabled; + if (enable) + unblock_signals(); + else block_signals(); + + return ret; +} + +int os_is_signal_stack(void) +{ + stack_t ss; + sigaltstack(NULL, &ss); + + return ss.ss_flags & SS_ONSTACK; +} diff --git a/arch/um/os-Linux/skas/Makefile b/arch/um/os-Linux/skas/Makefile new file mode 100644 index 00000000000..d2ea3409e07 --- /dev/null +++ b/arch/um/os-Linux/skas/Makefile @@ -0,0 +1,10 @@ +# +# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) +# Licensed under the GPL +# + +obj-y := mem.o process.o + +USER_OBJS := $(obj-y) + +include arch/um/scripts/Makefile.rules diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c new file mode 100644 index 00000000000..689b18db798 --- /dev/null +++ b/arch/um/os-Linux/skas/mem.c @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <stddef.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/mman.h> +#include <init.h> +#include <as-layout.h> +#include <mm_id.h> +#include <os.h> +#include <proc_mm.h> +#include <ptrace_user.h> +#include <registers.h> +#include <skas.h> +#include <sysdep/ptrace.h> +#include <sysdep/stub.h> + +extern unsigned long batch_syscall_stub, __syscall_stub_start; + +extern void wait_stub_done(int pid); + +static inline unsigned long *check_init_stack(struct mm_id * mm_idp, + unsigned long *stack) +{ + if (stack == NULL) { + stack = (unsigned long *) mm_idp->stack + 2; + *stack = 0; + } + return stack; +} + +static unsigned long syscall_regs[MAX_REG_NR]; + +static int __init init_syscall_regs(void) +{ + get_safe_registers(syscall_regs, NULL); + syscall_regs[REGS_IP_INDEX] = STUB_CODE + + ((unsigned long) &batch_syscall_stub - + (unsigned long) &__syscall_stub_start); + return 0; +} + +__initcall(init_syscall_regs); + +extern int proc_mm; + +static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) +{ + int n, i; + long ret, offset; + unsigned long * data; + unsigned long * syscall; + int err, pid = mm_idp->u.pid; + + if (proc_mm) + /* FIXME: Need to look up userspace_pid by cpu */ + pid = userspace_pid[0]; + + n = ptrace_setregs(pid, syscall_regs); + if (n < 0) { + printk(UM_KERN_ERR "Registers - \n"); + for (i = 0; i < MAX_REG_NR; i++) + printk(UM_KERN_ERR "\t%d\t0x%lx\n", i, syscall_regs[i]); + panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", + -n); + } + + err = ptrace(PTRACE_CONT, pid, 0, 0); + if (err) + panic("Failed to continue stub, pid = %d, errno = %d\n", pid, + errno); + + wait_stub_done(pid); + + /* + * When the stub stops, we find the following values on the + * beginning of the stack: + * (long )return_value + * (long )offset to failed sycall-data (0, if no error) + */ + ret = *((unsigned long *) mm_idp->stack); + offset = *((unsigned long *) mm_idp->stack + 1); + if (offset) { + data = (unsigned long *)(mm_idp->stack + offset - STUB_DATA); + printk(UM_KERN_ERR "do_syscall_stub : ret = %ld, offset = %ld, " + "data = %p\n", ret, offset, data); + syscall = (unsigned long *)((unsigned long)data + data[0]); + printk(UM_KERN_ERR "do_syscall_stub: syscall %ld failed, " + "return value = 0x%lx, expected return value = 0x%lx\n", + syscall[0], ret, syscall[7]); + printk(UM_KERN_ERR " syscall parameters: " + "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", + syscall[1], syscall[2], syscall[3], + syscall[4], syscall[5], syscall[6]); + for (n = 1; n < data[0]/sizeof(long); n++) { + if (n == 1) + printk(UM_KERN_ERR " additional syscall " + "data:"); + if (n % 4 == 1) + printk("\n" UM_KERN_ERR " "); + printk(" 0x%lx", data[n]); + } + if (n > 1) + printk("\n"); + } + else ret = 0; + + *addr = check_init_stack(mm_idp, NULL); + + return ret; +} + +long run_syscall_stub(struct mm_id * mm_idp, int syscall, + unsigned long *args, long expected, void **addr, + int done) +{ + unsigned long *stack = check_init_stack(mm_idp, *addr); + + *stack += sizeof(long); + stack += *stack / sizeof(long); + + *stack++ = syscall; + *stack++ = args[0]; + *stack++ = args[1]; + *stack++ = args[2]; + *stack++ = args[3]; + *stack++ = args[4]; + *stack++ = args[5]; + *stack++ = expected; + *stack = 0; + + if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) < + UM_KERN_PAGE_SIZE - 10 * sizeof(long))) { + *addr = stack; + return 0; + } + + return do_syscall_stub(mm_idp, addr); +} + +long syscall_stub_data(struct mm_id * mm_idp, + unsigned long *data, int data_count, + void **addr, void **stub_addr) +{ + unsigned long *stack; + int ret = 0; + + /* + * If *addr still is uninitialized, it *must* contain NULL. + * Thus in this case do_syscall_stub correctly won't be called. + */ + if ((((unsigned long) *addr) & ~UM_KERN_PAGE_MASK) >= + UM_KERN_PAGE_SIZE - (10 + data_count) * sizeof(long)) { + ret = do_syscall_stub(mm_idp, addr); + /* in case of error, don't overwrite data on stack */ + if (ret) + return ret; + } + + stack = check_init_stack(mm_idp, *addr); + *addr = stack; + + *stack = data_count * sizeof(long); + + memcpy(stack + 1, data, data_count * sizeof(long)); + + *stub_addr = (void *)(((unsigned long)(stack + 1) & + ~UM_KERN_PAGE_MASK) + STUB_DATA); + + return 0; +} + +int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot, + int phys_fd, unsigned long long offset, int done, void **data) +{ + int ret; + + if (proc_mm) { + struct proc_mm_op map; + int fd = mm_idp->u.mm_fd; + + map = ((struct proc_mm_op) { .op = MM_MMAP, + .u = + { .mmap = + { .addr = virt, + .len = len, + .prot = prot, + .flags = MAP_SHARED | + MAP_FIXED, + .fd = phys_fd, + .offset= offset + } } } ); + CATCH_EINTR(ret = write(fd, &map, sizeof(map))); + if (ret != sizeof(map)) { + ret = -errno; + printk(UM_KERN_ERR "map : /proc/mm map failed, " + "err = %d\n", -ret); + } + else ret = 0; + } + else { + unsigned long args[] = { virt, len, prot, + MAP_SHARED | MAP_FIXED, phys_fd, + MMAP_OFFSET(offset) }; + + ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, + data, done); + } + + return ret; +} + +int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, + int done, void **data) +{ + int ret; + + if (proc_mm) { + struct proc_mm_op unmap; + int fd = mm_idp->u.mm_fd; + + unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, + .u = + { .munmap = + { .addr = + (unsigned long) addr, + .len = len } } } ); + CATCH_EINTR(ret = write(fd, &unmap, sizeof(unmap))); + if (ret != sizeof(unmap)) { + ret = -errno; + printk(UM_KERN_ERR "unmap - proc_mm write returned " + "%d\n", ret); + } + else ret = 0; + } + else { + unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, + 0 }; + + ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, + data, done); + } + + return ret; +} + +int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, + unsigned int prot, int done, void **data) +{ + struct proc_mm_op protect; + int ret; + + if (proc_mm) { + int fd = mm_idp->u.mm_fd; + + protect = ((struct proc_mm_op) { .op = MM_MPROTECT, + .u = + { .mprotect = + { .addr = + (unsigned long) addr, + .len = len, + .prot = prot } } } ); + + CATCH_EINTR(ret = write(fd, &protect, sizeof(protect))); + if (ret != sizeof(protect)) { + ret = -errno; + printk(UM_KERN_ERR "protect failed, err = %d", -ret); + } + else ret = 0; + } + else { + unsigned long args[] = { addr, len, prot, 0, 0, 0 }; + + ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, + data, done); + } + + return ret; +} diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c new file mode 100644 index 00000000000..908579f2b0a --- /dev/null +++ b/arch/um/os-Linux/skas/process.c @@ -0,0 +1,744 @@ +/* + * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <unistd.h> +#include <sched.h> +#include <errno.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <asm/unistd.h> +#include <as-layout.h> +#include <init.h> +#include <kern_util.h> +#include <mem.h> +#include <os.h> +#include <proc_mm.h> +#include <ptrace_user.h> +#include <registers.h> +#include <skas.h> +#include <skas_ptrace.h> +#include <sysdep/stub.h> + +int is_skas_winch(int pid, int fd, void *data) +{ + return pid == getpgrp(); +} + +static int ptrace_dump_regs(int pid) +{ + unsigned long regs[MAX_REG_NR]; + int i; + + if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) + return -errno; + + printk(UM_KERN_ERR "Stub registers -\n"); + for (i = 0; i < ARRAY_SIZE(regs); i++) + printk(UM_KERN_ERR "\t%d - %lx\n", i, regs[i]); + + return 0; +} + +/* + * Signals that are OK to receive in the stub - we'll just continue it. + * SIGWINCH will happen when UML is inside a detached screen. + */ +#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH)) + +/* Signals that the stub will finish with - anything else is an error */ +#define STUB_DONE_MASK (1 << SIGTRAP) + +void wait_stub_done(int pid) +{ + int n, status, err; + + while (1) { + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL)); + if ((n < 0) || !WIFSTOPPED(status)) + goto bad_wait; + + if (((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0) + break; + + err = ptrace(PTRACE_CONT, pid, 0, 0); + if (err) { + printk(UM_KERN_ERR "wait_stub_done : continue failed, " + "errno = %d\n", errno); + fatal_sigsegv(); + } + } + + if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0) + return; + +bad_wait: + err = ptrace_dump_regs(pid); + if (err) + printk(UM_KERN_ERR "Failed to get registers from stub, " + "errno = %d\n", -err); + printk(UM_KERN_ERR "wait_stub_done : failed to wait for SIGTRAP, " + "pid = %d, n = %d, errno = %d, status = 0x%x\n", pid, n, errno, + status); + fatal_sigsegv(); +} + +extern unsigned long current_stub_stack(void); + +static void get_skas_faultinfo(int pid, struct faultinfo *fi) +{ + int err; + + if (ptrace_faultinfo) { + err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); + if (err) { + printk(UM_KERN_ERR "get_skas_faultinfo - " + "PTRACE_FAULTINFO failed, errno = %d\n", errno); + fatal_sigsegv(); + } + + /* Special handling for i386, which has different structs */ + if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) + memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, + sizeof(struct faultinfo) - + sizeof(struct ptrace_faultinfo)); + } + else { + unsigned long fpregs[FP_SIZE]; + + err = get_fp_registers(pid, fpregs); + if (err < 0) { + printk(UM_KERN_ERR "save_fp_registers returned %d\n", + err); + fatal_sigsegv(); + } + err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); + if (err) { + printk(UM_KERN_ERR "Failed to continue stub, pid = %d, " + "errno = %d\n", pid, errno); + fatal_sigsegv(); + } + wait_stub_done(pid); + + /* + * faultinfo is prepared by the stub-segv-handler at start of + * the stub stack page. We just have to copy it. + */ + memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); + + err = put_fp_registers(pid, fpregs); + if (err < 0) { + printk(UM_KERN_ERR "put_fp_registers returned %d\n", + err); + fatal_sigsegv(); + } + } +} + +static void handle_segv(int pid, struct uml_pt_regs * regs) +{ + get_skas_faultinfo(pid, ®s->faultinfo); + segv(regs->faultinfo, 0, 1, NULL); +} + +/* + * To use the same value of using_sysemu as the caller, ask it that value + * (in local_using_sysemu + */ +static void handle_trap(int pid, struct uml_pt_regs *regs, + int local_using_sysemu) +{ + int err, status; + + if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END)) + fatal_sigsegv(); + + /* Mark this as a syscall */ + UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->gp); + + if (!local_using_sysemu) + { + err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, + __NR_getpid); + if (err < 0) { + printk(UM_KERN_ERR "handle_trap - nullifying syscall " + "failed, errno = %d\n", errno); + fatal_sigsegv(); + } + + err = ptrace(PTRACE_SYSCALL, pid, 0, 0); + if (err < 0) { + printk(UM_KERN_ERR "handle_trap - continuing to end of " + "syscall failed, errno = %d\n", errno); + fatal_sigsegv(); + } + + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); + if ((err < 0) || !WIFSTOPPED(status) || + (WSTOPSIG(status) != SIGTRAP + 0x80)) { + err = ptrace_dump_regs(pid); + if (err) + printk(UM_KERN_ERR "Failed to get registers " + "from process, errno = %d\n", -err); + printk(UM_KERN_ERR "handle_trap - failed to wait at " + "end of syscall, errno = %d, status = %d\n", + errno, status); + fatal_sigsegv(); + } + } + + handle_syscall(regs); +} + +extern int __syscall_stub_start; + +static int userspace_tramp(void *stack) +{ + void *addr; + int err; + + ptrace(PTRACE_TRACEME, 0, 0, 0); + + signal(SIGTERM, SIG_DFL); + signal(SIGWINCH, SIG_IGN); + err = set_interval(); + if (err) { + printk(UM_KERN_ERR "userspace_tramp - setting timer failed, " + "errno = %d\n", err); + exit(1); + } + + if (!proc_mm) { + /* + * This has a pte, but it can't be mapped in with the usual + * tlb_flush mechanism because this is part of that mechanism + */ + int fd; + unsigned long long offset; + fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); + addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE, + PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); + if (addr == MAP_FAILED) { + printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, " + "errno = %d\n", STUB_CODE, errno); + exit(1); + } + + if (stack != NULL) { + fd = phys_mapping(to_phys(stack), &offset); + addr = mmap((void *) STUB_DATA, + UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd, offset); + if (addr == MAP_FAILED) { + printk(UM_KERN_ERR "mapping segfault stack " + "at 0x%lx failed, errno = %d\n", + STUB_DATA, errno); + exit(1); + } + } + } + if (!ptrace_faultinfo && (stack != NULL)) { + struct sigaction sa; + + unsigned long v = STUB_CODE + + (unsigned long) stub_segv_handler - + (unsigned long) &__syscall_stub_start; + + set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO; + sa.sa_sigaction = (void *) v; + sa.sa_restorer = NULL; + if (sigaction(SIGSEGV, &sa, NULL) < 0) { + printk(UM_KERN_ERR "userspace_tramp - setting SIGSEGV " + "handler failed - errno = %d\n", errno); + exit(1); + } + } + + kill(os_getpid(), SIGSTOP); + return 0; +} + +/* Each element set once, and only accessed by a single processor anyway */ +#undef NR_CPUS +#define NR_CPUS 1 +int userspace_pid[NR_CPUS]; + +int start_userspace(unsigned long stub_stack) +{ + void *stack; + unsigned long sp; + int pid, status, n, flags, err; + + stack = mmap(NULL, UM_KERN_PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (stack == MAP_FAILED) { + err = -errno; + printk(UM_KERN_ERR "start_userspace : mmap failed, " + "errno = %d\n", errno); + return err; + } + + sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *); + + flags = CLONE_FILES; + if (proc_mm) + flags |= CLONE_VM; + else + flags |= SIGCHLD; + + pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); + if (pid < 0) { + err = -errno; + printk(UM_KERN_ERR "start_userspace : clone failed, " + "errno = %d\n", errno); + return err; + } + + do { + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL)); + if (n < 0) { + err = -errno; + printk(UM_KERN_ERR "start_userspace : wait failed, " + "errno = %d\n", errno); + goto out_kill; + } + } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); + + if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) { + err = -EINVAL; + printk(UM_KERN_ERR "start_userspace : expected SIGSTOP, got " + "status = %d\n", status); + goto out_kill; + } + + if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, + (void *) PTRACE_O_TRACESYSGOOD) < 0) { + err = -errno; + printk(UM_KERN_ERR "start_userspace : PTRACE_OLDSETOPTIONS " + "failed, errno = %d\n", errno); + goto out_kill; + } + + if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) { + err = -errno; + printk(UM_KERN_ERR "start_userspace : munmap failed, " + "errno = %d\n", errno); + goto out_kill; + } + + return pid; + + out_kill: + os_kill_ptraced_process(pid, 1); + return err; +} + +void userspace(struct uml_pt_regs *regs) +{ + struct itimerval timer; + unsigned long long nsecs, now; + int err, status, op, pid = userspace_pid[0]; + /* To prevent races if using_sysemu changes under us.*/ + int local_using_sysemu; + siginfo_t si; + + /* Handle any immediate reschedules or signals */ + interrupt_end(); + + if (getitimer(ITIMER_VIRTUAL, &timer)) + printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno); + nsecs = timer.it_value.tv_sec * UM_NSEC_PER_SEC + + timer.it_value.tv_usec * UM_NSEC_PER_USEC; + nsecs += os_nsecs(); + + while (1) { + /* + * This can legitimately fail if the process loads a + * bogus value into a segment register. It will + * segfault and PTRACE_GETREGS will read that value + * out of the process. However, PTRACE_SETREGS will + * fail. In this case, there is nothing to do but + * just kill the process. + */ + if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) + fatal_sigsegv(); + + if (put_fp_registers(pid, regs->fp)) + fatal_sigsegv(); + + /* Now we set local_using_sysemu to be used for one loop */ + local_using_sysemu = get_using_sysemu(); + + op = SELECT_PTRACE_OPERATION(local_using_sysemu, + singlestepping(NULL)); + + if (ptrace(op, pid, 0, 0)) { + printk(UM_KERN_ERR "userspace - ptrace continue " + "failed, op = %d, errno = %d\n", op, errno); + fatal_sigsegv(); + } + + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); + if (err < 0) { + printk(UM_KERN_ERR "userspace - wait failed, " + "errno = %d\n", errno); + fatal_sigsegv(); + } + + regs->is_user = 1; + if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) { + printk(UM_KERN_ERR "userspace - PTRACE_GETREGS failed, " + "errno = %d\n", errno); + fatal_sigsegv(); + } + + if (get_fp_registers(pid, regs->fp)) { + printk(UM_KERN_ERR "userspace - get_fp_registers failed, " + "errno = %d\n", errno); + fatal_sigsegv(); + } + + UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ + + if (WIFSTOPPED(status)) { + int sig = WSTOPSIG(status); + + ptrace(PTRACE_GETSIGINFO, pid, 0, (struct siginfo *)&si); + + switch (sig) { + case SIGSEGV: + if (PTRACE_FULL_FAULTINFO || + !ptrace_faultinfo) { + get_skas_faultinfo(pid, + ®s->faultinfo); + (*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si, + regs); + } + else handle_segv(pid, regs); + break; + case SIGTRAP + 0x80: + handle_trap(pid, regs, local_using_sysemu); + break; + case SIGTRAP: + relay_signal(SIGTRAP, (struct siginfo *)&si, regs); + break; + case SIGVTALRM: + now = os_nsecs(); + if (now < nsecs) + break; + block_signals(); + (*sig_info[sig])(sig, (struct siginfo *)&si, regs); + unblock_signals(); + nsecs = timer.it_value.tv_sec * + UM_NSEC_PER_SEC + + timer.it_value.tv_usec * + UM_NSEC_PER_USEC; + nsecs += os_nsecs(); + break; + case SIGIO: + case SIGILL: + case SIGBUS: + case SIGFPE: + case SIGWINCH: + block_signals(); + (*sig_info[sig])(sig, (struct siginfo *)&si, regs); + unblock_signals(); + break; + default: + printk(UM_KERN_ERR "userspace - child stopped " + "with signal %d\n", sig); + fatal_sigsegv(); + } + pid = userspace_pid[0]; + interrupt_end(); + + /* Avoid -ERESTARTSYS handling in host */ + if (PT_SYSCALL_NR_OFFSET != PT_SYSCALL_RET_OFFSET) + PT_SYSCALL_NR(regs->gp) = -1; + } + } +} + +static unsigned long thread_regs[MAX_REG_NR]; +static unsigned long thread_fp_regs[FP_SIZE]; + +static int __init init_thread_regs(void) +{ + get_safe_registers(thread_regs, thread_fp_regs); + /* Set parent's instruction pointer to start of clone-stub */ + thread_regs[REGS_IP_INDEX] = STUB_CODE + + (unsigned long) stub_clone_handler - + (unsigned long) &__syscall_stub_start; + thread_regs[REGS_SP_INDEX] = STUB_DATA + UM_KERN_PAGE_SIZE - + sizeof(void *); +#ifdef __SIGNAL_FRAMESIZE + thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; +#endif + return 0; +} + +__initcall(init_thread_regs); + +int copy_context_skas0(unsigned long new_stack, int pid) +{ + struct timeval tv = { .tv_sec = 0, .tv_usec = UM_USEC_PER_SEC / UM_HZ }; + int err; + unsigned long current_stack = current_stub_stack(); + struct stub_data *data = (struct stub_data *) current_stack; + struct stub_data *child_data = (struct stub_data *) new_stack; + unsigned long long new_offset; + int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset); + + /* + * prepare offset and fd of child's stack as argument for parent's + * and child's mmap2 calls + */ + *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset), + .fd = new_fd, + .timer = ((struct itimerval) + { .it_value = tv, + .it_interval = tv }) }); + + err = ptrace_setregs(pid, thread_regs); + if (err < 0) { + err = -errno; + printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_SETREGS " + "failed, pid = %d, errno = %d\n", pid, -err); + return err; + } + + err = put_fp_registers(pid, thread_fp_regs); + if (err < 0) { + printk(UM_KERN_ERR "copy_context_skas0 : put_fp_registers " + "failed, pid = %d, err = %d\n", pid, err); + return err; + } + + /* set a well known return code for detection of child write failure */ + child_data->err = 12345678; + + /* + * Wait, until parent has finished its work: read child's pid from + * parent's stack, and check, if bad result. + */ + err = ptrace(PTRACE_CONT, pid, 0, 0); + if (err) { + err = -errno; + printk(UM_KERN_ERR "Failed to continue new process, pid = %d, " + "errno = %d\n", pid, errno); + return err; + } + + wait_stub_done(pid); + + pid = data->err; + if (pid < 0) { + printk(UM_KERN_ERR "copy_context_skas0 - stub-parent reports " + "error %d\n", -pid); + return pid; + } + + /* + * Wait, until child has finished too: read child's result from + * child's stack and check it. + */ + wait_stub_done(pid); + if (child_data->err != STUB_DATA) { + printk(UM_KERN_ERR "copy_context_skas0 - stub-child reports " + "error %ld\n", child_data->err); + err = child_data->err; + goto out_kill; + } + + if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, + (void *)PTRACE_O_TRACESYSGOOD) < 0) { + err = -errno; + printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_OLDSETOPTIONS " + "failed, errno = %d\n", errno); + goto out_kill; + } + + return pid; + + out_kill: + os_kill_ptraced_process(pid, 1); + return err; +} + +/* + * This is used only, if stub pages are needed, while proc_mm is + * available. Opening /proc/mm creates a new mm_context, which lacks + * the stub-pages. Thus, we map them using /proc/mm-fd + */ +int map_stub_pages(int fd, unsigned long code, unsigned long data, + unsigned long stack) +{ + struct proc_mm_op mmop; + int n; + unsigned long long code_offset; + int code_fd = phys_mapping(to_phys((void *) &__syscall_stub_start), + &code_offset); + + mmop = ((struct proc_mm_op) { .op = MM_MMAP, + .u = + { .mmap = + { .addr = code, + .len = UM_KERN_PAGE_SIZE, + .prot = PROT_EXEC, + .flags = MAP_FIXED | MAP_PRIVATE, + .fd = code_fd, + .offset = code_offset + } } }); + CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); + if (n != sizeof(mmop)) { + n = errno; + printk(UM_KERN_ERR "mmap args - addr = 0x%lx, fd = %d, " + "offset = %llx\n", code, code_fd, + (unsigned long long) code_offset); + printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for code " + "failed, err = %d\n", n); + return -n; + } + + if (stack) { + unsigned long long map_offset; + int map_fd = phys_mapping(to_phys((void *)stack), &map_offset); + mmop = ((struct proc_mm_op) + { .op = MM_MMAP, + .u = + { .mmap = + { .addr = data, + .len = UM_KERN_PAGE_SIZE, + .prot = PROT_READ | PROT_WRITE, + .flags = MAP_FIXED | MAP_SHARED, + .fd = map_fd, + .offset = map_offset + } } }); + CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); + if (n != sizeof(mmop)) { + n = errno; + printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for " + "data failed, err = %d\n", n); + return -n; + } + } + + return 0; +} + +void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) +{ + (*buf)[0].JB_IP = (unsigned long) handler; + (*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE - + sizeof(void *); +} + +#define INIT_JMP_NEW_THREAD 0 +#define INIT_JMP_CALLBACK 1 +#define INIT_JMP_HALT 2 +#define INIT_JMP_REBOOT 3 + +void switch_threads(jmp_buf *me, jmp_buf *you) +{ + if (UML_SETJMP(me) == 0) + UML_LONGJMP(you, 1); +} + +static jmp_buf initial_jmpbuf; + +/* XXX Make these percpu */ +static void (*cb_proc)(void *arg); +static void *cb_arg; +static jmp_buf *cb_back; + +int start_idle_thread(void *stack, jmp_buf *switch_buf) +{ + int n; + + set_handler(SIGWINCH); + + /* + * Can't use UML_SETJMP or UML_LONGJMP here because they save + * and restore signals, with the possible side-effect of + * trying to handle any signals which came when they were + * blocked, which can't be done on this stack. + * Signals must be blocked when jumping back here and restored + * after returning to the jumper. + */ + n = setjmp(initial_jmpbuf); + switch (n) { + case INIT_JMP_NEW_THREAD: + (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; + (*switch_buf)[0].JB_SP = (unsigned long) stack + + UM_THREAD_SIZE - sizeof(void *); + break; + case INIT_JMP_CALLBACK: + (*cb_proc)(cb_arg); + longjmp(*cb_back, 1); + break; + case INIT_JMP_HALT: + kmalloc_ok = 0; + return 0; + case INIT_JMP_REBOOT: + kmalloc_ok = 0; + return 1; + default: + printk(UM_KERN_ERR "Bad sigsetjmp return in " + "start_idle_thread - %d\n", n); + fatal_sigsegv(); + } + longjmp(*switch_buf, 1); +} + +void initial_thread_cb_skas(void (*proc)(void *), void *arg) +{ + jmp_buf here; + + cb_proc = proc; + cb_arg = arg; + cb_back = &here; + + block_signals(); + if (UML_SETJMP(&here) == 0) + UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK); + unblock_signals(); + + cb_proc = NULL; + cb_arg = NULL; + cb_back = NULL; +} + +void halt_skas(void) +{ + block_signals(); + UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT); +} + +void reboot_skas(void) +{ + block_signals(); + UML_LONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT); +} + +void __switch_mm(struct mm_id *mm_idp) +{ + int err; + + /* FIXME: need cpu pid in __switch_mm */ + if (proc_mm) { + err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, + mm_idp->u.mm_fd); + if (err) { + printk(UM_KERN_ERR "__switch_mm - PTRACE_SWITCH_MM " + "failed, errno = %d\n", errno); + fatal_sigsegv(); + } + } + else userspace_pid[0] = mm_idp->u.pid; +} diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 37517d49c4a..337518c5042 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -1,102 +1,114 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #include <stdio.h> -#include <stddef.h> -#include <stdarg.h> #include <stdlib.h> -#include <string.h> +#include <stdarg.h> #include <unistd.h> -#include <signal.h> -#include <sched.h> -#include <fcntl.h> #include <errno.h> -#include <setjmp.h> -#include <sys/time.h> -#include <sys/wait.h> +#include <fcntl.h> +#include <sched.h> +#include <signal.h> +#include <string.h> #include <sys/mman.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <sys/resource.h> #include <asm/unistd.h> -#include <asm/page.h> -#include <sys/types.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "signal_kern.h" -#include "signal_user.h" -#include "sysdep/ptrace.h" -#include "sysdep/sigcontext.h" -#include "irq_user.h" -#include "ptrace_user.h" -#include "mem_user.h" -#include "time_user.h" -#include "init.h" -#include "os.h" -#include "uml-config.h" -#include "choose-mode.h" -#include "mode.h" -#include "tempfile.h" -#include "kern_constants.h" - -#ifdef UML_CONFIG_MODE_SKAS -#include "skas.h" -#include "skas_ptrace.h" -#include "registers.h" -#endif - -static int ptrace_child(void *arg) +#include <init.h> +#include <os.h> +#include <mem_user.h> +#include <ptrace_user.h> +#include <registers.h> +#include <skas.h> +#include <skas_ptrace.h> + +static void ptrace_child(void) { int ret; + /* Calling os_getpid because some libcs cached getpid incorrectly */ int pid = os_getpid(), ppid = getppid(); int sc_result; - if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ + if (change_sig(SIGWINCH, 0) < 0 || + ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { perror("ptrace"); - os_kill_process(pid, 0); + kill(pid, SIGKILL); } - os_stop_process(pid); + kill(pid, SIGSTOP); - /*This syscall will be intercepted by the parent. Don't call more than - * once, please.*/ + /* + * This syscall will be intercepted by the parent. Don't call more than + * once, please. + */ sc_result = os_getpid(); if (sc_result == pid) - ret = 1; /*Nothing modified by the parent, we are running - normally.*/ + /* Nothing modified by the parent, we are running normally. */ + ret = 1; else if (sc_result == ppid) - ret = 0; /*Expected in check_ptrace and check_sysemu when they - succeed in modifying the stack frame*/ + /* + * Expected in check_ptrace and check_sysemu when they succeed + * in modifying the stack frame + */ + ret = 0; else - ret = 2; /*Serious trouble! This could be caused by a bug in - host 2.6 SKAS3/2.6 patch before release -V6, together - with a bug in the UML code itself.*/ - _exit(ret); + /* Serious trouble! This could be caused by a bug in host 2.6 + * SKAS3/2.6 patch before release -V6, together with a bug in + * the UML code itself. + */ + ret = 2; + + exit(ret); +} + +static void fatal_perror(const char *str) +{ + perror(str); + exit(1); +} + +static void fatal(char *fmt, ...) +{ + va_list list; + + va_start(list, fmt); + vfprintf(stderr, fmt, list); + va_end(list); + + exit(1); } -static int start_ptraced_child(void **stack_out) +static void non_fatal(char *fmt, ...) +{ + va_list list; + + va_start(list, fmt); + vfprintf(stderr, fmt, list); + va_end(list); +} + +static int start_ptraced_child(void) { - void *stack; - unsigned long sp; int pid, n, status; - stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if(stack == MAP_FAILED) - panic("check_ptrace : mmap failed, errno = %d", errno); - sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); - pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); - if(pid < 0) - panic("start_ptraced_child : clone failed, errno = %d", errno); + pid = fork(); + if (pid == 0) + ptrace_child(); + else if (pid < 0) + fatal_perror("start_ptraced_child : fork failed"); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); - if(n < 0) - panic("check_ptrace : clone failed, errno = %d", errno); - if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) - panic("check_ptrace : expected SIGSTOP, got status = %d", + if (n < 0) + fatal_perror("check_ptrace : waitpid failed"); + if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) + fatal("check_ptrace : expected SIGSTOP, got status = %d", status); - *stack_out = stack; - return(pid); + return pid; } /* When testing for SYSEMU support, if it is one of the broken versions, we @@ -105,43 +117,53 @@ static int start_ptraced_child(void **stack_out) * So only for SYSEMU features we test mustpanic, while normal host features * must work anyway! */ -static int stop_ptraced_child(int pid, void *stack, int exitcode, - int mustpanic) +static int stop_ptraced_child(int pid, int exitcode, int mustexit) { int status, n, ret = 0; - if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) - panic("check_ptrace : ptrace failed, errno = %d", errno); + if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) { + perror("stop_ptraced_child : ptrace failed"); + return -1; + } CATCH_EINTR(n = waitpid(pid, &status, 0)); - if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { + if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { int exit_with = WEXITSTATUS(status); if (exit_with == 2) - printk("check_ptrace : child exited with status 2. " - "Serious trouble happening! Try updating your " - "host skas patch!\nDisabling SYSEMU support."); - printk("check_ptrace : child exited with exitcode %d, while " - "expecting %d; status 0x%x", exit_with, - exitcode, status); - if (mustpanic) - panic("\n"); - else - printk("\n"); + non_fatal("check_ptrace : child exited with status 2. " + "\nDisabling SYSEMU support.\n"); + non_fatal("check_ptrace : child exited with exitcode %d, while " + "expecting %d; status 0x%x\n", exit_with, + exitcode, status); + if (mustexit) + exit(1); ret = -1; } - if(munmap(stack, PAGE_SIZE) < 0) - panic("check_ptrace : munmap failed, errno = %d", errno); return ret; } -int ptrace_faultinfo = 1; -int ptrace_ldt = 1; -int proc_mm = 1; -int skas_needs_stub = 0; +/* Changed only during early boot */ +int ptrace_faultinfo; +static int disable_ptrace_faultinfo; + +int ptrace_ldt; +static int disable_ptrace_ldt; + +int proc_mm; +static int disable_proc_mm; + +int have_switch_mm; +static int disable_switch_mm; + +int skas_needs_stub; static int __init skas0_cmd_param(char *str, int* add) { - ptrace_faultinfo = proc_mm = 0; + disable_ptrace_faultinfo = 1; + disable_ptrace_ldt = 1; + disable_proc_mm = 1; + disable_switch_mm = 1; + return 0; } @@ -151,16 +173,14 @@ static int __init mode_skas0_cmd_param(char *str, int* add) __attribute__((alias("skas0_cmd_param"))); __uml_setup("skas0", skas0_cmd_param, - "skas0\n" - " Disables SKAS3 usage, so that SKAS0 is used, unless \n" - " you specify mode=tt.\n\n"); +"skas0\n" +" Disables SKAS3 and SKAS4 usage, so that SKAS0 is used\n\n"); __uml_setup("mode=skas0", mode_skas0_cmd_param, - "mode=skas0\n" - " Disables SKAS3 usage, so that SKAS0 is used, unless you \n" - " specify mode=tt. Note that this was recently added - on \n" - " older kernels you must use simply \"skas0\".\n\n"); +"mode=skas0\n" +" Disables SKAS3 and SKAS4 usage, so that SKAS0 is used.\n\n"); +/* Changed only during early boot */ static int force_sysemu_disabled = 0; static int __init nosysemu_cmd_param(char *str, int* add) @@ -180,159 +200,185 @@ __uml_setup("nosysemu", nosysemu_cmd_param, static void __init check_sysemu(void) { - void *stack; - int pid, n, status, count=0; + unsigned long regs[MAX_REG_NR]; + int pid, n, status, count=0; - printk("Checking syscall emulation patch for ptrace..."); + non_fatal("Checking syscall emulation patch for ptrace..."); sysemu_supported = 0; - pid = start_ptraced_child(&stack); + pid = start_ptraced_child(); - if(ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0) + if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0) goto fail; CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if (n < 0) - panic("check_sysemu : wait failed, errno = %d", errno); - if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) - panic("check_sysemu : expected SIGTRAP, " - "got status = %d", status); - - n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, - os_getpid()); - if(n < 0) - panic("check_sysemu : failed to modify system " - "call return, errno = %d", errno); - - if (stop_ptraced_child(pid, stack, 0, 0) < 0) + fatal_perror("check_sysemu : wait failed"); + if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) + fatal("check_sysemu : expected SIGTRAP, got status = %d\n", + status); + + if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) + fatal_perror("check_sysemu : PTRACE_GETREGS failed"); + if (PT_SYSCALL_NR(regs) != __NR_getpid) { + non_fatal("check_sysemu got system call number %d, " + "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid); + goto fail; + } + + n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); + if (n < 0) { + non_fatal("check_sysemu : failed to modify system call " + "return"); + goto fail; + } + + if (stop_ptraced_child(pid, 0, 0) < 0) goto fail_stopped; sysemu_supported = 1; - printk("OK\n"); + non_fatal("OK\n"); set_using_sysemu(!force_sysemu_disabled); - printk("Checking advanced syscall emulation patch for ptrace..."); - pid = start_ptraced_child(&stack); + non_fatal("Checking advanced syscall emulation patch for ptrace..."); + pid = start_ptraced_child(); - if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, - (void *) PTRACE_O_TRACESYSGOOD) < 0) - panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", - errno); + if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, + (void *) PTRACE_O_TRACESYSGOOD) < 0)) + fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed"); - while(1){ + while (1) { count++; - if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0) + if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0) goto fail; CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); - if(n < 0) - panic("check_ptrace : wait failed, errno = %d", errno); - if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){ - if (!count) - panic("check_ptrace : SYSEMU_SINGLESTEP " - "doesn't singlestep"); - n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, + if (n < 0) + fatal_perror("check_sysemu: wait failed"); + + if (WIFSTOPPED(status) && + (WSTOPSIG(status) == (SIGTRAP|0x80))) { + if (!count) { + non_fatal("check_sysemu: SYSEMU_SINGLESTEP " + "doesn't singlestep"); + goto fail; + } + n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); - if(n < 0) - panic("check_sysemu : failed to modify system " - "call return, errno = %d", errno); + if (n < 0) + fatal_perror("check_sysemu : failed to modify " + "system call return"); break; } - else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) + else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) count++; - else - panic("check_ptrace : expected SIGTRAP or " - "(SIGTRAP|0x80), got status = %d", status); + else { + non_fatal("check_sysemu: expected SIGTRAP or " + "(SIGTRAP | 0x80), got status = %d\n", + status); + goto fail; + } } - if (stop_ptraced_child(pid, stack, 0, 0) < 0) + if (stop_ptraced_child(pid, 0, 0) < 0) goto fail_stopped; sysemu_supported = 2; - printk("OK\n"); + non_fatal("OK\n"); - if ( !force_sysemu_disabled ) + if (!force_sysemu_disabled) set_using_sysemu(sysemu_supported); return; fail: - stop_ptraced_child(pid, stack, 1, 0); + stop_ptraced_child(pid, 1, 0); fail_stopped: - printk("missing\n"); + non_fatal("missing\n"); } static void __init check_ptrace(void) { - void *stack; int pid, syscall, n, status; - printk("Checking that ptrace can change system call numbers..."); - pid = start_ptraced_child(&stack); + non_fatal("Checking that ptrace can change system call numbers..."); + pid = start_ptraced_child(); + + if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, + (void *) PTRACE_O_TRACESYSGOOD) < 0)) + fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); - if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) - panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", errno); + while (1) { + if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) + fatal_perror("check_ptrace : ptrace failed"); - while(1){ - if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) - panic("check_ptrace : ptrace failed, errno = %d", - errno); CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); - if(n < 0) - panic("check_ptrace : wait failed, errno = %d", errno); - if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP|0x80))) - panic("check_ptrace : expected (SIGTRAP|0x80), " - "got status = %d", status); + if (n < 0) + fatal_perror("check_ptrace : wait failed"); - syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, + if (!WIFSTOPPED(status) || + (WSTOPSIG(status) != (SIGTRAP | 0x80))) + fatal("check_ptrace : expected (SIGTRAP|0x80), " + "got status = %d", status); + + syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0); - if(syscall == __NR_getpid){ - n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, + if (syscall == __NR_getpid) { + n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getppid); - if(n < 0) - panic("check_ptrace : failed to modify system " - "call, errno = %d", errno); + if (n < 0) + fatal_perror("check_ptrace : failed to modify " + "system call"); break; } } - stop_ptraced_child(pid, stack, 0, 1); - printk("OK\n"); + stop_ptraced_child(pid, 0, 1); + non_fatal("OK\n"); check_sysemu(); } -extern int create_tmp_file(unsigned long long len); +extern void check_tmpexec(void); -static void check_tmpexec(void) +static void __init check_coredump_limit(void) { - void *addr; - int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE); - - addr = mmap(NULL, UM_KERN_PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); - printf("Checking PROT_EXEC mmap in /tmp..."); - fflush(stdout); - if(addr == MAP_FAILED){ - err = errno; - perror("failed"); - if(err == EPERM) - printf("/tmp must be not mounted noexec\n"); - exit(1); + struct rlimit lim; + int err = getrlimit(RLIMIT_CORE, &lim); + + if (err) { + perror("Getting core dump limit"); + return; } - printf("OK\n"); - munmap(addr, UM_KERN_PAGE_SIZE); - close(fd); + printf("Core dump limits :\n\tsoft - "); + if (lim.rlim_cur == RLIM_INFINITY) + printf("NONE\n"); + else printf("%lu\n", lim.rlim_cur); + + printf("\thard - "); + if (lim.rlim_max == RLIM_INFINITY) + printf("NONE\n"); + else printf("%lu\n", lim.rlim_max); } -void os_early_checks(void) +void __init os_early_checks(void) { + int pid; + + /* Print out the core dump limits early */ + check_coredump_limit(); + check_ptrace(); /* Need to check this early because mmapping happens before the * kernel is running. */ check_tmpexec(); + + pid = start_ptraced_child(); + if (init_registers(pid)) + fatal("Failed to initialize default registers"); + stop_ptraced_child(pid, 1, 1); } static int __init noprocmm_cmd_param(char *str, int* add) { - proc_mm = 0; + disable_proc_mm = 1; return 0; } @@ -344,7 +390,7 @@ __uml_setup("noprocmm", noprocmm_cmd_param, static int __init noptracefaultinfo_cmd_param(char *str, int* add) { - ptrace_faultinfo = 0; + disable_ptrace_faultinfo = 1; return 0; } @@ -356,7 +402,7 @@ __uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param, static int __init noptraceldt_cmd_param(char *str, int* add) { - ptrace_ldt = 0; + disable_ptrace_ldt = 1; return 0; } @@ -366,39 +412,33 @@ __uml_setup("noptraceldt", noptraceldt_cmd_param, " To support PTRACE_LDT, the host needs to be patched using\n" " the current skas3 patch.\n\n"); -#ifdef UML_CONFIG_MODE_SKAS static inline void check_skas3_ptrace_faultinfo(void) { struct ptrace_faultinfo fi; - void *stack; int pid, n; - printf(" - PTRACE_FAULTINFO..."); - pid = start_ptraced_child(&stack); + non_fatal(" - PTRACE_FAULTINFO..."); + pid = start_ptraced_child(); n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); if (n < 0) { - ptrace_faultinfo = 0; - if(errno == EIO) - printf("not found\n"); + if (errno == EIO) + non_fatal("not found\n"); else perror("not found"); - } + } else if (disable_ptrace_faultinfo) + non_fatal("found but disabled on command line\n"); else { - if (!ptrace_faultinfo) - printf("found but disabled on command line\n"); - else - printf("found\n"); + ptrace_faultinfo = 1; + non_fatal("found\n"); } - init_registers(pid); - stop_ptraced_child(pid, stack, 1, 1); + stop_ptraced_child(pid, 1, 1); } static inline void check_skas3_ptrace_ldt(void) { #ifdef PTRACE_LDT - void *stack; int pid, n; unsigned char ldtbuf[40]; struct ptrace_ldt ldt_op = (struct ptrace_ldt) { @@ -406,121 +446,84 @@ static inline void check_skas3_ptrace_ldt(void) .ptr = ldtbuf, .bytecount = sizeof(ldtbuf)}; - printf(" - PTRACE_LDT..."); - pid = start_ptraced_child(&stack); + non_fatal(" - PTRACE_LDT..."); + pid = start_ptraced_child(); n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); if (n < 0) { - if(errno == EIO) - printf("not found\n"); - else { + if (errno == EIO) + non_fatal("not found\n"); + else perror("not found"); - } - ptrace_ldt = 0; - } + } else if (disable_ptrace_ldt) + non_fatal("found, but use is disabled\n"); else { - if(ptrace_ldt) - printf("found\n"); - else - printf("found, but use is disabled\n"); + ptrace_ldt = 1; + non_fatal("found\n"); } - stop_ptraced_child(pid, stack, 1, 1); -#else - /* PTRACE_LDT might be disabled via cmdline option. - * We want to override this, else we might use the stub - * without real need - */ - ptrace_ldt = 1; + stop_ptraced_child(pid, 1, 1); #endif } static inline void check_skas3_proc_mm(void) { - printf(" - /proc/mm..."); - if (os_access("/proc/mm", OS_ACC_W_OK) < 0) { - proc_mm = 0; - printf("not found\n"); - } + non_fatal(" - /proc/mm..."); + if (access("/proc/mm", W_OK) < 0) + perror("not found"); + else if (disable_proc_mm) + non_fatal("found but disabled on command line\n"); else { - if (!proc_mm) - printf("found but disabled on command line\n"); - else - printf("found\n"); + proc_mm = 1; + non_fatal("found\n"); } } -int can_do_skas(void) +void can_do_skas(void) { - printf("Checking for the skas3 patch in the host:\n"); + non_fatal("Checking for the skas3 patch in the host:\n"); check_skas3_proc_mm(); check_skas3_ptrace_faultinfo(); check_skas3_ptrace_ldt(); - if(!proc_mm || !ptrace_faultinfo || !ptrace_ldt) + if (!proc_mm || !ptrace_faultinfo || !ptrace_ldt) skas_needs_stub = 1; - - return 1; -} -#else -int can_do_skas(void) -{ - return(0); -} -#endif - -int have_devanon = 0; - -void check_devanon(void) -{ - int fd; - - printk("Checking for /dev/anon on the host..."); - fd = open("/dev/anon", O_RDWR); - if(fd < 0){ - printk("Not available (open failed with errno %d)\n", errno); - return; - } - - printk("OK\n"); - have_devanon = 1; } int __init parse_iomem(char *str, int *add) { struct iomem_region *new; - struct uml_stat buf; + struct stat64 buf; char *file, *driver; - int fd, err, size; + int fd, size; driver = str; file = strchr(str,','); - if(file == NULL){ - printf("parse_iomem : failed to parse iomem\n"); + if (file == NULL) { + fprintf(stderr, "parse_iomem : failed to parse iomem\n"); goto out; } *file = '\0'; file++; - fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0); - if(fd < 0){ - os_print_error(fd, "parse_iomem - Couldn't open io file"); + fd = open(file, O_RDWR, 0); + if (fd < 0) { + perror("parse_iomem - Couldn't open io file"); goto out; } - err = os_stat_fd(fd, &buf); - if(err < 0){ - os_print_error(err, "parse_iomem - cannot stat_fd file"); + if (fstat64(fd, &buf) < 0) { + perror("parse_iomem - cannot stat_fd file"); goto out_close; } new = malloc(sizeof(*new)); - if(new == NULL){ + if (new == NULL) { perror("Couldn't allocate iomem_region struct"); goto out_close; } - size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); + size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); *new = ((struct iomem_region) { .next = iomem_regions, .driver = driver, @@ -531,10 +534,9 @@ int __init parse_iomem(char *str, int *add) iomem_regions = new; iomem_size += new->size + UM_KERN_PAGE_SIZE; - return(0); + return 0; out_close: - os_close_file(fd); + close(fd); out: - return(1); + return 1; } - diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile deleted file mode 100644 index 340ef26f594..00000000000 --- a/arch/um/os-Linux/sys-i386/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) -# Licensed under the GPL -# - -obj-$(CONFIG_MODE_SKAS) = registers.o - -USER_OBJS := $(obj-y) - -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 deleted file mode 100644 index aee4812333c..00000000000 --- a/arch/um/os-Linux/sys-i386/registers.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2004 PathScale, Inc - * Licensed under the GPL - */ - -#include <errno.h> -#include <string.h> -#include <setjmp.h> -#include "sysdep/ptrace_user.h" -#include "sysdep/ptrace.h" -#include "uml-config.h" -#include "skas_ptregs.h" -#include "registers.h" -#include "user.h" - -/* These are set once at boot time and not changed thereafter */ - -static unsigned long exec_regs[HOST_FRAME_SIZE]; -static unsigned long exec_fp_regs[HOST_FP_SIZE]; -static unsigned long exec_fpx_regs[HOST_XFP_SIZE]; -static int have_fpx_regs = 1; - -void init_thread_registers(union uml_pt_regs *to) -{ - memcpy(to->skas.regs, exec_regs, sizeof(to->skas.regs)); - memcpy(to->skas.fp, exec_fp_regs, sizeof(to->skas.fp)); - if(have_fpx_regs) - memcpy(to->skas.xfp, exec_fpx_regs, sizeof(to->skas.xfp)); -} - -/* XXX These need to use [GS]ETFPXREGS and copy_sc_{to,from}_user_skas needs - * to pass in a sufficiently large buffer - */ -int save_fp_registers(int pid, unsigned long *fp_regs) -{ - if(ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) - return(-errno); - return(0); -} - -int restore_fp_registers(int pid, unsigned long *fp_regs) -{ - if(ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) - return(-errno); - return(0); -} - -static int move_registers(int pid, int int_op, union uml_pt_regs *regs, - int fp_op, unsigned long *fp_regs) -{ - if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) - return(-errno); - - if(ptrace(fp_op, pid, 0, fp_regs) < 0) - return(-errno); - - return(0); -} - -void save_registers(int pid, union uml_pt_regs *regs) -{ - unsigned long *fp_regs; - int err, fp_op; - - if(have_fpx_regs){ - fp_op = PTRACE_GETFPXREGS; - fp_regs = regs->skas.xfp; - } - else { - fp_op = PTRACE_GETFPREGS; - fp_regs = regs->skas.fp; - } - - err = move_registers(pid, PTRACE_GETREGS, regs, fp_op, fp_regs); - if(err) - panic("save_registers - saving registers failed, errno = %d\n", - -err); -} - -void restore_registers(int pid, union uml_pt_regs *regs) -{ - unsigned long *fp_regs; - int err, fp_op; - - if(have_fpx_regs){ - fp_op = PTRACE_SETFPXREGS; - fp_regs = regs->skas.xfp; - } - else { - fp_op = PTRACE_SETFPREGS; - fp_regs = regs->skas.fp; - } - - err = move_registers(pid, PTRACE_SETREGS, regs, fp_op, fp_regs); - if(err) - panic("restore_registers - saving registers failed, " - "errno = %d\n", -err); -} - -void init_registers(int pid) -{ - int err; - - err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs); - if(err) - panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", - err); - - errno = 0; - err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs); - if(!err) - return; - if(errno != EIO) - panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", - errno); - - have_fpx_regs = 0; - - err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs); - if(err) - panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d", - err); -} - -void get_safe_registers(unsigned long *regs) -{ - memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long)); -} - -void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer) -{ - struct __jmp_buf_tag *jmpbuf = buffer; - - UPT_SET(uml_regs, EIP, jmpbuf->__jmpbuf[JB_PC]); - UPT_SET(uml_regs, UESP, jmpbuf->__jmpbuf[JB_SP]); - UPT_SET(uml_regs, EBP, jmpbuf->__jmpbuf[JB_BP]); -} diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile deleted file mode 100644 index 340ef26f594..00000000000 --- a/arch/um/os-Linux/sys-x86_64/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) -# Licensed under the GPL -# - -obj-$(CONFIG_MODE_SKAS) = registers.o - -USER_OBJS := $(obj-y) - -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 deleted file mode 100644 index 4b638dfb52b..00000000000 --- a/arch/um/os-Linux/sys-x86_64/registers.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2004 PathScale, Inc - * Licensed under the GPL - */ - -#include <errno.h> -#include <string.h> -#include <setjmp.h> -#include "ptrace_user.h" -#include "uml-config.h" -#include "skas_ptregs.h" -#include "registers.h" -#include "user.h" - -/* These are set once at boot time and not changed thereafter */ - -static unsigned long exec_regs[HOST_FRAME_SIZE]; -static unsigned long exec_fp_regs[HOST_FP_SIZE]; - -void init_thread_registers(union uml_pt_regs *to) -{ - memcpy(to->skas.regs, exec_regs, sizeof(to->skas.regs)); - memcpy(to->skas.fp, exec_fp_regs, sizeof(to->skas.fp)); -} - -static int move_registers(int pid, int int_op, int fp_op, - union uml_pt_regs *regs) -{ - if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) - return(-errno); - - if(ptrace(fp_op, pid, 0, regs->skas.fp) < 0) - return(-errno); - - return(0); -} - -void save_registers(int pid, union uml_pt_regs *regs) -{ - int err; - - err = move_registers(pid, PTRACE_GETREGS, PTRACE_GETFPREGS, regs); - if(err) - panic("save_registers - saving registers failed, errno = %d\n", - -err); -} - -void restore_registers(int pid, union uml_pt_regs *regs) -{ - int err; - - err = move_registers(pid, PTRACE_SETREGS, PTRACE_SETFPREGS, regs); - if(err) - panic("restore_registers - saving registers failed, " - "errno = %d\n", -err); -} - -void init_registers(int pid) -{ - int err; - - err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs); - if(err) - panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", - err); - - err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs); - if(err) - panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d", - err); -} - -void get_safe_registers(unsigned long *regs) -{ - memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long)); -} - -void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer) -{ - struct __jmp_buf_tag *jmpbuf = buffer; - - UPT_SET(uml_regs, RIP, jmpbuf->__jmpbuf[JB_PC]); - UPT_SET(uml_regs, RSP, jmpbuf->__jmpbuf[JB_RSP]); - UPT_SET(uml_regs, RBP, jmpbuf->__jmpbuf[JB_RBP]); -} diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index cf30a39bc48..e9824d5dd7d 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -1,21 +1,186 @@ -#include <stdlib.h> +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <stddef.h> +#include <errno.h> +#include <signal.h> +#include <time.h> #include <sys/time.h> +#include <kern_util.h> +#include <os.h> +#include "internal.h" + +int set_interval(void) +{ + int usec = UM_USEC_PER_SEC / UM_HZ; + struct itimerval interval = ((struct itimerval) { { 0, usec }, + { 0, usec } }); + + if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) + return -errno; + + return 0; +} + +int timer_one_shot(int ticks) +{ + unsigned long usec = ticks * UM_USEC_PER_SEC / UM_HZ; + unsigned long sec = usec / UM_USEC_PER_SEC; + struct itimerval interval; + + usec %= UM_USEC_PER_SEC; + interval = ((struct itimerval) { { 0, 0 }, { sec, usec } }); + + if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) + return -errno; + + return 0; +} + +/** + * timeval_to_ns - Convert timeval to nanoseconds + * @ts: pointer to the timeval variable to be converted + * + * Returns the scalar nanosecond representation of the timeval + * parameter. + * + * Ripped from linux/time.h because it's a kernel header, and thus + * unusable from here. + */ +static inline long long timeval_to_ns(const struct timeval *tv) +{ + return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) + + tv->tv_usec * UM_NSEC_PER_USEC; +} + +long long disable_timer(void) +{ + struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } }); + long long remain, max = UM_NSEC_PER_SEC / UM_HZ; + + if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0) + printk(UM_KERN_ERR "disable_timer - setitimer failed, " + "errno = %d\n", errno); + + remain = timeval_to_ns(&time.it_value); + if (remain > max) + remain = max; + + return remain; +} -unsigned long long os_usecs(void) +long long os_nsecs(void) { struct timeval tv; gettimeofday(&tv, NULL); - return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec); + return timeval_to_ns(&tv); } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +#ifdef UML_CONFIG_NO_HZ_COMMON +static int after_sleep_interval(struct timespec *ts) +{ + return 0; +} + +static void deliver_alarm(void) +{ + alarm_handler(SIGVTALRM, NULL, NULL); +} + +static unsigned long long sleep_time(unsigned long long nsecs) +{ + return nsecs; +} + +#else +unsigned long long last_tick; +unsigned long long skew; + +static void deliver_alarm(void) +{ + unsigned long long this_tick = os_nsecs(); + int one_tick = UM_NSEC_PER_SEC / UM_HZ; + + /* Protection against the host's time going backwards */ + if ((last_tick != 0) && (this_tick < last_tick)) + this_tick = last_tick; + + if (last_tick == 0) + last_tick = this_tick - one_tick; + + skew += this_tick - last_tick; + + while (skew >= one_tick) { + alarm_handler(SIGVTALRM, NULL, NULL); + skew -= one_tick; + } + + last_tick = this_tick; +} + +static unsigned long long sleep_time(unsigned long long nsecs) +{ + return nsecs > skew ? nsecs - skew : 0; +} + +static inline long long timespec_to_us(const struct timespec *ts) +{ + return ((long long) ts->tv_sec * UM_USEC_PER_SEC) + + ts->tv_nsec / UM_NSEC_PER_USEC; +} + +static int after_sleep_interval(struct timespec *ts) +{ + int usec = UM_USEC_PER_SEC / UM_HZ; + long long start_usecs = timespec_to_us(ts); + struct timeval tv; + struct itimerval interval; + + /* + * It seems that rounding can increase the value returned from + * setitimer to larger than the one passed in. Over time, + * this will cause the remaining time to be greater than the + * tick interval. If this happens, then just reduce the first + * tick to the interval value. + */ + if (start_usecs > usec) + start_usecs = usec; + + start_usecs -= skew / UM_NSEC_PER_USEC; + if (start_usecs < 0) + start_usecs = 0; + + tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC, + .tv_usec = start_usecs % UM_USEC_PER_SEC }); + interval = ((struct itimerval) { { 0, usec }, tv }); + + if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) + return -errno; + + return 0; +} +#endif + +void idle_sleep(unsigned long long nsecs) +{ + struct timespec ts; + + /* + * nsecs can come in as zero, in which case, this starts a + * busy loop. To prevent this, reset nsecs to the tick + * interval if it is zero. + */ + if (nsecs == 0) + nsecs = UM_NSEC_PER_SEC / UM_HZ; + + nsecs = sleep_time(nsecs); + ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC, + .tv_nsec = nsecs % UM_NSEC_PER_SEC }); + + if (nanosleep(&ts, &ts) == 0) + deliver_alarm(); + after_sleep_interval(&ts); +} diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c deleted file mode 100644 index a6db8877931..00000000000 --- a/arch/um/os-Linux/tt.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdio.h> -#include <unistd.h> -#include <signal.h> -#include <sched.h> -#include <errno.h> -#include <stdarg.h> -#include <stdlib.h> -#include <setjmp.h> -#include <sys/time.h> -#include <sys/ptrace.h> -#include <linux/ptrace.h> -#include <sys/wait.h> -#include <sys/mman.h> -#include <asm/ptrace.h> -#include <asm/unistd.h> -#include <asm/page.h> -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "signal_kern.h" -#include "signal_user.h" -#include "sysdep/ptrace.h" -#include "sysdep/sigcontext.h" -#include "irq_user.h" -#include "ptrace_user.h" -#include "time_user.h" -#include "init.h" -#include "os.h" -#include "uml-config.h" -#include "choose-mode.h" -#include "mode.h" -#include "tempfile.h" - -int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, - int must_succeed) -{ - int err; - - err = os_protect_memory((void *) addr, len, r, w, x); - if(err < 0){ - if(must_succeed) - panic("protect failed, err = %d", -err); - else return(err); - } - return(0); -} - -/* - *------------------------- - * only for tt mode (will be deleted in future...) - *------------------------- - */ - -struct tramp { - int (*tramp)(void *); - void *tramp_data; - unsigned long temp_stack; - int flags; - int pid; -}; - -/* See above for why sigkill is here */ - -int sigkill = SIGKILL; - -int outer_tramp(void *arg) -{ - struct tramp *t; - int sig = sigkill; - - t = arg; - t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2, - t->flags, t->tramp_data); - if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL); - kill(os_getpid(), sig); - _exit(0); -} - -int start_fork_tramp(void *thread_arg, unsigned long temp_stack, - int clone_flags, int (*tramp)(void *)) -{ - struct tramp arg; - unsigned long sp; - int new_pid, status, err; - - /* The trampoline will run on the temporary stack */ - sp = stack_sp(temp_stack); - - clone_flags |= CLONE_FILES | SIGCHLD; - - arg.tramp = tramp; - arg.tramp_data = thread_arg; - arg.temp_stack = temp_stack; - arg.flags = clone_flags; - - /* Start the process and wait for it to kill itself */ - new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg); - if(new_pid < 0) - return(new_pid); - - CATCH_EINTR(err = waitpid(new_pid, &status, 0)); - if(err < 0) - panic("Waiting for outer trampoline failed - errno = %d", - errno); - - if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) - panic("outer trampoline didn't exit with SIGKILL, " - "status = %d", status); - - return(arg.pid); -} - -void forward_pending_sigio(int target) -{ - sigset_t sigs; - - if(sigpending(&sigs)) - panic("forward_pending_sigio : sigpending failed"); - if(sigismember(&sigs, SIGIO)) - kill(target, SIGIO); -} - diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c index 4cfdd18ea1e..721d8afa329 100644 --- a/arch/um/os-Linux/tty.c +++ b/arch/um/os-Linux/tty.c @@ -1,13 +1,14 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #include <stdlib.h> +#include <unistd.h> #include <errno.h> -#include "os.h" -#include "user.h" -#include "kern_util.h" +#include <fcntl.h> +#include <kern_util.h> +#include <os.h> struct grantpt_info { int fd; @@ -26,36 +27,34 @@ static void grantpt_cb(void *arg) int get_pty(void) { struct grantpt_info info; - int fd; - - fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0); - if(fd < 0){ - printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd); - return(fd); + int fd, err; + + fd = open("/dev/ptmx", O_RDWR); + if (fd < 0) { + err = -errno; + printk(UM_KERN_ERR "get_pty : Couldn't open /dev/ptmx - " + "err = %d\n", errno); + return err; } info.fd = fd; initial_thread_cb(grantpt_cb, &info); - if(info.res < 0){ - printk("get_pty : Couldn't grant pty - errno = %d\n", - -info.err); - return(-1); + if (info.res < 0) { + err = -info.err; + printk(UM_KERN_ERR "get_pty : Couldn't grant pty - " + "errno = %d\n", -info.err); + goto out; } - if(unlockpt(fd) < 0){ - printk("get_pty : Couldn't unlock pty - errno = %d\n", errno); - return(-1); + + if (unlockpt(fd) < 0) { + err = -errno; + printk(UM_KERN_ERR "get_pty : Couldn't unlock pty - " + "errno = %d\n", errno); + goto out; } - return(fd); + return fd; +out: + close(fd); + return err; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/uaccess.c b/arch/um/os-Linux/uaccess.c deleted file mode 100644 index 38d710158c3..00000000000 --- a/arch/um/os-Linux/uaccess.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <setjmp.h> -#include <string.h> - -unsigned long __do_user_copy(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher, - void (*op)(void *to, const void *from, - int n), int *faulted_out) -{ - unsigned long *faddrp = (unsigned long *) fault_addr, ret; - - sigjmp_buf jbuf; - *fault_catcher = &jbuf; - if(sigsetjmp(jbuf, 1) == 0){ - (*op)(to, from, n); - ret = 0; - *faulted_out = 0; - } - else { - ret = *faddrp; - *faulted_out = 1; - } - *fault_addr = NULL; - *fault_catcher = NULL; - return ret; -} - diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c new file mode 100644 index 00000000000..c1dc89261f6 --- /dev/null +++ b/arch/um/os-Linux/umid.c @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <init.h> +#include <os.h> + +#define UML_DIR "~/.uml/" + +#define UMID_LEN 64 + +/* Changed by set_umid, which is run early in boot */ +static char umid[UMID_LEN] = { 0 }; + +/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */ +static char *uml_dir = UML_DIR; + +static int __init make_uml_dir(void) +{ + char dir[512] = { '\0' }; + int len, err; + + if (*uml_dir == '~') { + char *home = getenv("HOME"); + + err = -ENOENT; + if (home == NULL) { + printk(UM_KERN_ERR "make_uml_dir : no value in " + "environment for $HOME\n"); + goto err; + } + strlcpy(dir, home, sizeof(dir)); + uml_dir++; + } + strlcat(dir, uml_dir, sizeof(dir)); + len = strlen(dir); + if (len > 0 && dir[len - 1] != '/') + strlcat(dir, "/", sizeof(dir)); + + err = -ENOMEM; + uml_dir = malloc(strlen(dir) + 1); + if (uml_dir == NULL) { + printf("make_uml_dir : malloc failed, errno = %d\n", errno); + goto err; + } + strcpy(uml_dir, dir); + + if ((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)) { + printf("Failed to mkdir '%s': %s\n", uml_dir, strerror(errno)); + err = -errno; + goto err_free; + } + return 0; + +err_free: + free(uml_dir); +err: + uml_dir = NULL; + return err; +} + +/* + * Unlinks the files contained in @dir and then removes @dir. + * Doesn't handle directory trees, so it's not like rm -rf, but almost such. We + * ignore ENOENT errors for anything (they happen, strangely enough - possibly + * due to races between multiple dying UML threads). + */ +static int remove_files_and_dir(char *dir) +{ + DIR *directory; + struct dirent *ent; + int len; + char file[256]; + int ret; + + directory = opendir(dir); + if (directory == NULL) { + if (errno != ENOENT) + return -errno; + else + return 0; + } + + while ((ent = readdir(directory)) != NULL) { + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + continue; + len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1; + if (len > sizeof(file)) { + ret = -E2BIG; + goto out; + } + + sprintf(file, "%s/%s", dir, ent->d_name); + if (unlink(file) < 0 && errno != ENOENT) { + ret = -errno; + goto out; + } + } + + if (rmdir(dir) < 0 && errno != ENOENT) { + ret = -errno; + goto out; + } + + ret = 0; +out: + closedir(directory); + return ret; +} + +/* + * This says that there isn't already a user of the specified directory even if + * there are errors during the checking. This is because if these errors + * happen, the directory is unusable by the pre-existing UML, so we might as + * well take it over. This could happen either by + * the existing UML somehow corrupting its umid directory + * something other than UML sticking stuff in the directory + * this boot racing with a shutdown of the other UML + * In any of these cases, the directory isn't useful for anything else. + * + * Boolean return: 1 if in use, 0 otherwise. + */ +static inline int is_umdir_used(char *dir) +{ + char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; + char pid[sizeof("nnnnn\0")], *end; + int dead, fd, p, n, err; + + n = snprintf(file, sizeof(file), "%s/pid", dir); + if (n >= sizeof(file)) { + printk(UM_KERN_ERR "is_umdir_used - pid filename too long\n"); + err = -E2BIG; + goto out; + } + + dead = 0; + fd = open(file, O_RDONLY); + if (fd < 0) { + fd = -errno; + if (fd != -ENOENT) { + printk(UM_KERN_ERR "is_umdir_used : couldn't open pid " + "file '%s', err = %d\n", file, -fd); + } + goto out; + } + + err = 0; + n = read(fd, pid, sizeof(pid)); + if (n < 0) { + printk(UM_KERN_ERR "is_umdir_used : couldn't read pid file " + "'%s', err = %d\n", file, errno); + goto out_close; + } else if (n == 0) { + printk(UM_KERN_ERR "is_umdir_used : couldn't read pid file " + "'%s', 0-byte read\n", file); + goto out_close; + } + + p = strtoul(pid, &end, 0); + if (end == pid) { + printk(UM_KERN_ERR "is_umdir_used : couldn't parse pid file " + "'%s', errno = %d\n", file, errno); + goto out_close; + } + + if ((kill(p, 0) == 0) || (errno != ESRCH)) { + printk(UM_KERN_ERR "umid \"%s\" is already in use by pid %d\n", + umid, p); + return 1; + } + +out_close: + close(fd); +out: + return 0; +} + +/* + * Try to remove the directory @dir unless it's in use. + * Precondition: @dir exists. + * Returns 0 for success, < 0 for failure in removal or if the directory is in + * use. + */ +static int umdir_take_if_dead(char *dir) +{ + int ret; + if (is_umdir_used(dir)) + return -EEXIST; + + ret = remove_files_and_dir(dir); + if (ret) { + printk(UM_KERN_ERR "is_umdir_used - remove_files_and_dir " + "failed with err = %d\n", ret); + } + return ret; +} + +static void __init create_pid_file(void) +{ + char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; + char pid[sizeof("nnnnn\0")]; + int fd, n; + + if (umid_file_name("pid", file, sizeof(file))) + return; + + fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0644); + if (fd < 0) { + printk(UM_KERN_ERR "Open of machine pid file \"%s\" failed: " + "%s\n", file, strerror(errno)); + return; + } + + snprintf(pid, sizeof(pid), "%d\n", getpid()); + n = write(fd, pid, strlen(pid)); + if (n != strlen(pid)) + printk(UM_KERN_ERR "Write of pid file failed - err = %d\n", + errno); + + close(fd); +} + +int __init set_umid(char *name) +{ + if (strlen(name) > UMID_LEN - 1) + return -E2BIG; + + strlcpy(umid, name, sizeof(umid)); + + return 0; +} + +/* Changed in make_umid, which is called during early boot */ +static int umid_setup = 0; + +static int __init make_umid(void) +{ + int fd, err; + char tmp[256]; + + if (umid_setup) + return 0; + + make_uml_dir(); + + if (*umid == '\0') { + strlcpy(tmp, uml_dir, sizeof(tmp)); + strlcat(tmp, "XXXXXX", sizeof(tmp)); + fd = mkstemp(tmp); + if (fd < 0) { + printk(UM_KERN_ERR "make_umid - mkstemp(%s) failed: " + "%s\n", tmp, strerror(errno)); + err = -errno; + goto err; + } + + close(fd); + + set_umid(&tmp[strlen(uml_dir)]); + + /* + * There's a nice tiny little race between this unlink and + * the mkdir below. It'd be nice if there were a mkstemp + * for directories. + */ + if (unlink(tmp)) { + err = -errno; + goto err; + } + } + + snprintf(tmp, sizeof(tmp), "%s%s", uml_dir, umid); + err = mkdir(tmp, 0777); + if (err < 0) { + err = -errno; + if (err != -EEXIST) + goto err; + + if (umdir_take_if_dead(tmp) < 0) + goto err; + + err = mkdir(tmp, 0777); + } + if (err) { + err = -errno; + printk(UM_KERN_ERR "Failed to create '%s' - err = %d\n", umid, + errno); + goto err; + } + + umid_setup = 1; + + create_pid_file(); + + err = 0; + err: + return err; +} + +static int __init make_umid_init(void) +{ + if (!make_umid()) + return 0; + + /* + * If initializing with the given umid failed, then try again with + * a random one. + */ + printk(UM_KERN_ERR "Failed to initialize umid \"%s\", trying with a " + "random umid\n", umid); + *umid = '\0'; + make_umid(); + + return 0; +} + +__initcall(make_umid_init); + +int __init umid_file_name(char *name, char *buf, int len) +{ + int n, err; + + err = make_umid(); + if (err) + return err; + + n = snprintf(buf, len, "%s%s/%s", uml_dir, umid, name); + if (n >= len) { + printk(UM_KERN_ERR "umid_file_name : buffer too short\n"); + return -E2BIG; + } + + return 0; +} + +char *get_umid(void) +{ + return umid; +} + +static int __init set_uml_dir(char *name, int *add) +{ + if (*name == '\0') { + printf("uml_dir can't be an empty string\n"); + return 0; + } + + if (name[strlen(name) - 1] == '/') { + uml_dir = name; + return 0; + } + + uml_dir = malloc(strlen(name) + 2); + if (uml_dir == NULL) { + printf("Failed to malloc uml_dir - error = %d\n", errno); + + /* + * Return 0 here because do_initcalls doesn't look at + * the return value. + */ + return 0; + } + sprintf(uml_dir, "%s/", name); + + return 0; +} + +__uml_setup("uml_dir=", set_uml_dir, +"uml_dir=<directory>\n" +" The location to place the pid and umid files.\n\n" +); + +static void remove_umid_dir(void) +{ + char dir[strlen(uml_dir) + UMID_LEN + 1], err; + + sprintf(dir, "%s%s", uml_dir, umid); + err = remove_files_and_dir(dir); + if (err) + printf("remove_umid_dir - remove_files_and_dir failed with " + "err = %d\n", err); +} + +__uml_exitcall(remove_umid_dir); diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index 56d3f870926..db4a034aeee 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c @@ -1,11 +1,12 @@ -#include "linux/types.h" -#include "linux/module.h" +#include <linux/types.h> +#include <linux/module.h> /* Some of this are builtin function (some are not but could in the future), * so I *must* declare good prototypes for them and then EXPORT them. * The kernel code uses the macro defined by include/linux/string.h, * so I undef macros; the userspace code does not include that and I - * add an EXPORT for the glibc one.*/ + * add an EXPORT for the glibc one. + */ #undef strlen #undef strstr @@ -13,28 +14,38 @@ #undef memset extern size_t strlen(const char *); -extern void *memcpy(void *, const void *, size_t); extern void *memmove(void *, const void *, size_t); extern void *memset(void *, int, size_t); extern int printf(const char *, ...); -EXPORT_SYMBOL(strlen); +/* If it's not defined, the export is included in lib/string.c.*/ +#ifdef __HAVE_ARCH_STRSTR +EXPORT_SYMBOL(strstr); +#endif + +#ifndef __x86_64__ +extern void *memcpy(void *, const void *, size_t); EXPORT_SYMBOL(memcpy); +#endif + EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(printf); -EXPORT_SYMBOL(strstr); - /* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. * However, the modules will use the CRC defined *here*, no matter if it is * good; so the versions of these symbols will always match */ #define EXPORT_SYMBOL_PROTO(sym) \ - int sym(void); \ - EXPORT_SYMBOL(sym); + int sym(void); \ + EXPORT_SYMBOL(sym); -#ifdef SUBARCH_i386 +extern void readdir64(void) __attribute__((weak)); +EXPORT_SYMBOL(readdir64); +extern void truncate64(void) __attribute__((weak)); +EXPORT_SYMBOL(truncate64); + +#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA EXPORT_SYMBOL(vsyscall_ehdr); EXPORT_SYMBOL(vsyscall_end); #endif @@ -51,12 +62,18 @@ EXPORT_SYMBOL_PROTO(dup2); EXPORT_SYMBOL_PROTO(__xstat); EXPORT_SYMBOL_PROTO(__lxstat); EXPORT_SYMBOL_PROTO(__lxstat64); +EXPORT_SYMBOL_PROTO(__fxstat64); EXPORT_SYMBOL_PROTO(lseek); EXPORT_SYMBOL_PROTO(lseek64); EXPORT_SYMBOL_PROTO(chown); +EXPORT_SYMBOL_PROTO(fchown); EXPORT_SYMBOL_PROTO(truncate); +EXPORT_SYMBOL_PROTO(ftruncate64); EXPORT_SYMBOL_PROTO(utime); +EXPORT_SYMBOL_PROTO(utimes); +EXPORT_SYMBOL_PROTO(futimes); EXPORT_SYMBOL_PROTO(chmod); +EXPORT_SYMBOL_PROTO(fchmod); EXPORT_SYMBOL_PROTO(rename); EXPORT_SYMBOL_PROTO(__xmknod); @@ -86,13 +103,18 @@ EXPORT_SYMBOL_PROTO(getuid); EXPORT_SYMBOL_PROTO(fsync); EXPORT_SYMBOL_PROTO(fdatasync); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +EXPORT_SYMBOL_PROTO(lstat64); +EXPORT_SYMBOL_PROTO(fstat64); +EXPORT_SYMBOL_PROTO(mknod); + +/* Export symbols used by GCC for the stack protector. */ +extern void __stack_smash_handler(void *) __attribute__((weak)); +EXPORT_SYMBOL(__stack_smash_handler); + +extern long __guard __attribute__((weak)); +EXPORT_SYMBOL(__guard); + +#ifdef _FORTIFY_SOURCE +extern int __sprintf_chk(char *str, int flag, size_t strlen, const char *format); +EXPORT_SYMBOL(__sprintf_chk); +#endif diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c new file mode 100644 index 00000000000..faee55ef6d2 --- /dev/null +++ b/arch/um/os-Linux/util.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <termios.h> +#include <wait.h> +#include <sys/mman.h> +#include <sys/utsname.h> +#include <os.h> + +void stack_protections(unsigned long address) +{ + if (mprotect((void *) address, UM_THREAD_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC) < 0) + panic("protecting stack failed, errno = %d", errno); +} + +int raw(int fd) +{ + struct termios tt; + int err; + + CATCH_EINTR(err = tcgetattr(fd, &tt)); + if (err < 0) + return -errno; + + cfmakeraw(&tt); + + CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); + if (err < 0) + return -errno; + + /* + * XXX tcsetattr could have applied only some changes + * (and cfmakeraw() is a set of changes) + */ + return 0; +} + +void setup_machinename(char *machine_out) +{ + struct utsname host; + + uname(&host); +#ifdef UML_CONFIG_UML_X86 +# ifndef UML_CONFIG_64BIT + if (!strcmp(host.machine, "x86_64")) { + strcpy(machine_out, "i686"); + return; + } +# else + if (!strcmp(host.machine, "i686")) { + strcpy(machine_out, "x86_64"); + return; + } +# endif +#endif + strcpy(machine_out, host.machine); +} + +void setup_hostinfo(char *buf, int len) +{ + struct utsname host; + + uname(&host); + snprintf(buf, len, "%s %s %s %s %s", host.sysname, host.nodename, + host.release, host.version, host.machine); +} + +/* + * We cannot use glibc's abort(). It makes use of tgkill() which + * has no effect within UML's kernel threads. + * After that glibc would execute an invalid instruction to kill + * the calling process and UML crashes with SIGSEGV. + */ +static inline void __attribute__ ((noreturn)) uml_abort(void) +{ + sigset_t sig; + + fflush(NULL); + + if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT)) + sigprocmask(SIG_UNBLOCK, &sig, 0); + + for (;;) + if (kill(getpid(), SIGABRT) < 0) + exit(127); +} + +/* + * UML helper threads must not handle SIGWINCH/INT/TERM + */ +void os_fix_helper_signals(void) +{ + signal(SIGWINCH, SIG_IGN); + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); +} + +void os_dump_core(void) +{ + int pid; + + signal(SIGSEGV, SIG_DFL); + + /* + * We are about to SIGTERM this entire process group to ensure that + * nothing is around to run after the kernel exits. The + * kernel wants to abort, not die through SIGTERM, so we + * ignore it here. + */ + + signal(SIGTERM, SIG_IGN); + kill(0, SIGTERM); + /* + * Most of the other processes associated with this UML are + * likely sTopped, so give them a SIGCONT so they see the + * SIGTERM. + */ + kill(0, SIGCONT); + + /* + * Now, having sent signals to everyone but us, make sure they + * die by ptrace. Processes can survive what's been done to + * them so far - the mechanism I understand is receiving a + * SIGSEGV and segfaulting immediately upon return. There is + * always a SIGSEGV pending, and (I'm guessing) signals are + * processed in numeric order so the SIGTERM (signal 15 vs + * SIGSEGV being signal 11) is never handled. + * + * Run a waitpid loop until we get some kind of error. + * Hopefully, it's ECHILD, but there's not a lot we can do if + * it's something else. Tell os_kill_ptraced_process not to + * wait for the child to report its death because there's + * nothing reasonable to do if that fails. + */ + + while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0) + os_kill_ptraced_process(pid, 0); + + uml_abort(); +} + +void um_early_printk(const char *s, unsigned int n) +{ + printf("%.*s", n, s); +} diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index b3fbf125709..15889df9b46 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -7,43 +7,20 @@ USER_SINGLE_OBJS := \ USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -$(USER_OBJS) $(USER_OBJS:.o=.i) $(USER_OBJS:.o=.s) $(USER_OBJS:.o=.lst): \ - c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(notdir $@)) -$(USER_OBJS): cmd_checksrc = -$(USER_OBJS): quiet_cmd_checksrc = -$(USER_OBJS): cmd_force_checksrc = -$(USER_OBJS): quiet_cmd_force_checksrc = +$(USER_OBJS:.o=.%): \ + c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include $(srctree)/include/linux/kern_levels.h -include user.h $(CFLAGS_$(basetarget).o) +# These are like USER_OBJS but filter USER_CFLAGS through unprofile instead of +# using it directly. +UNPROFILE_OBJS := $(foreach file,$(UNPROFILE_OBJS),$(obj)/$(file)) -# The stubs and unmap.o can't try to call mcount or update basic block data -define unprofile - $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) -endef +$(UNPROFILE_OBJS:.o=.%): \ + c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) $(CFLAGS_$(basetarget).o) +$(USER_OBJS) $(UNPROFILE_OBJS): \ + CHECKFLAGS := $(patsubst $(NOSTDINC_FLAGS),,$(CHECKFLAGS)) -# The stubs and unmap.o can't try to call mcount or update basic block data +# The stubs can't try to call mcount or update basic block data define unprofile $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) endef - -# cmd_make_link checks to see if the $(foo-dir) variable starts with a /. If -# so, it's considered to be a path relative to $(srcdir) rather than -# $(srcdir)/arch/$(SUBARCH). This is because x86_64 wants to get ldt.c from -# arch/um/sys-i386 rather than arch/i386 like the other borrowed files. So, -# it sets $(ldt.c-dir) to /arch/um/sys-i386. -quiet_cmd_make_link = SYMLINK $@ -cmd_make_link = rm -f $@; ln -sf $(srctree)$(if $(filter-out /%,$($(notdir $@)-dir)),/arch/$(SUBARCH))/$($(notdir $@)-dir)/$(notdir $@) $@ - -# this needs to be before the foreach, because targets does not accept -# complete paths like $(obj)/$(f). To make sure this works, use a := assignment -# or we will get $(obj)/$(f) in the "targets" value. -# Also, this forces you to use the := syntax when assigning to targets. -# Otherwise the line below will cause an infinite loop (if you don't know why, -# just do it). - -targets := $(targets) $(SYMLINKS) - -SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$(f)) - -$(SYMLINKS): FORCE - $(call if_changed,make_link) diff --git a/arch/um/scripts/Makefile.unmap b/arch/um/scripts/Makefile.unmap deleted file mode 100644 index b2165188d94..00000000000 --- a/arch/um/scripts/Makefile.unmap +++ /dev/null @@ -1,22 +0,0 @@ -clean-files += unmap_tmp.o unmap_fin.o unmap.o - -ifdef CONFIG_MODE_TT - -#Always build unmap_fin.o -extra-y += unmap_fin.o -#Do dependency tracking for unmap.o (it will be always built, but won't get the tracking unless we use this). -targets += unmap.o - -#XXX: partially copied from arch/um/scripts/Makefile.rules -$(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS)) - -quiet_cmd_wrapld = LD $@ -define cmd_wrapld - $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< ; \ - $(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo -endef - -$(obj)/unmap_fin.o : $(obj)/unmap.o FORCE - $(call if_changed,wrapld) - -endif diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile deleted file mode 100644 index 6dfeb70f695..00000000000 --- a/arch/um/sys-i386/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ - ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \ - syscalls.o sysrq.o sys_call_table.o - -obj-$(CONFIG_HIGHMEM) += highmem.o -obj-$(CONFIG_MODULES) += module.o - -USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o - -SYMLINKS = bitops.c semaphore.c highmem.c module.c - -include arch/um/scripts/Makefile.rules - -bitops.c-dir = lib -semaphore.c-dir = kernel -highmem.c-dir = mm -module.c-dir = kernel - -$(obj)/stub_segv.o : _c_flags = $(call unprofile,$(CFLAGS)) - -include arch/um/scripts/Makefile.unmap diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c deleted file mode 100644 index 41b0ab2fe83..00000000000 --- a/arch/um/sys-i386/bugs.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <sys/signal.h> -#include <asm/ldt.h> -#include "kern_util.h" -#include "user.h" -#include "sysdep/ptrace.h" -#include "task.h" -#include "os.h" - -#define MAXTOKEN 64 - -/* Set during early boot */ -int host_has_cmov = 1; -int host_has_xmm = 0; - -static char token(int fd, char *buf, int len, char stop) -{ - int n; - char *ptr, *end, c; - - ptr = buf; - end = &buf[len]; - do { - n = os_read_file(fd, ptr, sizeof(*ptr)); - c = *ptr++; - if(n != sizeof(*ptr)){ - if(n == 0) return(0); - printk("Reading /proc/cpuinfo failed, err = %d\n", -n); - if(n < 0) - return(n); - else - return(-EIO); - } - } while((c != '\n') && (c != stop) && (ptr < end)); - - if(ptr == end){ - printk("Failed to find '%c' in /proc/cpuinfo\n", stop); - return(-1); - } - *(ptr - 1) = '\0'; - return(c); -} - -static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) -{ - int n; - char c; - - scratch[len - 1] = '\0'; - while(1){ - c = token(fd, scratch, len - 1, ':'); - if(c <= 0) - return(0); - else if(c != ':'){ - printk("Failed to find ':' in /proc/cpuinfo\n"); - return(0); - } - - if(!strncmp(scratch, key, strlen(key))) - return(1); - - do { - n = os_read_file(fd, &c, sizeof(c)); - if(n != sizeof(c)){ - printk("Failed to find newline in " - "/proc/cpuinfo, err = %d\n", -n); - return(0); - } - } while(c != '\n'); - } - return(0); -} - -int cpu_feature(char *what, char *buf, int len) -{ - int fd, ret = 0; - - fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); - return(0); - } - - if(!find_cpuinfo_line(fd, what, buf, len)){ - printk("Couldn't find '%s' line in /proc/cpuinfo\n", what); - goto out_close; - } - - token(fd, buf, len, '\n'); - ret = 1; - - out_close: - os_close_file(fd); - return(ret); -} - -static int check_cpu_flag(char *feature, int *have_it) -{ - char buf[MAXTOKEN], c; - int fd, len = sizeof(buf)/sizeof(buf[0]); - - printk("Checking for host processor %s support...", feature); - fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); - return(0); - } - - *have_it = 0; - if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0]))) - goto out; - - c = token(fd, buf, len - 1, ' '); - if(c < 0) goto out; - else if(c != ' '){ - printk("Failed to find ' ' in /proc/cpuinfo\n"); - goto out; - } - - while(1){ - c = token(fd, buf, len - 1, ' '); - if(c < 0) goto out; - else if(c == '\n') break; - - if(!strcmp(buf, feature)){ - *have_it = 1; - goto out; - } - } - out: - if(*have_it == 0) printk("No\n"); - else if(*have_it == 1) printk("Yes\n"); - os_close_file(fd); - return(1); -} - -#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems - * for some people. - */ -static void disable_lcall(void) -{ - struct modify_ldt_ldt_s ldt; - int err; - - bzero(&ldt, sizeof(ldt)); - ldt.entry_number = 7; - ldt.base_addr = 0; - ldt.limit = 0; - err = modify_ldt(1, &ldt, sizeof(ldt)); - if(err) - printk("Failed to disable lcall7 - errno = %d\n", errno); -} -#endif - -void arch_init_thread(void) -{ -#if 0 - disable_lcall(); -#endif -} - -void arch_check_bugs(void) -{ - int have_it; - - if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){ - printk("/proc/cpuinfo not available - skipping CPU capability " - "checks\n"); - return; - } - if(check_cpu_flag("cmov", &have_it)) - host_has_cmov = have_it; - if(check_cpu_flag("xmm", &have_it)) - host_has_xmm = have_it; -} - -int arch_handle_signal(int sig, union uml_pt_regs *regs) -{ - unsigned char tmp[2]; - - /* This is testing for a cmov (0x0f 0x4x) instruction causing a - * SIGILL in init. - */ - if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0); - - if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) - panic("SIGILL in init, could not read instructions!\n"); - if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40)) - return(0); - - if(host_has_cmov == 0) - panic("SIGILL caused by cmov, which this processor doesn't " - "implement, boot a filesystem compiled for older " - "processors"); - else if(host_has_cmov == 1) - panic("SIGILL caused by cmov, which this processor claims to " - "implement"); - else if(host_has_cmov == -1) - panic("SIGILL caused by cmov, couldn't tell if this processor " - "implements it, boot a filesystem compiled for older " - "processors"); - else panic("Bad value for host_has_cmov (%d)", host_has_cmov); - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-i386/checksum.S b/arch/um/sys-i386/checksum.S deleted file mode 100644 index d98b2fff3d0..00000000000 --- a/arch/um/sys-i386/checksum.S +++ /dev/null @@ -1,460 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * IP/TCP/UDP checksumming routines - * - * Authors: Jorge Cwik, <jorge@laser.satlink.net> - * Arnt Gulbrandsen, <agulbra@nvg.unit.no> - * Tom May, <ftom@netcom.com> - * Pentium Pro/II routines: - * Alexander Kjeldaas <astor@guardian.no> - * Finn Arne Gangstad <finnag@guardian.no> - * Lots of code moved from tcp.c and ip.c; see those files - * for more names. - * - * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception - * handling. - * Andi Kleen, add zeroing on error - * converted to pure assembler - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/config.h> -#include <asm/errno.h> - -/* - * computes a partial checksum, e.g. for TCP/UDP fragments - */ - -/* -unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) - */ - -.text -.align 4 -.globl csum_partial - -#ifndef CONFIG_X86_USE_PPRO_CHECKSUM - - /* - * Experiments with Ethernet and SLIP connections show that buff - * is aligned on either a 2-byte or 4-byte boundary. We get at - * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. - * Fortunately, it is easy to convert 2-byte alignment to 4-byte - * alignment for the unrolled loop. - */ -csum_partial: - pushl %esi - pushl %ebx - movl 20(%esp),%eax # Function arg: unsigned int sum - movl 16(%esp),%ecx # Function arg: int len - movl 12(%esp),%esi # Function arg: unsigned char *buff - testl $2, %esi # Check alignment. - jz 2f # Jump if alignment is ok. - subl $2, %ecx # Alignment uses up two bytes. - jae 1f # Jump if we had at least two bytes. - addl $2, %ecx # ecx was < 2. Deal with it. - jmp 4f -1: movw (%esi), %bx - addl $2, %esi - addw %bx, %ax - adcl $0, %eax -2: - movl %ecx, %edx - shrl $5, %ecx - jz 2f - testl %esi, %esi -1: movl (%esi), %ebx - adcl %ebx, %eax - movl 4(%esi), %ebx - adcl %ebx, %eax - movl 8(%esi), %ebx - adcl %ebx, %eax - movl 12(%esi), %ebx - adcl %ebx, %eax - movl 16(%esi), %ebx - adcl %ebx, %eax - movl 20(%esi), %ebx - adcl %ebx, %eax - movl 24(%esi), %ebx - adcl %ebx, %eax - movl 28(%esi), %ebx - adcl %ebx, %eax - lea 32(%esi), %esi - dec %ecx - jne 1b - adcl $0, %eax -2: movl %edx, %ecx - andl $0x1c, %edx - je 4f - shrl $2, %edx # This clears CF -3: adcl (%esi), %eax - lea 4(%esi), %esi - dec %edx - jne 3b - adcl $0, %eax -4: andl $3, %ecx - jz 7f - cmpl $2, %ecx - jb 5f - movw (%esi),%cx - leal 2(%esi),%esi - je 6f - shll $16,%ecx -5: movb (%esi),%cl -6: addl %ecx,%eax - adcl $0, %eax -7: - popl %ebx - popl %esi - ret - -#else - -/* Version for PentiumII/PPro */ - -csum_partial: - pushl %esi - pushl %ebx - movl 20(%esp),%eax # Function arg: unsigned int sum - movl 16(%esp),%ecx # Function arg: int len - movl 12(%esp),%esi # Function arg: const unsigned char *buf - - testl $2, %esi - jnz 30f -10: - movl %ecx, %edx - movl %ecx, %ebx - andl $0x7c, %ebx - shrl $7, %ecx - addl %ebx,%esi - shrl $2, %ebx - negl %ebx - lea 45f(%ebx,%ebx,2), %ebx - testl %esi, %esi - jmp *%ebx - - # Handle 2-byte-aligned regions -20: addw (%esi), %ax - lea 2(%esi), %esi - adcl $0, %eax - jmp 10b - -30: subl $2, %ecx - ja 20b - je 32f - movzbl (%esi),%ebx # csumming 1 byte, 2-aligned - addl %ebx, %eax - adcl $0, %eax - jmp 80f -32: - addw (%esi), %ax # csumming 2 bytes, 2-aligned - adcl $0, %eax - jmp 80f - -40: - addl -128(%esi), %eax - adcl -124(%esi), %eax - adcl -120(%esi), %eax - adcl -116(%esi), %eax - adcl -112(%esi), %eax - adcl -108(%esi), %eax - adcl -104(%esi), %eax - adcl -100(%esi), %eax - adcl -96(%esi), %eax - adcl -92(%esi), %eax - adcl -88(%esi), %eax - adcl -84(%esi), %eax - adcl -80(%esi), %eax - adcl -76(%esi), %eax - adcl -72(%esi), %eax - adcl -68(%esi), %eax - adcl -64(%esi), %eax - adcl -60(%esi), %eax - adcl -56(%esi), %eax - adcl -52(%esi), %eax - adcl -48(%esi), %eax - adcl -44(%esi), %eax - adcl -40(%esi), %eax - adcl -36(%esi), %eax - adcl -32(%esi), %eax - adcl -28(%esi), %eax - adcl -24(%esi), %eax - adcl -20(%esi), %eax - adcl -16(%esi), %eax - adcl -12(%esi), %eax - adcl -8(%esi), %eax - adcl -4(%esi), %eax -45: - lea 128(%esi), %esi - adcl $0, %eax - dec %ecx - jge 40b - movl %edx, %ecx -50: andl $3, %ecx - jz 80f - - # Handle the last 1-3 bytes without jumping - notl %ecx # 1->2, 2->1, 3->0, higher bits are masked - movl $0xffffff,%ebx # by the shll and shrl instructions - shll $3,%ecx - shrl %cl,%ebx - andl -128(%esi),%ebx # esi is 4-aligned so should be ok - addl %ebx,%eax - adcl $0,%eax -80: - popl %ebx - popl %esi - ret - -#endif - -/* -unsigned int csum_partial_copy_generic (const char *src, char *dst, - int len, int sum, int *src_err_ptr, int *dst_err_ptr) - */ - -/* - * Copy from ds while checksumming, otherwise like csum_partial - * - * The macros SRC and DST specify the type of access for the instruction. - * thus we can call a custom exception handler for all access types. - * - * FIXME: could someone double-check whether I haven't mixed up some SRC and - * DST definitions? It's damn hard to trigger all cases. I hope I got - * them all but there's no guarantee. - */ - -#define SRC(y...) \ - 9999: y; \ - .section __ex_table, "a"; \ - .long 9999b, 6001f ; \ - .previous - -#define DST(y...) \ - 9999: y; \ - .section __ex_table, "a"; \ - .long 9999b, 6002f ; \ - .previous - -.align 4 -.globl csum_partial_copy_generic_i386 - -#ifndef CONFIG_X86_USE_PPRO_CHECKSUM - -#define ARGBASE 16 -#define FP 12 - -csum_partial_copy_generic_i386: - subl $4,%esp - pushl %edi - pushl %esi - pushl %ebx - movl ARGBASE+16(%esp),%eax # sum - movl ARGBASE+12(%esp),%ecx # len - movl ARGBASE+4(%esp),%esi # src - movl ARGBASE+8(%esp),%edi # dst - - testl $2, %edi # Check alignment. - jz 2f # Jump if alignment is ok. - subl $2, %ecx # Alignment uses up two bytes. - jae 1f # Jump if we had at least two bytes. - addl $2, %ecx # ecx was < 2. Deal with it. - jmp 4f -SRC(1: movw (%esi), %bx ) - addl $2, %esi -DST( movw %bx, (%edi) ) - addl $2, %edi - addw %bx, %ax - adcl $0, %eax -2: - movl %ecx, FP(%esp) - shrl $5, %ecx - jz 2f - testl %esi, %esi -SRC(1: movl (%esi), %ebx ) -SRC( movl 4(%esi), %edx ) - adcl %ebx, %eax -DST( movl %ebx, (%edi) ) - adcl %edx, %eax -DST( movl %edx, 4(%edi) ) - -SRC( movl 8(%esi), %ebx ) -SRC( movl 12(%esi), %edx ) - adcl %ebx, %eax -DST( movl %ebx, 8(%edi) ) - adcl %edx, %eax -DST( movl %edx, 12(%edi) ) - -SRC( movl 16(%esi), %ebx ) -SRC( movl 20(%esi), %edx ) - adcl %ebx, %eax -DST( movl %ebx, 16(%edi) ) - adcl %edx, %eax -DST( movl %edx, 20(%edi) ) - -SRC( movl 24(%esi), %ebx ) -SRC( movl 28(%esi), %edx ) - adcl %ebx, %eax -DST( movl %ebx, 24(%edi) ) - adcl %edx, %eax -DST( movl %edx, 28(%edi) ) - - lea 32(%esi), %esi - lea 32(%edi), %edi - dec %ecx - jne 1b - adcl $0, %eax -2: movl FP(%esp), %edx - movl %edx, %ecx - andl $0x1c, %edx - je 4f - shrl $2, %edx # This clears CF -SRC(3: movl (%esi), %ebx ) - adcl %ebx, %eax -DST( movl %ebx, (%edi) ) - lea 4(%esi), %esi - lea 4(%edi), %edi - dec %edx - jne 3b - adcl $0, %eax -4: andl $3, %ecx - jz 7f - cmpl $2, %ecx - jb 5f -SRC( movw (%esi), %cx ) - leal 2(%esi), %esi -DST( movw %cx, (%edi) ) - leal 2(%edi), %edi - je 6f - shll $16,%ecx -SRC(5: movb (%esi), %cl ) -DST( movb %cl, (%edi) ) -6: addl %ecx, %eax - adcl $0, %eax -7: -5000: - -# Exception handler: -.section .fixup, "ax" - -6001: - movl ARGBASE+20(%esp), %ebx # src_err_ptr - movl $-EFAULT, (%ebx) - - # zero the complete destination - computing the rest - # is too much work - movl ARGBASE+8(%esp), %edi # dst - movl ARGBASE+12(%esp), %ecx # len - xorl %eax,%eax - rep ; stosb - - jmp 5000b - -6002: - movl ARGBASE+24(%esp), %ebx # dst_err_ptr - movl $-EFAULT,(%ebx) - jmp 5000b - -.previous - - popl %ebx - popl %esi - popl %edi - popl %ecx # equivalent to addl $4,%esp - ret - -#else - -/* Version for PentiumII/PPro */ - -#define ROUND1(x) \ - SRC(movl x(%esi), %ebx ) ; \ - addl %ebx, %eax ; \ - DST(movl %ebx, x(%edi) ) ; - -#define ROUND(x) \ - SRC(movl x(%esi), %ebx ) ; \ - adcl %ebx, %eax ; \ - DST(movl %ebx, x(%edi) ) ; - -#define ARGBASE 12 - -csum_partial_copy_generic_i386: - pushl %ebx - pushl %edi - pushl %esi - movl ARGBASE+4(%esp),%esi #src - movl ARGBASE+8(%esp),%edi #dst - movl ARGBASE+12(%esp),%ecx #len - movl ARGBASE+16(%esp),%eax #sum -# movl %ecx, %edx - movl %ecx, %ebx - movl %esi, %edx - shrl $6, %ecx - andl $0x3c, %ebx - negl %ebx - subl %ebx, %esi - subl %ebx, %edi - lea -1(%esi),%edx - andl $-32,%edx - lea 3f(%ebx,%ebx), %ebx - testl %esi, %esi - jmp *%ebx -1: addl $64,%esi - addl $64,%edi - SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl) - ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52) - ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36) - ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20) - ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4) -3: adcl $0,%eax - addl $64, %edx - dec %ecx - jge 1b -4: movl ARGBASE+12(%esp),%edx #len - andl $3, %edx - jz 7f - cmpl $2, %edx - jb 5f -SRC( movw (%esi), %dx ) - leal 2(%esi), %esi -DST( movw %dx, (%edi) ) - leal 2(%edi), %edi - je 6f - shll $16,%edx -5: -SRC( movb (%esi), %dl ) -DST( movb %dl, (%edi) ) -6: addl %edx, %eax - adcl $0, %eax -7: -.section .fixup, "ax" -6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr - movl $-EFAULT, (%ebx) - # zero the complete destination (computing the rest is too much work) - movl ARGBASE+8(%esp),%edi # dst - movl ARGBASE+12(%esp),%ecx # len - xorl %eax,%eax - rep; stosb - jmp 7b -6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr - movl $-EFAULT, (%ebx) - jmp 7b -.previous - - popl %esi - popl %edi - popl %ebx - ret - -#undef ROUND -#undef ROUND1 - -#endif diff --git a/arch/um/sys-i386/delay.c b/arch/um/sys-i386/delay.c deleted file mode 100644 index 2c11b9770e8..00000000000 --- a/arch/um/sys-i386/delay.c +++ /dev/null @@ -1,40 +0,0 @@ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <asm/param.h> - -void __delay(unsigned long time) -{ - /* Stolen from the i386 __loop_delay */ - int d0; - __asm__ __volatile__( - "\tjmp 1f\n" - ".align 16\n" - "1:\tjmp 2f\n" - ".align 16\n" - "2:\tdecl %0\n\tjns 2b" - :"=&a" (d0) - :"0" (time)); -} - -void __udelay(unsigned long usecs) -{ - int i, n; - - n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) - cpu_relax(); -} - -EXPORT_SYMBOL(__udelay); - -void __const_udelay(unsigned long usecs) -{ - int i, n; - - n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) - cpu_relax(); -} - -EXPORT_SYMBOL(__const_udelay); diff --git a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c deleted file mode 100644 index d0bbcdfdb53..00000000000 --- a/arch/um/sys-i386/fault.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include <signal.h> -#include "sysdep/ptrace.h" -#include "sysdep/sigcontext.h" - -/* These two are from asm-um/uaccess.h and linux/module.h, check them. */ -struct exception_table_entry -{ - unsigned long insn; - unsigned long fixup; -}; - -const struct exception_table_entry *search_exception_tables(unsigned long add); - -/* Compare this to arch/i386/mm/extable.c:fixup_exception() */ -int arch_fixup(unsigned long address, void *sc_ptr) -{ - struct sigcontext *sc = sc_ptr; - const struct exception_table_entry *fixup; - - fixup = search_exception_tables(address); - if(fixup != 0){ - sc->eip = fixup->fixup; - return(1); - } - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-i386/kernel-offsets.c b/arch/um/sys-i386/kernel-offsets.c deleted file mode 100644 index 35db8505750..00000000000 --- a/arch/um/sys-i386/kernel-offsets.c +++ /dev/null @@ -1,26 +0,0 @@ -#include <linux/config.h> -#include <linux/stddef.h> -#include <linux/sched.h> -#include <linux/time.h> -#include <linux/elf.h> -#include <asm/page.h> - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define STR(x) #x -#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " STR(val) " " #val: : ) - -#define BLANK() asm volatile("\n->" : : ) - -#define OFFSET(sym, str, mem) \ - DEFINE(sym, offsetof(struct str, mem)); - -void foo(void) -{ - OFFSET(HOST_TASK_DEBUGREGS, task_struct, thread.arch.debugregs); -#ifdef CONFIG_MODE_TT - OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid); -#endif -#include <common-offsets.h> -} diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c deleted file mode 100644 index db524ab3f74..00000000000 --- a/arch/um/sys-i386/ksyms.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "linux/module.h" -#include "linux/in6.h" -#include "linux/rwsem.h" -#include "asm/byteorder.h" -#include "asm/delay.h" -#include "asm/semaphore.h" -#include "asm/uaccess.h" -#include "asm/checksum.h" -#include "asm/errno.h" - -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__down_failed_trylock); -EXPORT_SYMBOL(__up_wakeup); - -/* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial); - -/* delay core functions */ -EXPORT_SYMBOL(__const_udelay); -EXPORT_SYMBOL(__udelay); diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c deleted file mode 100644 index 6360f1c958d..00000000000 --- a/arch/um/sys-i386/ldt.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/stddef.h" -#include "linux/config.h" -#include "linux/sched.h" -#include "linux/slab.h" -#include "linux/types.h" -#include "linux/errno.h" -#include "asm/uaccess.h" -#include "asm/smp.h" -#include "asm/ldt.h" -#include "asm/unistd.h" -#include "choose-mode.h" -#include "kern.h" -#include "mode_kern.h" - -extern int modify_ldt(int func, void *ptr, unsigned long bytecount); - -#ifdef CONFIG_MODE_TT - -static long do_modify_ldt_tt(int func, void __user *ptr, - unsigned long bytecount) -{ - struct user_desc info; - int res = 0; - void *buf = NULL; - void *p = NULL; /* What we pass to host. */ - - switch(func){ - case 1: - case 0x11: /* write_ldt */ - /* Do this check now to avoid overflows. */ - if (bytecount != sizeof(struct user_desc)) { - res = -EINVAL; - goto out; - } - - if(copy_from_user(&info, ptr, sizeof(info))) { - res = -EFAULT; - goto out; - } - - p = &info; - break; - case 0: - case 2: /* read_ldt */ - - /* The use of info avoids kmalloc on the write case, not on the - * read one. */ - buf = kmalloc(bytecount, GFP_KERNEL); - if (!buf) { - res = -ENOMEM; - goto out; - } - p = buf; - break; - default: - res = -ENOSYS; - goto out; - } - - res = modify_ldt(func, p, bytecount); - if(res < 0) - goto out; - - switch(func){ - case 0: - case 2: - /* Modify_ldt was for reading and returned the number of read - * bytes.*/ - if(copy_to_user(ptr, p, res)) - res = -EFAULT; - break; - } - -out: - kfree(buf); - return res; -} - -#endif - -#ifdef CONFIG_MODE_SKAS - -#include "skas.h" -#include "skas_ptrace.h" -#include "asm/mmu_context.h" - -long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, - void **addr, int done) -{ - long res; - - if(proc_mm){ - /* This is a special handling for the case, that the mm to - * modify isn't current->active_mm. - * If this is called directly by modify_ldt, - * (current->active_mm->context.skas.u == mm_idp) - * will be true. So no call to switch_mm_skas(mm_idp) is done. - * If this is called in case of init_new_ldt or PTRACE_LDT, - * mm_idp won't belong to current->active_mm, but child->mm. - * So we need to switch child's mm into our userspace, then - * later switch back. - * - * Note: I'm unshure: should interrupts be disabled here? - */ - if(!current->active_mm || current->active_mm == &init_mm || - mm_idp != ¤t->active_mm->context.skas.id) - switch_mm_skas(mm_idp); - } - - if(ptrace_ldt) { - struct ptrace_ldt ldt_op = (struct ptrace_ldt) { - .func = func, - .ptr = desc, - .bytecount = sizeof(*desc)}; - u32 cpu; - int pid; - - if(!proc_mm) - pid = mm_idp->u.pid; - else { - cpu = get_cpu(); - pid = userspace_pid[cpu]; - } - - res = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); - if(res) - res = errno; - - if(proc_mm) - put_cpu(); - } - else { - void *stub_addr; - res = syscall_stub_data(mm_idp, (unsigned long *)desc, - (sizeof(*desc) + sizeof(long) - 1) & - ~(sizeof(long) - 1), - addr, &stub_addr); - if(!res){ - unsigned long args[] = { func, - (unsigned long)stub_addr, - sizeof(*desc), - 0, 0, 0 }; - res = run_syscall_stub(mm_idp, __NR_modify_ldt, args, - 0, addr, done); - } - } - - if(proc_mm){ - /* This is the second part of special handling, that makes - * PTRACE_LDT possible to implement. - */ - if(current->active_mm && current->active_mm != &init_mm && - mm_idp != ¤t->active_mm->context.skas.id) - switch_mm_skas(¤t->active_mm->context.skas.id); - } - - return res; -} - -static long read_ldt_from_host(void __user * ptr, unsigned long bytecount) -{ - int res, n; - struct ptrace_ldt ptrace_ldt = (struct ptrace_ldt) { - .func = 0, - .bytecount = bytecount, - .ptr = (void *)kmalloc(bytecount, GFP_KERNEL)}; - u32 cpu; - - if(ptrace_ldt.ptr == NULL) - return -ENOMEM; - - /* This is called from sys_modify_ldt only, so userspace_pid gives - * us the right number - */ - - cpu = get_cpu(); - res = ptrace(PTRACE_LDT, userspace_pid[cpu], 0, - (unsigned long) &ptrace_ldt); - put_cpu(); - if(res < 0) - goto out; - - n = copy_to_user(ptr, ptrace_ldt.ptr, res); - if(n != 0) - res = -EFAULT; - - out: - kfree(ptrace_ldt.ptr); - - return res; -} - -/* - * In skas mode, we hold our own ldt data in UML. - * Thus, the code implementing sys_modify_ldt_skas - * is very similar to (and mostly stolen from) sys_modify_ldt - * for arch/i386/kernel/ldt.c - * The routines copied and modified in part are: - * - read_ldt - * - read_default_ldt - * - write_ldt - * - sys_modify_ldt_skas - */ - -static int read_ldt(void __user * ptr, unsigned long bytecount) -{ - int i, err = 0; - unsigned long size; - uml_ldt_t * ldt = ¤t->mm->context.skas.ldt; - - if(!ldt->entry_count) - goto out; - if(bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) - bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; - err = bytecount; - - if(ptrace_ldt){ - return read_ldt_from_host(ptr, bytecount); - } - - down(&ldt->semaphore); - if(ldt->entry_count <= LDT_DIRECT_ENTRIES){ - size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES; - if(size > bytecount) - size = bytecount; - if(copy_to_user(ptr, ldt->entries, size)) - err = -EFAULT; - bytecount -= size; - ptr += size; - } - else { - for(i=0; i<ldt->entry_count/LDT_ENTRIES_PER_PAGE && bytecount; - i++){ - size = PAGE_SIZE; - if(size > bytecount) - size = bytecount; - if(copy_to_user(ptr, ldt->pages[i], size)){ - err = -EFAULT; - break; - } - bytecount -= size; - ptr += size; - } - } - up(&ldt->semaphore); - - if(bytecount == 0 || err == -EFAULT) - goto out; - - if(clear_user(ptr, bytecount)) - err = -EFAULT; - -out: - return err; -} - -static int read_default_ldt(void __user * ptr, unsigned long bytecount) -{ - int err; - - if(bytecount > 5*LDT_ENTRY_SIZE) - bytecount = 5*LDT_ENTRY_SIZE; - - err = bytecount; - /* UML doesn't support lcall7 and lcall27. - * So, we don't really have a default ldt, but emulate - * an empty ldt of common host default ldt size. - */ - if(clear_user(ptr, bytecount)) - err = -EFAULT; - - return err; -} - -static int write_ldt(void __user * ptr, unsigned long bytecount, int func) -{ - uml_ldt_t * ldt = ¤t->mm->context.skas.ldt; - struct mm_id * mm_idp = ¤t->mm->context.skas.id; - int i, err; - struct user_desc ldt_info; - struct ldt_entry entry0, *ldt_p; - void *addr = NULL; - - err = -EINVAL; - if(bytecount != sizeof(ldt_info)) - goto out; - err = -EFAULT; - if(copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) - goto out; - - err = -EINVAL; - if(ldt_info.entry_number >= LDT_ENTRIES) - goto out; - if(ldt_info.contents == 3){ - if (func == 1) - goto out; - if (ldt_info.seg_not_present == 0) - goto out; - } - - if(!ptrace_ldt) - down(&ldt->semaphore); - - err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); - if(err) - goto out_unlock; - else if(ptrace_ldt) { - /* With PTRACE_LDT available, this is used as a flag only */ - ldt->entry_count = 1; - goto out; - } - - if(ldt_info.entry_number >= ldt->entry_count && - ldt_info.entry_number >= LDT_DIRECT_ENTRIES){ - for(i=ldt->entry_count/LDT_ENTRIES_PER_PAGE; - i*LDT_ENTRIES_PER_PAGE <= ldt_info.entry_number; - i++){ - if(i == 0) - memcpy(&entry0, ldt->entries, sizeof(entry0)); - ldt->pages[i] = (struct ldt_entry *) - __get_free_page(GFP_KERNEL|__GFP_ZERO); - if(!ldt->pages[i]){ - err = -ENOMEM; - /* Undo the change in host */ - memset(&ldt_info, 0, sizeof(ldt_info)); - write_ldt_entry(mm_idp, 1, &ldt_info, &addr, 1); - goto out_unlock; - } - if(i == 0) { - memcpy(ldt->pages[0], &entry0, sizeof(entry0)); - memcpy(ldt->pages[0]+1, ldt->entries+1, - sizeof(entry0)*(LDT_DIRECT_ENTRIES-1)); - } - ldt->entry_count = (i + 1) * LDT_ENTRIES_PER_PAGE; - } - } - if(ldt->entry_count <= ldt_info.entry_number) - ldt->entry_count = ldt_info.entry_number + 1; - - if(ldt->entry_count <= LDT_DIRECT_ENTRIES) - ldt_p = ldt->entries + ldt_info.entry_number; - else - ldt_p = ldt->pages[ldt_info.entry_number/LDT_ENTRIES_PER_PAGE] + - ldt_info.entry_number%LDT_ENTRIES_PER_PAGE; - - if(ldt_info.base_addr == 0 && ldt_info.limit == 0 && - (func == 1 || LDT_empty(&ldt_info))){ - ldt_p->a = 0; - ldt_p->b = 0; - } - else{ - if (func == 1) - ldt_info.useable = 0; - ldt_p->a = LDT_entry_a(&ldt_info); - ldt_p->b = LDT_entry_b(&ldt_info); - } - err = 0; - -out_unlock: - up(&ldt->semaphore); -out: - return err; -} - -static long do_modify_ldt_skas(int func, void __user *ptr, - unsigned long bytecount) -{ - int ret = -ENOSYS; - - switch (func) { - case 0: - ret = read_ldt(ptr, bytecount); - break; - case 1: - case 0x11: - ret = write_ldt(ptr, bytecount, func); - break; - case 2: - ret = read_default_ldt(ptr, bytecount); - break; - } - return ret; -} - -short dummy_list[9] = {0, -1}; -short * host_ldt_entries = NULL; - -void ldt_get_host_info(void) -{ - long ret; - struct ldt_entry * ldt; - int i, size, k, order; - - host_ldt_entries = dummy_list+1; - - for(i = LDT_PAGES_MAX-1, order=0; i; i>>=1, order++); - - ldt = (struct ldt_entry *) - __get_free_pages(GFP_KERNEL|__GFP_ZERO, order); - if(ldt == NULL) { - printk("ldt_get_host_info: couldn't allocate buffer for host ldt\n"); - return; - } - - ret = modify_ldt(0, ldt, (1<<order)*PAGE_SIZE); - if(ret < 0) { - printk("ldt_get_host_info: couldn't read host ldt\n"); - goto out_free; - } - if(ret == 0) { - /* default_ldt is active, simply write an empty entry 0 */ - host_ldt_entries = dummy_list; - goto out_free; - } - - for(i=0, size=0; i<ret/LDT_ENTRY_SIZE; i++){ - if(ldt[i].a != 0 || ldt[i].b != 0) - size++; - } - - if(size < sizeof(dummy_list)/sizeof(dummy_list[0])) { - host_ldt_entries = dummy_list; - } - else { - size = (size + 1) * sizeof(dummy_list[0]); - host_ldt_entries = (short *)kmalloc(size, GFP_KERNEL); - if(host_ldt_entries == NULL) { - printk("ldt_get_host_info: couldn't allocate host ldt list\n"); - goto out_free; - } - } - - for(i=0, k=0; i<ret/LDT_ENTRY_SIZE; i++){ - if(ldt[i].a != 0 || ldt[i].b != 0) { - host_ldt_entries[k++] = i; - } - } - host_ldt_entries[k] = -1; - -out_free: - free_pages((unsigned long)ldt, order); -} - -long init_new_ldt(struct mmu_context_skas * new_mm, - struct mmu_context_skas * from_mm) -{ - struct user_desc desc; - short * num_p; - int i; - long page, err=0; - void *addr = NULL; - - memset(&desc, 0, sizeof(desc)); - - if(!ptrace_ldt) - init_MUTEX(&new_mm->ldt.semaphore); - - if(!from_mm){ - /* - * We have to initialize a clean ldt. - */ - if(proc_mm) { - /* - * If the new mm was created using proc_mm, host's - * default-ldt currently is assigned, which normally - * contains the call-gates for lcall7 and lcall27. - * To remove these gates, we simply write an empty - * entry as number 0 to the host. - */ - err = write_ldt_entry(&new_mm->id, 1, &desc, - &addr, 1); - } - else{ - /* - * Now we try to retrieve info about the ldt, we - * inherited from the host. All ldt-entries found - * will be reset in the following loop - */ - if(host_ldt_entries == NULL) - ldt_get_host_info(); - for(num_p=host_ldt_entries; *num_p != -1; num_p++){ - desc.entry_number = *num_p; - err = write_ldt_entry(&new_mm->id, 1, &desc, - &addr, *(num_p + 1) == -1); - if(err) - break; - } - } - new_mm->ldt.entry_count = 0; - } - else if (!ptrace_ldt) { - /* Our local LDT is used to supply the data for - * modify_ldt(READLDT), if PTRACE_LDT isn't available, - * i.e., we have to use the stub for modify_ldt, which - * can't handle the big read buffer of up to 64kB. - */ - down(&from_mm->ldt.semaphore); - if(from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES){ - memcpy(new_mm->ldt.entries, from_mm->ldt.entries, - sizeof(new_mm->ldt.entries)); - } - else{ - i = from_mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE; - while(i-->0){ - page = __get_free_page(GFP_KERNEL|__GFP_ZERO); - if (!page){ - err = -ENOMEM; - break; - } - new_mm->ldt.pages[i] = (struct ldt_entry*)page; - memcpy(new_mm->ldt.pages[i], - from_mm->ldt.pages[i], PAGE_SIZE); - } - } - new_mm->ldt.entry_count = from_mm->ldt.entry_count; - up(&from_mm->ldt.semaphore); - } - - return err; -} - - -void free_ldt(struct mmu_context_skas * mm) -{ - int i; - - if(!ptrace_ldt && mm->ldt.entry_count > LDT_DIRECT_ENTRIES){ - i = mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE; - while(i-- > 0){ - free_page((long )mm->ldt.pages[i]); - } - } - mm->ldt.entry_count = 0; -} -#endif - -int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) -{ - return(CHOOSE_MODE_PROC(do_modify_ldt_tt, do_modify_ldt_skas, func, - ptr, bytecount)); -} diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c deleted file mode 100644 index e839ce65ad2..00000000000 --- a/arch/um/sys-i386/ptrace.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <linux/config.h> -#include <linux/compiler.h> -#include "linux/sched.h" -#include "asm/elf.h" -#include "asm/ptrace.h" -#include "asm/uaccess.h" -#include "asm/unistd.h" -#include "sysdep/ptrace.h" -#include "sysdep/sigcontext.h" -#include "sysdep/sc.h" - -void arch_switch(void) -{ - update_debugregs(current->thread.arch.debugregs_seq); -} - -int is_syscall(unsigned long addr) -{ - unsigned short instr; - int n; - - n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); - if(n){ - printk("is_syscall : failed to read instruction from 0x%lx\n", - addr); - return(0); - } - /* int 0x80 or sysenter */ - return((instr == 0x80cd) || (instr == 0x340f)); -} - -/* determines which flags the user has access to. */ -/* 1 = access 0 = no access */ -#define FLAG_MASK 0x00044dd5 - -int putreg(struct task_struct *child, int regno, unsigned long value) -{ - regno >>= 2; - switch (regno) { - case FS: - if (value && (value & 3) != 3) - return -EIO; - PT_REGS_FS(&child->thread.regs) = value; - return 0; - case GS: - if (value && (value & 3) != 3) - return -EIO; - PT_REGS_GS(&child->thread.regs) = value; - return 0; - case DS: - case ES: - if (value && (value & 3) != 3) - return -EIO; - value &= 0xffff; - break; - case SS: - case CS: - if ((value & 3) != 3) - return -EIO; - value &= 0xffff; - break; - case EFL: - value &= FLAG_MASK; - value |= PT_REGS_EFLAGS(&child->thread.regs); - break; - } - PT_REGS_SET(&child->thread.regs, regno, value); - return 0; -} - -int poke_user(struct task_struct *child, long addr, long data) -{ - if ((addr & 3) || addr < 0) - return -EIO; - - if (addr < MAX_REG_OFFSET) - return putreg(child, addr, data); - - else if((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - if((addr == 4) || (addr == 5)) return -EIO; - child->thread.arch.debugregs[addr] = data; - return 0; - } - return -EIO; -} - -unsigned long getreg(struct task_struct *child, int regno) -{ - unsigned long retval = ~0UL; - - regno >>= 2; - switch (regno) { - case FS: - case GS: - case DS: - case ES: - case SS: - case CS: - retval = 0xffff; - /* fall through */ - default: - retval &= PT_REG(&child->thread.regs, regno); - } - return retval; -} - -int peek_user(struct task_struct *child, long addr, long data) -{ -/* read the word at location addr in the USER area. */ - unsigned long tmp; - - if ((addr & 3) || addr < 0) - return -EIO; - - tmp = 0; /* Default return condition */ - if(addr < MAX_REG_OFFSET){ - tmp = getreg(child, addr); - } - else if((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - tmp = child->thread.arch.debugregs[addr]; - } - return put_user(tmp, (unsigned long *) data); -} - -struct i387_fxsave_struct { - unsigned short cwd; - unsigned short swd; - unsigned short twd; - unsigned short fop; - long fip; - long fcs; - long foo; - long fos; - long mxcsr; - long reserved; - long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ - long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ - long padding[56]; -}; - -/* - * FPU tag word conversions. - */ - -static inline unsigned short twd_i387_to_fxsr( unsigned short twd ) -{ - unsigned int tmp; /* to avoid 16 bit prefixes in the code */ - - /* Transform each pair of bits into 01 (valid) or 00 (empty) */ - tmp = ~twd; - tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ - /* and move the valid bits to the lower byte. */ - tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ - tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ - tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ - return tmp; -} - -static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave ) -{ - struct _fpxreg *st = NULL; - unsigned long twd = (unsigned long) fxsave->twd; - unsigned long tag; - unsigned long ret = 0xffff0000; - int i; - -#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16); - - for ( i = 0 ; i < 8 ; i++ ) { - if ( twd & 0x1 ) { - st = (struct _fpxreg *) FPREG_ADDR( fxsave, i ); - - switch ( st->exponent & 0x7fff ) { - case 0x7fff: - tag = 2; /* Special */ - break; - case 0x0000: - if ( !st->significand[0] && - !st->significand[1] && - !st->significand[2] && - !st->significand[3] ) { - tag = 1; /* Zero */ - } else { - tag = 2; /* Special */ - } - break; - default: - if ( st->significand[3] & 0x8000 ) { - tag = 0; /* Valid */ - } else { - tag = 2; /* Special */ - } - break; - } - } else { - tag = 3; /* Empty */ - } - ret |= (tag << (2 * i)); - twd = twd >> 1; - } - return ret; -} - -/* - * FXSR floating point environment conversions. - */ - -#ifdef CONFIG_MODE_TT -static inline int convert_fxsr_to_user_tt(struct _fpstate __user *buf, - struct pt_regs *regs) -{ - struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); - unsigned long env[7]; - struct _fpreg __user *to; - struct _fpxreg *from; - int i; - - env[0] = (unsigned long)fxsave->cwd | 0xffff0000; - env[1] = (unsigned long)fxsave->swd | 0xffff0000; - env[2] = twd_fxsr_to_i387(fxsave); - env[3] = fxsave->fip; - env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); - env[5] = fxsave->foo; - env[6] = fxsave->fos; - - if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) - return 1; - - to = &buf->_st[0]; - from = (struct _fpxreg *) &fxsave->st_space[0]; - for ( i = 0 ; i < 8 ; i++, to++, from++ ) { - if ( __copy_to_user( to, from, sizeof(*to) ) ) - return 1; - } - return 0; -} -#endif - -static inline int convert_fxsr_to_user(struct _fpstate __user *buf, - struct pt_regs *regs) -{ - return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0)); -} - -#ifdef CONFIG_MODE_TT -static inline int convert_fxsr_from_user_tt(struct pt_regs *regs, - struct _fpstate __user *buf) -{ - struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); - unsigned long env[7]; - struct _fpxreg *to; - struct _fpreg __user *from; - int i; - - if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) - return 1; - - fxsave->cwd = (unsigned short)(env[0] & 0xffff); - fxsave->swd = (unsigned short)(env[1] & 0xffff); - fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); - fxsave->fip = env[3]; - fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16); - fxsave->fcs = (env[4] & 0xffff); - fxsave->foo = env[5]; - fxsave->fos = env[6]; - - to = (struct _fpxreg *) &fxsave->st_space[0]; - from = &buf->_st[0]; - for ( i = 0 ; i < 8 ; i++, to++, from++ ) { - if ( __copy_from_user( to, from, sizeof(*from) ) ) - return 1; - } - return 0; -} -#endif - -static inline int convert_fxsr_from_user(struct pt_regs *regs, - struct _fpstate __user *buf) -{ - return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0)); -} - -int get_fpregs(unsigned long buf, struct task_struct *child) -{ - int err; - - err = convert_fxsr_to_user((struct _fpstate __user *) buf, - &child->thread.regs); - if(err) return(-EFAULT); - else return(0); -} - -int set_fpregs(unsigned long buf, struct task_struct *child) -{ - int err; - - err = convert_fxsr_from_user(&child->thread.regs, - (struct _fpstate __user *) buf); - if(err) return(-EFAULT); - else return(0); -} - -#ifdef CONFIG_MODE_TT -int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk) -{ - struct pt_regs *regs = &tsk->thread.regs; - struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); - int err; - - err = __copy_to_user((void __user *) buf, fxsave, - sizeof(struct user_fxsr_struct)); - if(err) return -EFAULT; - else return 0; -} -#endif - -int get_fpxregs(unsigned long buf, struct task_struct *tsk) -{ - return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0)); -} - -#ifdef CONFIG_MODE_TT -int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk) -{ - struct pt_regs *regs = &tsk->thread.regs; - struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); - int err; - - err = __copy_from_user(fxsave, (void __user *) buf, - sizeof(struct user_fxsr_struct) ); - if(err) return -EFAULT; - else return 0; -} -#endif - -int set_fpxregs(unsigned long buf, struct task_struct *tsk) -{ - return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0)); -} - -#ifdef notdef -int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) -{ - fpu->cwd = (((SC_FP_CW(PT_REGS_SC(regs)) & 0xffff) << 16) | - (SC_FP_SW(PT_REGS_SC(regs)) & 0xffff)); - fpu->swd = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff; - fpu->twd = SC_FP_IPOFF(PT_REGS_SC(regs)); - fpu->fip = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff; - fpu->fcs = SC_FP_DATAOFF(PT_REGS_SC(regs)); - fpu->foo = SC_FP_DATASEL(PT_REGS_SC(regs)); - fpu->fos = 0; - memcpy(fpu->st_space, (void *) SC_FP_ST(PT_REGS_SC(regs)), - sizeof(fpu->st_space)); - return(1); -} -#endif - -#ifdef CONFIG_MODE_TT -static inline void copy_fpu_fxsave_tt(struct pt_regs *regs, - struct user_i387_struct *buf) -{ - struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs)); - unsigned short *to; - unsigned short *from; - int i; - - memcpy( buf, fpu, 7 * sizeof(long) ); - - to = (unsigned short *) &buf->st_space[0]; - from = (unsigned short *) &fpu->st_space[0]; - for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) { - memcpy( to, from, 5 * sizeof(unsigned short) ); - } -} -#endif - -static inline void copy_fpu_fxsave(struct pt_regs *regs, - struct user_i387_struct *buf) -{ - (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0); -} - -int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) -{ - copy_fpu_fxsave(regs, (struct user_i387_struct *) fpu); - return(1); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c deleted file mode 100644 index 7c376c95de5..00000000000 --- a/arch/um/sys-i386/ptrace_user.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <linux/stddef.h> -#include "ptrace_user.h" -/* Grr, asm/user.h includes asm/ptrace.h, so has to follow ptrace_user.h */ -#include <asm/user.h> -#include "kern_util.h" -#include "sysdep/thread.h" -#include "user.h" -#include "os.h" - -int ptrace_getregs(long pid, unsigned long *regs_out) -{ - if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) - return -errno; - return 0; -} - -int ptrace_setregs(long pid, unsigned long *regs) -{ - if (ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) - return -errno; - return 0; -} - -int ptrace_getfpregs(long pid, unsigned long *regs) -{ - if (ptrace(PTRACE_GETFPREGS, pid, 0, regs) < 0) - return -errno; - return 0; -} - -int ptrace_setfpregs(long pid, unsigned long *regs) -{ - if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0) - return -errno; - return 0; -} - -static void write_debugregs(int pid, unsigned long *regs) -{ - struct user *dummy; - int nregs, i; - - dummy = NULL; - nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); - for(i = 0; i < nregs; i++){ - if((i == 4) || (i == 5)) continue; - if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], - regs[i]) < 0) - printk("write_debugregs - ptrace failed on " - "register %d, value = 0x%x, errno = %d\n", i, - regs[i], errno); - } -} - -static void read_debugregs(int pid, unsigned long *regs) -{ - struct user *dummy; - int nregs, i; - - dummy = NULL; - nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); - for(i = 0; i < nregs; i++){ - regs[i] = ptrace(PTRACE_PEEKUSR, pid, - &dummy->u_debugreg[i], 0); - } -} - -/* Accessed only by the tracing thread */ -static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; -static int debugregs_seq = 0; - -void arch_enter_kernel(void *task, int pid) -{ - read_debugregs(pid, TASK_DEBUGREGS(task)); - write_debugregs(pid, kernel_debugregs); -} - -void arch_leave_kernel(void *task, int pid) -{ - read_debugregs(pid, kernel_debugregs); - write_debugregs(pid, TASK_DEBUGREGS(task)); -} - -void ptrace_pokeuser(unsigned long addr, unsigned long data) -{ - if((addr < offsetof(struct user, u_debugreg[0])) || - (addr > offsetof(struct user, u_debugreg[7]))) - return; - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - if(kernel_debugregs[addr] == data) return; - - kernel_debugregs[addr] = data; - debugregs_seq++; -} - -static void update_debugregs_cb(void *arg) -{ - int pid = *((int *) arg); - - write_debugregs(pid, kernel_debugregs); -} - -void update_debugregs(int seq) -{ - int me; - - if(seq == debugregs_seq) return; - - me = os_getpid(); - initial_thread_cb(update_debugregs_cb, &me); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-i386/sigcontext.c b/arch/um/sys-i386/sigcontext.c deleted file mode 100644 index 467d489c31c..00000000000 --- a/arch/um/sys-i386/sigcontext.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stddef.h> -#include <string.h> -#include <asm/ptrace.h> -#include <asm/sigcontext.h> -#include "sysdep/ptrace.h" -#include "kern_util.h" - -void sc_to_sc(void *to_ptr, void *from_ptr) -{ - struct sigcontext *to = to_ptr, *from = from_ptr; - - memcpy(to, from, sizeof(*to) + sizeof(struct _fpstate)); - if(from->fpstate != NULL) - to->fpstate = (struct _fpstate *) (to + 1); -} - -unsigned long *sc_sigmask(void *sc_ptr) -{ - struct sigcontext *sc = sc_ptr; - return &sc->oldmask; -} - -int sc_get_fpregs(unsigned long buf, void *sc_ptr) -{ - struct sigcontext *sc = sc_ptr; - struct _fpstate *from = sc->fpstate, *to = (struct _fpstate *) buf; - int err = 0; - - if(from == NULL){ - err |= clear_user_proc(&to->cw, sizeof(to->cw)); - err |= clear_user_proc(&to->sw, sizeof(to->sw)); - err |= clear_user_proc(&to->tag, sizeof(to->tag)); - err |= clear_user_proc(&to->ipoff, sizeof(to->ipoff)); - err |= clear_user_proc(&to->cssel, sizeof(to->cssel)); - err |= clear_user_proc(&to->dataoff, sizeof(to->dataoff)); - err |= clear_user_proc(&to->datasel, sizeof(to->datasel)); - err |= clear_user_proc(&to->_st, sizeof(to->_st)); - } - else { - err |= copy_to_user_proc(&to->cw, &from->cw, sizeof(to->cw)); - err |= copy_to_user_proc(&to->sw, &from->sw, sizeof(to->sw)); - err |= copy_to_user_proc(&to->tag, &from->tag, - sizeof(to->tag)); - err |= copy_to_user_proc(&to->ipoff, &from->ipoff, - sizeof(to->ipoff)); - err |= copy_to_user_proc(&to->cssel,& from->cssel, - sizeof(to->cssel)); - err |= copy_to_user_proc(&to->dataoff, &from->dataoff, - sizeof(to->dataoff)); - err |= copy_to_user_proc(&to->datasel, &from->datasel, - sizeof(to->datasel)); - err |= copy_to_user_proc(to->_st, from->_st, sizeof(to->_st)); - } - return(err); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c deleted file mode 100644 index 16bc19928b3..00000000000 --- a/arch/um/sys-i386/signal.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/signal.h" -#include "linux/ptrace.h" -#include "asm/current.h" -#include "asm/ucontext.h" -#include "asm/uaccess.h" -#include "asm/unistd.h" -#include "frame_kern.h" -#include "signal_user.h" -#include "sigcontext.h" -#include "registers.h" -#include "mode.h" - -#ifdef CONFIG_MODE_SKAS - -#include "skas.h" - -static int copy_sc_from_user_skas(struct pt_regs *regs, - struct sigcontext *from) -{ - struct sigcontext sc; - unsigned long fpregs[HOST_FP_SIZE]; - int err; - - err = copy_from_user(&sc, from, sizeof(sc)); - err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs)); - if(err) - return(err); - - REGS_GS(regs->regs.skas.regs) = sc.gs; - REGS_FS(regs->regs.skas.regs) = sc.fs; - REGS_ES(regs->regs.skas.regs) = sc.es; - REGS_DS(regs->regs.skas.regs) = sc.ds; - REGS_EDI(regs->regs.skas.regs) = sc.edi; - REGS_ESI(regs->regs.skas.regs) = sc.esi; - REGS_EBP(regs->regs.skas.regs) = sc.ebp; - REGS_SP(regs->regs.skas.regs) = sc.esp; - REGS_EBX(regs->regs.skas.regs) = sc.ebx; - REGS_EDX(regs->regs.skas.regs) = sc.edx; - REGS_ECX(regs->regs.skas.regs) = sc.ecx; - REGS_EAX(regs->regs.skas.regs) = sc.eax; - REGS_IP(regs->regs.skas.regs) = sc.eip; - REGS_CS(regs->regs.skas.regs) = sc.cs; - REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags; - REGS_SS(regs->regs.skas.regs) = sc.ss; - - err = restore_fp_registers(userspace_pid[0], fpregs); - if(err < 0){ - printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, " - "errno = %d\n", err); - return(1); - } - - return(0); -} - -int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, - struct pt_regs *regs) -{ - struct sigcontext sc; - unsigned long fpregs[HOST_FP_SIZE]; - struct faultinfo * fi = ¤t->thread.arch.faultinfo; - int err; - - sc.gs = REGS_GS(regs->regs.skas.regs); - sc.fs = REGS_FS(regs->regs.skas.regs); - sc.es = REGS_ES(regs->regs.skas.regs); - sc.ds = REGS_DS(regs->regs.skas.regs); - sc.edi = REGS_EDI(regs->regs.skas.regs); - sc.esi = REGS_ESI(regs->regs.skas.regs); - sc.ebp = REGS_EBP(regs->regs.skas.regs); - sc.esp = REGS_SP(regs->regs.skas.regs); - sc.ebx = REGS_EBX(regs->regs.skas.regs); - sc.edx = REGS_EDX(regs->regs.skas.regs); - sc.ecx = REGS_ECX(regs->regs.skas.regs); - sc.eax = REGS_EAX(regs->regs.skas.regs); - sc.eip = REGS_IP(regs->regs.skas.regs); - sc.cs = REGS_CS(regs->regs.skas.regs); - sc.eflags = REGS_EFLAGS(regs->regs.skas.regs); - sc.esp_at_signal = regs->regs.skas.regs[UESP]; - sc.ss = regs->regs.skas.regs[SS]; - sc.cr2 = fi->cr2; - sc.err = fi->error_code; - sc.trapno = fi->trap_no; - - err = save_fp_registers(userspace_pid[0], fpregs); - if(err < 0){ - printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, " - "errno = %d\n", err); - return(1); - } - to_fp = (to_fp ? to_fp : (struct _fpstate *) (to + 1)); - sc.fpstate = to_fp; - - if(err) - return(err); - - return(copy_to_user(to, &sc, sizeof(sc)) || - copy_to_user(to_fp, fpregs, sizeof(fpregs))); -} -#endif - -#ifdef CONFIG_MODE_TT - -/* These copy a sigcontext to/from userspace. They copy the fpstate pointer, - * blowing away the old, good one. So, that value is saved, and then restored - * after the sigcontext copy. In copy_from, the variable holding the saved - * fpstate pointer, and the sigcontext that it should be restored to are both - * in the kernel, so we can just restore using an assignment. In copy_to, the - * saved pointer is in the kernel, but the sigcontext is in userspace, so we - * copy_to_user it. - */ -int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, - int fpsize) -{ - struct _fpstate *to_fp, *from_fp; - unsigned long sigs; - int err; - - to_fp = to->fpstate; - sigs = to->oldmask; - err = copy_from_user(to, from, sizeof(*to)); - from_fp = to->fpstate; - to->oldmask = sigs; - to->fpstate = to_fp; - if(to_fp != NULL) - err |= copy_from_user(to_fp, from_fp, fpsize); - return(err); -} - -int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, - struct sigcontext *from, int fpsize) -{ - struct _fpstate *to_fp, *from_fp; - int err; - - to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); - from_fp = from->fpstate; - err = copy_to_user(to, from, sizeof(*to)); - if(from_fp != NULL){ - err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); - err |= copy_to_user(to_fp, from_fp, fpsize); - } - return(err); -} -#endif - -static int copy_sc_from_user(struct pt_regs *to, void __user *from) -{ - int ret; - - ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, - sizeof(struct _fpstate)), - copy_sc_from_user_skas(to, from)); - return(ret); -} - -static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, - struct pt_regs *from) -{ - return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), - sizeof(*fp)), - copy_sc_to_user_skas(to, fp, from))); -} - -static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, - sigset_t *set, unsigned long sp) -{ - int err = 0; - - err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp); - err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags); - err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); - err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs); - err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); - return(err); -} - -struct sigframe -{ - char *pretcode; - int sig; - struct sigcontext sc; - struct _fpstate fpstate; - unsigned long extramask[_NSIG_WORDS-1]; - char retcode[8]; -}; - -struct rt_sigframe -{ - char *pretcode; - int sig; - struct siginfo *pinfo; - void *puc; - struct siginfo info; - struct ucontext uc; - struct _fpstate fpstate; - char retcode[8]; -}; - -int setup_signal_stack_sc(unsigned long stack_top, int sig, - struct k_sigaction *ka, struct pt_regs *regs, - sigset_t *mask) -{ - struct sigframe __user *frame; - void *restorer; - int err = 0; - - stack_top &= -8UL; - frame = (struct sigframe *) stack_top - 1; - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - return 1; - - restorer = (void *) frame->retcode; - if(ka->sa.sa_flags & SA_RESTORER) - restorer = ka->sa.sa_restorer; - - err |= __put_user(restorer, &frame->pretcode); - err |= __put_user(sig, &frame->sig); - err |= copy_sc_to_user(&frame->sc, NULL, regs); - err |= __put_user(mask->sig[0], &frame->sc.oldmask); - if (_NSIG_WORDS > 1) - err |= __copy_to_user(&frame->extramask, &mask->sig[1], - sizeof(frame->extramask)); - - /* - * This is popl %eax ; movl $,%eax ; int $0x80 - * - * WE DO NOT USE IT ANY MORE! It's only left here for historical - * reasons and because gdb uses it as a signature to notice - * signal handler stack frames. - */ - err |= __put_user(0xb858, (short __user *)(frame->retcode+0)); - err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2)); - err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); - - if(err) - return(err); - - PT_REGS_SP(regs) = (unsigned long) frame; - PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; - PT_REGS_EAX(regs) = (unsigned long) sig; - PT_REGS_EDX(regs) = (unsigned long) 0; - PT_REGS_ECX(regs) = (unsigned long) 0; - - if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) - ptrace_notify(SIGTRAP); - return(0); -} - -int setup_signal_stack_si(unsigned long stack_top, int sig, - struct k_sigaction *ka, struct pt_regs *regs, - siginfo_t *info, sigset_t *mask) -{ - struct rt_sigframe __user *frame; - void *restorer; - int err = 0; - - stack_top &= -8UL; - frame = (struct rt_sigframe *) stack_top - 1; - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - return 1; - - restorer = (void *) frame->retcode; - if(ka->sa.sa_flags & SA_RESTORER) - restorer = ka->sa.sa_restorer; - - err |= __put_user(restorer, &frame->pretcode); - err |= __put_user(sig, &frame->sig); - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); - err |= copy_siginfo_to_user(&frame->info, info); - err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, - PT_REGS_SP(regs)); - - /* - * This is movl $,%eax ; int $0x80 - * - * WE DO NOT USE IT ANY MORE! It's only left here for historical - * reasons and because gdb uses it as a signature to notice - * signal handler stack frames. - */ - err |= __put_user(0xb8, (char __user *)(frame->retcode+0)); - err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1)); - err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); - - if(err) - return(err); - - PT_REGS_SP(regs) = (unsigned long) frame; - PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; - PT_REGS_EAX(regs) = (unsigned long) sig; - PT_REGS_EDX(regs) = (unsigned long) &frame->info; - PT_REGS_ECX(regs) = (unsigned long) &frame->uc; - - if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) - ptrace_notify(SIGTRAP); - return(0); -} - -long sys_sigreturn(struct pt_regs regs) -{ - unsigned long sp = PT_REGS_SP(¤t->thread.regs); - struct sigframe __user *frame = (struct sigframe *)(sp - 8); - sigset_t set; - struct sigcontext __user *sc = &frame->sc; - unsigned long __user *oldmask = &sc->oldmask; - unsigned long __user *extramask = frame->extramask; - int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); - - if(copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) || - copy_from_user(&set.sig[1], extramask, sig_size)) - goto segfault; - - sigdelsetmask(&set, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if(copy_sc_from_user(¤t->thread.regs, sc)) - goto segfault; - - /* Avoid ERESTART handling */ - PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; - return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); - - segfault: - force_sig(SIGSEGV, current); - return 0; -} - -long sys_rt_sigreturn(struct pt_regs regs) -{ - unsigned long __user sp = PT_REGS_SP(¤t->thread.regs); - struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4); - sigset_t set; - struct ucontext __user *uc = &frame->uc; - int sig_size = _NSIG_WORDS * sizeof(unsigned long); - - if(copy_from_user(&set, &uc->uc_sigmask, sig_size)) - goto segfault; - - sigdelsetmask(&set, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) - goto segfault; - - /* Avoid ERESTART handling */ - PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; - return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); - - segfault: - force_sig(SIGSEGV, current); - return 0; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S deleted file mode 100644 index 6a70d9ab5c2..00000000000 --- a/arch/um/sys-i386/stub.S +++ /dev/null @@ -1,51 +0,0 @@ -#include "uml-config.h" - - .globl syscall_stub -.section .__syscall_stub, "x" - - .globl batch_syscall_stub -batch_syscall_stub: - /* load pointer to first operation */ - mov $(UML_CONFIG_STUB_DATA+8), %esp - -again: - /* load length of additional data */ - mov 0x0(%esp), %eax - - /* if(length == 0) : end of list */ - /* write possible 0 to header */ - mov %eax, UML_CONFIG_STUB_DATA+4 - cmpl $0, %eax - jz done - - /* save current pointer */ - mov %esp, UML_CONFIG_STUB_DATA+4 - - /* skip additional data */ - add %eax, %esp - - /* load syscall-# */ - pop %eax - - /* load syscall params */ - pop %ebx - pop %ecx - pop %edx - pop %esi - pop %edi - pop %ebp - - /* execute syscall */ - int $0x80 - - /* check return value */ - pop %ebx - cmp %ebx, %eax - je again - -done: - /* save return value */ - mov %eax, UML_CONFIG_STUB_DATA - - /* stop */ - int3 diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c deleted file mode 100644 index 1e88b275eda..00000000000 --- a/arch/um/sys-i386/stub_segv.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include <asm/signal.h> -#include <asm/unistd.h> -#include "uml-config.h" -#include "sysdep/sigcontext.h" -#include "sysdep/faultinfo.h" - -void __attribute__ ((__section__ (".__syscall_stub"))) -stub_segv_handler(int sig) -{ - struct sigcontext *sc = (struct sigcontext *) (&sig + 1); - - GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA), - sc); - - __asm__("movl %0, %%eax ; int $0x80": : "g" (__NR_getpid)); - __asm__("movl %%eax, %%ebx ; movl %0, %%eax ; movl %1, %%ecx ;" - "int $0x80": : "g" (__NR_kill), "g" (SIGUSR1)); - /* Load pointer to sigcontext into esp, since we need to leave - * the stack in its original form when we do the sigreturn here, by - * hand. - */ - __asm__("mov %0,%%esp ; movl %1, %%eax ; " - "int $0x80" : : "a" (sc), "g" (__NR_sigreturn)); -} diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S deleted file mode 100644 index ad75c27afe3..00000000000 --- a/arch/um/sys-i386/sys_call_table.S +++ /dev/null @@ -1,16 +0,0 @@ -#include <linux/linkage.h> -/* Steal i386 syscall table for our purposes, but with some slight changes.*/ - -#define sys_iopl sys_ni_syscall -#define sys_ioperm sys_ni_syscall - -#define sys_vm86old sys_ni_syscall -#define sys_vm86 sys_ni_syscall -#define sys_set_thread_area sys_ni_syscall -#define sys_get_thread_area sys_ni_syscall - -#define sys_stime um_stime -#define sys_time um_time -#define old_mmap old_mmap_i386 - -#include "../../i386/kernel/syscall_table.S" diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c deleted file mode 100644 index 83e9be820a8..00000000000 --- a/arch/um/sys-i386/syscalls.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "linux/shm.h" -#include "asm/ipc.h" -#include "asm/mman.h" -#include "asm/uaccess.h" -#include "asm/unistd.h" - -/* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux/i386 didn't use to be able to handle more than - * 4 system call parameters, so these system calls used a memory - * block for parameter passing.. - */ - -struct mmap_arg_struct { - unsigned long addr; - unsigned long len; - unsigned long prot; - unsigned long flags; - unsigned long fd; - unsigned long offset; -}; - -extern int old_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long offset); - -long old_mmap_i386(struct mmap_arg_struct __user *arg) -{ - struct mmap_arg_struct a; - int err = -EFAULT; - - if (copy_from_user(&a, arg, sizeof(a))) - goto out; - - err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); - out: - return err; -} - -struct sel_arg_struct { - unsigned long n; - fd_set __user *inp; - fd_set __user *outp; - fd_set __user *exp; - struct timeval __user *tvp; -}; - -long old_select(struct sel_arg_struct __user *arg) -{ - struct sel_arg_struct a; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - /* sys_select() does the appropriate kernel locking */ - return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); -} - -/* The i386 version skips reading from %esi, the fourth argument. So we must do - * this, too. - */ -long sys_clone(unsigned long clone_flags, unsigned long newsp, - int __user *parent_tid, int unused, int __user *child_tid) -{ - long ret; - - if (!newsp) - newsp = UPT_SP(¤t->thread.regs.regs); - current->thread.forking = 1; - ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, - child_tid); - current->thread.forking = 0; - return(ret); -} - -/* - * sys_ipc() is the de-multiplexer for the SysV IPC calls.. - * - * This is really horribly ugly. - */ -long sys_ipc (uint call, int first, int second, - int third, void __user *ptr, long fifth) -{ - int version, ret; - - version = call >> 16; /* hack for backward compatibility */ - call &= 0xffff; - - switch (call) { - case SEMOP: - return sys_semtimedop(first, (struct sembuf *) ptr, second, - NULL); - case SEMTIMEDOP: - return sys_semtimedop(first, (struct sembuf *) ptr, second, - (const struct timespec *) fifth); - case SEMGET: - return sys_semget (first, second, third); - case SEMCTL: { - union semun fourth; - if (!ptr) - return -EINVAL; - if (get_user(fourth.__pad, (void **) ptr)) - return -EFAULT; - return sys_semctl (first, second, third, fourth); - } - - case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); - case MSGRCV: - switch (version) { - case 0: { - struct ipc_kludge tmp; - if (!ptr) - return -EINVAL; - - if (copy_from_user(&tmp, - (struct ipc_kludge *) ptr, - sizeof (tmp))) - return -EFAULT; - return sys_msgrcv (first, tmp.msgp, second, - tmp.msgtyp, third); - } - default: - panic("msgrcv with version != 0"); - return sys_msgrcv (first, - (struct msgbuf *) ptr, - second, fifth, third); - } - case MSGGET: - return sys_msgget ((key_t) first, second); - case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); - - case SHMAT: - switch (version) { - default: { - ulong raddr; - ret = do_shmat (first, (char *) ptr, second, &raddr); - if (ret) - return ret; - return put_user (raddr, (ulong *) third); - } - case 1: /* iBCS2 emulator entry point */ - if (!segment_eq(get_fs(), get_ds())) - return -EINVAL; - return do_shmat (first, (char *) ptr, second, (ulong *) third); - } - case SHMDT: - return sys_shmdt ((char *)ptr); - case SHMGET: - return sys_shmget (first, second, third); - case SHMCTL: - return sys_shmctl (first, second, - (struct shmid_ds *) ptr); - default: - return -ENOSYS; - } -} - -long sys_sigaction(int sig, const struct old_sigaction __user *act, - struct old_sigaction __user *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset_t mask; - if (!access_ok(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c deleted file mode 100644 index d5244f07053..00000000000 --- a/arch/um/sys-i386/sysrq.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/config.h" -#include "linux/kernel.h" -#include "linux/smp.h" -#include "linux/sched.h" -#include "linux/kallsyms.h" -#include "asm/ptrace.h" -#include "sysrq.h" - -/* This is declared by <linux/sched.h> */ -void show_regs(struct pt_regs *regs) -{ - printk("\n"); - printk("EIP: %04lx:[<%08lx>] CPU: %d %s", - 0xffff & PT_REGS_CS(regs), PT_REGS_IP(regs), - smp_processor_id(), print_tainted()); - if (PT_REGS_CS(regs) & 3) - printk(" ESP: %04lx:%08lx", 0xffff & PT_REGS_SS(regs), - PT_REGS_SP(regs)); - printk(" EFLAGS: %08lx\n %s\n", PT_REGS_EFLAGS(regs), - print_tainted()); - printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", - PT_REGS_EAX(regs), PT_REGS_EBX(regs), - PT_REGS_ECX(regs), - PT_REGS_EDX(regs)); - printk("ESI: %08lx EDI: %08lx EBP: %08lx", - PT_REGS_ESI(regs), PT_REGS_EDI(regs), - PT_REGS_EBP(regs)); - printk(" DS: %04lx ES: %04lx\n", - 0xffff & PT_REGS_DS(regs), - 0xffff & PT_REGS_ES(regs)); - - show_trace(NULL, (unsigned long *) ®s); -} - -/* Copied from i386. */ -static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) -{ - return p > (void *)tinfo && - p < (void *)tinfo + THREAD_SIZE - 3; -} - -/* Adapted from i386 (we also print the address we read from). */ -static inline unsigned long print_context_stack(struct thread_info *tinfo, - unsigned long *stack, unsigned long ebp) -{ - unsigned long addr; - -#ifdef CONFIG_FRAME_POINTER - while (valid_stack_ptr(tinfo, (void *)ebp)) { - addr = *(unsigned long *)(ebp + 4); - printk("%08lx: [<%08lx>]", ebp + 4, addr); - print_symbol(" %s", addr); - printk("\n"); - ebp = *(unsigned long *)ebp; - } -#else - while (valid_stack_ptr(tinfo, stack)) { - addr = *stack; - if (__kernel_text_address(addr)) { - printk("%08lx: [<%08lx>]", (unsigned long) stack, addr); - print_symbol(" %s", addr); - printk("\n"); - } - stack++; - } -#endif - return ebp; -} - -void show_trace(struct task_struct* task, unsigned long * stack) -{ - unsigned long ebp; - struct thread_info *context; - - /* Turn this into BUG_ON if possible. */ - if (!stack) { - stack = (unsigned long*) &stack; - printk("show_trace: got NULL stack, implicit assumption task == current"); - WARN_ON(1); - } - - if (!task) - task = current; - - if (task != current) { - ebp = (unsigned long) KSTK_EBP(task); - } else { - asm ("movl %%ebp, %0" : "=r" (ebp) : ); - } - - context = (struct thread_info *) - ((unsigned long)stack & (~(THREAD_SIZE - 1))); - print_context_stack(context, stack, ebp); - - printk("\n"); -} - diff --git a/arch/um/sys-i386/unmap.c b/arch/um/sys-i386/unmap.c deleted file mode 100644 index 1b0ad0e4adc..00000000000 --- a/arch/um/sys-i386/unmap.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <linux/mman.h> -#include <asm/unistd.h> - -static int errno; - -static inline _syscall2(int,munmap,void *,start,size_t,len) -static inline _syscall6(void *,mmap2,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset) -int switcheroo(int fd, int prot, void *from, void *to, int size) -{ - if(munmap(to, size) < 0){ - return(-1); - } - if(mmap2(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1 ){ - return(-1); - } - if(munmap(from, size) < 0){ - return(-1); - } - return(0); -} diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c deleted file mode 100644 index 26b68675053..00000000000 --- a/arch/um/sys-i386/user-offsets.c +++ /dev/null @@ -1,70 +0,0 @@ -#include <stdio.h> -#include <signal.h> -#include <asm/ptrace.h> -#include <asm/user.h> -#include <linux/stddef.h> - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define DEFINE_LONGS(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long))) - -#define OFFSET(sym, str, mem) \ - DEFINE(sym, offsetof(struct str, mem)); - -void foo(void) -{ - OFFSET(HOST_SC_IP, sigcontext, eip); - OFFSET(HOST_SC_SP, sigcontext, esp); - OFFSET(HOST_SC_FS, sigcontext, fs); - OFFSET(HOST_SC_GS, sigcontext, gs); - OFFSET(HOST_SC_DS, sigcontext, ds); - OFFSET(HOST_SC_ES, sigcontext, es); - OFFSET(HOST_SC_SS, sigcontext, ss); - OFFSET(HOST_SC_CS, sigcontext, cs); - OFFSET(HOST_SC_EFLAGS, sigcontext, eflags); - OFFSET(HOST_SC_EAX, sigcontext, eax); - OFFSET(HOST_SC_EBX, sigcontext, ebx); - OFFSET(HOST_SC_ECX, sigcontext, ecx); - OFFSET(HOST_SC_EDX, sigcontext, edx); - OFFSET(HOST_SC_EDI, sigcontext, edi); - OFFSET(HOST_SC_ESI, sigcontext, esi); - OFFSET(HOST_SC_EBP, sigcontext, ebp); - OFFSET(HOST_SC_TRAPNO, sigcontext, trapno); - OFFSET(HOST_SC_ERR, sigcontext, err); - OFFSET(HOST_SC_CR2, sigcontext, cr2); - OFFSET(HOST_SC_FPSTATE, sigcontext, fpstate); - OFFSET(HOST_SC_SIGMASK, sigcontext, oldmask); - OFFSET(HOST_SC_FP_CW, _fpstate, cw); - OFFSET(HOST_SC_FP_SW, _fpstate, sw); - OFFSET(HOST_SC_FP_TAG, _fpstate, tag); - OFFSET(HOST_SC_FP_IPOFF, _fpstate, ipoff); - OFFSET(HOST_SC_FP_CSSEL, _fpstate, cssel); - OFFSET(HOST_SC_FP_DATAOFF, _fpstate, dataoff); - OFFSET(HOST_SC_FP_DATASEL, _fpstate, datasel); - OFFSET(HOST_SC_FP_ST, _fpstate, _st); - OFFSET(HOST_SC_FXSR_ENV, _fpstate, _fxsr_env); - - DEFINE(HOST_FRAME_SIZE, FRAME_SIZE); - DEFINE_LONGS(HOST_FP_SIZE, sizeof(struct user_i387_struct)); - DEFINE_LONGS(HOST_XFP_SIZE, sizeof(struct user_fxsr_struct)); - - DEFINE(HOST_IP, EIP); - DEFINE(HOST_SP, UESP); - DEFINE(HOST_EFLAGS, EFL); - DEFINE(HOST_EAX, EAX); - DEFINE(HOST_EBX, EBX); - DEFINE(HOST_ECX, ECX); - DEFINE(HOST_EDX, EDX); - DEFINE(HOST_ESI, ESI); - DEFINE(HOST_EDI, EDI); - DEFINE(HOST_EBP, EBP); - DEFINE(HOST_CS, CS); - DEFINE(HOST_SS, SS); - DEFINE(HOST_DS, DS); - DEFINE(HOST_FS, FS); - DEFINE(HOST_ES, ES); - DEFINE(HOST_GS, GS); - DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); -} diff --git a/arch/um/sys-ia64/sysdep/ptrace.h b/arch/um/sys-ia64/sysdep/ptrace.h new file mode 100644 index 00000000000..0f0f4e6fd33 --- /dev/null +++ b/arch/um/sys-ia64/sysdep/ptrace.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_IA64_PTRACE_H +#define __SYSDEP_IA64_PTRACE_H + +struct sys_pt_regs { + int foo; +}; + +#define EMPTY_REGS { 0 } + +#endif + diff --git a/arch/um/sys-ia64/sysdep/sigcontext.h b/arch/um/sys-ia64/sysdep/sigcontext.h new file mode 100644 index 00000000000..76b43161e77 --- /dev/null +++ b/arch/um/sys-ia64/sysdep/sigcontext.h @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_IA64_SIGCONTEXT_H +#define __SYSDEP_IA64_SIGCONTEXT_H + +#endif + diff --git a/arch/um/include/sysdep-ia64/skas_ptrace.h b/arch/um/sys-ia64/sysdep/skas_ptrace.h index 25a38e71570..25a38e71570 100644 --- a/arch/um/include/sysdep-ia64/skas_ptrace.h +++ b/arch/um/sys-ia64/sysdep/skas_ptrace.h diff --git a/arch/um/sys-ia64/sysdep/syscalls.h b/arch/um/sys-ia64/sysdep/syscalls.h new file mode 100644 index 00000000000..5f6700c4155 --- /dev/null +++ b/arch/um/sys-ia64/sysdep/syscalls.h @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_IA64_SYSCALLS_H +#define __SYSDEP_IA64_SYSCALLS_H + +#endif + diff --git a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile index af200268fdd..20d363bd700 100644 --- a/arch/um/sys-ppc/Makefile +++ b/arch/um/sys-ppc/Makefile @@ -1,12 +1,12 @@ OBJ = built-in.o .S.o: - $(CC) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o + $(CC) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o -OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \ +OBJS = ptrace.o sigcontext.o checksum.o miscthings.o misc.o \ ptrace_user.o sysrq.o -EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(TOPDIR)/arch/ppc/kernel +asflags-y := -DCONFIG_PPC32 -I. -I$(srctree)/arch/ppc/kernel all: $(OBJ) @@ -15,32 +15,28 @@ $(OBJ): $(OBJS) $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ ptrace_user.o: ptrace_user.c - $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(ccflags-y) -c -o $@ $< sigcontext.o: sigcontext.c - $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< - -semaphore.c: - rm -f $@ - ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ + $(CC) $(USER_CFLAGS) $(ccflags-y) -c -o $@ $< checksum.S: rm -f $@ - ln -s $(TOPDIR)/arch/ppc/lib/$@ $@ + ln -s $(srctree)/arch/ppc/lib/$@ $@ mk_defs.c: rm -f $@ - ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ + ln -s $(srctree)/arch/ppc/kernel/$@ $@ ppc_defs.head: rm -f $@ - ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ + ln -s $(srctree)/arch/ppc/kernel/$@ $@ ppc_defs.h: mk_defs.c ppc_defs.head \ - $(TOPDIR)/include/asm-ppc/mmu.h \ - $(TOPDIR)/include/asm-ppc/processor.h \ - $(TOPDIR)/include/asm-ppc/pgtable.h \ - $(TOPDIR)/include/asm-ppc/ptrace.h + $(srctree)/include/asm-ppc/mmu.h \ + $(srctree)/include/asm-ppc/processor.h \ + $(srctree)/include/asm-ppc/pgtable.h \ + $(srctree)/include/asm-ppc/ptrace.h # $(CC) $(CFLAGS) -S mk_defs.c cp ppc_defs.head ppc_defs.h # for bk, this way we can write to the file even if it's not checked out @@ -56,14 +52,14 @@ ppc_defs.h: mk_defs.c ppc_defs.head \ checksum.o: checksum.S rm -f asm - ln -s $(TOPDIR)/include/asm-ppc asm - $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o + ln -s $(srctree)/include/asm-ppc asm + $(CC) $(asflags-y) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o rm -f asm misc.o: misc.S ppc_defs.h rm -f asm - ln -s $(TOPDIR)/include/asm-ppc asm - $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o + ln -s $(srctree)/include/asm-ppc asm + $(CC) $(asflags-y) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o rm -f asm -clean-files := $(OBJS) ppc_defs.h checksum.S semaphore.c mk_defs.c +clean-files := $(OBJS) ppc_defs.h checksum.S mk_defs.c diff --git a/arch/um/sys-ppc/asm/archparam.h b/arch/um/sys-ppc/asm/archparam.h new file mode 100644 index 00000000000..4269d8a37b4 --- /dev/null +++ b/arch/um/sys-ppc/asm/archparam.h @@ -0,0 +1,8 @@ +#ifndef __UM_ARCHPARAM_PPC_H +#define __UM_ARCHPARAM_PPC_H + +/********* Bits for asm-um/string.h **********/ + +#define __HAVE_ARCH_STRRCHR + +#endif diff --git a/arch/um/sys-ppc/asm/elf.h b/arch/um/sys-ppc/asm/elf.h new file mode 100644 index 00000000000..8aacaf56508 --- /dev/null +++ b/arch/um/sys-ppc/asm/elf.h @@ -0,0 +1,51 @@ +#ifndef __UM_ELF_PPC_H +#define __UM_ELF_PPC_H + + +extern long elf_aux_hwcap; +#define ELF_HWCAP (elf_aux_hwcap) + +#define SET_PERSONALITY(ex) do ; while(0) + +#define ELF_EXEC_PAGESIZE 4096 + +#define elf_check_arch(x) (1) + +#ifdef CONFIG_64BIT +#define ELF_CLASS ELFCLASS64 +#else +#define ELF_CLASS ELFCLASS32 +#endif + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + +#define ELF_PLATFORM (0) + +#define ELF_ET_DYN_BASE (0x08000000) + +/* the following stolen from asm-ppc/elf.h */ +#define ELF_NGREG 48 /* includes nip, msr, lr, etc. */ +#define ELF_NFPREG 33 /* includes fpscr */ +/* General registers */ +typedef unsigned long elf_greg_t; +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +/* Floating point registers */ +typedef double elf_fpreg_t; +typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_PPC + +#endif diff --git a/arch/um/sys-ppc/asm/processor.h b/arch/um/sys-ppc/asm/processor.h new file mode 100644 index 00000000000..95932315122 --- /dev/null +++ b/arch/um/sys-ppc/asm/processor.h @@ -0,0 +1,15 @@ +#ifndef __UM_PROCESSOR_PPC_H +#define __UM_PROCESSOR_PPC_H + +#if defined(__ASSEMBLY__) + +#define CONFIG_PPC_MULTIPLATFORM +#include "arch/processor.h" + +#else + +#include "asm/processor-generic.h" + +#endif + +#endif diff --git a/arch/um/sys-ppc/misc.S b/arch/um/sys-ppc/misc.S index 11b7bd768cf..1364b7da578 100644 --- a/arch/um/sys-ppc/misc.S +++ b/arch/um/sys-ppc/misc.S @@ -15,7 +15,6 @@ * */ -#include <linux/config.h> #include <asm/processor.h> #include "ppc_asm.h" @@ -23,14 +22,10 @@ #define CACHE_LINE_SIZE 16 #define LG_CACHE_LINE_SIZE 4 #define MAX_COPY_PREFETCH 1 -#elif !defined(CONFIG_PPC64BRIDGE) +#else #define CACHE_LINE_SIZE 32 #define LG_CACHE_LINE_SIZE 5 #define MAX_COPY_PREFETCH 4 -#else -#define CACHE_LINE_SIZE 128 -#define LG_CACHE_LINE_SIZE 7 -#define MAX_COPY_PREFETCH 1 #endif /* CONFIG_4xx || CONFIG_8xx */ .text diff --git a/arch/um/sys-ppc/miscthings.c b/arch/um/sys-ppc/miscthings.c index 373061c5012..25908d26ce0 100644 --- a/arch/um/sys-ppc/miscthings.c +++ b/arch/um/sys-ppc/miscthings.c @@ -1,6 +1,6 @@ -#include "linux/threads.h" -#include "linux/stddef.h" // for NULL -#include "linux/elf.h" // for AT_NULL +#include <linux/threads.h> +#include <linux/stddef.h> // for NULL +#include <linux/elf.h> // for AT_NULL /* The following function nicked from arch/ppc/kernel/process.c and * adapted slightly */ @@ -40,14 +40,3 @@ void shove_aux_table(unsigned long sp) } /* END stuff taken from arch/ppc/kernel/process.c */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-ppc/ptrace.c b/arch/um/sys-ppc/ptrace.c index 8e71b47f2b8..8245df41b20 100644 --- a/arch/um/sys-ppc/ptrace.c +++ b/arch/um/sys-ppc/ptrace.c @@ -1,4 +1,4 @@ -#include "linux/sched.h" +#include <linux/sched.h> #include "asm/ptrace.h" int putreg(struct task_struct *child, unsigned long regno, @@ -56,13 +56,3 @@ int peek_user(struct task_struct *child, long addr, long data) return put_user(tmp, (unsigned long *) data); } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-ppc/ptrace_user.c b/arch/um/sys-ppc/ptrace_user.c index ff0b9c077a1..4601b9296aa 100644 --- a/arch/um/sys-ppc/ptrace_user.c +++ b/arch/um/sys-ppc/ptrace_user.c @@ -1,6 +1,6 @@ #include <errno.h> #include <asm/ptrace.h> -#include "sysdep/ptrace.h" +#include <sysdep/ptrace.h> int ptrace_getregs(long pid, unsigned long *regs_out) { @@ -27,13 +27,3 @@ int ptrace_setregs(long pid, unsigned long *regs_in) } return 0; } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-ppc/ptrace.h b/arch/um/sys-ppc/shared/sysdep/ptrace.h index 8a27353733a..efe0c1a3ea9 100644 --- a/arch/um/include/sysdep-ppc/ptrace.h +++ b/arch/um/sys-ppc/shared/sysdep/ptrace.h @@ -5,8 +5,7 @@ #ifndef __SYS_PTRACE_PPC_H #define __SYS_PTRACE_PPC_H -#include "linux/config.h" -#include "linux/types.h" +#include <linux/types.h> /* the following taken from <asm-ppc/ptrace.h> */ @@ -92,13 +91,3 @@ extern void shove_aux_table(unsigned long sp); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-ppc/sigcontext.h b/arch/um/sys-ppc/shared/sysdep/sigcontext.h index f20d965de9c..b7286f0a1e0 100644 --- a/arch/um/include/sysdep-ppc/sigcontext.h +++ b/arch/um/sys-ppc/shared/sysdep/sigcontext.h @@ -50,13 +50,3 @@ #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-ppc/skas_ptrace.h b/arch/um/sys-ppc/shared/sysdep/skas_ptrace.h index d9fbbac10de..d9fbbac10de 100644 --- a/arch/um/include/sysdep-ppc/skas_ptrace.h +++ b/arch/um/sys-ppc/shared/sysdep/skas_ptrace.h diff --git a/arch/um/include/sysdep-ppc/syscalls.h b/arch/um/sys-ppc/shared/sysdep/syscalls.h index 679df351e19..1ff81552251 100644 --- a/arch/um/include/sysdep-ppc/syscalls.h +++ b/arch/um/sys-ppc/shared/sysdep/syscalls.h @@ -41,13 +41,3 @@ int old_mmap(unsigned long addr, unsigned long len, #define LAST_ARCH_SYSCALL __NR_fadvise64 -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-ppc/sigcontext.c b/arch/um/sys-ppc/sigcontext.c index 5d430fc994a..aac6c83fe44 100644 --- a/arch/um/sys-ppc/sigcontext.c +++ b/arch/um/sys-ppc/sigcontext.c @@ -1,15 +1,4 @@ #include "asm/ptrace.h" #include "asm/sigcontext.h" -#include "sysdep/ptrace.h" -#include "user_util.h" +#include <sysdep/ptrace.h> -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-ppc/sysrq.c b/arch/um/sys-ppc/sysrq.c index 2f816f1a0ff..1ff1ad7f27d 100644 --- a/arch/um/sys-ppc/sysrq.c +++ b/arch/um/sys-ppc/sysrq.c @@ -3,14 +3,16 @@ * Licensed under the GPL */ -#include "linux/kernel.h" -#include "linux/smp.h" +#include <linux/kernel.h> +#include <linux/smp.h> #include "asm/ptrace.h" #include "sysrq.h" void show_regs(struct pt_regs_subarch *regs) { printk("\n"); + show_regs_print_info(KERN_DEFAULT); + printk("show_regs(): insert regs here.\n"); #if 0 printk("\n"); diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile deleted file mode 100644 index ea977df395a..00000000000 --- a/arch/um/sys-x86_64/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright 2003 PathScale, Inc. -# -# Licensed under the GPL -# - -#XXX: why into lib-y? -lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o ldt.o mem.o memcpy.o \ - ptrace.o ptrace_user.o sigcontext.o signal.o stub.o \ - stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o - -obj-y := ksyms.o -obj-$(CONFIG_MODULES) += module.o um_module.o - -USER_OBJS := ptrace_user.o sigcontext.o - -SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c ldt.c memcpy.S \ - thunk.S module.c - -include arch/um/scripts/Makefile.rules - -bitops.c-dir = lib -csum-copy.S-dir = lib -csum-partial.c-dir = lib -csum-wrappers.c-dir = lib -ldt.c-dir = /arch/um/sys-i386 -memcpy.S-dir = lib -thunk.S-dir = lib -module.c-dir = kernel - -$(obj)/stub_segv.o: _c_flags = $(call unprofile,$(CFLAGS)) - -include arch/um/scripts/Makefile.unmap diff --git a/arch/um/sys-x86_64/bugs.c b/arch/um/sys-x86_64/bugs.c deleted file mode 100644 index fdce7ea98ca..00000000000 --- a/arch/um/sys-x86_64/bugs.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "linux/errno.h" -#include "asm/system.h" -#include "asm/pda.h" -#include "sysdep/ptrace.h" -#include "os.h" - -void arch_init_thread(void) -{ -} - -void arch_check_bugs(void) -{ -} - -int arch_handle_signal(int sig, union uml_pt_regs *regs) -{ - return(0); -} - -#define MAXTOKEN 64 - -/* Set during early boot */ -int host_has_cmov = 1; -int host_has_xmm = 0; - -static char token(int fd, char *buf, int len, char stop) -{ - int n; - char *ptr, *end, c; - - ptr = buf; - end = &buf[len]; - do { - n = os_read_file(fd, ptr, sizeof(*ptr)); - c = *ptr++; - if(n != sizeof(*ptr)){ - if(n == 0) return(0); - printk("Reading /proc/cpuinfo failed, err = %d\n", -n); - if(n < 0) - return(n); - else - return(-EIO); - } - } while((c != '\n') && (c != stop) && (ptr < end)); - - if(ptr == end){ - printk("Failed to find '%c' in /proc/cpuinfo\n", stop); - return(-1); - } - *(ptr - 1) = '\0'; - return(c); -} - -static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) -{ - int n; - char c; - - scratch[len - 1] = '\0'; - while(1){ - c = token(fd, scratch, len - 1, ':'); - if(c <= 0) - return(0); - else if(c != ':'){ - printk("Failed to find ':' in /proc/cpuinfo\n"); - return(0); - } - - if(!strncmp(scratch, key, strlen(key))) - return(1); - - do { - n = os_read_file(fd, &c, sizeof(c)); - if(n != sizeof(c)){ - printk("Failed to find newline in " - "/proc/cpuinfo, err = %d\n", -n); - return(0); - } - } while(c != '\n'); - } - return(0); -} - -int cpu_feature(char *what, char *buf, int len) -{ - int fd, ret = 0; - - fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); - return(0); - } - - if(!find_cpuinfo_line(fd, what, buf, len)){ - printk("Couldn't find '%s' line in /proc/cpuinfo\n", what); - goto out_close; - } - - token(fd, buf, len, '\n'); - ret = 1; - - out_close: - os_close_file(fd); - return(ret); -} - -/* Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-x86_64/delay.c b/arch/um/sys-x86_64/delay.c deleted file mode 100644 index 137f4446b43..00000000000 --- a/arch/um/sys-x86_64/delay.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * Copied from arch/x86_64 - * - * Licensed under the GPL - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <asm/processor.h> -#include <asm/param.h> - -void __delay(unsigned long loops) -{ - unsigned long i; - - for(i = 0; i < loops; i++) - cpu_relax(); -} - -void __udelay(unsigned long usecs) -{ - unsigned long i, n; - - n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) - cpu_relax(); -} - -EXPORT_SYMBOL(__udelay); - -void __const_udelay(unsigned long usecs) -{ - unsigned long i, n; - - n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) - cpu_relax(); -} - -EXPORT_SYMBOL(__const_udelay); diff --git a/arch/um/sys-x86_64/fault.c b/arch/um/sys-x86_64/fault.c deleted file mode 100644 index cee1513c5c3..00000000000 --- a/arch/um/sys-x86_64/fault.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include "user.h" - -int arch_fixup(unsigned long address, void *sc_ptr) -{ - /* XXX search_exception_tables() */ - return(0); -} - -/* Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-x86_64/kernel-offsets.c b/arch/um/sys-x86_64/kernel-offsets.c deleted file mode 100644 index bfcb104b846..00000000000 --- a/arch/um/sys-x86_64/kernel-offsets.c +++ /dev/null @@ -1,25 +0,0 @@ -#include <linux/config.h> -#include <linux/stddef.h> -#include <linux/sched.h> -#include <linux/time.h> -#include <linux/elf.h> -#include <asm/page.h> - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define DEFINE_STR1(x) #x -#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " DEFINE_STR1(val) " " #val: : ) - -#define BLANK() asm volatile("\n->" : : ) - -#define OFFSET(sym, str, mem) \ - DEFINE(sym, offsetof(struct str, mem)); - -void foo(void) -{ -#ifdef CONFIG_MODE_TT - OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid); -#endif -#include <common-offsets.h> -} diff --git a/arch/um/sys-x86_64/ksyms.c b/arch/um/sys-x86_64/ksyms.c deleted file mode 100644 index 85927380820..00000000000 --- a/arch/um/sys-x86_64/ksyms.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "linux/module.h" -#include "linux/in6.h" -#include "linux/rwsem.h" -#include "asm/byteorder.h" -#include "asm/semaphore.h" -#include "asm/uaccess.h" -#include "asm/checksum.h" -#include "asm/errno.h" - -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__down_failed_trylock); -EXPORT_SYMBOL(__up_wakeup); - -/*XXX: we need them because they would be exported by x86_64 */ -EXPORT_SYMBOL(__memcpy); - -/* Networking helper routines. */ -EXPORT_SYMBOL(ip_compute_csum); diff --git a/arch/um/sys-x86_64/mem.c b/arch/um/sys-x86_64/mem.c deleted file mode 100644 index 3f59a0a4f15..00000000000 --- a/arch/um/sys-x86_64/mem.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include "linux/mm.h" -#include "asm/page.h" -#include "asm/mman.h" - -unsigned long vm_stack_flags = __VM_STACK_FLAGS; -unsigned long vm_stack_flags32 = __VM_STACK_FLAGS; -unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS; -unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS; -unsigned long vm_force_exec32 = PROT_EXEC; - -/* Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c deleted file mode 100644 index 74eee5c7c6d..00000000000 --- a/arch/um/sys-x86_64/ptrace.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#define __FRAME_OFFSETS -#include <asm/ptrace.h> -#include <linux/sched.h> -#include <linux/errno.h> -#include <asm/uaccess.h> -#include <asm/elf.h> - -/* XXX x86_64 */ -unsigned long not_ss; -unsigned long not_ds; -unsigned long not_es; - -#define SC_SS(r) (not_ss) -#define SC_DS(r) (not_ds) -#define SC_ES(r) (not_es) - -/* determines which flags the user has access to. */ -/* 1 = access 0 = no access */ -#define FLAG_MASK 0x44dd5UL - -int putreg(struct task_struct *child, int regno, unsigned long value) -{ - unsigned long tmp; - -#ifdef TIF_IA32 - /* Some code in the 64bit emulation may not be 64bit clean. - Don't take any chances. */ - if (test_tsk_thread_flag(child, TIF_IA32)) - value &= 0xffffffff; -#endif - switch (regno){ - case FS: - case GS: - case DS: - case ES: - case SS: - case CS: - if (value && (value & 3) != 3) - return -EIO; - value &= 0xffff; - break; - - case FS_BASE: - case GS_BASE: - if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) - return -EIO; - break; - - case EFLAGS: - value &= FLAG_MASK; - tmp = PT_REGS_EFLAGS(&child->thread.regs) & ~FLAG_MASK; - value |= tmp; - break; - } - - PT_REGS_SET(&child->thread.regs, regno, value); - return 0; -} - -int poke_user(struct task_struct *child, long addr, long data) -{ - if ((addr & 3) || addr < 0) - return -EIO; - - if (addr < MAX_REG_OFFSET) - return putreg(child, addr, data); - -#if 0 /* Need x86_64 debugregs handling */ - else if((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - if((addr == 4) || (addr == 5)) return -EIO; - child->thread.arch.debugregs[addr] = data; - return 0; - } -#endif - return -EIO; -} - -unsigned long getreg(struct task_struct *child, int regno) -{ - unsigned long retval = ~0UL; - switch (regno) { - case FS: - case GS: - case DS: - case ES: - case SS: - case CS: - retval = 0xffff; - /* fall through */ - default: - retval &= PT_REG(&child->thread.regs, regno); -#ifdef TIF_IA32 - if (test_tsk_thread_flag(child, TIF_IA32)) - retval &= 0xffffffff; -#endif - } - return retval; -} - -int peek_user(struct task_struct *child, long addr, long data) -{ - /* read the word at location addr in the USER area. */ - unsigned long tmp; - - if ((addr & 3) || addr < 0) - return -EIO; - - tmp = 0; /* Default return condition */ - if(addr < MAX_REG_OFFSET){ - tmp = getreg(child, addr); - } -#if 0 /* Need x86_64 debugregs handling */ - else if((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - tmp = child->thread.arch.debugregs[addr]; - } -#endif - return put_user(tmp, (unsigned long *) data); -} - -void arch_switch(void) -{ -/* XXX - printk("arch_switch\n"); -*/ -} - -int is_syscall(unsigned long addr) -{ - panic("is_syscall"); -} - -int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) -{ - panic("dump_fpu"); - return(1); -} - -int get_fpregs(unsigned long buf, struct task_struct *child) -{ - panic("get_fpregs"); - return(0); -} - -int set_fpregs(unsigned long buf, struct task_struct *child) -{ - panic("set_fpregs"); - return(0); -} - -int get_fpxregs(unsigned long buf, struct task_struct *tsk) -{ - panic("get_fpxregs"); - return(0); -} - -int set_fpxregs(unsigned long buf, struct task_struct *tsk) -{ - panic("set_fxpregs"); - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-x86_64/ptrace_user.c b/arch/um/sys-x86_64/ptrace_user.c deleted file mode 100644 index 12e404c6fa4..00000000000 --- a/arch/um/sys-x86_64/ptrace_user.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include <stddef.h> -#include <errno.h> -#include "ptrace_user.h" -#include "user.h" -#include "kern_constants.h" - -int ptrace_getregs(long pid, unsigned long *regs_out) -{ - if(ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) - return(-errno); - return(0); -} - -int ptrace_setregs(long pid, unsigned long *regs) -{ - if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) - return(-errno); - return(0); -} - -void ptrace_pokeuser(unsigned long addr, unsigned long data) -{ - panic("ptrace_pokeuser"); -} - -#define DS 184 -#define ES 192 -#define __USER_DS 0x2b - -void arch_enter_kernel(void *task, int pid) -{ -} - -void arch_leave_kernel(void *task, int pid) -{ -#ifdef UM_USER_CS - if(ptrace(PTRACE_POKEUSR, pid, CS, UM_USER_CS) < 0) - printk("POKEUSR CS failed"); -#endif - - if(ptrace(PTRACE_POKEUSR, pid, DS, __USER_DS) < 0) - printk("POKEUSR DS failed"); - if(ptrace(PTRACE_POKEUSR, pid, ES, __USER_DS) < 0) - printk("POKEUSR ES failed"); -} diff --git a/arch/um/sys-x86_64/sigcontext.c b/arch/um/sys-x86_64/sigcontext.c deleted file mode 100644 index c88e64def6f..00000000000 --- a/arch/um/sys-x86_64/sigcontext.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include <stdio.h> -#include <string.h> -#include <signal.h> -#include "user.h" - -void sc_to_sc(void *to_ptr, void *from_ptr) -{ - struct sigcontext *to = to_ptr, *from = from_ptr; - int size = sizeof(*to); /* + sizeof(struct _fpstate); */ - - memcpy(to, from, size); - if(from->fpstate != NULL) - to->fpstate = (struct _fpstate *) (to + 1); - - to->fpstate = NULL; -} - -unsigned long *sc_sigmask(void *sc_ptr) -{ - struct sigcontext *sc = sc_ptr; - - return(&sc->oldmask); -} - -/* Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c deleted file mode 100644 index fe1d065332b..00000000000 --- a/arch/um/sys-x86_64/signal.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (C) 2003 PathScale, Inc. - * Licensed under the GPL - */ - -#include "linux/stddef.h" -#include "linux/errno.h" -#include "linux/personality.h" -#include "linux/ptrace.h" -#include "asm/current.h" -#include "asm/uaccess.h" -#include "asm/sigcontext.h" -#include "asm/ptrace.h" -#include "asm/arch/ucontext.h" -#include "choose-mode.h" -#include "sysdep/ptrace.h" -#include "frame_kern.h" - -#ifdef CONFIG_MODE_SKAS - -#include "skas.h" - -static int copy_sc_from_user_skas(struct pt_regs *regs, - struct sigcontext *from) -{ - int err = 0; - -#define GETREG(regs, regno, sc, regname) \ - __get_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \ - &(sc)->regname) - - err |= GETREG(regs, R8, from, r8); - err |= GETREG(regs, R9, from, r9); - err |= GETREG(regs, R10, from, r10); - err |= GETREG(regs, R11, from, r11); - err |= GETREG(regs, R12, from, r12); - err |= GETREG(regs, R13, from, r13); - err |= GETREG(regs, R14, from, r14); - err |= GETREG(regs, R15, from, r15); - err |= GETREG(regs, RDI, from, rdi); - err |= GETREG(regs, RSI, from, rsi); - err |= GETREG(regs, RBP, from, rbp); - err |= GETREG(regs, RBX, from, rbx); - err |= GETREG(regs, RDX, from, rdx); - err |= GETREG(regs, RAX, from, rax); - err |= GETREG(regs, RCX, from, rcx); - err |= GETREG(regs, RSP, from, rsp); - err |= GETREG(regs, RIP, from, rip); - err |= GETREG(regs, EFLAGS, from, eflags); - err |= GETREG(regs, CS, from, cs); - -#undef GETREG - - return(err); -} - -int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, - struct pt_regs *regs, unsigned long mask) -{ - struct faultinfo * fi = ¤t->thread.arch.faultinfo; - int err = 0; - - err |= __put_user(0, &to->gs); - err |= __put_user(0, &to->fs); - -#define PUTREG(regs, regno, sc, regname) \ - __put_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \ - &(sc)->regname) - - err |= PUTREG(regs, RDI, to, rdi); - err |= PUTREG(regs, RSI, to, rsi); - err |= PUTREG(regs, RBP, to, rbp); - err |= PUTREG(regs, RSP, to, rsp); - err |= PUTREG(regs, RBX, to, rbx); - err |= PUTREG(regs, RDX, to, rdx); - err |= PUTREG(regs, RCX, to, rcx); - err |= PUTREG(regs, RAX, to, rax); - err |= PUTREG(regs, R8, to, r8); - err |= PUTREG(regs, R9, to, r9); - err |= PUTREG(regs, R10, to, r10); - err |= PUTREG(regs, R11, to, r11); - err |= PUTREG(regs, R12, to, r12); - err |= PUTREG(regs, R13, to, r13); - err |= PUTREG(regs, R14, to, r14); - err |= PUTREG(regs, R15, to, r15); - err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */ - - err |= __put_user(fi->cr2, &to->cr2); - err |= __put_user(fi->error_code, &to->err); - err |= __put_user(fi->trap_no, &to->trapno); - - err |= PUTREG(regs, RIP, to, rip); - err |= PUTREG(regs, EFLAGS, to, eflags); -#undef PUTREG - - err |= __put_user(mask, &to->oldmask); - - return(err); -} - -#endif - -#ifdef CONFIG_MODE_TT -int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, - int fpsize) -{ - struct _fpstate *to_fp, *from_fp; - unsigned long sigs; - int err; - - to_fp = to->fpstate; - sigs = to->oldmask; - err = copy_from_user(to, from, sizeof(*to)); - from_fp = to->fpstate; - to->fpstate = to_fp; - to->oldmask = sigs; - if(to_fp != NULL) - err |= copy_from_user(to_fp, from_fp, fpsize); - return(err); -} - -int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, - struct sigcontext *from, int fpsize) -{ - struct _fpstate *to_fp, *from_fp; - int err; - - to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); - from_fp = from->fpstate; - err = copy_to_user(to, from, sizeof(*to)); - if(from_fp != NULL){ - err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); - err |= copy_to_user(to_fp, from_fp, fpsize); - } - return(err); -} - -#endif - -static int copy_sc_from_user(struct pt_regs *to, void __user *from) -{ - int ret; - - ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, - sizeof(struct _fpstate)), - copy_sc_from_user_skas(to, from)); - return(ret); -} - -static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, - struct pt_regs *from, unsigned long mask) -{ - return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), - sizeof(*fp)), - copy_sc_to_user_skas(to, fp, from, mask))); -} - -struct rt_sigframe -{ - char *pretcode; - struct ucontext uc; - struct siginfo info; -}; - -#define round_down(m, n) (((m) / (n)) * (n)) - -int setup_signal_stack_si(unsigned long stack_top, int sig, - struct k_sigaction *ka, struct pt_regs * regs, - siginfo_t *info, sigset_t *set) -{ - struct rt_sigframe __user *frame; - struct _fpstate __user *fp = NULL; - int err = 0; - struct task_struct *me = current; - - frame = (struct rt_sigframe __user *) - round_down(stack_top - sizeof(struct rt_sigframe), 16) - 8; - frame = (struct rt_sigframe *) ((unsigned long) frame - 128); - - if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) - goto out; - -#if 0 /* XXX */ - if (save_i387(fp) < 0) - err |= -1; -#endif - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto out; - - if (ka->sa.sa_flags & SA_SIGINFO) { - err |= copy_siginfo_to_user(&frame->info, info); - if (err) - goto out; - } - - /* Create the ucontext. */ - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)), - &frame->uc.uc_stack.ss_flags); - err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); - err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); - if (sizeof(*set) == 16) { - __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); - __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); - } - else - err |= __copy_to_user(&frame->uc.uc_sigmask, set, - sizeof(*set)); - - /* Set up to return from userspace. If provided, use a stub - already in userspace. */ - /* x86-64 should always use SA_RESTORER. */ - if (ka->sa.sa_flags & SA_RESTORER) - err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); - else - /* could use a vstub here */ - goto out; - - if (err) - goto out; - - /* Set up registers for signal handler */ - { - struct exec_domain *ed = current_thread_info()->exec_domain; - if (unlikely(ed && ed->signal_invmap && sig < 32)) - sig = ed->signal_invmap[sig]; - } - - PT_REGS_RDI(regs) = sig; - /* In case the signal handler was declared without prototypes */ - PT_REGS_RAX(regs) = 0; - - /* This also works for non SA_SIGINFO handlers because they expect the - next argument after the signal number on the stack. */ - PT_REGS_RSI(regs) = (unsigned long) &frame->info; - PT_REGS_RDX(regs) = (unsigned long) &frame->uc; - PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; - - PT_REGS_RSP(regs) = (unsigned long) frame; - out: - return(err); -} - -long sys_rt_sigreturn(struct pt_regs *regs) -{ - unsigned long sp = PT_REGS_SP(¤t->thread.regs); - struct rt_sigframe __user *frame = - (struct rt_sigframe __user *)(sp - 8); - struct ucontext __user *uc = &frame->uc; - sigset_t set; - - if(copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) - goto segfault; - - sigdelsetmask(&set, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) - goto segfault; - - /* Avoid ERESTART handling */ - PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; - return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); - - segfault: - force_sig(SIGSEGV, current); - return 0; -} -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S deleted file mode 100644 index 03c27973578..00000000000 --- a/arch/um/sys-x86_64/stub.S +++ /dev/null @@ -1,66 +0,0 @@ -#include "uml-config.h" - - .globl syscall_stub -.section .__syscall_stub, "x" -syscall_stub: - syscall - /* We don't have 64-bit constants, so this constructs the address - * we need. - */ - movq $(UML_CONFIG_STUB_DATA >> 32), %rbx - salq $32, %rbx - movq $(UML_CONFIG_STUB_DATA & 0xffffffff), %rcx - or %rcx, %rbx - movq %rax, (%rbx) - int3 - - .globl batch_syscall_stub -batch_syscall_stub: - mov $(UML_CONFIG_STUB_DATA >> 32), %rbx - sal $32, %rbx - mov $(UML_CONFIG_STUB_DATA & 0xffffffff), %rax - or %rax, %rbx - /* load pointer to first operation */ - mov %rbx, %rsp - add $0x10, %rsp -again: - /* load length of additional data */ - mov 0x0(%rsp), %rax - - /* if(length == 0) : end of list */ - /* write possible 0 to header */ - mov %rax, 8(%rbx) - cmp $0, %rax - jz done - - /* save current pointer */ - mov %rsp, 8(%rbx) - - /* skip additional data */ - add %rax, %rsp - - /* load syscall-# */ - pop %rax - - /* load syscall params */ - pop %rdi - pop %rsi - pop %rdx - pop %r10 - pop %r8 - pop %r9 - - /* execute syscall */ - syscall - - /* check return value */ - pop %rcx - cmp %rcx, %rax - je again - -done: - /* save return value */ - mov %rax, (%rbx) - - /* stop */ - int3 diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c deleted file mode 100644 index d1e53bdf2e8..00000000000 --- a/arch/um/sys-x86_64/stub_segv.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include <asm/signal.h> -#include <linux/compiler.h> -#include <asm/unistd.h> -#include <asm/ucontext.h> -#include "uml-config.h" -#include "sysdep/sigcontext.h" -#include "sysdep/faultinfo.h" -#include <stddef.h> - -/* Copied from sys-x86_64/signal.c - Can't find an equivalent definition - * in the libc headers anywhere. - */ -struct rt_sigframe -{ - char *pretcode; - struct ucontext uc; - struct siginfo info; -}; - -/* Copied here from <linux/kernel.h> - we're userspace. */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -void __attribute__ ((__section__ (".__syscall_stub"))) -stub_segv_handler(int sig) -{ - struct ucontext *uc; - - __asm__("movq %%rdx, %0" : "=g" (uc) :); - GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA), - &uc->uc_mcontext); - - __asm__("movq %0, %%rax ; syscall": : "g" (__NR_getpid)); - __asm__("movq %%rax, %%rdi ; movq %0, %%rax ; movq %1, %%rsi ;" - "syscall": : "g" (__NR_kill), "g" (SIGUSR1) : - "%rdi", "%rax", "%rsi"); - /* sys_sigreturn expects that the stack pointer will be 8 bytes into - * the signal frame. So, we use the ucontext pointer, which we know - * already, to get the signal frame pointer, and add 8 to that. - */ - __asm__("movq %0, %%rsp": : - "g" ((unsigned long) container_of(uc, struct rt_sigframe, - uc) + 8)); - __asm__("movq %0, %%rax ; syscall" : : "g" (__NR_rt_sigreturn)); -} diff --git a/arch/um/sys-x86_64/syscall_table.c b/arch/um/sys-x86_64/syscall_table.c deleted file mode 100644 index 34b2e842864..00000000000 --- a/arch/um/sys-x86_64/syscall_table.c +++ /dev/null @@ -1,59 +0,0 @@ -/* System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c - * with some changes for UML. */ - -#include <linux/linkage.h> -#include <linux/sys.h> -#include <linux/cache.h> -#include <linux/config.h> - -#define __NO_STUBS - -/* Below you can see, in terms of #define's, the differences between the x86-64 - * and the UML syscall table. */ - -/* Not going to be implemented by UML, since we have no hardware. */ -#define stub_iopl sys_ni_syscall -#define sys_ioperm sys_ni_syscall - -/* The UML TLS problem. Note that x86_64 does not implement this, so the below - * is needed only for the ia32 compatibility. */ -/*#define sys_set_thread_area sys_ni_syscall -#define sys_get_thread_area sys_ni_syscall*/ - -/* For __NR_time. The x86-64 name hopefully will change from sys_time64 to - * sys_time (since the current situation is bogus). I've sent a patch to cleanup - * this. Remove below the obsoleted line. */ -#define sys_time64 um_time -#define sys_time um_time - -/* On UML we call it this way ("old" means it's not mmap2) */ -#define sys_mmap old_mmap -/* On x86-64 sys_uname is actually sys_newuname plus a compatibility trick. - * See arch/x86_64/kernel/sys_x86_64.c */ -#define sys_uname sys_uname64 - -#define stub_clone sys_clone -#define stub_fork sys_fork -#define stub_vfork sys_vfork -#define stub_execve sys_execve -#define stub_rt_sigsuspend sys_rt_sigsuspend -#define stub_sigaltstack sys_sigaltstack -#define stub_rt_sigreturn sys_rt_sigreturn - -#define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ; -#undef _ASM_X86_64_UNISTD_H_ -#include <asm-x86_64/unistd.h> - -#undef __SYSCALL -#define __SYSCALL(nr, sym) [ nr ] = sym, -#undef _ASM_X86_64_UNISTD_H_ - -typedef void (*sys_call_ptr_t)(void); - -extern void sys_ni_syscall(void); - -sys_call_ptr_t sys_call_table[__NR_syscall_max+1] __cacheline_aligned = { - /* Smells like a like a compiler bug -- it doesn't work when the & below is removed. */ - [0 ... __NR_syscall_max] = &sys_ni_syscall, -#include <asm-x86_64/unistd.h> -}; diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c deleted file mode 100644 index 6acee5c4ada..00000000000 --- a/arch/um/sys-x86_64/syscalls.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include "linux/linkage.h" -#include "linux/slab.h" -#include "linux/shm.h" -#include "linux/utsname.h" -#include "linux/personality.h" -#include "asm/uaccess.h" -#define __FRAME_OFFSETS -#include "asm/ptrace.h" -#include "asm/unistd.h" -#include "asm/prctl.h" /* XXX This should get the constants from libc */ -#include "choose-mode.h" -#include "kern.h" - -asmlinkage long sys_uname64(struct new_utsname __user * name) -{ - int err; - down_read(&uts_sem); - err = copy_to_user(name, &system_utsname, sizeof (*name)); - up_read(&uts_sem); - if (personality(current->personality) == PER_LINUX32) - err |= copy_to_user(&name->machine, "i686", 5); - return err ? -EFAULT : 0; -} - -#ifdef CONFIG_MODE_TT -extern long arch_prctl(int code, unsigned long addr); - -static long arch_prctl_tt(int code, unsigned long addr) -{ - unsigned long tmp; - long ret; - - switch(code){ - case ARCH_SET_GS: - case ARCH_SET_FS: - ret = arch_prctl(code, addr); - break; - case ARCH_GET_FS: - case ARCH_GET_GS: - ret = arch_prctl(code, (unsigned long) &tmp); - if(!ret) - ret = put_user(tmp, &addr); - break; - default: - ret = -EINVAL; - break; - } - - return(ret); -} -#endif - -#ifdef CONFIG_MODE_SKAS - -/* XXX: Must also call arch_prctl in the host, beside saving the segment bases! */ -static long arch_prctl_skas(int code, unsigned long addr) -{ - long ret = 0; - - switch(code){ - case ARCH_SET_FS: - current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr; - break; - case ARCH_SET_GS: - current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr; - break; - case ARCH_GET_FS: - ret = put_user(current->thread.regs.regs.skas. - regs[FS_BASE / sizeof(unsigned long)], - (unsigned long __user *)addr); - break; - case ARCH_GET_GS: - ret = put_user(current->thread.regs.regs.skas. - regs[GS_BASE / sizeof(unsigned long)], - (unsigned long __user *)addr); - break; - default: - ret = -EINVAL; - break; - } - - return(ret); -} -#endif - -long sys_arch_prctl(int code, unsigned long addr) -{ - return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr)); -} - -long sys_clone(unsigned long clone_flags, unsigned long newsp, - void __user *parent_tid, void __user *child_tid) -{ - long ret; - - if (!newsp) - newsp = UPT_SP(¤t->thread.regs.regs); - current->thread.forking = 1; - ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, - child_tid); - current->thread.forking = 0; - return(ret); -} diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c deleted file mode 100644 index d0a25af19a5..00000000000 --- a/arch/um/sys-x86_64/sysrq.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include "linux/kernel.h" -#include "linux/utsname.h" -#include "linux/module.h" -#include "asm/current.h" -#include "asm/ptrace.h" -#include "sysrq.h" - -void __show_regs(struct pt_regs * regs) -{ - printk("\n"); - print_modules(); - printk("Pid: %d, comm: %.20s %s %s\n", - current->pid, current->comm, print_tainted(), system_utsname.release); - printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff, - PT_REGS_RIP(regs)); - printk("\nRSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs), - PT_REGS_EFLAGS(regs)); - printk("RAX: %016lx RBX: %016lx RCX: %016lx\n", - PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs)); - printk("RDX: %016lx RSI: %016lx RDI: %016lx\n", - PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs)); - printk("RBP: %016lx R08: %016lx R09: %016lx\n", - PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs)); - printk("R10: %016lx R11: %016lx R12: %016lx\n", - PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs)); - printk("R13: %016lx R14: %016lx R15: %016lx\n", - PT_REGS_R13(regs), PT_REGS_R14(regs), PT_REGS_R15(regs)); -} - -void show_regs(struct pt_regs *regs) -{ - __show_regs(regs); - show_trace(current, (unsigned long *) ®s); -} diff --git a/arch/um/sys-x86_64/um_module.c b/arch/um/sys-x86_64/um_module.c deleted file mode 100644 index 8b8eff1bd97..00000000000 --- a/arch/um/sys-x86_64/um_module.c +++ /dev/null @@ -1,19 +0,0 @@ -#include <linux/vmalloc.h> -#include <linux/moduleloader.h> - -/*Copied from i386 arch/i386/kernel/module.c */ -void *module_alloc(unsigned long size) -{ - if (size == 0) - return NULL; - return vmalloc_exec(size); -} - -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) -{ - vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ -} - diff --git a/arch/um/sys-x86_64/unmap.c b/arch/um/sys-x86_64/unmap.c deleted file mode 100644 index f4a4bffd8a1..00000000000 --- a/arch/um/sys-x86_64/unmap.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <linux/mman.h> -#include <asm/unistd.h> - -static int errno; - -static inline _syscall2(int,munmap,void *,start,size_t,len) -static inline _syscall6(void *,mmap,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset) -int switcheroo(int fd, int prot, void *from, void *to, int size) -{ - if(munmap(to, size) < 0){ - return(-1); - } - if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1){ - return(-1); - } - if(munmap(from, size) < 0){ - return(-1); - } - return(0); -} diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c deleted file mode 100644 index 5a585bfbb8c..00000000000 --- a/arch/um/sys-x86_64/user-offsets.c +++ /dev/null @@ -1,91 +0,0 @@ -#include <stdio.h> -#include <stddef.h> -#include <signal.h> -#define __FRAME_OFFSETS -#include <asm/ptrace.h> -#include <asm/types.h> -/* For some reason, x86_64 defines u64 and u32 only in <pci/types.h>, which I - * refuse to include here, even though they're used throughout the headers. - * These are used in asm/user.h, and that include can't be avoided because of - * the sizeof(struct user_regs_struct) below. - */ -typedef __u64 u64; -typedef __u32 u32; -#include <asm/user.h> - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define DEFINE_LONGS(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long))) - -#define OFFSET(sym, str, mem) \ - DEFINE(sym, offsetof(struct str, mem)); - -void foo(void) -{ - OFFSET(HOST_SC_RBX, sigcontext, rbx); - OFFSET(HOST_SC_RCX, sigcontext, rcx); - OFFSET(HOST_SC_RDX, sigcontext, rdx); - OFFSET(HOST_SC_RSI, sigcontext, rsi); - OFFSET(HOST_SC_RDI, sigcontext, rdi); - OFFSET(HOST_SC_RBP, sigcontext, rbp); - OFFSET(HOST_SC_RAX, sigcontext, rax); - OFFSET(HOST_SC_R8, sigcontext, r8); - OFFSET(HOST_SC_R9, sigcontext, r9); - OFFSET(HOST_SC_R10, sigcontext, r10); - OFFSET(HOST_SC_R11, sigcontext, r11); - OFFSET(HOST_SC_R12, sigcontext, r12); - OFFSET(HOST_SC_R13, sigcontext, r13); - OFFSET(HOST_SC_R14, sigcontext, r14); - OFFSET(HOST_SC_R15, sigcontext, r15); - OFFSET(HOST_SC_IP, sigcontext, rip); - OFFSET(HOST_SC_SP, sigcontext, rsp); - OFFSET(HOST_SC_CR2, sigcontext, cr2); - OFFSET(HOST_SC_ERR, sigcontext, err); - OFFSET(HOST_SC_TRAPNO, sigcontext, trapno); - OFFSET(HOST_SC_CS, sigcontext, cs); - OFFSET(HOST_SC_FS, sigcontext, fs); - OFFSET(HOST_SC_GS, sigcontext, gs); - OFFSET(HOST_SC_EFLAGS, sigcontext, eflags); - OFFSET(HOST_SC_SIGMASK, sigcontext, oldmask); -#if 0 - OFFSET(HOST_SC_ORIG_RAX, sigcontext, orig_rax); - OFFSET(HOST_SC_DS, sigcontext, ds); - OFFSET(HOST_SC_ES, sigcontext, es); - OFFSET(HOST_SC_SS, sigcontext, ss); -#endif - - DEFINE_LONGS(HOST_FRAME_SIZE, FRAME_SIZE); - DEFINE(HOST_FP_SIZE, 0); - DEFINE(HOST_XFP_SIZE, 0); - DEFINE_LONGS(HOST_RBX, RBX); - DEFINE_LONGS(HOST_RCX, RCX); - DEFINE_LONGS(HOST_RDI, RDI); - DEFINE_LONGS(HOST_RSI, RSI); - DEFINE_LONGS(HOST_RDX, RDX); - DEFINE_LONGS(HOST_RBP, RBP); - DEFINE_LONGS(HOST_RAX, RAX); - DEFINE_LONGS(HOST_R8, R8); - DEFINE_LONGS(HOST_R9, R9); - DEFINE_LONGS(HOST_R10, R10); - DEFINE_LONGS(HOST_R11, R11); - DEFINE_LONGS(HOST_R12, R12); - DEFINE_LONGS(HOST_R13, R13); - DEFINE_LONGS(HOST_R14, R14); - DEFINE_LONGS(HOST_R15, R15); - DEFINE_LONGS(HOST_ORIG_RAX, ORIG_RAX); - DEFINE_LONGS(HOST_CS, CS); - DEFINE_LONGS(HOST_SS, SS); - DEFINE_LONGS(HOST_EFLAGS, EFLAGS); -#if 0 - DEFINE_LONGS(HOST_FS, FS); - DEFINE_LONGS(HOST_GS, GS); - DEFINE_LONGS(HOST_DS, DS); - DEFINE_LONGS(HOST_ES, ES); -#endif - - DEFINE_LONGS(HOST_IP, RIP); - DEFINE_LONGS(HOST_SP, RSP); - DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); -} |
