Creation of Cybook 2416 (actually Gen4) repository

This commit is contained in:
mlt
2009-12-18 17:10:00 +00:00
committed by godzil
commit 76f20f4d40
13791 changed files with 6812321 additions and 0 deletions

350
arch/um/Kconfig Normal file
View File

@@ -0,0 +1,350 @@
config DEFCONFIG_LIST
string
option defconfig_list
default "arch/$ARCH/defconfig"
# UML uses the generic IRQ sugsystem
config GENERIC_HARDIRQS
bool
default y
config UML
bool
default y
config MMU
bool
default y
config NO_IOMEM
def_bool y
mainmenu "Linux/Usermode Kernel Configuration"
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
# Used in kernel/irq/manage.c and include/linux/irq.h
config IRQ_RELEASE_METHOD
bool
default y
menu "UML-specific options"
config MODE_TT
bool "Tracing thread support (DEPRECATED)"
default n
depends on BROKEN
help
This option controls whether tracing thread support is compiled
into UML. This option is largely obsolete, given that skas0 provides
skas security and performance without needing to patch the host.
It is safe to say 'N' here; saying 'Y' may cause additional problems
with the resulting binary even if you run UML in SKAS mode, and running
in TT mode is strongly *NOT RECOMMENDED*.
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.
Additionally, this option enables using higher memory spaces (up to
2.75G) for UML - disabling CONFIG_MODE_TT and enabling this option leads
to best results for this.
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" if MODE_TT
default y
help
This option controls whether skas (separate kernel address space)
support is compiled in.
Unless you have specific needs to use TT mode (which applies almost only
to developers), you should say Y here.
SKAS mode will make use of the SKAS3 patch if it is applied on the host
(and your UML will run in SKAS3 mode), but if no SKAS patch is applied
on the host it will run in SKAS0 mode, which is anyway faster than TT
mode.
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)"
depends on 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.
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
#SMP_BROKEN is for x86_64.
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 (EXPERIMENTAL)"
depends on !64BIT && EXPERIMENTAL
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 to disable TT mode (i.e.
CONFIG_MODE_TT) and 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 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
noticeable lag. If this is a problem, then disable this option.
endmenu
source "init/Kconfig"
source "drivers/block/Kconfig"
source "arch/um/Kconfig.char"
source "drivers/base/Kconfig"
source "net/Kconfig"
source "arch/um/Kconfig.net"
source "drivers/net/Kconfig"
source "drivers/connector/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"

238
arch/um/Kconfig.char Normal file
View File

@@ -0,0 +1,238 @@
menu "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
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.
See <http://user-mode-linux.sourceforge.net/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.
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.
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.
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.
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.
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.
config NOCONFIG_CHAN
bool
default !(XTERM_CHAN && TTY_CHAN && PTY_CHAN && PORT_CHAN && NULL_CHAN)
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.
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.
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 RAW_DRIVER
tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)"
help
The raw driver permits block devices to be bound to /dev/raw/rawN.
Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
See the raw(8) manpage for more details.
The raw driver is deprecated and will be removed soon.
Applications should simply open the device (eg /dev/hda1)
with the O_DIRECT flag.
config MAX_RAW_DEVS
int "Maximum number of RAW devices to support (1-8192)"
depends on RAW_DRIVER
default "256"
help
The maximum number of RAW devices that are supported.
Default is 256. Increase this number in case you need lots of
raw devices.
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
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.
config SOUND
tristate
default UML_SOUND
config HOSTAUDIO
tristate
default UML_SOUND
#It is selected elsewhere, so kconfig would warn without this.
config HW_RANDOM
tristate
default n
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

50
arch/um/Kconfig.debug Normal file
View File

@@ -0,0 +1,50 @@
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
help
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.
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
help
This option allows developers to retrieve coverage data from a UML
session.
See <http://user-mode-linux.sourceforge.net/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.
endmenu

93
arch/um/Kconfig.i386 Normal file
View File

@@ -0,0 +1,93 @@
menu "Host processor type and features"
source "arch/i386/Kconfig.cpu"
endmenu
config UML_X86
bool
default y
config 64BIT
bool
default n
config SEMAPHORE_SLEEPERS
bool
default y
choice
prompt "Host memory split"
default HOST_VMSPLIT_3G
help
This is needed when the host kernel on which you run has a non-default
(like 2G/2G) memory split, instead of the customary 3G/1G. If you did
not recompile your own kernel but use the default distro's one, you can
safely accept the "Default split" option.
It can be enabled on recent (>=2.6.16-rc2) vanilla kernels via
CONFIG_VM_SPLIT_*, or on previous kernels with special patches (-ck
patchset by Con Kolivas, or other ones) - option names match closely the
host CONFIG_VM_SPLIT_* ones.
A lower setting (where 1G/3G is lowest and 3G/1G is higher) will
tolerate even more "normal" host kernels, but an higher setting will be
stricter.
So, if you do not know what to do here, say 'Default split'.
config HOST_VMSPLIT_3G
bool "Default split (3G/1G user/kernel host split)"
config HOST_VMSPLIT_3G_OPT
bool "3G/1G user/kernel host split (for full 1G low memory)"
config HOST_VMSPLIT_2G
bool "2G/2G user/kernel host split"
config HOST_VMSPLIT_1G
bool "1G/3G user/kernel host split"
endchoice
config TOP_ADDR
hex
default 0xB0000000 if HOST_VMSPLIT_3G_OPT
default 0x78000000 if HOST_VMSPLIT_2G
default 0x40000000 if HOST_VMSPLIT_1G
default 0xC0000000
config 3_LEVEL_PGTABLES
bool "Three-level pagetables (EXPERIMENTAL)"
default n
depends on EXPERIMENTAL
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.
However, this it experimental on 32-bit architectures, so if unsure say
N (on x86-64 it's automatically enabled, instead, as it's safe there).
config STUB_CODE
hex
default 0xbfffe000 if !HOST_VMSPLIT_2G
default 0x7fffe000 if HOST_VMSPLIT_2G
config STUB_DATA
hex
default 0xbffff000 if !HOST_VMSPLIT_2G
default 0x7ffff000 if HOST_VMSPLIT_2G
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 GENERIC_HWEIGHT
bool
default y

180
arch/um/Kconfig.net Normal file
View File

@@ -0,0 +1,180 @@
menu "UML Network Devices"
depends on NET
# UML virtual driver
config UML_NET
bool "Virtual network device"
help
While the User-Mode port cannot directly talk to any physical
hardware devices, this choice and the following transport options
provide one or more virtual network devices through which the UML
kernels can talk to each other, the host, and with the host's help,
machines on the outside world.
For more information, including explanations of the networking and
sample configurations, see
<http://user-mode-linux.sourceforge.net/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
enable at least one of the following transport options to actually
make use of UML networking.
config UML_NET_ETHERTAP
bool "Ethertap transport"
depends on UML_NET
help
The Ethertap User-Mode Linux network transport allows a single
running UML to exchange packets with its host over one of the
host's Ethertap devices, such as /dev/tap0. Additional running
UMLs can use additional Ethertap devices, one per running UML.
While the UML believes it's on a (multi-device, broadcast) virtual
Ethernet network, it's in fact communicating over a point-to-point
link with the host.
To use this, your host kernel must have support for Ethertap
devices. Also, if your host kernel is 2.4.x, it must have
CONFIG_NETLINK_DEV configured as Y or M.
For more information, see
<http://user-mode-linux.sourceforge.net/networking.html> That site
has examples of the UML command line to use to enable Ethertap
networking.
If you'd like to set up an IP network with the host and/or the
outside world, say Y to this, the Daemon Transport and/or the
Slip Transport. You'll need at least one of them, but may choose
more than one without conflict. If you don't need UML networking,
say N.
config UML_NET_TUNTAP
bool "TUN/TAP transport"
depends on UML_NET
help
The UML TUN/TAP network transport allows a UML instance to exchange
packets with the host over a TUN/TAP device. This option will only
work with a 2.4 host, unless you've applied the TUN/TAP patch to
your 2.2 host kernel.
To use this transport, your host kernel must have support for TUN/TAP
devices, either built-in or as a module.
config UML_NET_SLIP
bool "SLIP transport"
depends on UML_NET
help
The slip User-Mode Linux network transport allows a running UML to
network with its host over a point-to-point link. Unlike Ethertap,
which can carry any Ethernet frame (and hence even non-IP packets),
the slip transport can only carry IP packets.
To use this, your host must support slip devices.
For more information, see
<http://user-mode-linux.sourceforge.net/networking.html>. That site
has examples of the UML command line to use to enable slip
networking, and details of a few quirks with it.
The Ethertap Transport is preferred over slip because of its
limitations. If you prefer slip, however, say Y here. Otherwise
choose the Multicast transport (to network multiple UMLs on
multiple hosts), Ethertap (to network with the host and the
outside world), and/or the Daemon transport (to network multiple
UMLs on a single host). You may choose more than one without
conflict. If you don't need UML networking, say N.
config UML_NET_DAEMON
bool "Daemon 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, but not to
the host.
To use this form of networking, you'll need to run the UML
networking daemon on the host.
For more information, see
<http://user-mode-linux.sourceforge.net/networking.html> That site
has examples of the UML command line to use to enable Daemon
networking.
If you'd like to set up a network with other UMLs on a single host,
say Y. If you need a network between UMLs on multiple physical
hosts, choose the Multicast Transport. To set up a network with
the host and/or other IP machines, say Y to the Ethertap or Slip
transports. You'll need at least one of them, but may choose
more than one without conflict. If you don't need UML networking,
say N.
config UML_NET_MCAST
bool "Multicast transport"
depends on UML_NET
help
This Multicast User-Mode Linux network transport allows multiple
UMLs (even ones running on different host machines!) to talk to
each other over a virtual ethernet network. However, it requires
at least one UML with one of the other transports to act as a
bridge if any of them need to be able to talk to their hosts or any
other IP machines.
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
has examples of the UML command line to use to enable Multicast
networking, and notes about the security of this approach.
If you need UMLs on multiple physical hosts to communicate as if
they shared an Ethernet network, say Y. If you need to communicate
with other IP machines, make sure you select one of the other
transports (possibly in addition to Multicast; they're not
exclusive). If you don't need to network UMLs say N to each of
the transports.
config UML_NET_PCAP
bool "pcap transport"
depends on UML_NET && EXPERIMENTAL
help
The pcap transport makes a pcap packet stream on the host look
like an ethernet device inside UML. This is useful for making
UML act as a network monitor for the host. You must have libcap
installed in order to build the pcap transport into UML.
For more information, see
<http://user-mode-linux.sourceforge.net/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
Y here. Otherwise, say N.
config UML_NET_SLIRP
bool "SLiRP transport"
depends on UML_NET
help
The SLiRP User-Mode Linux network transport allows a running UML
to network by invoking a program that can handle SLIP encapsulated
packets. This is commonly (but not limited to) the application
known as SLiRP, a program that can re-socket IP packets back onto
the host on which it is run. Only IP packets are supported,
unlike other network transports that can handle all Ethernet
frames. In general, slirp allows the UML the same IP connectivity
to the outside world that the host user is permitted, and unlike
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
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
connections passing through it (but is less secure).
To use this you should first have slirp compiled somewhere
accessible on the host, and have read its documentation. If you
don't need UML networking, say N.
Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
endmenu

58
arch/um/Kconfig.scsi Normal file
View File

@@ -0,0 +1,58 @@
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

53
arch/um/Kconfig.x86_64 Normal file
View File

@@ -0,0 +1,53 @@
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
config GENERIC_HWEIGHT
bool
default y

235
arch/um/Makefile Normal file
View File

@@ -0,0 +1,235 @@
#
# This file is included by the global makefile so that you can add your own
# architecture-specific flags and dependencies.
#
# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
ARCH_DIR := arch/um
OS := $(shell uname -s)
# We require bash because the vmlinux link and loader script cpp use bash
# features.
SHELL := /bin/bash
filechk_gen_header = $<
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 host_ldt.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)/include/$(mode))
MAKEFILES-INCL += $(foreach mode,$(um-modes-y),\
$(srctree)/$(ARCH_DIR)/Makefile-$(mode))
ifneq ($(MAKEFILES-INCL),)
include $(MAKEFILES-INCL)
endif
ARCH_INCLUDE := -I$(ARCH_DIR)/include
ifneq ($(KBUILD_SRC),)
ARCH_INCLUDE += -I$(srctree)/$(ARCH_DIR)/include
endif
SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH)
# -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 += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
$(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \
-Din6addr_loopback=kernel_in6addr_loopback
AFLAGS += $(ARCH_INCLUDE)
USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -D__KERNEL__,,\
$(patsubst -I%,,$(CFLAGS)))) $(ARCH_INCLUDE) $(MODE_INCLUDE) \
-D_FILE_OFFSET_BITS=64
include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
#This will adjust *FLAGS accordingly to the platform.
include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS)
# -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.
# These apply to kernelspace only.
KERNEL_DEFINES = -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \
-Dmktime=kernel_mktime $(ARCH_KERNEL_DEFINES)
CFLAGS += $(KERNEL_DEFINES)
CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
# These are needed for clean and mrproper, since in that case .config is not
# included; the values here are meaningless
CONFIG_NEST_LEVEL ?= 0
CONFIG_KERNEL_HALF_GIGS ?= 0
SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
PHONY += linux
all: linux
linux: vmlinux
@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 "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
archprepare: $(ARCH_SYMLINKS) $(ARCH_DIR)/include/user_constants.h
prepare: $(ARCH_DIR)/include/kern_constants.h
LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static
LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib
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,)
CPP_MODE-$(CONFIG_MODE_TT) := -DMODE_TT
CONFIG_KERNEL_STACK_ORDER ?= 2
STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
ifndef START
START = $(shell echo $$[ $(TOP_ADDR) - $(SIZE) ] )
endif
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.o
#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
#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
MRPROPER_FILES += $(ARCH_SYMLINKS)
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)mkdir -p $(objtree)/include/asm-um
$(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 $(objtree)/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
$(objtree)/$(ARCH_DIR)/include:
@echo ' MKDIR $@'
$(Q)mkdir -p $@
$(ARCH_DIR)/include/sysdep: $(objtree)/$(ARCH_DIR)/include
@echo ' SYMLINK $@'
ifneq ($(KBUILD_SRC),)
$(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
$(ARCH_DIR)/include/uml-config.h : include/linux/autoconf.h
$(call filechk,umlconfig)
$(ARCH_DIR)/sys-$(SUBARCH)/user-offsets.s: FORCE
$(Q)$(MAKE) $(build)=$(ARCH_DIR)/sys-$(SUBARCH) $@
define filechk_gen-asm-offsets
(set -e; \
echo "/*"; \
echo " * DO NOT MODIFY."; \
echo " *"; \
echo " * This file was generated by arch/$(ARCH)/Makefile"; \
echo " *"; \
echo " */"; \
echo ""; \
sed -ne "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"; \
echo ""; )
endef
$(ARCH_DIR)/include/user_constants.h: $(ARCH_DIR)/sys-$(SUBARCH)/user-offsets.s
$(call filechk,gen-asm-offsets)
$(ARCH_DIR)/include/kern_constants.h: $(objtree)/$(ARCH_DIR)/include
@echo ' SYMLINK $@'
$(Q)ln -sf ../../../include/asm-um/asm-offsets.h $@
export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS

39
arch/um/Makefile-i386 Normal file
View File

@@ -0,0 +1,39 @@
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)
AFLAGS += $(call cc-option,-m32)
LINK-y += $(call cc-option,-m32)
UML_OBJCOPYFLAGS += -F $(ELF_FORMAT)
export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UML_OBJCOPYFLAGS
endif
endif
ARCH_KERNEL_DEFINES += -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)
# Prevent sprintf in nfsd from being converted to strcpy and resulting in
# an unresolved reference.
cflags-y += -ffreestanding
CFLAGS += $(cflags-y)

1
arch/um/Makefile-ia64 Normal file
View File

@@ -0,0 +1 @@
START_ADDR = 0x1000000000000000

View File

@@ -0,0 +1,8 @@
#
# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
# To get a definition of F_SETSIG
USER_CFLAGS += -D_GNU_SOURCE -D_LARGEFILE64_SOURCE
CFLAGS += -D_LARGEFILE64_SOURCE

9
arch/um/Makefile-ppc Normal file
View File

@@ -0,0 +1,9 @@
ifeq ($(CONFIG_HOST_2G_2G), y)
START_ADDR = 0x80000000
else
START_ADDR = 0xc0000000
endif
ARCH_CFLAGS = -U__powerpc__ -D__UM_PPC__
# The arch is ppc, but the elf32 name is powerpc
ELF_SUBARCH = powerpc

12
arch/um/Makefile-skas Normal file
View File

@@ -0,0 +1,12 @@
#
# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
GPROF_OPT += -pg
GCOV_OPT += -fprofile-arcs -ftest-coverage
CFLAGS-$(CONFIG_GCOV) += $(GCOV_OPT)
CFLAGS-$(CONFIG_GPROF) += $(GPROF_OPT)
LINK-$(CONFIG_GCOV) += $(GCOV_OPT)
LINK-$(CONFIG_GPROF) += $(GPROF_OPT)

5
arch/um/Makefile-tt Normal file
View File

@@ -0,0 +1,5 @@
#
# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#

25
arch/um/Makefile-x86_64 Normal file
View File

@@ -0,0 +1,25 @@
# Copyright 2003 - 2004 Pathscale, Inc
# Released under the GPL
core-y += arch/um/sys-x86_64/ arch/x86_64/crypto/
START := 0x60000000
_extra_flags_ = -fno-builtin -m64
#We #undef __x86_64__ for kernelspace, not for userspace where
#it's needed for headers to work!
ARCH_KERNEL_DEFINES = -U__$(SUBARCH)__
CFLAGS += $(_extra_flags_)
CHECKFLAGS += -m64
AFLAGS += -m64
LDFLAGS += -m elf_x86_64
CPPFLAGS += -m64
ELF_ARCH := i386:x86-64
ELF_FORMAT := elf64-x86-64
# Not on all 64-bit distros /lib is a symlink to /lib64. PLD is an example.
LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib64
LINK-y += -m64

333
arch/um/config.release Normal file
View File

@@ -0,0 +1,333 @@
#
# 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

528
arch/um/defconfig Normal file
View File

@@ -0,0 +1,528 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.17-rc3
# Fri Apr 28 09:31:20 2006
#
CONFIG_GENERIC_HARDIRQS=y
CONFIG_UML=y
CONFIG_MMU=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_IRQ_RELEASE_METHOD=y
#
# UML-specific options
#
# CONFIG_MODE_TT is not set
# CONFIG_STATIC_LINK is not set
CONFIG_MODE_SKAS=y
#
# Host processor type and features
#
# CONFIG_M386 is not set
# CONFIG_M486 is not set
# CONFIG_M586 is not set
# CONFIG_M586TSC is not set
# CONFIG_M586MMX is not set
CONFIG_M686=y
# CONFIG_MPENTIUMII is not set
# CONFIG_MPENTIUMIII is not set
# CONFIG_MPENTIUMM is not set
# CONFIG_MPENTIUM4 is not set
# CONFIG_MK6 is not set
# CONFIG_MK7 is not set
# CONFIG_MK8 is not set
# CONFIG_MCRUSOE is not set
# CONFIG_MEFFICEON is not set
# CONFIG_MWINCHIPC6 is not set
# CONFIG_MWINCHIP2 is not set
# CONFIG_MWINCHIP3D is not set
# CONFIG_MGEODEGX1 is not set
# CONFIG_MGEODE_LX is not set
# CONFIG_MCYRIXIII is not set
# CONFIG_MVIAC3_2 is not set
# CONFIG_X86_GENERIC is not set
CONFIG_X86_CMPXCHG=y
CONFIG_X86_XADD=y
CONFIG_X86_L1_CACHE_SHIFT=5
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_X86_PPRO_FENCE=y
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
CONFIG_X86_BSWAP=y
CONFIG_X86_POPAD_OK=y
CONFIG_X86_CMPXCHG64=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
CONFIG_X86_TSC=y
CONFIG_UML_X86=y
# CONFIG_64BIT is not set
CONFIG_SEMAPHORE_SLEEPERS=y
# CONFIG_HOST_2G_2G 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_GENERIC_HWEIGHT=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_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_LD_SCRIPT_DYN=y
CONFIG_NET=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
# CONFIG_HOSTFS is not set
# CONFIG_HPPFS is not set
CONFIG_MCONSOLE=y
# CONFIG_MAGIC_SYSRQ is not set
CONFIG_NEST_LEVEL=0
# CONFIG_HIGHMEM is not set
CONFIG_KERNEL_STACK_ORDER=2
CONFIG_UML_REAL_TIME_CLOCK=y
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
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_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_UID16=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
#
# Loadable module support
#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
#
# Block layer
#
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# Block devices
#
CONFIG_BLK_DEV_UBD=y
# CONFIG_BLK_DEV_UBD_SYNC is not set
CONFIG_BLK_DEV_COW_COMMON=y
# CONFIG_MMAPPER is not set
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_INITRD is not set
# CONFIG_ATA_OVER_ETH 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
#
# Generic Driver Options
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
#
# Networking
#
#
# Networking options
#
# CONFIG_NETDEBUG is not set
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_FIB_HASH=y
# 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_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
# CONFIG_NETFILTER is not set
#
# DCCP Configuration (EXPERIMENTAL)
#
# CONFIG_IP_DCCP is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
# CONFIG_IP_SCTP is not set
#
# TIPC Configuration (EXPERIMENTAL)
#
# CONFIG_TIPC 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
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_IEEE80211 is not set
#
# 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_PCAP is not set
CONFIG_UML_NET_SLIRP=y
#
# Network device support
#
CONFIG_NETDEVICES=y
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=m
#
# PHY device support
#
#
# Wireless LAN (non-hamradio)
#
# CONFIG_NET_RADIO is not set
#
# 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
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
#
# Connector - unified userspace <-> kernelspace linker
#
# CONFIG_CONNECTOR 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_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
# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_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
# 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_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_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_CRC16 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_SLAB_LEAK is not set
# CONFIG_DEBUG_MUTEXES is not set
# 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_DEBUG_VM is not set
CONFIG_FRAME_POINTER=y
# CONFIG_UNWIND_INFO is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_GPROF is not set
# CONFIG_GCOV is not set

