Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
350
arch/um/Kconfig
Normal file
350
arch/um/Kconfig
Normal 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
238
arch/um/Kconfig.char
Normal 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
50
arch/um/Kconfig.debug
Normal 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
93
arch/um/Kconfig.i386
Normal 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
180
arch/um/Kconfig.net
Normal 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
58
arch/um/Kconfig.scsi
Normal 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
53
arch/um/Kconfig.x86_64
Normal 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
235
arch/um/Makefile
Normal 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
39
arch/um/Makefile-i386
Normal 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
1
arch/um/Makefile-ia64
Normal file
@@ -0,0 +1 @@
|
||||
START_ADDR = 0x1000000000000000
|
||||
8
arch/um/Makefile-os-Linux
Normal file
8
arch/um/Makefile-os-Linux
Normal 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
9
arch/um/Makefile-ppc
Normal 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
12
arch/um/Makefile-skas
Normal 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
5
arch/um/Makefile-tt
Normal 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
25
arch/um/Makefile-x86_64
Normal 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
333
arch/um/config.release
Normal 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
528
arch/um/defconfig
Normal 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
59
arch/um/drivers/Makefile
Normal 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
660
arch/um/drivers/chan_kern.c
Normal 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", ¬_configged_ops },
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PORT_CHAN
|
||||
{ "port", &port_ops },
|
||||
#else
|
||||
{ "port", ¬_configged_ops },
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PTY_CHAN
|
||||
{ "pty", &pty_ops },
|
||||
{ "pts", &pts_ops },
|
||||
#else
|
||||
{ "pty", ¬_configged_ops },
|
||||
{ "pts", ¬_configged_ops },
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TTY_CHAN
|
||||
{ "tty", &tty_ops },
|
||||
#else
|
||||
{ "tty", ¬_configged_ops },
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XTERM_CHAN
|
||||
{ "xterm", &xterm_ops },
|
||||
#else
|
||||
{ "xterm", ¬_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
217
arch/um/drivers/chan_user.c
Normal 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
67
arch/um/drivers/cow.h
Normal 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
49
arch/um/drivers/cow_sys.h
Normal 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
443
arch/um/drivers/cow_user.c
Normal 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
35
arch/um/drivers/daemon.h
Normal 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:
|
||||
*/
|
||||
101
arch/um/drivers/daemon_kern.c
Normal file
101
arch/um/drivers/daemon_kern.c
Normal 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);
|
||||
207
arch/um/drivers/daemon_user.c
Normal file
207
arch/um/drivers/daemon_user.c
Normal 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
103
arch/um/drivers/fd.c
Normal 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:
|
||||
*/
|
||||
184
arch/um/drivers/harddog_kern.c
Normal file
184
arch/um/drivers/harddog_kern.c
Normal 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);
|
||||
131
arch/um/drivers/harddog_user.c
Normal file
131
arch/um/drivers/harddog_user.c
Normal 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;
|
||||
|
||||
}
|
||||
340
arch/um/drivers/hostaudio_kern.c
Normal file
340
arch/um/drivers/hostaudio_kern.c
Normal 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
875
arch/um/drivers/line.c
Normal 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
30
arch/um/drivers/mcast.h
Normal 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:
|
||||
*/
|
||||
130
arch/um/drivers/mcast_kern.c
Normal file
130
arch/um/drivers/mcast_kern.c
Normal 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);
|
||||
173
arch/um/drivers/mcast_user.c
Normal file
173
arch/um/drivers/mcast_user.c
Normal 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
|
||||
};
|
||||
952
arch/um/drivers/mconsole_kern.c
Normal file
952
arch/um/drivers/mconsole_kern.c
Normal 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(¬ify_spinlock);
|
||||
}
|
||||
|
||||
void unlock_notify(void)
|
||||
{
|
||||
spin_unlock(¬ify_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);
|
||||
233
arch/um/drivers/mconsole_user.c
Normal file
233
arch/um/drivers/mconsole_user.c
Normal 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:
|
||||
*/
|
||||
144
arch/um/drivers/mmapper_kern.c
Normal file
144
arch/um/drivers/mmapper_kern.c
Normal 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
859
arch/um/drivers/net_kern.c
Normal 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(¨_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 = ¨_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, ð_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(ð->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, ð_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(¨_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
262
arch/um/drivers/net_user.c
Normal 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
57
arch/um/drivers/null.c
Normal 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
112
arch/um/drivers/pcap_kern.c
Normal 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
144
arch/um/drivers/pcap_user.c
Normal 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:
|
||||
*/
|
||||
31
arch/um/drivers/pcap_user.h
Normal file
31
arch/um/drivers/pcap_user.h
Normal 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
30
arch/um/drivers/port.h
Normal 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
307
arch/um/drivers/port_kern.c
Normal 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
207
arch/um/drivers/port_user.c
Normal 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
157
arch/um/drivers/pty.c
Normal 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
131
arch/um/drivers/random.c
Normal 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
20
arch/um/drivers/slip.h
Normal 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
|
||||
54
arch/um/drivers/slip_common.c
Normal file
54
arch/um/drivers/slip_common.c
Normal 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;
|
||||
}
|
||||
105
arch/um/drivers/slip_common.h
Normal file
105
arch/um/drivers/slip_common.h
Normal 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
|
||||
98
arch/um/drivers/slip_kern.c
Normal file
98
arch/um/drivers/slip_kern.c
Normal 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
254
arch/um/drivers/slip_user.c
Normal 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
33
arch/um/drivers/slirp.h
Normal 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
|
||||
122
arch/um/drivers/slirp_kern.c
Normal file
122
arch/um/drivers/slirp_kern.c
Normal 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);
|
||||
138
arch/um/drivers/slirp_user.c
Normal file
138
arch/um/drivers/slirp_user.c
Normal 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
229
arch/um/drivers/ssl.c
Normal 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
23
arch/um/drivers/ssl.h
Normal 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:
|
||||
*/
|
||||
61
arch/um/drivers/stderr_console.c
Normal file
61
arch/um/drivers/stderr_console.c
Normal 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);
|
||||
203
arch/um/drivers/stdio_console.c
Normal file
203
arch/um/drivers/stdio_console.c
Normal 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");
|
||||
21
arch/um/drivers/stdio_console.h
Normal file
21
arch/um/drivers/stdio_console.h
Normal 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
77
arch/um/drivers/tty.c
Normal 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
1437
arch/um/drivers/ubd_kern.c
Normal file
File diff suppressed because it is too large
Load Diff
75
arch/um/drivers/ubd_user.c
Normal file
75
arch/um/drivers/ubd_user.c
Normal 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
217
arch/um/drivers/xterm.c
Normal 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
22
arch/um/drivers/xterm.h
Normal 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:
|
||||
*/
|
||||
91
arch/um/drivers/xterm_kern.c
Normal file
91
arch/um/drivers/xterm_kern.c
Normal 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
28
arch/um/include/aio.h
Normal 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
|
||||
52
arch/um/include/chan_kern.h
Normal file
52
arch/um/include/chan_kern.h
Normal 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
|
||||
56
arch/um/include/chan_user.h
Normal file
56
arch/um/include/chan_user.h
Normal 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
|
||||
38
arch/um/include/choose-mode.h
Normal file
38
arch/um/include/choose-mode.h
Normal 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
|
||||
28
arch/um/include/common-offsets.h
Normal file
28
arch/um/include/common-offsets.h
Normal 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));
|
||||
19
arch/um/include/elf_user.h
Normal file
19
arch/um/include/elf_user.h
Normal 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
|
||||
32
arch/um/include/frame_kern.h
Normal file
32
arch/um/include/frame_kern.h
Normal 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
140
arch/um/include/init.h
Normal 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
22
arch/um/include/initrd.h
Normal 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:
|
||||
*/
|
||||
30
arch/um/include/irq_kern.h
Normal file
30
arch/um/include/irq_kern.h
Normal 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:
|
||||
*/
|
||||
37
arch/um/include/irq_user.h
Normal file
37
arch/um/include/irq_user.h
Normal 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
40
arch/um/include/kern.h
Normal 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
121
arch/um/include/kern_util.h
Normal 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
105
arch/um/include/line.h
Normal 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
23
arch/um/include/longjmp.h
Normal 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
109
arch/um/include/mconsole.h
Normal 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:
|
||||
*/
|
||||
52
arch/um/include/mconsole_kern.h
Normal file
52
arch/um/include/mconsole_kern.h
Normal 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
39
arch/um/include/mem.h
Normal 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:
|
||||
*/
|
||||
30
arch/um/include/mem_kern.h
Normal file
30
arch/um/include/mem_kern.h
Normal 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:
|
||||
*/
|
||||
67
arch/um/include/mem_user.h
Normal file
67
arch/um/include/mem_user.h
Normal 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
|
||||
6
arch/um/include/misc_constants.h
Normal file
6
arch/um/include/misc_constants.h
Normal 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
30
arch/um/include/mode.h
Normal 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:
|
||||
*/
|
||||
17
arch/um/include/mode_kern.h
Normal file
17
arch/um/include/mode_kern.h
Normal 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
|
||||
71
arch/um/include/net_kern.h
Normal file
71
arch/um/include/net_kern.h
Normal 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
|
||||
53
arch/um/include/net_user.h
Normal file
53
arch/um/include/net_user.h
Normal 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
346
arch/um/include/os.h
Normal 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
25
arch/um/include/process.h
Normal 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:
|
||||
*/
|
||||
60
arch/um/include/ptrace_user.h
Normal file
60
arch/um/include/ptrace_user.h
Normal 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
|
||||
21
arch/um/include/registers.h
Normal file
21
arch/um/include/registers.h
Normal 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
|
||||
25
arch/um/include/sigcontext.h
Normal file
25
arch/um/include/sigcontext.h
Normal 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
14
arch/um/include/sigio.h
Normal 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
|
||||
22
arch/um/include/signal_kern.h
Normal file
22
arch/um/include/signal_kern.h
Normal 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:
|
||||
*/
|
||||
17
arch/um/include/skas/mm_id.h
Normal file
17
arch/um/include/skas/mm_id.h
Normal 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
Reference in New Issue
Block a user