59
arch/um/drivers/Makefile Normal file
View File

@@ -0,0 +1,59 @@
#
# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
# pcap is broken in 2.5 because kbuild doesn't allow pcap.a to be linked
# in to pcap.o
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
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
hostaudio-objs := hostaudio_kern.o
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)
targets := pcap_kern.o pcap_user.o
$(obj)/pcap.o: $(obj)/pcap_kern.o $(obj)/pcap_user.o
$(LD) -r -dp -o $@ $^ $(LDFLAGS) $(LDFLAGS_pcap.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)
# When the above is fixed, don't forget to add this too!
#targets += $(obj)/pcap.o
obj-y := stdio_console.o fd.o chan_kern.o chan_user.o line.o
obj-$(CONFIG_SSL) += ssl.o
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_PCAP) += pcap.o
obj-$(CONFIG_UML_NET) += net.o
obj-$(CONFIG_MCONSOLE) += mconsole.o
obj-$(CONFIG_MMAPPER) += mmapper_kern.o
obj-$(CONFIG_BLK_DEV_UBD) += ubd.o
obj-$(CONFIG_HOSTAUDIO) += hostaudio.o
obj-$(CONFIG_NULL_CHAN) += null.o
obj-$(CONFIG_PORT_CHAN) += port.o
obj-$(CONFIG_PTY_CHAN) += pty.o
obj-$(CONFIG_TTY_CHAN) += tty.o
obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
obj-$(CONFIG_UML_WATCHDOG) += harddog.o
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
include arch/um/scripts/Makefile.rules

660
arch/um/drivers/chan_kern.c Normal file
View File

@@ -0,0 +1,660 @@
/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.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"
#ifdef CONFIG_NOCONFIG_CHAN
static void *not_configged_init(char *str, int device,
const struct chan_opts *opts)
{
printk("Using a channel type which is configured out of "
"UML\n");
return NULL;
}
static int not_configged_open(int input, int output, int primary, void *data,
char **dev_out)
{
printk("Using a channel type which is configured out of "
"UML\n");
return -ENODEV;
}
static void not_configged_close(int fd, void *data)
{
printk("Using a channel type which is configured out of "
"UML\n");
}
static int not_configged_read(int fd, char *c_out, void *data)
{
printk("Using a channel type which is configured out of "
"UML\n");
return -EIO;
}
static int not_configged_write(int fd, const char *buf, int len, void *data)
{
printk("Using a channel type which is configured out of "
"UML\n");
return -EIO;
}
static int not_configged_console_write(int fd, const char *buf, int len)
{
printk("Using a channel type which is configured out of "
"UML\n");
return -EIO;
}
static int not_configged_window_size(int fd, void *data, unsigned short *rows,
unsigned short *cols)
{
printk("Using a channel type which is configured out of "
"UML\n");
return -ENODEV;
}
static void not_configged_free(void *data)
{
printk("Using a channel type which is configured out of "
"UML\n");
}
static const struct chan_ops not_configged_ops = {
.init = not_configged_init,
.open = not_configged_open,
.close = not_configged_close,
.read = not_configged_read,
.write = not_configged_write,
.console_write = not_configged_console_write,
.window_size = not_configged_window_size,
.free = not_configged_free,
.winch = 0,
};
#endif /* CONFIG_NOCONFIG_CHAN */
void generic_close(int fd, void *unused)
{
os_close_file(fd);
}
int generic_read(int fd, char *c_out, void *unused)
{
int n;
n = os_read_file(fd, c_out, sizeof(*c_out));
if(n == -EAGAIN)
return 0;
else if(n == 0)
return -EIO;
return n;
}
/* XXX Trivial wrapper around os_write_file */
int generic_write(int fd, const char *buf, int n, void *unused)
{
return os_write_file(fd, buf, n);
}
int generic_window_size(int fd, void *unused, unsigned short *rows_out,
unsigned short *cols_out)
{
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;
return ret;
}
void generic_free(void *data)
{
kfree(data);
}
static void tty_receive_char(struct tty_struct *tty, char ch)
{
if(tty == NULL) return;
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;
}
}
tty_insert_flip_char(tty, ch, TTY_NORMAL);
}
static int open_one_chan(struct chan *chan)
{
int fd;
if(chan->opened)
return 0;
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;
chan->fd = fd;
chan->opened = 1;
return 0;
}
int open_chan(struct list_head *chans)
{
struct list_head *ele;
struct chan *chan;
int ret, err = 0;
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 chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
{
struct list_head *ele;
struct chan *chan;
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;
}
}
}
void enable_chan(struct line *line)
{
struct list_head *ele;
struct chan *chan;
list_for_each(ele, &line->chan_list){
chan = list_entry(ele, struct chan, list);
if(open_one_chan(chan))
continue;
if(chan->enabled)
continue;
line_setup_irq(chan->fd, chan->input, chan->output, line,
chan);
chan->enabled = 1;
}
}
/* 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 chan *chan;
LIST_HEAD(list);
struct list_head *ele;
unsigned long flags;
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)
free_irq(chan->line->driver->read_irq, chan);
if(chan->output)
free_irq(chan->line->driver->write_irq, chan);
chan->enabled = 0;
}
}
static void close_one_chan(struct chan *chan, int delay_free_irq)
{
unsigned long flags;
if(!chan->opened)
return;
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)
free_irq(chan->line->driver->read_irq, chan);
if(chan->output)
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, int delay_free_irq)
{
struct chan *chan;
/* Close in reverse order as open in case more than one of them
* refers to the same device and they save and restore that device's
* 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) {
close_one_chan(chan, delay_free_irq);
}
}
void deactivate_chan(struct list_head *chans, int irq)
{
struct list_head *ele;
struct chan *chan;
list_for_each(ele, chans) {
chan = list_entry(ele, struct chan, list);
if(chan->enabled && chan->input)
deactivate_fd(chan->fd, irq);
}
}
void reactivate_chan(struct list_head *chans, int irq)
{
struct list_head *ele;
struct chan *chan;
list_for_each(ele, chans) {
chan = list_entry(ele, struct chan, list);
if(chan->enabled && chan->input)
reactivate_fd(chan->fd, irq);
}
}
int write_chan(struct list_head *chans, 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);
}
}
return ret;
}
int console_write_chan(struct list_head *chans, 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);
if(chan->primary) ret = n;
}
return ret;
}
int console_open_chan(struct line *line, struct console *co)
{
int err;
err = open_chan(&line->chan_list);
if(err)
return err;
printk("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,
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);
}
}
return 0;
}
static void free_one_chan(struct chan *chan, int delay_free_irq)
{
list_del(&chan->list);
close_one_chan(chan, delay_free_irq);
if(chan->ops->free != NULL)
(*chan->ops->free)(chan->data);
if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
kfree(chan);
}
static void free_chan(struct list_head *chans, int delay_free_irq)
{
struct list_head *ele, *next;
struct chan *chan;
list_for_each_safe(ele, next, chans){
chan = list_entry(ele, struct chan, list);
free_one_chan(chan, delay_free_irq);
}
}
static int one_chan_config_string(struct chan *chan, char *str, int size,
char **error_out)
{
int n = 0;
if(chan == NULL){
CONFIG_CHUNK(str, size, n, "none", 1);
return n;
}
CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
if(chan->dev == NULL){
CONFIG_CHUNK(str, size, n, "", 1);
return n;
}
CONFIG_CHUNK(str, size, n, ":", 0);
CONFIG_CHUNK(str, size, n, chan->dev, 0);
return n;
}
static int chan_pair_config_string(struct chan *in, struct chan *out,
char *str, int size, char **error_out)
{
int n;
n = one_chan_config_string(in, str, size, error_out);
str += n;
size -= n;
if(in == out){
CONFIG_CHUNK(str, size, n, "", 1);
return n;
}
CONFIG_CHUNK(str, size, n, ",", 1);
n = one_chan_config_string(out, str, size, error_out);
str += n;
size -= n;
CONFIG_CHUNK(str, size, n, "", 1);
return n;
}
int chan_config_string(struct list_head *chans, char *str, int size,
char **error_out)
{
struct list_head *ele;
struct chan *chan, *in = NULL, *out = NULL;
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;
}
return chan_pair_config_string(in, out, str, size, error_out);
}
struct chan_type {
char *key;
const struct chan_ops *ops;
};
static const struct chan_type chan_table[] = {
{ "fd", &fd_ops },
#ifdef CONFIG_NULL_CHAN
{ "null", &null_ops },
#else
{ "null", &not_configged_ops },
#endif
#ifdef CONFIG_PORT_CHAN
{ "port", &port_ops },
#else
{ "port", &not_configged_ops },
#endif
#ifdef CONFIG_PTY_CHAN
{ "pty", &pty_ops },
{ "pts", &pts_ops },
#else
{ "pty", &not_configged_ops },
{ "pts", &not_configged_ops },
#endif
#ifdef CONFIG_TTY_CHAN
{ "tty", &tty_ops },
#else
{ "tty", &not_configged_ops },
#endif
#ifdef CONFIG_XTERM_CHAN
{ "xterm", &xterm_ops },
#else
{ "xterm", &not_configged_ops },
#endif
};
static struct chan *parse_chan(struct line *line, char *str, int device,
const struct chan_opts *opts, char **error_out)
{
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 < ARRAY_SIZE(chan_table); i++){
entry = &chan_table[i];
if(!strncmp(str, entry->key, strlen(entry->key))){
ops = entry->ops;
str += strlen(entry->key);
break;
}
}
if(ops == NULL){
*error_out = "No match for configured backends";
return NULL;
}
data = (*ops->init)(str, device, opts);
if(data == NULL){
*error_out = "Configuration failed";
return NULL;
}
chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
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,
.ops = ops,
.data = data });
return chan;
}
int parse_chan_pair(char *str, struct line *line, int device,
const struct chan_opts *opts, char **error_out)
{
struct list_head *chans = &line->chan_list;
struct chan *new, *chan;
char *in, *out;
if(!list_empty(chans)){
chan = list_entry(chans->next, struct chan, list);
free_chan(chans, 0);
INIT_LIST_HEAD(chans);
}
out = strchr(str, ',');
if(out != NULL){
in = str;
*out = '\0';
out++;
new = parse_chan(line, in, device, opts, error_out);
if(new == NULL)
return -1;
new->input = 1;
list_add(&new->list, chans);
new = parse_chan(line, out, device, opts, error_out);
if(new == NULL)
return -1;
list_add(&new->list, chans);
new->output = 1;
}
else {
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;
}
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;
}
void chan_interrupt(struct list_head *chans, struct delayed_work *task,
struct tty_struct *tty, int irq)
{
struct list_head *ele, *next;
struct chan *chan;
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 && !tty_buffer_request_room(tty, 1)) {
schedule_delayed_work(task, 1);
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);
close_chan(chans, 1);
return;
}
else close_one_chan(chan, 1);
}
}
out:
if(tty) tty_flip_buffer_push(tty);
}

217
arch/um/drivers/chan_user.c Normal file
View File

@@ -0,0 +1,217 @@
/*
* Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <termios.h>
#include <string.h>
#include <signal.h>
#include <sched.h>
#include <sys/stat.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"
int generic_console_write(int fd, const char *buf, int n)
{
struct termios save, new;
int err;
if(isatty(fd)){
CATCH_EINTR(err = tcgetattr(fd, &save));
if (err)
goto error;
new = save;
/* 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.*/
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))
CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save));
return(err);
error:
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).
*
* 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).
*
* 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)
{
}
struct winch_data {
int pty_fd;
int pipe_fd;
};
static int winch_thread(void *arg)
{
struct winch_data *data = arg;
sigset_t sigs;
int pty_fd, pipe_fd;
int count, err;
char c = 1;
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);
/* 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. */
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);
exit(1);
}
/* In sigsuspend(), block anything else than SIGWINCH. */
sigdelset(&sigs, SIGWINCH);
if(setsid() < 0){
printk("winch_thread : setsid failed, errno = %d\n", 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);
exit(1);
}
/* 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
* persistent. */
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.*/
sigsuspend(&sigs);
count = os_write_file(pipe_fd, &c, sizeof(c));
if(count != sizeof(c))
printk("winch_thread : write failed, err = %d\n",
-count);
}
}
static int winch_tramp(int fd, struct tty_struct *tty, int *fd_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);
goto out;
}
data = ((struct winch_data) { .pty_fd = fd,
.pipe_fd = fds[1] } );
/* CLONE_FILES so this thread doesn't hold open files which are open
* now, but later closed. This is a problem with /dev/net/tun.
*/
err = run_helper_thread(winch_thread, &data, CLONE_FILES, &stack, 0);
if(err < 0){
printk("fork of winch_thread failed - errno = %d\n", errno);
goto out_close;
}
*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_close;
}
return err ;
out_close:
os_close_file(fds[1]);
os_close_file(fds[0]);
out:
return err;
}
void register_winch(int fd, struct tty_struct *tty)
{
int pid, thread, thread_fd = -1;
int count;
char c = 1;
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);
}
}
}
/*
* 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:
*/

67
arch/um/drivers/cow.h Normal file
View File

@@ -0,0 +1,67 @@
#ifndef __COW_H__
#define __COW_H__
#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);
extern int file_reader(__u64 offset, char *buf, int len, void *arg);
extern int read_cow_header(int (*reader)(__u64, char *, int, void *),
void *arg, __u32 *version_out,
char **backing_file_out, time_t *mtime_out,
unsigned long long *size_out, int *sectorsize_out,
__u32 *align_out, int *bitmap_offset_out);
extern int write_cow_header(char *cow_file, int fd, char *backing_file,
int sectorsize, int alignment,
unsigned long long *size);
extern void cow_sizes(int version, __u64 size, int sectorsize, int align,
int bitmap_offset, unsigned long *bitmap_len_out,
int *data_offset_out);
#endif
/*
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

49
arch/um/drivers/cow_sys.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef __COW_SYS_H__
#define __COW_SYS_H__
#include "kern_util.h"
#include "user_util.h"
#include "os.h"
#include "user.h"
#include "um_malloc.h"
static inline void *cow_malloc(int size)
{
return(um_kmalloc(size));
}
static inline void cow_free(void *ptr)
{
kfree(ptr);
}
#define cow_printf printk
static inline char *cow_strdup(char *str)
{
return(uml_strdup(str));
}
static inline int cow_seek_file(int fd, __u64 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));
}
static inline int cow_write_file(int fd, void *buf, int size)
{
return(os_write_file(fd, buf, size));
}
#endif
/*
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

443
arch/um/drivers/cow_user.c Normal file
View File

@@ -0,0 +1,443 @@
#include <stddef.h>
#include <string.h>
#include <errno.h>
/* _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 "cow.h"
#include "cow_sys.h"
#define PATH_LEN_V1 256
typedef __u32 time32_t;
struct cow_header_v1 {
__s32 magic;
__s32 version;
char backing_file[PATH_LEN_V1];
time32_t mtime;
__u64 size;
__s32 sectorsize;
} __attribute__((packed));
/* 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];
time32_t mtime;
__u64 size;
__s32 sectorsize;
} __attribute__((packed));
/* 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
* time_t should be changed, this can be changed later without
* breaking compatibility
* Add alignment field so that different alignments can be used for the
* bitmap and data
* Add cow_format field to allow for the possibility of different ways
* of specifying the COW blocks. For now, the only value is 0,
* for the traditional COW bitmap.
* Move the backing_file field to the end of the header. This allows
* for the possibility of expanding it into the padding required
* by the bitmap alignment.
* The bitmap and data portions of the file will be aligned as specified
* by the alignment field. This is to allow COW files to be
* put on devices with restrictions on access alignments, such as
* /dev/raw, with a 512 byte alignment restriction. This also
* allows the data to be more aligned more strictly than on
* sector boundaries. This is needed for ubd-mmap, which needs
* the data to be page aligned.
* 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;
__u32 mtime;
__u64 size;
__u32 sectorsize;
__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 */
#define COW_BITMAP 0
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 */
#define COW_VERSION 3
#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
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){
*bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
*data_offset_out = bitmap_offset + *bitmap_len_out;
*data_offset_out = (*data_offset_out + sectorsize - 1) /
sectorsize;
*data_offset_out *= sectorsize;
}
else {
*bitmap_len_out = DIV_ROUND(size, sectorsize);
*bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
*data_offset_out = bitmap_offset + *bitmap_len_out;
*data_offset_out = ROUND_UP(*data_offset_out, align);
}
}
static int absolutize(char *to, int size, char *from)
{
char save_cwd[256], *slash;
int remaining;
if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
cow_printf("absolutize : unable to get cwd - errno = %d\n",
errno);
return(-1);
}
slash = strrchr(from, '/');
if(slash != NULL){
*slash = '\0';
if(chdir(from)){
*slash = '/';
cow_printf("absolutize : Can't cd to '%s' - "
"errno = %d\n", from, errno);
return(-1);
}
*slash = '/';
if(getcwd(to, size) == NULL){
cow_printf("absolutize : unable to get cwd of '%s' - "
"errno = %d\n", from, errno);
return(-1);
}
remaining = size - strlen(to);
if(strlen(slash) + 1 > remaining){
cow_printf("absolutize : unable to fit '%s' into %d "
"chars\n", from, size);
return(-1);
}
strcat(to, slash);
}
else {
if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
cow_printf("absolutize : unable to fit '%s' into %d "
"chars\n", from, size);
return(-1);
}
strcpy(to, save_cwd);
strcat(to, "/");
strcat(to, from);
}
chdir(save_cwd);
return(0);
}
int write_cow_header(char *cow_file, int fd, char *backing_file,
int sectorsize, int alignment, unsigned long long *size)
{
struct cow_header_v3 *header;
unsigned long modtime;
int err;
err = cow_seek_file(fd, 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("write_cow_header - failed to allocate COW V3 header\n");
goto out;
}
header->magic = htonl(COW_MAGIC);
header->version = htonl(COW_VERSION);
err = -EINVAL;
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 %zd characters\n", backing_file,
sizeof(header->backing_file) - 1);
goto out_free;
}
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("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("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->cow_format = COW_BITMAP;
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);
}
int file_reader(__u64 offset, char *buf, int len, void *arg)
{
int fd = *((int *) arg);
return(pread(fd, buf, len, offset));
}
/* XXX Need to sanity-check the values read from the header */
int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
__u32 *version_out, char **backing_file_out,
time_t *mtime_out, unsigned long long *size_out,
int *sectorsize_out, __u32 *align_out,
int *bitmap_offset_out)
{
union cow_header *header;
char *file;
int err, n;
unsigned long version, magic;
header = cow_malloc(sizeof(*header));
if(header == NULL){
cow_printf("read_cow_header - Failed to allocate header\n");
return(-ENOMEM);
}
err = -EINVAL;
n = (*reader)(0, (char *) header, sizeof(*header), arg);
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) {
version = header->v1.version;
}
else if(magic == ntohl(COW_MAGIC)){
version = ntohl(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)){
cow_printf("read_cow_header - failed to read V1 "
"header\n");
goto out;
}
*mtime_out = header->v1.mtime;
*size_out = header->v1.size;
*sectorsize_out = header->v1.sectorsize;
*bitmap_offset_out = sizeof(header->v1);
*align_out = *sectorsize_out;
file = header->v1.backing_file;
}
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);
*bitmap_offset_out = sizeof(header->v2);
*align_out = *sectorsize_out;
file = header->v2.backing_file;
}
/* 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);
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 ntohl() instead of ntohll(), 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) ntohl(header->v3_b.mtime);
*size_out = ntohll(header->v3_b.size);
*sectorsize_out = ntohl(header->v3_b.sectorsize);
*align_out = ntohl(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){
cow_printf("read_cow_header - failed to allocate backing "
"file\n");
goto out;
}
err = 0;
out:
cow_free(header);
return(err);
}
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)
{
unsigned long long size, offset;
char zero = 0;
int err;
err = write_cow_header(cow_file, fd, backing_file, sectorsize,
alignment, &size);
if(err)
goto out;
*bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
bitmap_len_out, data_offset_out);
offset = *data_offset_out + size - sizeof(zero);
err = cow_seek_file(fd, offset);
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
* 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)){
cow_printf("Write of bitmap to new COW file '%s' failed, "
"err = %d\n", cow_file, -err);
if (err >= 0)
err = -EINVAL;
goto out;
}
return(0);
out:
return(err);
}
/*
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

35
arch/um/drivers/daemon.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include "net_user.h"
#define SWITCH_VERSION 3
struct daemon_data {
char *sock_type;
char *ctl_sock;
void *ctl_addr;
void *data_addr;
void *local_addr;
int fd;
int control;
void *dev;
};
extern const struct net_user_info daemon_user_info;
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:
*/

View File

@@ -0,0 +1,101 @@
/*
* 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 "net_kern.h"
#include "net_user.h"
#include "daemon.h"
struct daemon_init {
char *sock_type;
char *ctl_sock;
};
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;
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",
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)
{
*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 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));
}
static const struct net_kern_info daemon_kern_info = {
.init = daemon_init,
.protocol = eth_protocol,
.read = daemon_read,
.write = daemon_write,
};
static int daemon_setup(char *str, char **mac_out, void *data)
{
struct daemon_init *init = data;
char *remain;
*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)
printk(KERN_WARNING "daemon_setup : Ignoring data socket "
"specification\n");
return(1);
}
static struct transport daemon_transport = {
.list = LIST_HEAD_INIT(daemon_transport.list),
.name = "daemon",
.setup = daemon_setup,
.user = &daemon_user_info,
.kern = &daemon_kern_info,
.private_size = sizeof(struct daemon_data),
.setup_size = sizeof(struct daemon_init),
};
static int register_daemon(void)
{
register_transport(&daemon_transport);
return 0;
}
late_initcall(register_daemon);

View File

@@ -0,0 +1,207 @@
/*
* 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 <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include "net_user.h"
#include "daemon.h"
#include "kern_util.h"
#include "user_util.h"
#include "user.h"
#include "os.h"
#include "um_malloc.h"
#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
enum request_type { REQ_NEW_CONTROL };
#define SWITCH_MAGIC 0xfeedface
struct request_v3 {
uint32_t magic;
uint32_t version;
enum request_type type;
struct sockaddr_un sock;
};
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->sun_family = AF_UNIX;
memcpy(sun->sun_path, name, len);
return(sun);
}
static int connect_to_switch(struct daemon_data *pri)
{
struct sockaddr_un *ctl_addr = pri->ctl_addr;
struct sockaddr_un *local_addr = pri->local_addr;
struct sockaddr_un *sun;
struct request_v3 req;
int fd, n, err;
pri->control = socket(AF_UNIX, SOCK_STREAM, 0);
if(pri->control < 0){
err = -errno;
printk("daemon_open : control socket failed, errno = %d\n",
-err);
return err;
}
if(connect(pri->control, (struct sockaddr *) ctl_addr,
sizeof(*ctl_addr)) < 0){
err = -errno;
printk("daemon_open : control connect failed, errno = %d\n",
-err);
goto out;
}
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if(fd < 0){
err = -errno;
printk("daemon_open : data socket failed, errno = %d\n",
-err);
goto out;
}
if(bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0){
err = -errno;
printk("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");
err = -ENOMEM;
goto out_close;
}
req.magic = SWITCH_MAGIC;
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);
err = -ENOTCONN;
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);
err = -ENOTCONN;
goto out_free;
}
pri->data_addr = sun;
return(fd);
out_free:
kfree(sun);
out_close:
os_close_file(fd);
out:
os_close_file(pri->control);
return(err);
}
static void daemon_user_init(void *data, void *dev)
{
struct daemon_data *pri = data;
struct timeval tv;
struct {
char zero;
int pid;
int usecs;
} name;
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();
gettimeofday(&tv, NULL);
name.usecs = tv.tv_usec;
pri->local_addr = new_addr(&name, sizeof(name));
pri->dev = dev;
pri->fd = connect_to_switch(pri);
if(pri->fd < 0){
kfree(pri->local_addr);
pri->local_addr = NULL;
}
}
static int daemon_open(void *data)
{
struct daemon_data *pri = data;
return(pri->fd);
}
static void daemon_remove(void *data)
{
struct daemon_data *pri = data;
os_close_file(pri->fd);
pri->fd = -1;
os_close_file(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);
}
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
};
/*
* 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:
*/

103
arch/um/drivers/fd.c Normal file
View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2001 Jeff Dike (jdike@karaya.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 "chan_user.h"
#include "os.h"
#include "um_malloc.h"
struct fd_chan {
int fd;
int raw;
struct termios tt;
char str[sizeof("1234567890\0")];
};
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);
}
str++;
n = strtoul(str, &end, 0);
if((*end != '\0') || (end == str)){
printk("fd_init : couldn't parse file descriptor '%s'\n", str);
return(NULL);
}
data = um_kmalloc(sizeof(*data));
if(data == NULL) return(NULL);
*data = ((struct fd_chan) { .fd = n,
.raw = opts->raw });
return(data);
}
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)){
CATCH_EINTR(err = tcgetattr(data->fd, &data->tt));
if(err)
return(err);
err = raw(data->fd);
if(err)
return(err);
}
sprintf(data->str, "%d", data->fd);
*dev_out = data->str;
return(data->fd);
}
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;
}
}
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 = 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:
*/

View File

@@ -0,0 +1,184 @@
/* UML hardware watchdog, shamelessly stolen from:
*
* SoftDog 0.05: A Software Watchdog Device
*
* (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
* http://www.redhat.com
*
* 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.
*
* 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>
*
* Software only watchdog driver. Unlike its big brother the WDT501P
* driver this won't always recover a failed machine.
*
* 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
* Modularised.
* Added soft_margin; use upon insmod to change the timer delay.
* NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
* minors.
*
* 19980911 Alan Cox
* Made SMP safe for 2.3.x
*
* 20011127 Joel Becker (jlbec@evilplan.org>
* Added soft_noboot; Allows testing the softdog trigger without
* requiring a recompile.
* Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/reboot.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include "mconsole.h"
MODULE_LICENSE("GPL");
static DEFINE_SPINLOCK(lock);
static int timer_alive;
static int harddog_in_fd = -1;
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 = -EBUSY;
char *sock = NULL;
spin_lock(&lock);
if(timer_alive)
goto err;
#ifdef CONFIG_HARDDOG_NOWAYOUT
__module_get(THIS_MODULE);
#endif
#ifdef CONFIG_MCONSOLE
sock = mconsole_notify_socket();
#endif
err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock);
if(err)
goto err;
timer_alive = 1;
spin_unlock(&lock);
return nonseekable_open(inode, file);
err:
spin_unlock(&lock);
return err;
}
extern void stop_watchdog(int in_fd, int out_fd);
static int harddog_release(struct inode *inode, struct file *file)
{
/*
* Shut off the timer.
*/
spin_lock(&lock);
stop_watchdog(harddog_in_fd, harddog_out_fd);
harddog_in_fd = -1;
harddog_out_fd = -1;
timer_alive=0;
spin_unlock(&lock);
return 0;
}
extern int ping_watchdog(int fd);
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 0;
}
static int harddog_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
void __user *argp= (void __user *)arg;
static struct watchdog_info ident = {
WDIOC_SETTIMEOUT,
0,
"UML Hardware Watchdog"
};
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
if(copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
return 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0,(int __user *)argp);
case WDIOC_KEEPALIVE:
return ping_watchdog(harddog_out_fd);
}
}
static const struct file_operations harddog_fops = {
.owner = THIS_MODULE,
.write = harddog_write,
.ioctl = harddog_ioctl,
.open = harddog_open,
.release = harddog_release,
};
static struct miscdevice harddog_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &harddog_fops,
};
static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n";
static int __init harddog_init(void)
{
int ret;
ret = misc_register(&harddog_miscdev);
if (ret)
return ret;
printk(banner);
return 0;
}
static void __exit harddog_exit(void)
{
misc_deregister(&harddog_miscdev);
}
module_init(harddog_init);
module_exit(harddog_exit);

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.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"
struct dog_data {
int stdin;
int stdout;
int close_me[2];
};
static void pre_exec(void *d)
{
struct dog_data *data = 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]);
}
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_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL };
char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL,
NULL };
char **args = NULL;
err = os_pipe(in_fds, 1, 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){
printk("harddog_open - os_pipe failed, err = %d\n", -err);
goto out_close_in;
}
data.stdin = out_fds[0];
data.stdout = in_fds[1];
data.close_me[0] = out_fds[1];
data.close_me[1] = in_fds[0];
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()));
args = pid_args;
}
pid = run_helper(pre_exec, &data, args, NULL);
os_close_file(out_fds[0]);
os_close_file(in_fds[1]);
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){
printk("harddog_open - EOF on watchdog pipe\n");
helper_wait(pid);
err = -EIO;
goto out_close_out;
}
else if(n < 0){
printk("harddog_open - read of watchdog pipe failed, "
"err = %d\n", -n);
helper_wait(pid);
err = n;
goto out_close_out;
}
*in_fd_ret = in_fds[0];
*out_fd_ret = out_fds[1];
return 0;
out_close_in:
os_close_file(in_fds[0]);
os_close_file(in_fds[1]);
out_close_out:
os_close_file(out_fds[0]);
os_close_file(out_fds[1]);
out:
return err;
}
void stop_watchdog(int in_fd, int out_fd)
{
os_close_file(in_fd);
os_close_file(out_fd);
}
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;
}
return 1;
}

View File

@@ -0,0 +1,340 @@
/*
* Copyright (C) 2002 Steve Schmidtke
* Licensed under the GPL
*/
#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"
struct hostaudio_state {
int fd;
};
struct hostmixer_state {
int fd;
};
#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
#define HOSTAUDIO_DEV_MIXER "/dev/sound/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" \
" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
#define MIXER_HELP \
" This is used to specify the host mixer device to the hostaudio driver.\n"\
" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
#ifndef MODULE
static int set_dsp(char *name, int *add)
{
dsp = name;
return(0);
}
__uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP);
static int set_mixer(char *name, int *add)
{
mixer = name;
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
/* /dev/dsp file operations */
static ssize_t hostaudio_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct hostaudio_state *state = file->private_data;
void *kbuf;
int err;
#ifdef DEBUG
printk("hostaudio: read called, count = %d\n", count);
#endif
kbuf = kmalloc(count, GFP_KERNEL);
if(kbuf == NULL)
return(-ENOMEM);
err = os_read_file(state->fd, kbuf, count);
if(err < 0)
goto out;
if(copy_to_user(buffer, kbuf, err))
err = -EFAULT;
out:
kfree(kbuf);
return(err);
}
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;
void *kbuf;
int err;
#ifdef DEBUG
printk("hostaudio: write called, count = %d\n", count);
#endif
kbuf = kmalloc(count, GFP_KERNEL);
if(kbuf == NULL)
return(-ENOMEM);
err = -EFAULT;
if(copy_from_user(kbuf, buffer, count))
goto out;
err = os_write_file(state->fd, kbuf, count);
if(err < 0)
goto out;
*ppos += err;
out:
kfree(kbuf);
return(err);
}
static unsigned int hostaudio_poll(struct file *file,
struct poll_table_struct *wait)
{
unsigned int mask = 0;
#ifdef DEBUG
printk("hostaudio: poll called (unimplemented)\n");
#endif
return(mask);
}
static int hostaudio_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct hostaudio_state *state = file->private_data;
unsigned long data = 0;
int err;
#ifdef DEBUG
printk("hostaudio: ioctl called, cmd = %u\n", cmd);
#endif
switch(cmd){
case SNDCTL_DSP_SPEED:
case SNDCTL_DSP_STEREO:
case SNDCTL_DSP_GETBLKSIZE:
case SNDCTL_DSP_CHANNELS:
case SNDCTL_DSP_SUBDIVIDE:
case SNDCTL_DSP_SETFRAGMENT:
if(get_user(data, (int __user *) arg))
return(-EFAULT);
break;
default:
break;
}
err = os_ioctl_generic(state->fd, cmd, (unsigned long) &data);
switch(cmd){
case SNDCTL_DSP_SPEED:
case SNDCTL_DSP_STEREO:
case SNDCTL_DSP_GETBLKSIZE:
case SNDCTL_DSP_CHANNELS:
case SNDCTL_DSP_SUBDIVIDE:
case SNDCTL_DSP_SETFRAGMENT:
if(put_user(data, (int __user *) arg))
return(-EFAULT);
break;
default:
break;
}
return(err);
}
static int hostaudio_open(struct inode *inode, struct file *file)
{
struct hostaudio_state *state;
int r = 0, w = 0;
int ret;
#ifdef DEBUG
printk("hostaudio: open called (host: %s)\n", dsp);
#endif
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;
ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
if(ret < 0){
kfree(state);
return(ret);
}
state->fd = ret;
file->private_data = state;
return(0);
}
static int hostaudio_release(struct inode *inode, struct file *file)
{
struct hostaudio_state *state = file->private_data;
#ifdef DEBUG
printk("hostaudio: release called\n");
#endif
os_close_file(state->fd);
kfree(state);
return(0);
}
/* /dev/mixer file operations */
static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct hostmixer_state *state = file->private_data;
#ifdef DEBUG
printk("hostmixer: ioctl called\n");
#endif
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;
#ifdef DEBUG
printk("hostmixer: open called (host: %s)\n", mixer);
#endif
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;
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);
kfree(state);
return(ret);
}
file->private_data = state;
return(0);
}
static int hostmixer_release(struct inode *inode, struct file *file)
{
struct hostmixer_state *state = file->private_data;
#ifdef DEBUG
printk("hostmixer: release called\n");
#endif
os_close_file(state->fd);
kfree(state);
return(0);
}
/* kernel module operations */
static const 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 hostmixer_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = hostmixer_ioctl_mixdev,
.open = hostmixer_open_mixdev,
.release = hostmixer_release,
};
struct {
int dev_audio;
int dev_mixer;
} module_data;
MODULE_AUTHOR("Steve Schmidtke");
MODULE_DESCRIPTION("UML Audio Relay");
MODULE_LICENSE("GPL");
static int __init hostaudio_init_module(void)
{
printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
dsp, mixer);
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;
}
module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1);
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;
}
return 0;
}
static void __exit hostaudio_cleanup_module (void)
{
unregister_sound_mixer(module_data.dev_mixer);
unregister_sound_dsp(module_data.dev_audio);
}
module_init(hostaudio_init_module);
module_exit(hostaudio_cleanup_module);

875
arch/um/drivers/line.c Normal file
View File

@@ -0,0 +1,875 @@
/*
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.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 "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"
#define LINE_BUFSIZE 4096
static irqreturn_t line_interrupt(int irq, void *data)
{
struct chan *chan = data;
struct line *line = chan->line;
struct tty_struct *tty = line->tty;
if (line)
chan_interrupt(&line->chan_list, &line->task, tty, irq);
return IRQ_HANDLED;
}
static void line_timer_cb(struct work_struct *work)
{
struct line *line = container_of(work, struct line, task.work);
if(!line->throttled)
chan_interrupt(&line->chan_list, &line->task, line->tty,
line->driver->read_irq);
}
/* Returns the free space inside the ring buffer of this line.
*
* Should be called while holding line->lock (this does not modify datas).
*/
static int write_room(struct line *line)
{
int n;
if (line->buffer == NULL)
return LINE_BUFSIZE - 1;
/* This is for the case where the buffer is wrapped! */
n = line->head - line->tail;
if (n <= 0)
n = LINE_BUFSIZE + n; /* The other case */
return n - 1;
}
int line_write_room(struct tty_struct *tty)
{
struct line *line = tty->driver_data;
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;
}
int line_chars_in_buffer(struct tty_struct *tty)
{
struct line *line = tty->driver_data;
unsigned long flags;
int ret;
spin_lock_irqsave(&line->lock, flags);
/*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);
return ret;
}
/*
* This copies the content of buf into the circular buffer associated with
* this line.
* The return value is the number of characters actually copied, i.e. the ones
* for which there was space: this function is not supposed to ever flush out
* the circular buffer.
*
* Must be called while holding line->lock!
*/
static int buffer_data(struct line *line, const char *buf, int len)
{
int end, room;
if(line->buffer == NULL){
line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
if (line->buffer == NULL) {
printk("buffer_data - atomic allocation failed\n");
return(0);
}
line->head = line->buffer;
line->tail = line->buffer;
}
room = write_room(line);
len = (len > room) ? room : len;
end = line->buffer + LINE_BUFSIZE - line->tail;
if (len < end){
memcpy(line->tail, buf, len);
line->tail += len;
}
else {
/* The circular buffer is wrapping */
memcpy(line->tail, buf, end);
buf += end;
memcpy(line->buffer, buf, len - end);
line->tail = line->buffer + len - end;
}
return len;
}
/*
* Flushes the ring buffer to the output channels. That is, write_chan is
* called, passing it line->head as buffer, and an appropriate count.
*
* On exit, returns 1 when the buffer is empty,
* 0 when the buffer is not empty on exit,
* and -errno when an error occurred.
*
* Must be called while holding line->lock!*/
static int flush_buffer(struct line *line)
{
int n, count;
if ((line->buffer == NULL) || (line->head == line->tail))
return 1;
if (line->tail < line->head) {
/* 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,
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.*/
line->head = line->buffer;
} else {
line->head += n;
return 0;
}
}
count = line->tail - line->head;
n = write_chan(&line->chan_list, line->head, count,
line->driver->write_irq);
if(n < 0)
return n;
line->head += n;
return line->head == line->tail;
}
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;
spin_lock_irqsave(&line->lock, flags);
err = flush_buffer(line);
/*if (err == 1)
err = 0;*/
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.*/
void line_flush_chars(struct tty_struct *tty)
{
line_flush_buffer(tty);
}
void line_put_char(struct tty_struct *tty, unsigned char ch)
{
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;
spin_lock_irqsave(&line->lock, flags);
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,
line->driver->write_irq);
if (n < 0) {
ret = n;
goto out_up;
}
len -= n;
ret += n;
if (len > 0)
ret += buffer_data(line, buf + n, len);
}
out_up:
spin_unlock_irqrestore(&line->lock, flags);
return ret;
}
void line_set_termios(struct tty_struct *tty, struct ktermios * old)
{
/* nothing */
}
static const 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)
{
int ret;
int i;
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;
}
void line_throttle(struct tty_struct *tty)
{
struct line *line = tty->driver_data;
deactivate_chan(&line->chan_list, line->driver->read_irq);
line->throttled = 1;
}
void line_unthrottle(struct tty_struct *tty)
{
struct line *line = tty->driver_data;
line->throttled = 0;
chan_interrupt(&line->chan_list, &line->task, tty,
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_list, line->driver->read_irq);
}
static irqreturn_t line_write_interrupt(int irq, void *data)
{
struct chan *chan = data;
struct line *line = chan->line;
struct tty_struct *tty = line->tty;
int err;
/* Interrupts are disabled here because we registered the interrupt with
* IRQF_DISABLED (see line_setup_irq).*/
spin_lock(&line->lock);
err = flush_buffer(line);
if (err == 0) {
return IRQ_NONE;
} else if(err < 0) {
line->head = line->buffer;
line->tail = line->buffer;
}
spin_unlock(&line->lock);
if(tty == NULL)
return IRQ_NONE;
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 line *line, void *data)
{
const struct line_driver *driver = line->driver;
int err = 0, flags = IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM;
if (input)
err = um_request_irq(driver->read_irq, fd, IRQ_READ,
line_interrupt, flags,
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, data);
line->have_irq = 1;
return err;
}
/* Normally, a driver like this can rely mostly on the tty layer
* locking, particularly when it comes to the driver structure.
* However, in this case, mconsole requests can come in "from the
* side", and race with opens and closes.
*
* mconsole config requests will want to be sure the device isn't in
* use, and get_config, open, and close will want a stable
* configuration. The checking and modification of the configuration
* is done under a spinlock. Checking whether the device is in use is
* line->tty->count > 1, also under the spinlock.
*
* tty->count serves to decide whether the device should be enabled or
* disabled on the host. If it's equal to 1, then we are doing the
* first open or last close. Otherwise, open and close just return.
*/
int line_open(struct line *lines, struct tty_struct *tty)
{
struct line *line = &lines[tty->index];
int err = -ENODEV;
spin_lock(&line->count_lock);
if(!line->valid)
goto out_unlock;
err = 0;
if(tty->count > 1)
goto out_unlock;
spin_unlock(&line->count_lock);
tty->driver_data = line;
line->tty = tty;
enable_chan(line);
INIT_DELAYED_WORK(&line->task, line_timer_cb);
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);
return err;
out_unlock:
spin_unlock(&line->count_lock);
return err;
}
static void unregister_winch(struct tty_struct *tty);
void line_close(struct tty_struct *tty, struct file * filp)
{
struct line *line = tty->driver_data;
/* If line_open fails (and tty->driver_data is never set),
* tty_open will call line_close. So just return in this case.
*/
if(line == NULL)
return;
/* We ignore the error anyway! */
flush_buffer(line);
spin_lock(&line->count_lock);
if(!line->valid)
goto out_unlock;
if(tty->count > 1)
goto out_unlock;
spin_unlock(&line->count_lock);
line->tty = NULL;
tty->driver_data = NULL;
if(line->sigio){
unregister_winch(tty);
line->sigio = 0;
}
return;
out_unlock:
spin_unlock(&line->count_lock);
}
void close_lines(struct line *lines, int nlines)
{
int i;
for(i = 0; i < nlines; i++)
close_chan(&lines[i].chan_list, 0);
}
static int setup_one_line(struct line *lines, int n, char *init, int init_prio,
char **error_out)
{
struct line *line = &lines[n];
int err = -EINVAL;
spin_lock(&line->count_lock);
if(line->tty != NULL){
*error_out = "Device is already open";
goto out;
}
if (line->init_pri <= init_prio){
line->init_pri = init_prio;
if (!strcmp(init, "none"))
line->valid = 0;
else {
line->init_str = init;
line->valid = 1;
}
}
err = 0;
out:
spin_unlock(&line->count_lock);
return err;
}
/* 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(struct line *lines, unsigned int num, char *init,
char **error_out)
{
int i, n, err;
char *end;
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 != '='){
*error_out = "Couldn't parse device number";
return -EINVAL;
}
init = end;
}
init++;
if (n >= (signed int) num) {
*error_out = "Device number out of range";
return -EINVAL;
}
else if (n >= 0){
err = setup_one_line(lines, n, init, INIT_ONE, error_out);
if(err)
return err;
}
else {
for(i = 0; i < num; i++){
err = setup_one_line(lines, i, init, INIT_ALL,
error_out);
if(err)
return err;
}
}
return n == -1 ? num : n;
}
int line_config(struct line *lines, unsigned int num, char *str,
const struct chan_opts *opts, char **error_out)
{
struct line *line;
char *new;
int n;
if(*str == '='){
*error_out = "Can't configure all devices from mconsole";
return -EINVAL;
}
new = kstrdup(str, GFP_KERNEL);
if(new == NULL){
*error_out = "Failed to allocate memory";
return -ENOMEM;
}
n = line_setup(lines, num, new, error_out);
if(n < 0)
return n;
line = &lines[n];
return parse_chan_pair(line->init_str, line, n, opts, error_out);
}
int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
int size, char **error_out)
{
struct line *line;
char *end;
int dev, n = 0;
dev = simple_strtoul(name, &end, 0);
if((*end != '\0') || (end == name)){
*error_out = "line_get_config failed to parse device number";
return 0;
}
if((dev < 0) || (dev >= num)){
*error_out = "device number out of range";
return 0;
}
line = &lines[dev];
spin_lock(&line->count_lock);
if(!line->valid)
CONFIG_CHUNK(str, size, n, "none", 1);
else if(line->tty == NULL)
CONFIG_CHUNK(str, size, n, line->init_str, 1);
else n = chan_config_string(&line->chan_list, str, size, error_out);
spin_unlock(&line->count_lock);
return n;
}
int line_id(char **str, int *start_out, int *end_out)
{
char *end;
int n;
n = simple_strtoul(*str, &end, 0);
if((*end != '\0') || (end == *str))
return -1;
*str = end;
*start_out = n;
*end_out = n;
return n;
}
int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
{
int err;
char config[sizeof("conxxxx=none\0")];
sprintf(config, "%d=none", n);
err = line_setup(lines, num, config, error_out);
if(err >= 0)
err = 0;
return err;
}
struct tty_driver *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);
if (!driver)
return NULL;
driver->driver_name = line_driver->name;
driver->name = line_driver->device_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->init_termios = tty_std_termios;
tty_set_operations(driver, ops);
if (tty_register_driver(driver)) {
printk("%s: can't register %s driver\n",
__FUNCTION__,line_driver->name);
put_tty_driver(driver);
return NULL;
}
for(i = 0; i < nlines; i++){
if(!lines[i].valid)
tty_unregister_device(driver, i);
}
mconsole_register_dev(&line_driver->mc);
return driver;
}
static DEFINE_SPINLOCK(winch_handler_lock);
static LIST_HEAD(winch_handlers);
void lines_init(struct line *lines, int nlines, struct chan_opts *opts)
{
struct line *line;
char *error;
int i;
for(i = 0; i < nlines; i++){
line = &lines[i];
INIT_LIST_HEAD(&line->chan_list);
if(line->init_str == NULL)
continue;
line->init_str = kstrdup(line->init_str, GFP_KERNEL);
if(line->init_str == NULL)
printk("lines_init - kstrdup returned NULL\n");
if(parse_chan_pair(line->init_str, line, i, opts, &error)){
printk("parse_chan_pair failed for device %d : %s\n",
i, error);
line->valid = 0;
}
}
}
struct winch {
struct list_head list;
int fd;
int tty_fd;
int pid;
struct tty_struct *tty;
};
static irqreturn_t winch_interrupt(int irq, void *data)
{
struct winch *winch = data;
struct tty_struct *tty;
struct line *line;
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);
return IRQ_HANDLED;
}
goto out;
}
}
tty = winch->tty;
if (tty != NULL) {
line = tty->driver_data;
chan_window_size(&line->chan_list, &tty->winsize.ws_row,
&tty->winsize.ws_col);
kill_pgrp(tty->pgrp, SIGWINCH, 1);
}
out:
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)
{
struct winch *winch;
winch = kmalloc(sizeof(*winch), GFP_KERNEL);
if (winch == NULL) {
printk("register_winch_irq - kmalloc failed\n");
return;
}
*winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
.fd = fd,
.tty_fd = tty_fd,
.pid = pid,
.tty = tty });
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,
IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
"winch", winch) < 0)
printk("register_winch_irq - failed to register IRQ\n");
}
static void free_winch(struct winch *winch)
{
list_del(&winch->list);
if(winch->pid != -1)
os_kill_process(winch->pid, 1);
if(winch->fd != -1)
os_close_file(winch->fd);
free_irq(WINCH_IRQ, winch);
kfree(winch);
}
static void unregister_winch(struct tty_struct *tty)
{
struct list_head *ele;
struct winch *winch;
spin_lock(&winch_handler_lock);
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->tty == tty){
free_winch(winch);
break;
}
}
spin_unlock(&winch_handler_lock);
}
static void winch_cleanup(void)
{
struct list_head *ele, *next;
struct winch *winch;
spin_lock(&winch_handler_lock);
list_for_each_safe(ele, next, &winch_handlers){
winch = list_entry(ele, struct winch, list);
free_winch(winch);
}
spin_unlock(&winch_handler_lock);
}
__uml_exitcall(winch_cleanup);
char *add_xterm_umid(char *base)
{
char *umid, *title;
int len;
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");
return base;
}
snprintf(title, len, "%s (%s)", base, umid);
return title;
}

30
arch/um/drivers/mcast.h Normal file
View File

@@ -0,0 +1,30 @@
/*
* 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 const 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:
*/

View File

@@ -0,0 +1,130 @@
/*
* 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;
};
static 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 address: %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 const 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 0;
}
late_initcall(register_mcast);

View File

@@ -0,0 +1,173 @@
/*
* 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"
#include "um_malloc.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 void mcast_remove(void *data)
{
struct mcast_data *pri = data;
kfree(pri->mcast_addr);
pri->mcast_addr = NULL;
}
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 = -EINVAL;
if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0))
goto out;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0){
err = -errno;
printk("mcast_open : data socket failed, errno = %d\n",
errno);
goto out;
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
err = -errno;
printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
errno);
goto out_close;
}
/* set ttl according to config */
if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
sizeof(pri->ttl)) < 0) {
err = -errno;
printk("mcast_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("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
errno);
goto out_close;
}
/* bind socket to mcast address */
if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
err = -errno;
printk("mcast_open : data bind failed, errno = %d\n", 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) {
err = -errno;
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");
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);
}
const struct net_user_info mcast_user_info = {
.init = mcast_user_init,
.open = mcast_open,
.close = mcast_close,
.remove = mcast_remove,
.set_mtu = mcast_set_mtu,
.add_address = NULL,
.delete_address = NULL,
.max_packet = MAX_PACKET - ETH_HEADER_OTHER
};

View File

@@ -0,0 +1,952 @@
/*
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
* Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.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 "linux/list.h"
#include "linux/mm.h"
#include "linux/console.h"
#include "asm/irq.h"
#include "asm/uaccess.h"
#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
#include "mconsole.h"
#include "mconsole_kern.h"
#include "irq_user.h"
#include "init.h"
#include "os.h"
#include "irq_kern.h"
#include "choose-mode.h"
static int do_unlink_socket(struct notifier_block *notifier,
unsigned long what, void *data)
{
return(mconsole_unlink_socket());
}
static struct notifier_block reboot_notifier = {
.notifier_call = do_unlink_socket,
.priority = 0,
};
/* 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.
*/
static LIST_HEAD(mc_requests);
static void mc_work_proc(struct work_struct *unused)
{
struct mconsole_entry *req;
unsigned long flags;
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);
kfree(req);
}
}
static DECLARE_WORK(mconsole_work, mc_work_proc);
static irqreturn_t mconsole_interrupt(int irq, void *dev_id)
{
/* long to avoid size mismatch warnings from gcc */
long fd;
struct mconsole_entry *new;
static struct mc_request req; /* that's OK */
fd = (long) dev_id;
while (mconsole_get_request(fd, &req)){
if(req.cmd->context == MCONSOLE_INTR)
(*req.cmd->handler)(&req);
else {
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))
schedule_work(&mconsole_work);
reactivate_fd(fd, MCONSOLE_IRQ);
return(IRQ_HANDLED);
}
void mconsole_version(struct mc_request *req)
{
char version[256];
sprintf(version, "%s %s %s %s %s", utsname()->sysname,
utsname()->nodename, utsname()->release,
utsname()->version, utsname()->machine);
mconsole_reply(req, version, 0, 0);
}
void mconsole_log(struct mc_request *req)
{
int len;
char *ptr = req->request.data;
ptr += strlen("log ");
len = req->len - (ptr - req->request.data);
printk("%.*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];
char *buf;
int len;
int fd;
int first_chunk = 1;
char *ptr = req->request.data;
ptr += strlen("proc");
while(isspace(*ptr)) ptr++;
snprintf(path, sizeof(path), "/proc/%s", ptr);
fd = sys_open(path, 0, 0);
if (fd < 0) {
mconsole_reply(req, "Failed to open file", 1, 0);
printk("open %s: %d\n",path,fd);
goto out;
}
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if(buf == NULL){
mconsole_reply(req, "Failed to allocate buffer", 1, 0);
goto out_close;
}
for (;;) {
len = sys_read(fd, buf, PAGE_SIZE-1);
if (len < 0) {
mconsole_reply(req, "Read of file failed", 1, 0);
goto out_free;
}
/*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;
}
}
out_free:
kfree(buf);
out_close:
sys_close(fd);
out:
/* nothing */;
}
#define UML_MCONSOLE_HELPTEXT \
"Commands: \n\
version - Get kernel version \n\
help - Print this message \n\
halt - Halt UML \n\
reboot - Reboot UML \n\
config <dev>=<config> - Add a new device to UML; \n\
same syntax as command line \n\
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 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\
proc <file> - returns the contents of the UML's /proc/<file>\n\
stack <pid> - returns the stack of the specified pid\n\
"
void mconsole_help(struct mc_request *req)
{
mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
}
void mconsole_halt(struct mc_request *req)
{
mconsole_reply(req, "", 0, 0);
machine_halt();
}
void mconsole_reboot(struct mc_request *req)
{
mconsole_reply(req, "", 0, 0);
machine_restart(NULL);
}
void mconsole_cad(struct mc_request *req)
{
mconsole_reply(req, "", 0, 0);
ctrl_alt_del();
}
void mconsole_go(struct mc_request *req)
{
mconsole_reply(req, "Not stopped", 1, 0);
}
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, "stopped", 0, 0);
while (mconsole_get_request(req->originating_fd, req)) {
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);
reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
mconsole_reply(req, "", 0, 0);
}
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)
{
struct list_head *ele;
struct mc_device *dev;
list_for_each(ele, &mconsole_devices){
dev = list_entry(ele, struct mc_device, list);
if(!strncmp(name, dev->name, strlen(dev->name)))
return(dev);
}
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 DECLARE_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;
down(&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("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:
up(&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 mem_mc_init(void)
{
if(can_drop_memory())
mconsole_register_dev(&mem_mc);
else printk("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,
char **),
struct mc_request *req, char *name)
{
char default_buf[CONFIG_BUF_SIZE], *error, *buf;
int n, size;
if(get_config == NULL){
mconsole_reply(req, "No get_config routine defined", 1, 0);
return;
}
error = NULL;
size = ARRAY_SIZE(default_buf);
buf = default_buf;
while(1){
n = (*get_config)(name, buf, size, &error);
if(error != NULL){
mconsole_reply(req, error, 1, 0);
goto out;
}
if(n <= size){
mconsole_reply(req, buf, 0, 0);
goto out;
}
if(buf != default_buf)
kfree(buf);
size = n;
buf = kmalloc(size, GFP_KERNEL);
if(buf == NULL){
mconsole_reply(req, "Failed to allocate buffer", 1, 0);
return;
}
}
out:
if(buf != default_buf)
kfree(buf);
}
void mconsole_config(struct mc_request *req)
{
struct mc_device *dev;
char *ptr = req->request.data, *name, *error_string = "";
int err;
ptr += strlen("config");
while(isspace(*ptr)) ptr++;
dev = mconsole_find_dev(ptr);
if(dev == NULL){
mconsole_reply(req, "Bad configuration option", 1, 0);
return;
}
name = &ptr[strlen(dev->name)];
ptr = name;
while((*ptr != '=') && (*ptr != '\0'))
ptr++;
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;
char *ptr = req->request.data, *err_msg = "";
char error[256];
int err, start, end, n;
ptr += strlen("remove");
while(isspace(*ptr)) ptr++;
dev = mconsole_find_dev(ptr);
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_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 int console_index = 0;
static void console_write(struct console *console, const char *string,
unsigned len)
{
struct list_head *ele;
int n;
if(list_empty(&clients))
return;
while(1){
n = min((size_t) len, ARRAY_SIZE(console_buf) - console_index);
strncpy(&console_buf[console_index], string, n);
console_index += n;
string += n;
len -= n;
if(len == 0)
return;
list_for_each(ele, &clients){
struct mconsole_output *entry;
entry = list_entry(ele, struct mconsole_output, list);
mconsole_reply_len(entry->req, console_buf,
console_index, 0, 1);
}
console_index = 0;
}
}
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, console_buf, console_index, 0, 0);
console_index = 0;
spin_lock_irqsave(&client_lock, flags);
list_del(&entry.list);
spin_unlock_irqrestore(&client_lock, flags);
}
#ifdef CONFIG_MAGIC_SYSRQ
static void sysrq_proc(void *arg)
{
char *op = arg;
handle_sysrq(*op, NULL);
}
void mconsole_sysrq(struct mc_request *req)
{
char *ptr = req->request.data;
ptr += strlen("sysrq");
while(isspace(*ptr)) ptr++;
/* 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)
{
mconsole_reply(req, "Sysrq not compiled in", 1, 0);
}
#endif
#ifdef CONFIG_MODE_SKAS
static void stack_proc(void *arg)
{
struct task_struct *from = current, *to = arg;
to->thread.saved_task = from;
switch_to(from, to, from);
}
/* Mconsole stack trace
* Added by Allan Graves, Jeff Dike
* Dumps a stacks registers to the linux console.
* Usage stack <pid>.
*/
static void do_stack_trace(struct mc_request *req)
{
char *ptr = req->request.data;
int pid_requested= -1;
struct task_struct *from = NULL;
struct task_struct *to = NULL;
/* 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;
}
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;
}
with_console(req, stack_proc, to);
}
#endif /* CONFIG_MODE_SKAS */
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
*/
CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode",
1, 0),
do_stack_trace(req));
}
/* Changed by mconsole_setup, which is __setup, and called before SMP is
* active.
*/
static char *notify_socket = NULL;
static int mconsole_init(void)
{
/* long to avoid size mismatch warnings from gcc */
long sock;
int err;
char file[256];
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);
}
register_reboot_notifier(&reboot_notifier);
err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
"mconsole", (void *)sock);
if (err){
printk("Failed to get IRQ for management console\n");
return(1);
}
if(notify_socket != NULL){
notify_socket = kstrdup(notify_socket, GFP_KERNEL);
if(notify_socket != NULL)
mconsole_notify(notify_socket, MCONSOLE_SOCKET,
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",
MCONSOLE_VERSION, mconsole_socket_name);
return(0);
}
__initcall(mconsole_init);
static int write_proc_mconsole(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char *buf;
buf = kmalloc(count + 1, GFP_KERNEL);
if(buf == NULL)
return(-ENOMEM);
if(copy_from_user(buf, buffer, count)){
count = -EFAULT;
goto out;
}
buf[count] = '\0';
mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
out:
kfree(buf);
return(count);
}
static int create_proc_mconsole(void)
{
struct proc_dir_entry *ent;
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->read_proc = NULL;
ent->write_proc = write_proc_mconsole;
return(0);
}
static DEFINE_SPINLOCK(notify_spinlock);
void lock_notify(void)
{
spin_lock(&notify_spinlock);
}
void unlock_notify(void)
{
spin_unlock(&notify_spinlock);
}
__initcall(create_proc_mconsole);
#define NOTIFY "=notify:"
static int mconsole_setup(char *str)
{
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);
}
__setup("mconsole", mconsole_setup);
__uml_help(mconsole_setup,
"mconsole=notify:<socket>\n"
" Requests that the mconsole driver send a message to the named Unix\n"
" socket containing the name of the mconsole socket. This also serves\n"
" to notify outside processes when UML has booted far enough to respond\n"
" to mconsole requests.\n\n"
);
static int notify_panic(struct notifier_block *self, unsigned long unused1,
void *ptr)
{
char *message = ptr;
if(notify_socket == NULL) return(0);
mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
strlen(message) + 1);
return(0);
}
static struct notifier_block panic_exit_notifier = {
.notifier_call = notify_panic,
.next = NULL,
.priority = 1
};
static int add_notifier(void)
{
atomic_notifier_chain_register(&panic_notifier_list,
&panic_exit_notifier);
return(0);
}
__initcall(add_notifier);
char *mconsole_notify_socket(void)
{
return(notify_socket);
}
EXPORT_SYMBOL(mconsole_notify_socket);

View File

@@ -0,0 +1,233 @@
/*
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
* Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <unistd.h>
#include "user.h"
#include "sysdep/ptrace.h"
#include "mconsole.h"
#include "os.h"
#include "user_util.h"
static struct mconsole_command commands[] = {
/* 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 },
{ "remove", mconsole_remove, MCONSOLE_PROC },
{ "sysrq", mconsole_sysrq, MCONSOLE_INTR },
{ "help", mconsole_help, MCONSOLE_INTR },
{ "cad", mconsole_cad, MCONSOLE_INTR },
{ "stop", mconsole_stop, MCONSOLE_PROC },
{ "go", mconsole_go, MCONSOLE_INTR },
{ "log", mconsole_log, MCONSOLE_INTR },
{ "proc", mconsole_proc, MCONSOLE_PROC },
{ "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)
{
struct iovec iov;
struct msghdr msg;
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;
return sendmsg(req->originating_fd, &msg, 0);
}
static struct mconsole_command *mconsole_parse(struct mc_request *req)
{
struct mconsole_command *cmd;
int i;
for(i = 0; i < ARRAY_SIZE(commands); i++){
cmd = &commands[i];
if(!strncmp(req->request.data, cmd->command,
strlen(cmd->command))){
return cmd;
}
}
return NULL;
}
#define MIN(a,b) ((a)<(b) ? (a):(b))
#define STRINGX(x) #x
#define STRING(x) STRINGX(x)
int mconsole_get_request(int fd, struct mc_request *req)
{
int len;
req->originlen = sizeof(req->origin);
req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
(struct sockaddr *) req->origin, &req->originlen);
if (req->len < 0)
return 0;
req->originating_fd = fd;
if(req->request.magic != MCONSOLE_MAGIC){
/* Unversioned request */
len = MIN(sizeof(req->request.data) - 1,
strlen((char *) &req->request));
memmove(req->request.data, &req->request, len);
req->request.data[len] = '\0';
req->request.magic = MCONSOLE_MAGIC;
req->request.version = 0;
req->request.len = len;
mconsole_reply_v0(req, "ERR Version 0 mconsole clients are "
"not supported by this driver");
return(0);
}
if(req->request.len >= MCONSOLE_MAX_DATA){
mconsole_reply(req, "Request too large", 1, 0);
return(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){
mconsole_reply(req, "Unknown command", 1, 0);
return(0);
}
return(1);
}
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 len, n;
do {
reply.err = err;
/* err can only be true on the first packet */
err = 0;
len = MIN(total, MCONSOLE_MAX_DATA - 1);
if(len == total) reply.more = more;
else reply.more = 1;
memcpy(reply.data, str, len);
reply.data[len] = '\0';
total -= len;
str += len;
reply.len = len + 1;
len = sizeof(reply) + reply.len - sizeof(reply.data);
n = sendto(req->originating_fd, &reply, len, 0,
(struct sockaddr *) req->origin, req->originlen);
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);
return 0;
}
static int notify_sock = -1;
int mconsole_notify(char *sock_name, int type, const void *data, int len)
{
struct sockaddr_un target;
struct mconsole_notify packet;
int n, err = 0;
lock_notify();
if(notify_sock < 0){
notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if(notify_sock < 0){
err = -errno;
printk("mconsole_notify - socket failed, errno = %d\n",
err);
}
}
unlock_notify();
if(err)
return(err);
target.sun_family = AF_UNIX;
strcpy(target.sun_path, sock_name);
packet.magic = MCONSOLE_MAGIC;
packet.version = MCONSOLE_VERSION;
packet.type = type;
len = (len > sizeof(packet.data)) ? sizeof(packet.data) : len;
packet.len = len;
memcpy(packet.data, data, len);
err = 0;
len = sizeof(packet) + packet.len - sizeof(packet.data);
n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target,
sizeof(target));
if(n < 0){
err = -errno;
printk("mconsole_notify - sendto failed, errno = %d\n", errno);
}
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:
*/

View File

@@ -0,0 +1,144 @@
/*
* arch/um/drivers/mmapper_kern.c
*
* BRIEF MODULE DESCRIPTION
*
* Copyright (C) 2000 RidgeRun, Inc.
* Author: RidgeRun, Inc.
* Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include "mem_user.h"
#include "user_util.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 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)
{
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;
}
static int
mmapper_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
return(-ENOIOCTLCMD);
}
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);
/* 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))
goto out;
ret = 0;
out:
return ret;
}
static int
mmapper_open(struct inode *inode, struct file *file)
{
return 0;
}
static int
mmapper_release(struct inode *inode, struct file *file)
{
return 0;
}
static const struct file_operations mmapper_fops = {
.owner = THIS_MODULE,
.read = mmapper_read,
.write = mmapper_write,
.ioctl = mmapper_ioctl,
.mmap = mmapper_mmap,
.open = mmapper_open,
.release = mmapper_release,
};
/* No locking needed - only used (and modified) by below initcall and exitcall. */
static struct miscdevice mmapper_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mmapper",
.fops = &mmapper_fops
};
static int __init mmapper_init(void)
{
int err;
printk(KERN_INFO "Mapper v0.1\n");
v_buf = (char *) find_iomem("mmapper", &mmapper_size);
if(mmapper_size == 0){
printk(KERN_ERR "mmapper_init - find_iomem failed\n");
goto out;
}
err = misc_register(&mmapper_dev);
if(err){
printk(KERN_ERR "mmapper - misc_register failed, err = %d\n",
err);
goto out;
}
p_buf = __pa(v_buf);
out:
return 0;
}
static void mmapper_exit(void)
{
misc_deregister(&mmapper_dev);
}
module_init(mmapper_init);
module_exit(mmapper_exit);
MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>");
MODULE_DESCRIPTION("DSPLinux simulator mmapper driver");
/*
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

859
arch/um/drivers/net_kern.c Normal file
View File

@@ -0,0 +1,859 @@
/*
* 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/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 "mconsole_kern.h"
#include "init.h"
#include "irq_user.h"
#include "irq_kern.h"
static inline void set_ether_mac(struct net_device *dev, unsigned char *addr)
{
memcpy(dev->dev_addr, addr, ETH_ALEN);
}
#define DRIVER_NAME "uml-netdev"
static DEFINE_SPINLOCK(opened_lock);
static LIST_HEAD(opened);
static int uml_net_rx(struct net_device *dev)
{
struct uml_net_private *lp = dev->priv;
int pkt_len;
struct sk_buff *skb;
/* If we can't allocate memory, try again next round. */
skb = dev_alloc_skb(dev->mtu);
if (skb == NULL) {
lp->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);
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++;
return pkt_len;
}
kfree_skb(skb);
return pkt_len;
}
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);
}
irqreturn_t uml_net_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct uml_net_private *lp = dev->priv;
int err;
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",
dev->name, err);
/* 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:
spin_unlock(&lp->lock);
return IRQ_HANDLED;
}
static int uml_net_open(struct net_device *dev)
{
struct uml_net_private *lp = dev->priv;
int err;
if(lp->fd >= 0){
err = -ENXIO;
goto out;
}
lp->fd = (*lp->open)(&lp->user);
if(lp->fd < 0){
err = lp->fd;
goto out;
}
err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,
IRQF_DISABLED | IRQF_SHARED, dev->name, dev);
if(err != 0){
printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);
err = -ENETUNREACH;
goto out_close;
}
lp->tl.data = (unsigned long) &lp->user;
netif_start_queue(dev);
/* clear buffer - it can happen that the host side of the interface
* 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) ;
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;
netif_stop_queue(dev);
free_irq(dev->irq, dev);
if(lp->close != NULL)
(*lp->close)(lp->fd, &lp->user);
lp->fd = -1;
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;
unsigned long flags;
int len;
netif_stop_queue(dev);
spin_lock_irqsave(&lp->lock, flags);
len = (*lp->write)(lp->fd, &skb, lp);
if(len == skb->len) {
lp->stats.tx_packets++;
lp->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){
netif_start_queue(dev);
lp->stats.tx_dropped++;
}
else {
netif_start_queue(dev);
printk(KERN_ERR "uml_net_start_xmit: failed(%d)\n", len);
}
spin_unlock_irqrestore(&lp->lock, flags);
dev_kfree_skb(skb);
return 0;
}
static struct net_device_stats *uml_net_get_stats(struct net_device *dev)
{
struct uml_net_private *lp = dev->priv;
return &lp->stats;
}
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;
}
static void uml_net_tx_timeout(struct net_device *dev)
{
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
static int uml_net_set_mac(struct net_device *dev, void *addr)
{
struct uml_net_private *lp = dev->priv;
struct sockaddr *hwaddr = addr;
spin_lock_irq(&lp->lock);
set_ether_mac(dev, hwaddr->sa_data);
spin_unlock_irq(&lp->lock);
return 0;
}
static int uml_net_change_mtu(struct net_device *dev, int new_mtu)
{
struct uml_net_private *lp = dev->priv;
int err = 0;
spin_lock_irq(&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_irq(&lp->lock);
return err;
}
static void uml_net_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
strcpy(info->driver, DRIVER_NAME);
strcpy(info->version, "42");
}
static struct ethtool_ops uml_net_ethtool_ops = {
.get_drvinfo = uml_net_get_drvinfo,
.get_link = ethtool_op_get_link,
};
void uml_net_user_timer_expire(unsigned long _conn)
{
#ifdef undef
struct connection *conn = (struct connection *)_conn;
dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn);
do_connect(conn);
#endif
}
static void setup_etheraddr(char *str, unsigned char *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(addr[0] & 1){
printk(KERN_ERR
"Attempt to assign a broadcast ethernet address to a "
"device disallowed\n");
goto random;
}
return;
random:
random_ether_addr(addr);
}
static DEFINE_SPINLOCK(devices_lock);
static LIST_HEAD(devices);
static struct platform_driver uml_net_driver = {
.driver = {
.name = DRIVER_NAME,
},
};
static int driver_registered;
static int 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;
size = transport->private_size + sizeof(struct uml_net_private) +
sizeof(((struct uml_net_private *) 0)->user);
device = kzalloc(sizeof(*device), GFP_KERNEL);
if (device == NULL) {
printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
return(1);
}
INIT_LIST_HEAD(&device->list);
device->index = n;
spin_lock(&devices_lock);
list_add(&device->list, &devices);
spin_unlock(&devices_lock);
setup_etheraddr(mac, device->mac);
printk(KERN_INFO "Netdevice %d ", n);
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;
}
lp = dev->priv;
/* 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) {
platform_driver_register(&uml_net_driver);
driver_registered = 1;
}
device->pdev.id = n;
device->pdev.name = DRIVER_NAME;
platform_device_register(&device->pdev);
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;
(*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->ethtool_ops = &uml_net_ethtool_ops;
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.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},
.protocol = transport->kern->protocol,
.open = transport->user->open,
.close = transport->user->close,
.remove = transport->user->remove,
.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 } });
init_timer(&lp->tl);
spin_lock_init(&lp->lock);
lp->tl.function = uml_net_user_timer_expire;
memcpy(lp->mac, device->mac, sizeof(lp->mac));
if (transport->user->init)
(*transport->user->init)(&lp->user, dev);
set_ether_mac(dev, device->mac);
return 0;
}
static struct uml_net *find_device(int n)
{
struct uml_net *device;
struct list_head *ele;
spin_lock(&devices_lock);
list_for_each(ele, &devices){
device = list_entry(ele, struct uml_net, list);
if(device->index == n)
goto out;
}
device = NULL;
out:
spin_unlock(&devices_lock);
return device;
}
static int eth_parse(char *str, int *index_out, char **str_out,
char **error_out)
{
char *end;
int n, err = -EINVAL;;
n = simple_strtoul(str, &end, 0);
if(end == str){
*error_out = "Bad device number";
return err;
}
str = end;
if(*str != '='){
*error_out = "Expected '=' after device number";
return err;
}
str++;
if(find_device(n)){
*error_out = "Device already configured";
return err;
}
*index_out = n;
*str_out = str;
return 0;
}
struct eth_init {
struct list_head list;
char *init;
int index;
};
static DEFINE_SPINLOCK(transports_lock);
static LIST_HEAD(transports);
/* Filled in during early boot */
static LIST_HEAD(eth_cmd_line);
static int check_transport(struct transport *transport, char *eth, int n,
void **init_out, char **mac_out)
{
int len;
len = strlen(transport->name);
if(strncmp(eth, transport->name, len))
return 0;
eth += len;
if(*eth == ',')
eth++;
else if(*eth != '\0')
return 0;
*init_out = kmalloc(transport->setup_size, GFP_KERNEL);
if(*init_out == NULL)
return 1;
if(!transport->setup(eth, mac_out, *init_out)){
kfree(*init_out);
*init_out = NULL;
}
return 1;
}
void register_transport(struct transport *new)
{
struct list_head *ele, *next;
struct eth_init *eth;
void *init;
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, &eth_cmd_line){
eth = list_entry(ele, struct eth_init, list);
match = check_transport(new, eth->init, eth->index, &init,
&mac);
if(!match)
continue;
else if(init != NULL){
eth_configure(eth->index, init, mac, new);
kfree(init);
}
list_del(&eth->list);
}
}
static int eth_setup_common(char *str, int index)
{
struct list_head *ele;
struct transport *transport;
void *init;
char *mac = NULL;
int found = 0;
spin_lock(&transports_lock);
list_for_each(ele, &transports){
transport = list_entry(ele, struct transport, list);
if(!check_transport(transport, str, index, &init, &mac))
continue;
if(init != NULL){
eth_configure(index, init, mac, transport);
kfree(init);
}
found = 1;
break;
}
spin_unlock(&transports_lock);
return found;
}
static int eth_setup(char *str)
{
struct eth_init *new;
char *error;
int n, err;
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;
}
INIT_LIST_HEAD(&new->list);
new->index = n;
new->init = str;
list_add_tail(&new->list, &eth_cmd_line);
return 1;
}
__setup("eth", eth_setup);
__uml_help(eth_setup,
"eth[0-9]+=<transport>,<options>\n"
" Configure a network device.\n\n"
);
static int net_config(char *str, char **error_out)
{
int n, err;
err = eth_parse(str, &n, &str, error_out);
if(err)
return err;
/* 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)
kfree(str);
return(err);
}
static int net_id(char **str, int *start_out, int *end_out)
{
char *end;
int n;
n = simple_strtoul(*str, &end, 0);
if((*end != '\0') || (end == *str))
return -1;
*start_out = n;
*end_out = n;
*str = end;
return 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)
return -ENODEV;
dev = device->dev;
lp = dev->priv;
if(lp->fd > 0)
return -EBUSY;
if(lp->remove != NULL) (*lp->remove)(&lp->user);
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,
.remove = net_remove,
};
static int uml_inetaddr_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
struct in_ifaddr *ifa = ptr;
struct net_device *dev = ifa->ifa_dev->dev;
struct uml_net_private *lp;
void (*proc)(unsigned char *, unsigned char *, void *);
unsigned char addr_buf[4], netmask_buf[4];
if(dev->open != uml_net_open)
return NOTIFY_DONE;
lp = dev->priv;
proc = NULL;
switch (event){
case NETDEV_UP:
proc = lp->add_address;
break;
case NETDEV_DOWN:
proc = lp->delete_address;
break;
}
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;
}
/* uml_net_init shouldn't be called twice on two CPUs at the same time */
struct notifier_block uml_inetaddr_notifier = {
.notifier_call = uml_inetaddr_event,
};
static int uml_net_init(void)
{
struct list_head *ele;
struct uml_net_private *lp;
struct in_device *ip;
struct in_ifaddr *in;
mconsole_register_dev(&net_mc);
register_inetaddr_notifier(&uml_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.
*/
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;
in = ip->ifa_list;
while(in != NULL){
uml_inetaddr_event(NULL, NETDEV_UP, in);
in = in->ifa_next;
}
}
spin_unlock(&opened_lock);
return 0;
}
__initcall(uml_net_init);
static void close_devices(void)
{
struct list_head *ele;
struct uml_net_private *lp;
spin_lock(&opened_lock);
list_for_each(ele, &opened){
lp = list_entry(ele, struct uml_net_private, list);
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);
}
spin_unlock(&opened_lock);
}
__uml_exitcall(close_devices);
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 *arg)
{
struct net_device *dev = d;
struct in_device *ip = dev->ip_ptr;
struct in_ifaddr *in;
unsigned char address[4], netmask[4];
if(ip == NULL) return;
in = ip->ifa_list;
while(in != NULL){
memcpy(address, &in->ifa_address, sizeof(address));
memcpy(netmask, &in->ifa_mask, sizeof(netmask));
(*cb)(address, netmask, arg);
in = in->ifa_next;
}
}
int dev_netmask(void *d, void *m)
{
struct net_device *dev = d;
struct in_device *ip = dev->ip_ptr;
struct in_ifaddr *in;
__be32 *mask_out = m;
if(ip == NULL)
return(1);
in = ip->ifa_list;
if(in == NULL)
return(1);
*mask_out = in->ifa_mask;
return(0);
}
void *get_output_buffer(int *len_out)
{
void *ret;
ret = (void *) __get_free_pages(GFP_KERNEL, 0);
if(ret) *len_out = PAGE_SIZE;
else *len_out = 0;
return ret;
}
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,
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);
}
return(0);
}
unsigned short eth_protocol(struct sk_buff *skb)
{
return(eth_type_trans(skb, skb->dev));
}

262
arch/um/drivers/net_user.c Normal file
View File

@@ -0,0 +1,262 @@
/*
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include <stddef.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include "user.h"
#include "user_util.h"
#include "kern_util.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;
}
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");
}
}
/* Do reliable error handling as this fails frequently enough. */
void read_output(int fd, char *output, int len)
{
int remain, ret, expected;
char c;
char *str;
if(output == NULL){
output = &c;
len = sizeof(c);
}
*output = '\0';
ret = os_read_file(fd, &remain, sizeof(remain));
if (ret != sizeof(remain)) {
expected = sizeof(remain);
str = "length";
goto err;
}
while(remain != 0){
expected = (remain < len) ? remain : len;
ret = os_read_file(fd, output, expected);
if (ret != expected) {
str = "data";
goto err;
}
remain -= ret;
}
return;
err:
if (ret < 0)
printk("read_output - read of %s failed, errno = %d\n", str, -ret);
else
printk("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);
if(n == -EAGAIN)
return 0;
else if(n == 0)
return -ENOTCONN;
return n;
}
int net_recvfrom(int fd, void *buf, int len)
{
int n;
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;
}
int net_write(int fd, void *buf, int len)
{
int n;
n = os_write_file(fd, buf, len);
if(n == -EAGAIN)
return 0;
else if(n == 0)
return -ENOTCONN;
return n;
}
int net_send(int fd, void *buf, int len)
{
int n;
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;
}
int net_sendto(int fd, void *buf, int len, void *to, int sock_len)
{
int n;
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;
}
struct change_pre_exec_data {
int close_me;
int stdout;
};
static void change_pre_exec(void *arg)
{
struct change_pre_exec_data *data = arg;
os_close_file(data->close_me);
dup2(data->stdout, 1);
}
static int change_tramp(char **argv, char *output, int output_len)
{
int pid, fds[2], err;
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;
}
pe_data.close_me = fds[0];
pe_data.stdout = fds[1];
pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
if (pid > 0) /* Avoid hang as we won't get data in failure case. */
read_output(fds[0], output, output_len);
os_close_file(fds[0]);
os_close_file(fds[1]);
if (pid > 0)
CATCH_EINTR(err = waitpid(pid, NULL, 0));
return pid;
}
static void change(char *dev, char *what, unsigned char *addr,
unsigned char *netmask)
{
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,
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],
netmask[2], netmask[3]);
output_len = page_size();
output = um_kmalloc(output_len);
if(output == NULL)
printk("change : failed to allocate output buffer\n");
pid = change_tramp(argv, output, output_len);
if(pid < 0) return;
if(output != NULL){
printk("%s", output);
kfree(output);
}
}
void open_addr(unsigned char *addr, unsigned char *netmask, void *arg)
{
change(arg, "add", addr, netmask);
}
void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
{
change(arg, "del", addr, netmask);
}
char *split_if_spec(char *str, ...)
{
char **arg, *end;
va_list ap;
va_start(ap, str);
while((arg = va_arg(ap, char **)) != NULL){
if(*str == '\0')
return NULL;
end = strchr(str, ',');
if(end != str)
*arg = str;
if(end == NULL)
return NULL;
*end++ = '\0';
str = end;
}
va_end(ap);
return str;
}

57
arch/um/drivers/null.c Normal file
View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include <stdlib.h>
#include <errno.h>
#include "chan_user.h"
#include "os.h"
/* This address is used only as a unique identifer */
static int null_chan;
static void *null_init(char *str, int device, const struct chan_opts *opts)
{
return(&null_chan);
}
static int null_open(int input, int output, int primary, void *d,
char **dev_out)
{
*dev_out = NULL;
return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0));
}
static int null_read(int fd, char *c_out, void *unused)
{
return(-ENODEV);
}
static void null_free(void *data)
{
}
const struct chan_ops null_ops = {
.type = "null",
.init = null_init,
.open = null_open,
.close = generic_close,
.read = null_read,
.write = generic_write,
.console_write = generic_console_write,
.window_size = generic_window_size,
.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:
*/

112
arch/um/drivers/pcap_kern.c Normal file
View File

@@ -0,0 +1,112 @@
/*
* Copyright (C) 2002 Jeff Dike <jdike@karaya.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 "pcap_user.h"
struct pcap_init {
char *host_if;
int promisc;
int optimize;
char *filter;
};
void pcap_init(struct net_device *dev, void *data)
{
struct uml_net_private *pri;
struct pcap_data *ppri;
struct pcap_init *init = data;
pri = dev->priv;
ppri = (struct pcap_data *) pri->user;
ppri->host_if = init->host_if;
ppri->promisc = init->promisc;
ppri->optimize = init->optimize;
ppri->filter = init->filter;
}
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));
}
static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
{
return(-EPERM);
}
static const struct net_kern_info pcap_kern_info = {
.init = pcap_init,
.protocol = eth_protocol,
.read = pcap_read,
.write = pcap_write,
};
int pcap_setup(char *str, char **mac_out, void *data)
{
struct pcap_init *init = data;
char *remain, *host_if = NULL, *options[2] = { NULL, NULL };
int i;
*init = ((struct pcap_init)
{ .host_if = "eth0",
.promisc = 1,
.optimize = 0,
.filter = NULL });
remain = split_if_spec(str, &host_if, &init->filter,
&options[0], &options[1], NULL);
if(remain != NULL){
printk(KERN_ERR "pcap_setup - Extra garbage on "
"specification : '%s'\n", remain);
return(0);
}
if(host_if != NULL)
init->host_if = host_if;
for(i = 0; i < ARRAY_SIZE(options); i++){
if(options[i] == NULL)
continue;
if(!strcmp(options[i], "promisc"))
init->promisc = 1;
else if(!strcmp(options[i], "nopromisc"))
init->promisc = 0;
else if(!strcmp(options[i], "optimize"))
init->optimize = 1;
else if(!strcmp(options[i], "nooptimize"))
init->optimize = 0;
else printk("pcap_setup : bad option - '%s'\n", options[i]);
}
return(1);
}
static struct transport pcap_transport = {
.list = LIST_HEAD_INIT(pcap_transport.list),
.name = "pcap",
.setup = pcap_setup,
.user = &pcap_user_info,
.kern = &pcap_kern_info,
.private_size = sizeof(struct pcap_data),
.setup_size = sizeof(struct pcap_init),
};
static int register_pcap(void)
{
register_transport(&pcap_transport);
return 0;
}
late_initcall(register_pcap);

144
arch/um/drivers/pcap_user.c Normal file
View File

@@ -0,0 +1,144 @@
/*
* Copyright (C) 2002 Jeff Dike <jdike@karaya.com>
* Licensed under the GPL.
*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pcap.h>
#include <asm/types.h>
#include "net_user.h"
#include "pcap_user.h"
#include "user.h"
#include "um_malloc.h"
#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
#define PCAP_FD(p) (*(int *)(p))
static void 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;
}
pri->dev = dev;
pri->pcap = p;
}
static int pcap_open(void *data)
{
struct pcap_data *pri = data;
__u32 netmask;
int err;
if(pri->pcap == NULL)
return(-ENODEV);
if(pri->filter != NULL){
err = dev_netmask(pri->dev, &netmask);
if(err < 0){
printk("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);
}
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);
}
err = pcap_setfilter(pri->pcap, pri->compiled);
if(err < 0){
printk("pcap_open : pcap_setfilter failed - '%s'\n",
pcap_geterr(pri->pcap));
return(-EIO);
}
}
return(PCAP_FD(pri->pcap));
}
static void pcap_remove(void *data)
{
struct pcap_data *pri = data;
if(pri->compiled != NULL)
pcap_freecode(pri->compiled);
pcap_close(pri->pcap);
}
struct pcap_handler_data {
char *buffer;
int len;
};
static void handler(u_char *data, const struct pcap_pkthdr *header,
const u_char *packet)
{
int len;
struct pcap_handler_data *hdata = (struct pcap_handler_data *) data;
len = hdata->len < header->caplen ? hdata->len : header->caplen;
memcpy(hdata->buffer, packet, len);
hdata->len = len;
}
int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri)
{
struct pcap_handler_data hdata = ((struct pcap_handler_data)
{ .buffer = buffer,
.len = len });
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);
}
else if(n == 0)
return(0);
return(hdata.len);
}
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
};
/*
* 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:
*/

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include "net_user.h"
struct pcap_data {
char *host_if;
int promisc;
int optimize;
char *filter;
void *compiled;
void *pcap;
void *dev;
};
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:
*/

30
arch/um/drivers/port.h Normal file
View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __PORT_H__
#define __PORT_H__
extern void *port_data(int port);
extern int port_wait(void *data);
extern void port_kern_close(void *d);
extern int port_connection(int fd, int *socket_out, int *pid_out);
extern int port_listen_fd(int port);
extern void port_read(int fd, void *data);
extern void port_kern_free(void *d);
extern int port_rcv_fd(int fd);
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:
*/

307
arch/um/drivers/port_kern.c Normal file
View File

@@ -0,0 +1,307 @@
/*
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.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 "port.h"
#include "init.h"
#include "os.h"
struct port_list {
struct list_head list;
atomic_t wait_count;
int has_connection;
struct completion done;
int port;
int fd;
spinlock_t lock;
struct list_head pending;
struct list_head connections;
};
struct port_dev {
struct port_list *port;
int helper_pid;
int telnetd_pid;
};
struct connection {
struct list_head list;
int fd;
int helper_pid;
int socket[2];
int telnetd_pid;
struct port_list *port;
};
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;
printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n",
-fd);
os_close_file(conn->fd);
}
list_del(&conn->list);
conn->fd = fd;
list_add(&conn->list, &conn->port->connections);
complete(&conn->port->done);
return IRQ_HANDLED;
}
#define NO_WAITER_MSG \
"****\n" \
"There are currently no UML consoles waiting for port connections.\n" \
"Either disconnect from one to make it available or activate some more\n" \
"by enabling more consoles in the UML /etc/inittab.\n" \
"****\n"
static int port_accept(struct port_list *port)
{
struct connection *conn;
int fd, socket[2], pid, ret = 0;
fd = port_connection(port->fd, socket, &pid);
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){
printk(KERN_ERR "port_accept : failed to allocate "
"connection\n");
goto out_close;
}
*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,
IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
"telnetd", conn)){
printk(KERN_ERR "port_accept : failed to get IRQ for "
"telnetd\n");
goto out_free;
}
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");
}
list_add(&conn->list, &port->pending);
return 1;
out_free:
kfree(conn);
out_close:
os_close_file(fd);
if(pid != -1)
os_kill_process(pid, 1);
out:
return ret;
}
static DECLARE_MUTEX(ports_sem);
static LIST_HEAD(ports);
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){
port = list_entry(ele, struct port_list, list);
if(!port->has_connection)
continue;
reactivate_fd(port->fd, ACCEPT_IRQ);
while(port_accept(port)) ;
port->has_connection = 0;
}
local_irq_restore(flags);
}
DECLARE_WORK(port_work, port_work_proc);
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;
}
void *port_data(int port_num)
{
struct list_head *ele;
struct port_list *port;
struct port_dev *dev = NULL;
int fd;
down(&ports_sem);
list_for_each(ele, &ports){
port = list_entry(ele, struct port_list, list);
if(port->port == port_num) goto found;
}
port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
if(port == NULL){
printk(KERN_ERR "Allocation of port list failed\n");
goto out;
}
fd = port_listen_fd(port_num);
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,
IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
"port", port)){
printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
goto out_close;
}
*port = ((struct port_list)
{ .list = LIST_HEAD_INIT(port->list),
.wait_count = ATOMIC_INIT(0),
.has_connection = 0,
.port = port_num,
.fd = fd,
.pending = LIST_HEAD_INIT(port->pending),
.connections = LIST_HEAD_INIT(port->connections) });
spin_lock_init(&port->lock);
init_completion(&port->done);
list_add(&port->list, &ports);
found:
dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
if(dev == NULL){
printk(KERN_ERR "Allocation of port device entry failed\n");
goto out;
}
*dev = ((struct port_dev) { .port = port,
.helper_pid = -1,
.telnetd_pid = -1 });
goto out;
out_free:
kfree(port);
out_close:
os_close_file(fd);
out:
up(&ports_sem);
return dev;
}
int port_wait(void *data)
{
struct port_dev *dev = data;
struct connection *conn;
struct port_list *port = dev->port;
int fd;
atomic_inc(&port->wait_count);
while(1){
fd = -ERESTARTSYS;
if(wait_for_completion_interruptible(&port->done))
goto out;
spin_lock(&port->lock);
conn = list_entry(port->connections.next, struct connection,
list);
list_del(&conn->list);
spin_unlock(&port->lock);
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]);
/* 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
* connections until a good one is found.
*/
free_irq(TELNETD_IRQ, conn);
if(conn->fd >= 0) break;
os_close_file(conn->fd);
kfree(conn);
}
fd = conn->fd;
dev->helper_pid = conn->helper_pid;
dev->telnetd_pid = conn->telnetd_pid;
kfree(conn);
out:
atomic_dec(&port->wait_count);
return fd;
}
void port_remove_dev(void *d)
{
struct port_dev *dev = d;
if(dev->helper_pid != -1)
os_kill_process(dev->helper_pid, 0);
if(dev->telnetd_pid != -1)
os_kill_process(dev->telnetd_pid, 1);
dev->helper_pid = -1;
dev->telnetd_pid = -1;
}
void port_kern_free(void *d)
{
struct port_dev *dev = d;
port_remove_dev(dev);
kfree(dev);
}
static void free_port(void)
{
struct list_head *ele;
struct port_list *port;
list_for_each(ele, &ports){
port = list_entry(ele, struct port_list, list);
free_irq_by_fd(port->fd);
os_close_file(port->fd);
}
}
__uml_exitcall(free_port);

207
arch/um/drivers/port_user.c Normal file
View File

@@ -0,0 +1,207 @@
/*
* Copyright (C) 2001 Jeff Dike (jdike@karaya.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 <netinet/in.h>
#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "chan_user.h"
#include "port.h"
#include "os.h"
#include "um_malloc.h"
struct port_chan {
int raw;
struct termios tt;
void *kernel_data;
char dev[sizeof("32768\0")];
};
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;
}
str++;
port = strtoul(str, &end, 0);
if((*end != '\0') || (end == str)){
printk("port_init : couldn't parse port '%s'\n", str);
return NULL;
}
kern_data = port_data(port);
if(kern_data == NULL)
return NULL;
data = um_kmalloc(sizeof(*data));
if(data == NULL)
goto err;
*data = ((struct port_chan) { .raw = opts->raw,
.kernel_data = kern_data });
sprintf(data->dev, "%d", port);
return data;
err:
port_kern_free(kern_data);
return NULL;
}
static void port_free(void *d)
{
struct port_chan *data = d;
port_kern_free(data->kernel_data);
kfree(data);
}
static int port_open(int input, int output, int primary, void *d,
char **dev_out)
{
struct port_chan *data = d;
int fd, err;
fd = port_wait(data->kernel_data);
if((fd >= 0) && data->raw){
CATCH_EINTR(err = tcgetattr(fd, &data->tt));
if(err)
return err;
err = raw(fd);
if(err)
return err;
}
*dev_out = data->dev;
return fd;
}
static void port_close(int fd, void *d)
{
struct port_chan *data = d;
port_remove_dev(data->kernel_data);
os_close_file(fd);
}
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 = generic_console_write,
.window_size = generic_window_size,
.free = port_free,
.winch = 1,
};
int port_listen_fd(int port)
{
struct sockaddr_in addr;
int fd, err, arg;
fd = socket(PF_INET, SOCK_STREAM, 0);
if(fd == -1)
return -errno;
arg = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){
err = -errno;
goto out;
}
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){
err = -errno;
goto out;
}
if(listen(fd, 1) < 0){
err = -errno;
goto out;
}
err = os_set_fd_block(fd, 0);
if(err < 0)
goto out;
return fd;
out:
os_close_file(fd);
return err;
}
struct port_pre_exec_data {
int sock_fd;
int pipe_fd;
};
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);
dup2(data->pipe_fd, 3);
os_shutdown_socket(3, 1, 0);
os_close_file(data->pipe_fd);
}
int port_connection(int fd, int *socket, int *pid_out)
{
int new, err;
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;
err = os_pipe(socket, 0, 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)
goto out_shutdown;
*pid_out = err;
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]);
out_close:
os_close_file(new);
return err;
}

157
arch/um/drivers/pty.c Normal file
View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
#include "chan_user.h"
#include "user.h"
#include "user_util.h"
#include "kern_util.h"
#include "os.h"
#include "um_malloc.h"
struct pty_chan {
void (*announce)(char *dev_name, int dev);
int dev;
int raw;
struct termios tt;
char dev_name[sizeof("/dev/pts/0123456\0")];
};
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,
.dev = device,
.raw = opts->raw });
return(data);
}
static int pts_open(int input, int output, int primary, void *d,
char **dev_out)
{
struct pty_chan *data = d;
char *dev;
int fd, err;
fd = get_pty();
if(fd < 0){
err = -errno;
printk("open_pts : Failed to open pts\n");
return err;
}
if(data->raw){
CATCH_EINTR(err = tcgetattr(fd, &data->tt));
if(err)
return(err);
err = raw(fd);
if(err)
return(err);
}
dev = ptsname(fd);
sprintf(data->dev_name, "%s", dev);
*dev_out = data->dev_name;
if (data->announce)
(*data->announce)(dev, data->dev);
return(fd);
}
static int getmaster(char *line)
{
char *pty, *bank, *cp;
int master, err;
pty = &line[strlen("/dev/ptyp")];
for (bank = "pqrs"; *bank; bank++) {
line[strlen("/dev/pty")] = *bank;
*pty = '0';
if (os_stat_file(line, NULL) < 0)
break;
for (cp = "0123456789abcdef"; *cp; cp++) {
*pty = *cp;
master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
if (master >= 0) {
char *tp = &line[strlen("/dev/")];
/* verify slave side is usable */
*tp = 't';
err = os_access(line, OS_ACC_RW_OK);
*tp = 'p';
if(err == 0) return(master);
(void) os_close_file(master);
}
}
}
return(-1);
}
static int pty_open(int input, int output, int primary, void *d,
char **dev_out)
{
struct pty_chan *data = d;
int fd, err;
char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
fd = getmaster(dev);
if(fd < 0)
return(-errno);
if(data->raw){
err = raw(fd);
if(err)
return(err);
}
if(data->announce) (*data->announce)(dev, data->dev);
sprintf(data->dev_name, "%s", dev);
*dev_out = data->dev_name;
return(fd);
}
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 = generic_console_write,
.window_size = generic_window_size,
.free = generic_free,
.winch = 0,
};
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 = 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:
*/

131
arch/um/drivers/random.c Normal file
View File

@@ -0,0 +1,131 @@
/* Copyright (C) 2005 Jeff Dike <jdike@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/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include "os.h"
/*
* core module and version information
*/
#define RNG_VERSION "1.0.0"
#define RNG_MODULE_NAME "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 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)
return -EINVAL;
return 0;
}
static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
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())
schedule_timeout_interruptible(1);
}
else return n;
if (signal_pending (current))
return ret ? : -ERESTARTSYS;
}
return ret;
}
static const struct file_operations rng_chrdev_ops = {
.owner = THIS_MODULE,
.open = rng_dev_open,
.read = rng_dev_read,
};
/* 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,
};
/*
* rng_init - initialize RNG module
*/
static int __init rng_init (void)
{
int err;
err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
if(err < 0)
goto out;
random_fd = err;
err = os_set_fd_block(random_fd, 0);
if(err)
goto err_out_cleanup_hw;
err = misc_register (&rng_miscdev);
if (err) {
printk (KERN_ERR RNG_MODULE_NAME ": misc device register failed\n");
goto err_out_cleanup_hw;
}
out:
return err;
err_out_cleanup_hw:
random_fd = -1;
goto out;
}
/*
* rng_cleanup - shutdown RNG module
*/
static void __exit rng_cleanup (void)
{
misc_deregister (&rng_miscdev);
}
module_init (rng_init);
module_exit (rng_cleanup);
MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
MODULE_LICENSE("GPL");

20
arch/um/drivers/slip.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef __UM_SLIP_H
#define __UM_SLIP_H
#include "slip_common.h"
struct slip_data {
void *dev;
char name[sizeof("slnnnnn\0")];
char *addr;
char *gate_addr;
int slave;
struct slip_proto slip;
};
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);
#endif

View File

@@ -0,0 +1,54 @@
#include <string.h>
#include "slip_common.h"
#include "net_user.h"
int slip_proto_read(int fd, void *buf, int len, struct slip_proto *slip)
{
int i, n, size, start;
if(slip->more > 0){
i = 0;
while(i < slip->more){
size = slip_unesc(slip->ibuf[i++], slip->ibuf,
&slip->pos, &slip->esc);
if(size){
memcpy(buf, slip->ibuf, size);
memmove(slip->ibuf, &slip->ibuf[i],
slip->more - i);
slip->more = slip->more - i;
return size;
}
}
slip->more = 0;
}
n = net_read(fd, &slip->ibuf[slip->pos],
sizeof(slip->ibuf) - slip->pos);
if(n <= 0)
return n;
start = slip->pos;
for(i = 0; i < n; i++){
size = slip_unesc(slip->ibuf[start + i], slip->ibuf,&slip->pos,
&slip->esc);
if(size){
memcpy(buf, slip->ibuf, size);
memmove(slip->ibuf, &slip->ibuf[start+i+1],
n - (i + 1));
slip->more = n - (i + 1);
return size;
}
}
return 0;
}
int slip_proto_write(int fd, void *buf, int len, struct slip_proto *slip)
{
int actual, n;
actual = slip_esc(buf, slip->obuf, len);
n = net_write(fd, slip->obuf, actual);
if(n < 0)
return n;
else return len;
}

View File

@@ -0,0 +1,105 @@
#ifndef __UM_SLIP_COMMON_H
#define __UM_SLIP_COMMON_H
#define BUF_SIZE 1500
/* two bytes each for a (pathological) max packet of escaped chars + *
* terminating END char + initial END char */
#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
/* SLIP protocol characters. */
#define SLIP_END 0300 /* indicates end of frame */
#define SLIP_ESC 0333 /* indicates byte stuffing */
#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */
#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
static inline int slip_unesc(unsigned char c, unsigned char *buf, int *pos,
int *esc)
{
int ret;
switch(c){
case SLIP_END:
*esc = 0;
ret=*pos;
*pos=0;
return(ret);
case SLIP_ESC:
*esc = 1;
return(0);
case SLIP_ESC_ESC:
if(*esc){
*esc = 0;
c = SLIP_ESC;
}
break;
case SLIP_ESC_END:
if(*esc){
*esc = 0;
c = SLIP_END;
}
break;
}
buf[(*pos)++] = c;
return(0);
}
static inline int slip_esc(unsigned char *s, unsigned char *d, int len)
{
unsigned char *ptr = d;
unsigned char c;
/*
* Send an initial END character to flush out any
* data that may have accumulated in the receiver
* due to line noise.
*/
*ptr++ = SLIP_END;
/*
* For each byte in the packet, send the appropriate
* character sequence, according to the SLIP protocol.
*/
while (len-- > 0) {
switch(c = *s++) {
case SLIP_END:
*ptr++ = SLIP_ESC;
*ptr++ = SLIP_ESC_END;
break;
case SLIP_ESC:
*ptr++ = SLIP_ESC;
*ptr++ = SLIP_ESC_ESC;
break;
default:
*ptr++ = c;
break;
}
}
*ptr++ = SLIP_END;
return (ptr - d);
}
struct slip_proto {
unsigned char ibuf[ENC_BUF_SIZE];
unsigned char obuf[ENC_BUF_SIZE];
int more; /* more data: do not read fd until ibuf has been drained */
int pos;
int esc;
};
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,
struct slip_proto *slip);
extern int slip_proto_write(int fd, void *buf, int len,
struct slip_proto *slip);
#endif

View File

@@ -0,0 +1,98 @@
#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"
#include "slip.h"
struct slip_init {
char *gate_addr;
};
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;
spri = (struct slip_data *) private->user;
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->init = NULL;
dev->header_cache_update = NULL;
dev->hard_header_cache = NULL;
dev->hard_header = NULL;
dev->hard_header_len = 0;
dev->addr_len = 0;
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = 256;
dev->flags = IFF_NOARP;
printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
}
static unsigned short slip_protocol(struct sk_buff *skbuff)
{
return(htons(ETH_P_IP));
}
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));
}
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));
}
const struct net_kern_info slip_kern_info = {
.init = slip_init,
.protocol = slip_protocol,
.read = slip_read,
.write = slip_write,
};
static int slip_setup(char *str, char **mac_out, void *data)
{
struct slip_init *init = data;
*init = ((struct slip_init)
{ .gate_addr = NULL });
if(str[0] != '\0')
init->gate_addr = str;
return(1);
}
static struct transport slip_transport = {
.list = LIST_HEAD_INIT(slip_transport.list),
.name = "slip",
.setup = slip_setup,
.user = &slip_user_info,
.kern = &slip_kern_info,
.private_size = sizeof(struct slip_data),
.setup_size = sizeof(struct slip_init),
};
static int register_slip(void)
{
register_transport(&slip_transport);
return 0;
}
late_initcall(register_slip);

254
arch/um/drivers/slip_user.c Normal file
View File

@@ -0,0 +1,254 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <sched.h>
#include <string.h>
#include <errno.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 "slip.h"
#include "slip_common.h"
#include "os.h"
#include "um_malloc.h"
void slip_user_init(void *data, void *dev)
{
struct slip_data *pri = data;
pri->dev = dev;
}
static int set_up_tty(int fd)
{
int i;
struct termios tios;
if (tcgetattr(fd, &tios) < 0) {
printk("could not get initial terminal attributes\n");
return(-1);
}
tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
tios.c_iflag = IGNBRK | IGNPAR;
tios.c_oflag = 0;
tios.c_lflag = 0;
for (i = 0; i < NCCS; i++)
tios.c_cc[i] = 0;
tios.c_cc[VMIN] = 1;
tios.c_cc[VTIME] = 0;
cfsetospeed(&tios, B38400);
cfsetispeed(&tios, B38400);
if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
printk("failed to set terminal attributes\n");
return(-1);
}
return(0);
}
struct slip_pre_exec_data {
int stdin;
int stdout;
int close_me;
};
static void slip_pre_exec(void *arg)
{
struct slip_pre_exec_data *data = arg;
if(data->stdin >= 0) dup2(data->stdin, 0);
dup2(data->stdout, 1);
if(data->close_me >= 0) os_close_file(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;
err = os_pipe(fds, 1, 0);
if(err < 0){
printk("slip_tramp : pipe failed, err = %d\n", -err);
goto out;
}
err = 0;
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)
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");
os_kill_process(pid, 1);
err = -ENOMEM;
goto out_free;
}
os_close_file(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;
os_close_file(fds[0]);
out_free:
kfree(output);
return err;
out_close:
os_close_file(fds[0]);
os_close_file(fds[1]);
out:
return err;
}
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,
NULL };
int sfd, mfd, err;
err = get_pty();
if(err < 0){
printk("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);
goto out_close;
}
sfd = err;
if(set_up_tty(sfd))
goto out_close2;
pri->slave = sfd;
pri->slip.pos = 0;
pri->slip.esc = 0;
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);
goto out_close2;
}
err = os_get_ifname(pri->slave, pri->name);
if(err < 0){
printk("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);
goto out_close2;
}
}
return(mfd);
out_close2:
os_close_file(sfd);
out_close:
os_close_file(mfd);
out:
return err;
}
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,
NULL };
int err;
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);
pri->slave = -1;
}
int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
{
return slip_proto_read(fd, buf, len, &pri->slip);
}
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;
open_addr(addr, netmask, pri->name);
}
static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
void *data)
{
struct slip_data *pri = data;
if(pri->slave < 0) return;
close_addr(addr, netmask, pri->name);
}
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
};

33
arch/um/drivers/slirp.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef __UM_SLIRP_H
#define __UM_SLIRP_H
#include "slip_common.h"
#define SLIRP_MAX_ARGS 100
/*
* XXX this next definition is here because I don't understand why this
* initializer doesn't work in slirp_kern.c:
*
* argv : { init->argv[ 0 ... SLIRP_MAX_ARGS-1 ] },
*
* or why I can't typecast like this:
*
* argv : (char* [SLIRP_MAX_ARGS])(init->argv),
*/
struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; };
struct slirp_data {
void *dev;
struct arg_list_dummy_wrapper argw;
int pid;
int slave;
struct slip_proto slip;
};
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,
struct slirp_data *pri);
#endif

View File

@@ -0,0 +1,122 @@
#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"
#include "slirp.h"
struct slirp_init {
struct arg_list_dummy_wrapper argw; /* XXX should be simpler... */
};
void slirp_init(struct net_device *dev, void *data)
{
struct uml_net_private *private;
struct slirp_data *spri;
struct slirp_init *init = data;
int i;
private = dev->priv;
spri = (struct slirp_data *) private->user;
spri->argw = init->argw;
spri->pid = -1;
spri->slave = -1;
spri->dev = dev;
slip_proto_init(&spri->slip);
dev->init = NULL;
dev->hard_header_len = 0;
dev->header_cache_update = NULL;
dev->hard_header_cache = NULL;
dev->hard_header = 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++) {
printk(" '%s'",spri->argw.argv[i]);
}
printk("\n");
}
static unsigned short slirp_protocol(struct sk_buff *skbuff)
{
return(htons(ETH_P_IP));
}
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));
}
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));
}
const struct net_kern_info slirp_kern_info = {
.init = slirp_init,
.protocol = slirp_protocol,
.read = slirp_read,
.write = slirp_write,
};
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 } } });
str = split_if_spec(str, mac_out, NULL);
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");
break;
}
init->argw.argv[i++] = str;
while(*str && *str!=',') {
if(*str=='_') *str=' ';
str++;
}
if(*str!=',')
break;
*str++='\0';
} while(1);
init->argw.argv[i]=NULL;
return(1);
}
static struct transport slirp_transport = {
.list = LIST_HEAD_INIT(slirp_transport.list),
.name = "slirp",
.setup = slirp_setup,
.user = &slirp_user_info,
.kern = &slirp_kern_info,
.private_size = sizeof(struct slirp_data),
.setup_size = sizeof(struct slirp_init),
};
static int register_slirp(void)
{
register_transport(&slirp_transport);
return 0;
}
late_initcall(register_slirp);

View File

@@ -0,0 +1,138 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <sched.h>
#include <string.h>
#include <errno.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 "slirp.h"
#include "slip_common.h"
#include "os.h"
void slirp_user_init(void *data, void *dev)
{
struct slirp_data *pri = data;
pri->dev = dev;
}
struct slirp_pre_exec_data {
int stdin;
int stdout;
};
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);
}
static int slirp_tramp(char **argv, int fd)
{
struct slirp_pre_exec_data pe_data;
int pid;
pe_data.stdin = fd;
pe_data.stdout = fd;
pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL);
return(pid);
}
static int slirp_open(void *data)
{
struct slirp_data *pri = data;
int fds[2], pid, err;
err = os_pipe(fds, 1, 1);
if(err)
return(err);
err = slirp_tramp(pri->argw.argv, fds[1]);
if(err < 0){
printk("slirp_tramp failed - errno = %d\n", -err);
goto out;
}
pid = err;
pri->slave = fds[1];
pri->slip.pos = 0;
pri->slip.esc = 0;
pri->pid = err;
return(fds[0]);
out:
os_close_file(fds[0]);
os_close_file(fds[1]);
return err;
}
static void slirp_close(int fd, void *data)
{
struct slirp_data *pri = data;
int status,err;
os_close_file(fd);
os_close_file(pri->slave);
pri->slave = -1;
if(pri->pid<1) {
printk("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);
}
#endif
CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG));
if(err < 0) {
printk("slirp_close: waitpid returned %d\n", errno);
return;
}
if(err == 0) {
printk("slirp_close: process %d has not exited\n", pri->pid);
return;
}
pri->pid = -1;
}
int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
{
return slip_proto_read(fd, buf, len, &pri->slip);
}
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);
}
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
};

229
arch/um/drivers/ssl.c Normal file
View File

@@ -0,0 +1,229 @@
/*
* Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#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 "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 "mconsole_kern.h"
static const 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;
#define NR_PORTS 64
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, char **error_out);
static int ssl_get_config(char *dev, char *str, int size, char **error_out);
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",
.major = TTY_MAJOR,
.minor_start = 64,
.type = TTY_DRIVER_TYPE_SERIAL,
.subtype = 0,
.read_irq = SSL_IRQ,
.read_irq_name = "ssl",
.write_irq = SSL_WRITE_IRQ,
.write_irq_name = "ssl-write",
.mc = {
.list = LIST_HEAD_INIT(driver.mc.list),
.name = "ssl",
.config = ssl_config,
.get_config = ssl_get_config,
.id = line_id,
.remove = ssl_remove,
},
};
/* 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 int ssl_config(char *str, char **error_out)
{
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, ARRAY_SIZE(serial_lines), str,
size, error_out);
}
static int ssl_remove(int n, char **error_out)
{
return line_remove(serial_lines, ARRAY_SIZE(serial_lines), n,
error_out);
}
static int ssl_open(struct tty_struct *tty, struct file *filp)
{
return line_open(serial_lines, tty);
}
#if 0
static void ssl_flush_buffer(struct tty_struct *tty)
{
return;
}
static void ssl_stop(struct tty_struct *tty)
{
printk(KERN_ERR "Someone should implement ssl_stop\n");
}
static void ssl_start(struct tty_struct *tty)
{
printk(KERN_ERR "Someone should implement ssl_start\n");
}
void ssl_hangup(struct tty_struct *tty)
{
}
#endif
static const struct tty_operations ssl_ops = {
.open = ssl_open,
.close = line_close,
.write = line_write,
.put_char = line_put_char,
.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,
#if 0
.stop = ssl_stop,
.start = ssl_start,
.hangup = ssl_hangup,
#endif
};
/* Changed by ssl_init and referenced by ssl_exit, which are both serialized
* by being an initcall and exitcall, respectively.
*/
static int ssl_init_done = 0;
static void ssl_console_write(struct console *c, const char *string,
unsigned len)
{
struct line *line = &serial_lines[c->index];
unsigned long flags;
spin_lock_irqsave(&line->lock, flags);
console_write_chan(&line->chan_list, 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;
}
static int ssl_console_setup(struct console *co, char *options)
{
struct line *line = &serial_lines[co->index];
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|CON_ANYTIME,
.index = -1,
};
static int ssl_init(void)
{
char *new_title;
printk(KERN_INFO "Initializing software serial port version %d\n",
ssl_version);
ssl_driver = register_lines(&driver, &ssl_ops, serial_lines,
ARRAY_SIZE(serial_lines));
lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts);
new_title = add_xterm_umid(opts.xterm_title);
if (new_title != NULL)
opts.xterm_title = new_title;
ssl_init_done = 1;
register_console(&ssl_cons);
return 0;
}
late_initcall(ssl_init);
static void ssl_exit(void)
{
if (!ssl_init_done)
return;
close_lines(serial_lines, ARRAY_SIZE(serial_lines));
}
__uml_exitcall(ssl_exit);
static int ssl_chan_setup(char *str)
{
char *error;
int ret;
ret = line_setup(serial_lines, ARRAY_SIZE(serial_lines), str, &error);
if(ret < 0)
printk(KERN_ERR "Failed to set up serial line with "
"configuration string \"%s\" : %s\n", str, error);
return 1;
}
__setup("ssl", ssl_chan_setup);
__channel_help(ssl_chan_setup, "ssl");

23
arch/um/drivers/ssl.h Normal file
View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __SSL_H__
#define __SSL_H__
extern int ssl_read(int fd, int line);
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:
*/

View File

@@ -0,0 +1,61 @@
#include <linux/init.h>
#include <linux/console.h>
#include "chan_user.h"
/* ----------------------------------------------------------------------------- */
/* 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.
*
* Initialized at init time.
*/
static int use_stderr_console = 0;
static void stderr_console_write(struct console *console, const char *string,
unsigned len)
{
generic_write(2 /* stderr */, string, len, NULL);
}
static struct console stderr_console = {
.name = "stderr",
.write = stderr_console_write,
.flags = CON_PRINTBUFFER,
};
static int __init stderr_console_init(void)
{
if (use_stderr_console)
register_console(&stderr_console);
return 0;
}
console_initcall(stderr_console_init);
static int stderr_setup(char *str)
{
if (!str)
return 0;
use_stderr_console = simple_strtoul(str,&str,0);
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);

View File

@@ -0,0 +1,203 @@
/*
* Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#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 "mconsole_kern.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)
{
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, char **error_out);
static int con_get_config(char *dev, char *str, int size, char **error_out);
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",
.major = TTY_MAJOR,
.minor_start = 0,
.type = TTY_DRIVER_TYPE_CONSOLE,
.subtype = SYSTEM_TYPE_CONSOLE,
.read_irq = CONSOLE_IRQ,
.read_irq_name = "console",
.write_irq = CONSOLE_WRITE_IRQ,
.write_irq_name = "console-write",
.mc = {
.list = LIST_HEAD_INIT(driver.mc.list),
.name = "con",
.config = con_config,
.get_config = con_get_config,
.id = line_id,
.remove = con_remove,
},
};
/* The array is initialized by line_init, at initcall time. The
* elements are locked individually as needed.
*/
static struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
[ 1 ... MAX_TTYS - 1 ] =
LINE_INIT(CONFIG_CON_CHAN, &driver) };
static int con_config(char *str, char **error_out)
{
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, ARRAY_SIZE(vts), str, size, error_out);
}
static int con_remove(int n, char **error_out)
{
return line_remove(vts, ARRAY_SIZE(vts), n, error_out);
}
static int con_open(struct tty_struct *tty, struct file *filp)
{
return line_open(vts, tty);
}
/* Set in an initcall, checked in an exitcall */
static int con_init_done = 0;
static const struct tty_operations console_ops = {
.open = con_open,
.close = line_close,
.write = line_write,
.put_char = line_put_char,
.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,
};
static void uml_console_write(struct console *console, const char *string,
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);
spin_unlock_irqrestore(&line->lock, flags);
}
static struct tty_driver *uml_console_device(struct console *c, int *index)
{
*index = c->index;
return console_driver;
}
static int uml_console_setup(struct console *co, char *options)
{
struct line *line = &vts[co->index];
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|CON_ANYTIME,
.index = -1,
};
int stdio_init(void)
{
char *new_title;
console_driver = register_lines(&driver, &console_ops, vts,
ARRAY_SIZE(vts));
if (console_driver == NULL)
return -1;
printk(KERN_INFO "Initialized stdio console driver\n");
lines_init(vts, ARRAY_SIZE(vts), &opts);
new_title = add_xterm_umid(opts.xterm_title);
if(new_title != NULL)
opts.xterm_title = new_title;
con_init_done = 1;
register_console(&stdiocons);
return 0;
}
late_initcall(stdio_init);
static void console_exit(void)
{
if (!con_init_done)
return;
close_lines(vts, ARRAY_SIZE(vts));
}
__uml_exitcall(console_exit);
static int console_chan_setup(char *str)
{
char *error;
int ret;
ret = line_setup(vts, ARRAY_SIZE(vts), str, &error);
if(ret < 0)
printk(KERN_ERR "Failed to set up console with "
"configuration string \"%s\" : %s\n", str, error);
return 1;
}
__setup("con", console_chan_setup);
__channel_help(console_chan_setup, "con");

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __STDIO_CONSOLE_H
#define __STDIO_CONSOLE_H
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:
*/

77
arch/um/drivers/tty.c Normal file
View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include <stdio.h>
#include <termios.h>
#include <errno.h>
#include <unistd.h>
#include "chan_user.h"
#include "user_util.h"
#include "user.h"
#include "os.h"
#include "um_malloc.h"
struct tty_chan {
char *dev;
int raw;
struct termios tt;
};
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 "
"a device\n");
return NULL;
}
str++;
data = um_kmalloc(sizeof(*data));
if(data == NULL)
return NULL;
*data = ((struct tty_chan) { .dev = str,
.raw = opts->raw });
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;
fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0);
if(fd < 0)
return fd;
if(data->raw){
CATCH_EINTR(err = tcgetattr(fd, &data->tt));
if(err)
return err;
err = raw(fd);
if(err)
return err;
}
*dev_out = data->dev;
return fd;
}
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 = generic_console_write,
.window_size = generic_window_size,
.free = generic_free,
.winch = 0,
};

1437
arch/um/drivers/ubd_kern.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com)
* Licensed under the GPL
*/
#include <stddef.h>
#include <unistd.h>
#include <errno.h>
#include <sched.h>
#include <signal.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/time.h>
#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);
}
int start_io_thread(unsigned long sp, int *fd_out)
{
int pid, fds[2], err;
err = os_pipe(fds, 1, 1);
if(err < 0){
printk("start_io_thread - os_pipe failed, err = %d\n", -err);
goto out;
}
kernel_fd = fds[0];
*fd_out = fds[1];
pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
NULL);
if(pid < 0){
printk("start_io_thread - clone failed : errno = %d\n", errno);
err = -errno;
goto out_close;
}
return(pid);
out_close:
os_close_file(fds[0]);
os_close_file(fds[1]);
kernel_fd = -1;
*fd_out = -1;
out:
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:
*/

217
arch/um/drivers/xterm.c Normal file
View File

@@ -0,0 +1,217 @@
/*
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.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 "xterm.h"
struct xterm_chan {
int pid;
int helper_pid;
char *title;
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, const struct chan_opts *opts)
{
struct xterm_chan *data;
data = malloc(sizeof(*data));
if(data == NULL) return(NULL);
*data = ((struct xterm_chan) { .pid = -1,
.helper_pid = -1,
.device = device,
.title = opts->xterm_title,
.raw = opts->raw,
.stack = opts->tramp_stack,
.direct_rcv = !opts->in_kernel } );
return(data);
}
/* Only changed by xterm_setup, which is a setup */
static char *terminal_emulator = "xterm";
static char *title_switch = "-T";
static char *exec_switch = "-e";
static int __init xterm_setup(char *line, int *add)
{
*add = 0;
terminal_emulator = line;
line = strchr(line, ',');
if(line == NULL) return(0);
*line++ = '\0';
if(*line) title_switch = line;
line = strchr(line, ',');
if(line == NULL) return(0);
*line++ = '\0';
if(*line) exec_switch = line;
return(0);
}
__uml_setup("xterm=", xterm_setup,
"xterm=<terminal emulator>,<title switch>,<exec switch>\n"
" Specifies an alternate terminal emulator to use for the debugger,\n"
" consoles, and serial lines when they are attached to the xterm channel.\n"
" The values are the terminal emulator binary, the switch it uses to set\n"
" its title, and the switch it uses to execute a subprocess,\n"
" respectively. The title switch must have the form '<switch> title',\n"
" not '<switch>=title'. Similarly, the exec switch must have the form\n"
" '<switch> command arg1 arg2 ...'.\n"
" The default values are 'xterm=xterm,-T,-e'. Values for gnome-terminal\n"
" 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,
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",
file, NULL };
if(os_access(argv[4], OS_ACC_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");
return -ENODEV;
}
fd = mkstemp(file);
if(fd < 0){
err = -errno;
printk("xterm_open : mkstemp failed, errno = %d\n", errno);
return err;
}
if(unlink(file)){
err = -errno;
printk("xterm_open : unlink failed, errno = %d\n", errno);
return err;
}
os_close_file(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);
}
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);
}
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);
}
if(new < 0){
printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
goto out;
}
CATCH_EINTR(err = tcgetattr(new, &data->tt));
if(err){
new = err;
goto out;
}
if(data->raw){
err = raw(new);
if(err){
new = err;
goto out;
}
}
data->pid = pid;
*dev_out = NULL;
out:
unlink(file);
return(new);
}
/* Not static because it's called directly by the tt mode gdb code */
void xterm_close(int fd, void *d)
{
struct xterm_chan *data = d;
if(data->pid != -1)
os_kill_process(data->pid, 1);
data->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);
}
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 = generic_console_write,
.window_size = generic_window_size,
.free = xterm_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:
*/

22
arch/um/drivers/xterm.h Normal file
View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __XTERM_H__
#define __XTERM_H__
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:
*/

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.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"
struct xterm_wait {
struct completion ready;
int fd;
int pid;
int new_fd;
};
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);
xterm->new_fd = fd;
complete(&xterm->ready);
return(IRQ_HANDLED);
}
int xterm_fd(int socket, int *pid_out)
{
struct xterm_wait *data;
int err, ret;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if(data == NULL){
printk(KERN_ERR "xterm_fd : failed to allocate xterm_wait\n");
return(-ENOMEM);
}
/* This is a locked semaphore... */
*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,
IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
"xterm", data);
if (err){
printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
"err = %d\n", err);
ret = err;
goto out;
}
/* ... so here we wait for an xterm interrupt.
*
* XXX Note, if the xterm doesn't work for some reason (eg. DISPLAY
* isn't set) this will hang... */
wait_for_completion(&data->ready);
free_irq(XTERM_IRQ, data);
ret = data->new_fd;
*pid_out = data->pid;
out:
kfree(data);
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:
*/

28
arch/um/include/aio.h Normal file
View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2004 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef AIO_H__
#define AIO_H__
enum aio_type { AIO_READ, AIO_WRITE, AIO_MMAP };
struct aio_thread_reply {
void *data;
int err;
};
struct aio_context {
int reply_fd;
struct aio_context *next;
};
#define INIT_AIO_CONTEXT { .reply_fd = -1, \
.next = NULL }
extern int submit_aio(enum aio_type type, int fd, char *buf, int len,
unsigned long long offset, int reply_fd,
struct aio_context *aio);
#endif

View File

@@ -0,0 +1,52 @@
/*
* 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 list_head *chans, struct delayed_work *task,
struct tty_struct *tty, int irq);
extern int parse_chan_pair(char *str, struct line *line, int device,
const struct chan_opts *opts, char **error_out);
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);
extern void deactivate_chan(struct list_head *chans, int irq);
extern void reactivate_chan(struct list_head *chans, int irq);
extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty);
extern void enable_chan(struct line *line);
extern void close_chan(struct list_head *chans, int delay_free_irq);
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

View File

@@ -0,0 +1,56 @@
/*
* 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;
const unsigned long tramp_stack;
const int in_kernel;
};
enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
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_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

View File

@@ -0,0 +1,38 @@
/*
* 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)
#else
#error CONFIG_MODE_SKAS and CONFIG_MODE_TT are both disabled
#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

View File

@@ -0,0 +1,28 @@
/* for use by sys-$SUBARCH/kernel-offsets.c */
DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
#ifdef CONFIG_MODE_TT
OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
#endif
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);
/* For crypto assembler code. */
DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2004 Fujitsu Siemens Computers GmbH
* Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
* Licensed under the GPL
*/
#ifndef __ELF_USER_H__
#define __ELF_USER_H__
/* For compilation on a host that doesn't support AT_SYSINFO (Linux 2.4) */
#ifndef AT_SYSINFO
#define AT_SYSINFO 32
#endif
#ifndef AT_SYSINFO_EHDR
#define AT_SYSINFO_EHDR 33
#endif
#endif

View File

@@ -0,0 +1,32 @@
/*
* 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:
*/

140
arch/um/include/init.h Normal file
View File

@@ -0,0 +1,140 @@
#ifndef _LINUX_UML_INIT_H
#define _LINUX_UML_INIT_H
/* These macros are used to mark some functions or
* initialized data (doesn't apply to uninitialized data)
* as `initialization' functions. The kernel can take this
* as hint that the function is used only during the initialization
* phase and free up used memory resources after
*
* Usage:
* For functions:
*
* You should add __init immediately before the function name, like:
*
* static void __init initme(int x, int y)
* {
* extern int z; z = x * y;
* }
*
* If the function has a prototype somewhere, you can also add
* __init between closing brace of the prototype and semicolon:
*
* extern int initialize_foobar_device(int, int, int) __init;
*
* For initialized data:
* You should insert __initdata between the variable name and equal
* sign followed by value, e.g.:
*
* static int init_variable __initdata = 0;
* static char linux_logo[] __initdata = { 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
* section.
*
* Also note, that this data cannot be "const".
*/
#ifndef _LINUX_INIT_H
typedef int (*initcall_t)(void);
typedef void (*exitcall_t)(void);
/* 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")))
#ifdef MODULE
#define __exit __attribute__ ((__section__(".exit.text")))
#else
#define __exit __attribute_used__ __attribute__ ((__section__(".exit.text")))
#endif
#endif
#ifndef MODULE
struct uml_param {
const char *str;
int (*setup_func)(char *, int *);
};
extern initcall_t __uml_initcall_start, __uml_initcall_end;
extern initcall_t __uml_postsetup_start, __uml_postsetup_end;
extern const char *__uml_help_start, *__uml_help_end;
#endif
#define __uml_initcall(fn) \
static initcall_t __uml_initcall_##fn __uml_init_call = fn
#define __uml_exitcall(fn) \
static exitcall_t __uml_exitcall_##fn __uml_exit_call = fn
extern struct uml_param __uml_setup_start, __uml_setup_end;
#define __uml_postsetup(fn) \
static initcall_t __uml_postsetup_##fn __uml_postsetup_call = fn
#define __non_empty_string(dummyname,string) \
struct __uml_non_empty_string_struct_##dummyname \
{ \
char _string[sizeof(string)-2]; \
}
#ifndef MODULE
#define __uml_setup(str, fn, help...) \
__non_empty_string(fn ##_setup, str); \
__uml_help(fn, help); \
static char __uml_setup_str_##fn[] __initdata = str; \
static struct uml_param __uml_setup_##fn __uml_init_setup = { __uml_setup_str_##fn, fn }
#else
#define __uml_setup(str, fn, help...) \
#endif
#define __uml_help(fn, help...) \
__non_empty_string(fn ##__help, help); \
static char __uml_help_str_##fn[] __initdata = help; \
static const char *__uml_help_##fn __uml_setup_help = __uml_help_str_##fn
/*
* 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")))
#ifndef __KERNEL__
#define __define_initcall(level,fn) \
static initcall_t __initcall_##fn __attribute_used__ \
__attribute__((__section__(".initcall" level ".init"))) = fn
/* Userspace initcalls shouldn't depend on anything in the kernel, so we'll
* make them run first.
*/
#define __initcall(fn) __define_initcall("1", fn)
#define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn
#define __init_call __attribute_used__ __attribute__ ((__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:
*/

22
arch/um/include/initrd.h Normal file
View File

@@ -0,0 +1,22 @@
/*
* 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:
*/

View File

@@ -0,0 +1,30 @@
/*
* 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);
extern int init_aio_irq(int irq, char *name,
irq_handler_t handler);
#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:
*/

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __IRQ_USER_H__
#define __IRQ_USER_H__
#include "uml-config.h"
struct irq_fd {
struct irq_fd *next;
void *id;
int fd;
int type;
int irq;
int pid;
int events;
int current_events;
};
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 int activate_ipi(int fd, int pid);
#ifdef CONFIG_MODE_TT
extern void forward_interrupts(int pid);
#endif
#endif

40
arch/um/include/kern.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* 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(const 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 void 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

121
arch/um/include/kern_util.h Normal file
View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __KERN_UTIL_H__
#define __KERN_UTIL_H__
#include "sysdep/ptrace.h"
#include "sysdep/faultinfo.h"
typedef void (*kern_hndl)(int, union uml_pt_regs *);
struct kern_handlers {
kern_hndl relay_signal;
kern_hndl winch;
kern_hndl bus_handler;
kern_hndl page_fault;
kern_hndl sigio_handler;
kern_hndl timer_handler;
};
extern const struct kern_handlers handlinfo_kern;
extern int ncpus;
extern char *linux_prog;
extern char *gdb_init;
extern int kmalloc_ok;
extern int jail;
extern int nsyscalls;
#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 deliver_signals(void *t);
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 unsigned int do_IRQ(int irq, union uml_pt_regs *regs);
extern int external_pid(void *t);
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 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 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 free_irq(unsigned int, void *);
extern int cpu(void);
extern void time_init_kern(void);
/* Are we disallowed to sleep? Used to choose between GFP_KERNEL and GFP_ATOMIC. */
extern int __cant_sleep(void);
extern void sigio_handler(int sig, union uml_pt_regs *regs);
#endif

105
arch/um/include/line.h Normal file
View File

@@ -0,0 +1,105 @@
/*
* 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 one modifiable field in this - .mc.list */
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 line {
struct tty_struct *tty;
spinlock_t count_lock;
int valid;
char *init_str;
int init_pri;
struct list_head chan_list;
/*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;
int have_irq;
};
#define LINE_INIT(str, d) \
{ .count_lock = SPIN_LOCK_UNLOCKED, \
.init_str = str, \
.init_pri = INIT_STATIC, \
.valid = 1, \
.lock = SPIN_LOCK_UNLOCKED, \
.driver = d }
extern void line_close(struct tty_struct *tty, struct file * filp);
extern int line_open(struct line *lines, struct tty_struct *tty);
extern int line_setup(struct line *lines, unsigned int sizeof_lines,
char *init, char **error_out);
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 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 int line_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
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 struct tty_driver *register_lines(struct line_driver *line_driver,
const struct tty_operations *driver,
struct line *lines, int nlines);
extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts);
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

23
arch/um/include/longjmp.h Normal file
View File

@@ -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

109
arch/um/include/mconsole.h Normal file
View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __MCONSOLE_H__
#define __MCONSOLE_H__
#ifndef __KERNEL__
#include <stdint.h>
#define u32 uint32_t
#endif
#include "sysdep/ptrace.h"
#define MCONSOLE_MAGIC (0xcafebabe)
#define MCONSOLE_MAX_DATA (512)
#define MCONSOLE_VERSION 2
struct mconsole_request {
u32 magic;
u32 version;
u32 len;
char data[MCONSOLE_MAX_DATA];
};
struct mconsole_reply {
u32 err;
u32 more;
u32 len;
char data[MCONSOLE_MAX_DATA];
};
struct mconsole_notify {
u32 magic;
u32 version;
enum { MCONSOLE_SOCKET, MCONSOLE_PANIC, MCONSOLE_HANG,
MCONSOLE_USER_NOTIFY } type;
u32 len;
char data[MCONSOLE_MAX_DATA];
};
struct mc_request;
enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC };
struct mconsole_command
{
char *command;
void (*handler)(struct mc_request *req);
enum mc_context context;
};
struct mc_request
{
int len;
int as_interrupt;
int originating_fd;
unsigned int originlen;
unsigned char origin[128]; /* sockaddr_un */
struct mconsole_request request;
struct mconsole_command *cmd;
union uml_pt_regs regs;
};
extern char mconsole_socket_name[];
extern int mconsole_unlink_socket(void);
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);
extern void mconsole_help(struct mc_request *req);
extern void mconsole_halt(struct mc_request *req);
extern void mconsole_reboot(struct mc_request *req);
extern void mconsole_config(struct mc_request *req);
extern void mconsole_remove(struct mc_request *req);
extern void mconsole_sysrq(struct mc_request *req);
extern void mconsole_cad(struct mc_request *req);
extern void mconsole_stop(struct mc_request *req);
extern void mconsole_go(struct mc_request *req);
extern void mconsole_log(struct mc_request *req);
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,
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:
*/

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __MCONSOLE_KERN_H__
#define __MCONSOLE_KERN_H__
#include "linux/list.h"
#include "mconsole.h"
struct mconsole_entry {
struct list_head list;
struct mc_request request;
};
/* All these methods are called in process context. */
struct mc_device {
struct list_head list;
char *name;
int (*config)(char *, char **);
int (*get_config)(char *, char *, int, char **);
int (*id)(char **, int *, int *);
int (*remove)(int, char **);
};
#define CONFIG_CHUNK(str, size, current, chunk, end) \
do { \
current += strlen(chunk); \
if(current >= size) \
str = NULL; \
if(str != NULL){ \
strcpy(str, chunk); \
str += strlen(chunk); \
} \
if(end) \
current++; \
} while(0)
#ifdef CONFIG_MCONSOLE
extern void mconsole_register_dev(struct mc_device *new);
#else
static inline void mconsole_register_dev(struct mc_device *new)
{
}
#endif
#endif

39
arch/um/include/mem.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* 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:
*/

View File

@@ -0,0 +1,30 @@
/*
* 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:
*/

View File

@@ -0,0 +1,67 @@
/*
* arch/um/include/mem_user.h
*
* BRIEF MODULE DESCRIPTION
* user side memory interface for support IO memory inside user mode linux
*
* Copyright (C) 2001 RidgeRun, Inc.
* Author: RidgeRun, Inc.
* Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
*
* 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.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _MEM_USER_H
#define _MEM_USER_H
struct iomem_region {
struct iomem_region *next;
char *driver;
int fd;
int size;
unsigned long phys;
unsigned long virt;
};
extern struct iomem_region *iomem_regions;
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 int init_mem_user(void);
extern void setup_memory(void *entry);
extern unsigned long find_iomem(char *driver, unsigned long *len_out);
extern int init_maps(unsigned long physmem, unsigned long iomem,
unsigned long highmem);
extern unsigned long get_vm(unsigned long len);
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

View File

@@ -0,0 +1,6 @@
#ifndef __MISC_CONSTANT_H_
#define __MISC_CONSTANT_H_
#include <user_constants.h>
#endif

30
arch/um/include/mode.h Normal file
View File

@@ -0,0 +1,30 @@
/*
* 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:
*/

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __MODE_KERN_H__
#define __MODE_KERN_H__
#ifdef CONFIG_MODE_TT
#include "mode_kern_tt.h"
#endif
#ifdef CONFIG_MODE_SKAS
#include "mode_kern_skas.h"
#endif
#endif

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __UM_NET_KERN_H
#define __UM_NET_KERN_H
#include <linux/netdevice.h>
#include <linux/platform_device.h>
#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];
};
struct uml_net_private {
struct list_head list;
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];
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 *);
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];
};
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 *);
};
struct transport {
struct list_head list;
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 struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra);
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

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __UM_NET_USER_H__
#define __UM_NET_USER_H__
#define ETH_ADDR_LEN (6)
#define ETH_HEADER_ETHERTAP (16)
#define ETH_HEADER_OTHER (14)
#define ETH_MAX_PACKET (1500)
#define UML_NET_VERSION (4)
struct net_user_info {
void (*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;
};
extern void ether_user_init(void *data, void *dev);
extern void iter_addresses(void *d, void (*cb)(unsigned char *,
unsigned char *, void *),
void *arg);
extern void *get_output_buffer(int *len_out);
extern void free_output_buffer(void *buffer);
extern int tap_open_common(void *dev, char *gate_addr);
extern void tap_check_ips(char *gate_addr, unsigned char *eth_addr);
extern void read_output(int fd, char *output_out, int len);
extern int net_read(int fd, void *buf, int len);
extern int net_recvfrom(int fd, void *buf, int len);
extern int net_write(int fd, void *buf, int len);
extern int net_send(int fd, void *buf, int len);
extern int net_sendto(int fd, void *buf, int len, void *to, int sock_len);
extern void open_addr(unsigned char *addr, unsigned char *netmask, void *arg);
extern void close_addr(unsigned char *addr, unsigned char *netmask, void *arg);
extern char *split_if_spec(char *str, ...);
extern int dev_netmask(void *d, void *m);
#endif

346
arch/um/include/os.h Normal file
View File

@@ -0,0 +1,346 @@
/*
* 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"
#include "sysdep/ptrace.h"
#include "kern_util.h"
#include "skas/mm_id.h"
#include "irq_user.h"
#include "sysdep/tls.h"
#include "sysdep/archsetjmp.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;
}
/* 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 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_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);
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);
/* start_up.c */
extern void os_early_checks(void);
extern int can_do_skas(void);
extern void os_check_bugs(void);
extern void check_host_supports_tls(int *supports_tls, int *tls_min);
/* 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);
#ifdef UML_CONFIG_MODE_TT
extern void os_usr1_process(int pid);
#endif
extern long os_ptrace_ldt(long pid, long addr, long data);
extern int os_getpid(void);
extern int os_getpgrp(void);
#ifdef UML_CONFIG_MODE_TT
extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
extern void stop(void);
#endif
extern void init_new_thread_signals(void);
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 int os_drop_memory(void *addr, int length);
extern int can_drop_memory(void);
extern void os_flush_stdout(void);
/* tt.c
* for tt mode only (will be deleted in future...)
*/
extern void forward_ipi(int fd, int pid);
extern void kill_child_dead(int pid);
extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
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);
/* 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,
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);
/* tls.c */
extern int os_set_thread_area(user_desc_t *info, int pid);
extern int os_get_thread_area(user_desc_t *info, 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 set_sigstack(void *sig_stack, int size);
extern void remove_sigstack(void);
extern void set_handler(int sig, void (*handler)(int), int flags, ...);
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);
/* trap.c */
extern void os_fill_handlinfo(struct kern_handlers h);
extern void do_longjmp(void *p, int val);
/* util.c */
extern void stack_protections(unsigned long address);
extern void task_protections(unsigned long address);
extern int raw(int fd);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(void);
extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
/* time.c */
#define BILLION (1000 * 1000 * 1000)
extern void switch_timers(int to_real);
extern void idle_sleep(int secs);
extern int set_interval(int is_virtual);
#ifdef CONFIG_MODE_TT
extern void enable_timer(void);
#endif
extern void disable_timer(void);
extern void uml_idle_timer(void);
extern unsigned 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 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);
/* 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(union uml_pt_regs *regs);
extern void 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);
extern void init_irq_signals(int on_sigstack);
/* 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);
/* skas/trap */
extern void sig_handler_common_skas(int sig, void *sc_ptr);
extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
extern int os_arch_prctl(int pid, int code, unsigned long *addr);
#endif

25
arch/um/include/process.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* 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:
*/

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __PTRACE_USER_H__
#define __PTRACE_USER_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 */
#ifndef PTRACE_SYSEMU
#define PTRACE_SYSEMU 31
#endif
#ifndef PTRACE_SYSEMU_SINGLESTEP
#define PTRACE_SYSEMU_SINGLESTEP 32
#endif
/* On architectures, that started to support PTRACE_O_TRACESYSGOOD
* in linux 2.4, there are two different definitions of
* PTRACE_SETOPTIONS: linux 2.4 uses 21 while linux 2.6 uses 0x4200.
* For binary compatibility, 2.6 also supports the old "21", named
* PTRACE_OLDSETOPTION. On these architectures, UML always must use
* "21", to ensure the kernel runs on 2.4 and 2.6 host without
* 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.
*
* On architectures, that start to support PTRACE_O_TRACESYSGOOD on
* linux 2.6, PTRACE_OLDSETOPTIONS never is defined, and also isn't
* supported by the host kernel. In that case, our trick lets us use
* the new 0x4200 with the name PTRACE_OLDSETOPTIONS.
*/
#ifndef PTRACE_OLDSETOPTIONS
#define PTRACE_OLDSETOPTIONS PTRACE_SETOPTIONS
#endif
void set_using_sysemu(int value);
int get_using_sysemu(void);
extern int sysemu_supported;
#define SELECT_PTRACE_OPERATION(sysemu_mode, singlestep_mode) \
(((int[3][3] ) { \
{ PTRACE_SYSCALL, PTRACE_SYSCALL, PTRACE_SINGLESTEP }, \
{ PTRACE_SYSEMU, PTRACE_SYSEMU, PTRACE_SINGLESTEP }, \
{ PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, PTRACE_SYSEMU_SINGLESTEP }}) \
[sysemu_mode][singlestep_mode])
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2004 PathScale, Inc
* Licensed under the GPL
*/
#ifndef __REGISTERS_H
#define __REGISTERS_H
#include "sysdep/ptrace.h"
#include "sysdep/archsetjmp.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, unsigned long * fp_regs);
extern unsigned long get_thread_reg(int reg, jmp_buf *buf);
#endif

View File

@@ -0,0 +1,25 @@
/*
* 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:
*/

14
arch/um/include/sigio.h Normal file
View File

@@ -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

View File

@@ -0,0 +1,22 @@
/*
* 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:
*/

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __MM_ID_H
#define __MM_ID_H
struct mm_id {
union {
int mm_fd;
int pid;
} u;
unsigned long stack;
};
#endif

Some files were not shown because too many files have changed in this diff Show More