diff options
Diffstat (limited to 'arch/um')
305 files changed, 5284 insertions, 11426 deletions
diff --git a/arch/um/.gitignore b/arch/um/.gitignore new file mode 100644 index 00000000000..a73d3a1cc74 --- /dev/null +++ b/arch/um/.gitignore @@ -0,0 +1,3 @@ +kernel/config.c +kernel/config.tmp +kernel/vmlinux.lds diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char index 3a4b396d797..f10738d68b2 100644 --- a/arch/um/Kconfig.char +++ b/arch/um/Kconfig.char @@ -1,5 +1,4 @@ - -menu "Character Devices" +menu "UML Character Devices" config STDERR_CONSOLE bool "stderr console" @@ -7,10 +6,6 @@ config STDERR_CONSOLE help console driver which dumps all printk messages to stderr. -config STDIO_CONSOLE - bool - default y - config SSL bool "Virtual serial line" help @@ -105,92 +100,6 @@ config SSL_CHAN 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 @@ -203,33 +112,12 @@ config SOUND tristate default UML_SOUND -config HOSTAUDIO - tristate +config SOUND_OSS_CORE + bool default UML_SOUND -#It is selected elsewhere, so kconfig would warn without this. -config HW_RANDOM +config HOSTAUDIO 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. + default UML_SOUND endmenu diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common new file mode 100644 index 00000000000..6915d28cf11 --- /dev/null +++ b/arch/um/Kconfig.common @@ -0,0 +1,59 @@ +config UML + bool + default y + select HAVE_ARCH_AUDITSYSCALL + select HAVE_UID16 + select GENERIC_IRQ_SHOW + select GENERIC_CPU_DEVICES + select GENERIC_IO + select GENERIC_CLOCKEVENTS + select TTY # Needed for line.c + +config MMU + bool + default y + +config NO_IOMEM + def_bool y + +config ISA + bool + +config SBUS + bool + +config PCI + bool + +config PCMCIA + bool + +# Yet to do! +config TRACE_IRQFLAGS_SUPPORT + bool + default n + +config LOCKDEP_SUPPORT + bool + default y + +config STACKTRACE_SUPPORT + bool + default n + +config GENERIC_CALIBRATE_DELAY + bool + default y + +config GENERIC_BUG + bool + default y + depends on BUG + +config HZ + int + default 100 + +config SUBARCH + string + option env="SUBARCH" diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug index 8fce5e536b0..68205fd3b08 100644 --- a/arch/um/Kconfig.debug +++ b/arch/um/Kconfig.debug @@ -28,13 +28,13 @@ config GCOV If you're involved in UML kernel development and want to use gcov, say Y. If you're unsure, say N. -config DEBUG_STACK_USAGE - bool "Stack utilization instrumentation" - default N - help - Track the maximum kernel stack usage - this will look at each - kernel stack at process exit and log it if it's the deepest - stack seen so far. +config EARLY_PRINTK + bool "Early printk" + default y + ---help--- + Write kernel log output directly to stdout. + + This is useful for kernel debugging when your machine crashes very + early before the console code is initialized. - This option will slow down process creation and destruction somewhat. endmenu diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386 deleted file mode 100644 index 3cd8a04d66d..00000000000 --- a/arch/um/Kconfig.i386 +++ /dev/null @@ -1,51 +0,0 @@ -menu "Host processor type and features" - -source "arch/x86/Kconfig.cpu" - -endmenu - -config UML_X86 - bool - default y - -config X86_32 - bool - default y - -config RWSEM_XCHGADD_ALGORITHM - def_bool y - -config 64BIT - bool - default n - -config SEMAPHORE_SLEEPERS - bool - default y - -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 ARCH_HAS_SC_SIGNALS - bool - default y - -config ARCH_REUSE_HOST_VSYSCALL_AREA - bool - default y - -config GENERIC_HWEIGHT - bool - default y - -config ARCH_SUPPORTS_AOUT - def_bool y diff --git a/arch/um/Kconfig.net b/arch/um/Kconfig.net index 9e9a4aaa703..820a56f0033 100644 --- a/arch/um/Kconfig.net +++ b/arch/um/Kconfig.net @@ -157,7 +157,7 @@ config UML_NET_MCAST config UML_NET_PCAP bool "pcap transport" - depends on UML_NET && EXPERIMENTAL + depends on UML_NET help The pcap transport makes a pcap packet stream on the host look like an ethernet device inside UML. This is useful for making @@ -186,7 +186,7 @@ config UML_NET_SLIRP other transports, SLiRP works without the need of root level privleges, setuid binaries, or SLIP devices on the host. This also means not every type of connection is possible, but most - situations can be accomodated with carefully crafted slirp + situations can be accommodated with carefully crafted slirp commands that can be passed along as part of the network device's setup string. The effect of this transport on the UML is similar that of a host behind a firewall that masquerades all network diff --git a/arch/um/Kconfig.rest b/arch/um/Kconfig.rest new file mode 100644 index 00000000000..567eb5fc21d --- /dev/null +++ b/arch/um/Kconfig.rest @@ -0,0 +1,21 @@ +source "init/Kconfig" + +source "kernel/Kconfig.freezer" + +source "arch/um/Kconfig.char" + +source "drivers/Kconfig" + +source "net/Kconfig" + +source "arch/um/Kconfig.net" + +source "fs/Kconfig" + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + +source "arch/um/Kconfig.debug" diff --git a/arch/um/Kconfig b/arch/um/Kconfig.um index dba8e05f028..a7520c90f62 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig.um @@ -1,79 +1,3 @@ -config DEFCONFIG_LIST - string - option defconfig_list - default "arch/$ARCH/defconfig" - -# UML uses the generic IRQ subsystem -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 - -config GENERIC_TIME - bool - default y - -config GENERIC_CLOCKEVENTS - bool - default y - -# Used in kernel/irq/manage.c and include/linux/irq.h -config IRQ_RELEASE_METHOD - bool - default y - -config HZ - int - default 100 - -menu "UML-specific options" - config STATIC_LINK bool "Force a static link" default n @@ -85,9 +9,7 @@ config STATIC_LINK Additionally, this option enables using higher memory spaces (up to 2.75G) for UML. -source "arch/um/Kconfig.arch" source "mm/Kconfig" -source "kernel/time/Kconfig" config LD_SCRIPT_STATIC bool @@ -123,8 +45,8 @@ config HOSTFS say Y or M here; otherwise say N. config HPPFS - tristate "HoneyPot ProcFS (EXPERIMENTAL)" - depends on EXPERIMENTAL + tristate "HoneyPot ProcFS" + depends on PROC_FS help hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc entries to be overridden, removed, or fabricated from the host. @@ -174,7 +96,7 @@ config MAGIC_SYSRQ unless you really know what this hack does. config SMP - bool "Symmetric multi-processing support (EXPERIMENTAL)" + bool "Symmetric multi-processing support" default n depends on BROKEN help @@ -204,8 +126,8 @@ config NR_CPUS default "32" config HIGHMEM - bool "Highmem support (EXPERIMENTAL)" - depends on !64BIT && EXPERIMENTAL + bool "Highmem support" + depends on !64BIT && BROKEN default n help This was used to allow UML to run with big amounts of memory. @@ -225,43 +147,11 @@ config KERNEL_STACK_ORDER be 1 << order pages. The default is OK unless you're running Valgrind on UML, in which case, set this to 3. -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" - -source "drivers/scsi/Kconfig" - -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 +config MMAPPER + tristate "iomem emulation driver" + help + This driver allows a host file to be used as emulated IO memory inside + UML. -source "arch/um/Kconfig.debug" +config NO_DMA + def_bool y diff --git a/arch/um/Kconfig.x86_64 b/arch/um/Kconfig.x86_64 deleted file mode 100644 index 6533b349f06..00000000000 --- a/arch/um/Kconfig.x86_64 +++ /dev/null @@ -1,39 +0,0 @@ -config UML_X86 - bool - default y - -config 64BIT - bool - default y - -#XXX: this is so in the underlying arch, but it's wrong!!! -config RWSEM_GENERIC_SPINLOCK - bool - default y - -config SEMAPHORE_SLEEPERS - bool - default y - -config 3_LEVEL_PGTABLES - bool - default y - -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 - -config ARCH_SUPPORTS_AOUT - def_bool y diff --git a/arch/um/Makefile b/arch/um/Makefile index dbeab15e7bb..e4b1a9639c4 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -6,6 +6,17 @@ # Licensed under the GPL # +# select defconfig based on actual architecture +ifeq ($(SUBARCH),x86) + ifeq ($(shell uname -m),x86_64) + KBUILD_DEFCONFIG := x86_64_defconfig + else + KBUILD_DEFCONFIG := i386_defconfig + endif +else + KBUILD_DEFCONFIG := $(SUBARCH)_defconfig +endif + ARCH_DIR := arch/um OS := $(shell uname -s) # We require bash because the vmlinux link and loader script cpp use bash @@ -18,28 +29,29 @@ 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)) +MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/include/shared/skas -# 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 +HEADER_ARCH := $(SUBARCH) -MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/include/skas +ifneq ($(filter $(SUBARCH),x86 x86_64 i386),) + HEADER_ARCH := x86 +endif + +ifdef CONFIG_64BIT + KBUILD_CFLAGS += -mcmodel=large +endif + +HOST_DIR := arch/$(HEADER_ARCH) include $(srctree)/$(ARCH_DIR)/Makefile-skas +include $(srctree)/$(HOST_DIR)/Makefile.um -ARCH_INCLUDE := -I$(ARCH_DIR)/include -ifneq ($(KBUILD_SRC),) -ARCH_INCLUDE += -I$(srctree)/$(ARCH_DIR)/include -endif -SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH) +core-y += $(HOST_DIR)/um/ + +SHARED_HEADERS := $(ARCH_DIR)/include/shared +ARCH_INCLUDE := -I$(srctree)/$(SHARED_HEADERS) +ARCH_INCLUDE += -I$(srctree)/$(HOST_DIR)/um/shared +KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/um # -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. @@ -49,22 +61,25 @@ SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH) # # These apply to USER_CFLAGS to. -KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ +KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \ $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \ -Din6addr_loopback=kernel_in6addr_loopback \ - -Din6addr_any=kernel_in6addr_any + -Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr KBUILD_AFLAGS += $(ARCH_INCLUDE) USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -D__KERNEL__,,\ $(patsubst -I%,,$(KBUILD_CFLAGS)))) $(ARCH_INCLUDE) $(MODE_INCLUDE) \ - $(filter -I%,$(CFLAGS)) -D_FILE_OFFSET_BITS=64 - -include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH) + $(filter -I%,$(CFLAGS)) -D_FILE_OFFSET_BITS=64 -idirafter include #This will adjust *FLAGS accordingly to the platform. include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS) +KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/include \ + -I$(srctree)/$(HOST_DIR)/include/uapi \ + -I$(HOST_DIR)/include/generated \ + -I$(HOST_DIR)/include/generated/uapi + # -Derrno=kernel_errno - This turns all kernel references to errno into # kernel_errno to separate them from the libc errno. This allows -fno-common # in KBUILD_CFLAGS. Otherwise, it would cause ld to complain about the two different @@ -77,7 +92,6 @@ include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS) KERNEL_DEFINES = $(strip -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \ -Dmktime=kernel_mktime $(ARCH_KERNEL_DEFINES)) KBUILD_CFLAGS += $(KERNEL_DEFINES) -KBUILD_CFLAGS += $(call cc-option,-fno-unit-at-a-time,) PHONY += linux @@ -94,14 +108,12 @@ define archhelp echo ' find in the kernel root.' endef -ifneq ($(KBUILD_SRC),) -$(shell mkdir -p $(ARCH_DIR) && ln -fsn $(srctree)/$(ARCH_DIR)/Kconfig.$(SUBARCH) $(ARCH_DIR)/Kconfig.arch) -else -$(shell cd $(ARCH_DIR) && ln -sf Kconfig.$(SUBARCH) Kconfig.arch) -endif +KBUILD_KCONFIG := $(HOST_DIR)/um/Kconfig + +archheaders: + $(Q)$(MAKE) KBUILD_SRC= ARCH=$(HEADER_ARCH) archheaders -archprepare: $(ARCH_SYMLINKS) $(ARCH_DIR)/include/user_constants.h -prepare: $(ARCH_DIR)/include/kern_constants.h +archprepare: include/generated/user_constants.h LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib @@ -110,88 +122,31 @@ 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,) -CONFIG_KERNEL_STACK_ORDER ?= 2 -STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] ) - -CPPFLAGS_vmlinux.lds = -U$(SUBARCH) -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ - -DELF_FORMAT="$(ELF_FORMAT)" -DKERNEL_STACK_SIZE=$(STACK_SIZE) +# Options used by linker script +export LDS_START := $(START) +export LDS_ELF_ARCH := $(ELF_ARCH) +export LDS_ELF_FORMAT := $(ELF_FORMAT) # The wrappers will select whether using "malloc" or the kernel allocator. LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) -CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) -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) vmlinux.o \ - FORCE ,$^) ; rm -f linux -endef +# Used by link-vmlinux.sh which has special support for um link +export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) # 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) +CLEAN_FILES += linux x.i gmon.out archclean: @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ -o -name '*.gcov' \) -type f -print | xargs rm -f -$(SYMLINK_HEADERS): - @echo ' SYMLINK $@' -ifneq ($(KBUILD_SRC),) - $(Q)mkdir -p $(objtree)/include/asm-um - $(Q)ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@ -else - $(Q)cd $(srctree)/$(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-$(HEADER_ARCH) include/asm-um/arch -else - $(Q)cd $(srctree)/include/asm-um && ln -fsn ../asm-$(HEADER_ARCH) 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 -fsn 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 -fsn 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) $@ +$(HOST_DIR)/um/user-offsets.s: __headers FORCE + $(Q)$(MAKE) $(build)=$(HOST_DIR)/um $@ define filechk_gen-asm-offsets (set -e; \ @@ -206,11 +161,7 @@ define filechk_gen-asm-offsets echo ""; ) endef -$(ARCH_DIR)/include/user_constants.h: $(ARCH_DIR)/sys-$(SUBARCH)/user-offsets.s +include/generated/user_constants.h: $(HOST_DIR)/um/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 HEADER_ARCH +export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS DEV_NULL_PATH diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 deleted file mode 100644 index 561e373bd85..00000000000 --- a/arch/um/Makefile-i386 +++ /dev/null @@ -1,35 +0,0 @@ -core-y += arch/um/sys-i386/ arch/x86/crypto/ - -TOP_ADDR := $(CONFIG_TOP_ADDR) - -START := 0x8048000 - -LDFLAGS += -m elf_i386 -ELF_ARCH := $(SUBARCH) -ELF_FORMAT := elf32-$(SUBARCH) -OBJCOPYFLAGS := -O binary -R .note -R .comment -S -HEADER_ARCH := x86 -CHECKFLAGS += -D__i386__ - -ifeq ("$(origin SUBARCH)", "command line") -ifneq ("$(shell uname -m | sed -e s/i.86/i386/)", "$(SUBARCH)") -KBUILD_CFLAGS += $(call cc-option,-m32) -KBUILD_AFLAGS += $(call cc-option,-m32) -LINK-y += $(call cc-option,-m32) -UML_OBJCOPYFLAGS += -F $(ELF_FORMAT) - -export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UML_OBJCOPYFLAGS -endif -endif - -# First of all, tune CFLAGS for the specific CPU. This actually sets cflags-y. -include $(srctree)/arch/x86/Makefile_32.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 - -KBUILD_CFLAGS += $(cflags-y) diff --git a/arch/um/Makefile-os-Linux b/arch/um/Makefile-os-Linux index 52859487c95..2c8a598ec14 100644 --- a/arch/um/Makefile-os-Linux +++ b/arch/um/Makefile-os-Linux @@ -6,3 +6,4 @@ # To get a definition of F_SETSIG USER_CFLAGS += -D_GNU_SOURCE -D_LARGEFILE64_SOURCE KBUILD_CFLAGS += -D_LARGEFILE64_SOURCE +DEV_NULL_PATH = \"/dev/null\" diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 deleted file mode 100644 index 8ed362f9358..00000000000 --- a/arch/um/Makefile-x86_64 +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2003 - 2004 Pathscale, Inc -# Released under the GPL - -core-y += arch/um/sys-x86_64/ arch/x86/crypto/ -START := 0x60000000 - -_extra_flags_ = -fno-builtin -m64 - -KBUILD_CFLAGS += $(_extra_flags_) - -CHECKFLAGS += -m64 -D__x86_64__ -KBUILD_AFLAGS += -m64 -LDFLAGS += -m elf_x86_64 -KBUILD_CPPFLAGS += -m64 - -ELF_ARCH := i386:x86-64 -ELF_FORMAT := elf64-x86-64 -HEADER_ARCH := x86 - -# 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 diff --git a/arch/um/configs/i386_defconfig b/arch/um/configs/i386_defconfig new file mode 100644 index 00000000000..a12bf68c9f3 --- /dev/null +++ b/arch/um/configs/i386_defconfig @@ -0,0 +1,76 @@ +CONFIG_3_LEVEL_PGTABLES=y +# CONFIG_COMPACTION is not set +CONFIG_BINFMT_MISC=m +CONFIG_HOSTFS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_KERNEL_STACK_ORDER=1 +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CGROUPS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_BLK_CGROUP=y +# CONFIG_PID_NS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_IOSCHED_CFQ=m +CONFIG_SSL=y +CONFIG_NULL_CHAN=y +CONFIG_PORT_CHAN=y +CONFIG_PTY_CHAN=y +CONFIG_TTY_CHAN=y +CONFIG_XTERM_CHAN=y +CONFIG_CON_CHAN="pts" +CONFIG_SSL_CHAN="pts" +CONFIG_UML_SOUND=m +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_BLK_DEV_UBD=y +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_DUMMY=m +CONFIG_TUN=m +CONFIG_PPP=m +CONFIG_SLIP=m +CONFIG_LEGACY_PTY_COUNT=32 +# CONFIG_HW_RANDOM is not set +CONFIG_UML_RANDOM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_UML_NET=y +CONFIG_UML_NET_ETHERTAP=y +CONFIG_UML_NET_TUNTAP=y +CONFIG_UML_NET_SLIP=y +CONFIG_UML_NET_DAEMON=y +CONFIG_UML_NET_MCAST=y +CONFIG_UML_NET_SLIRP=y +CONFIG_EXT4_FS=y +CONFIG_REISERFS_FS=y +CONFIG_QUOTA=y +CONFIG_AUTOFS4_FS=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_NLS=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_KERNEL=y diff --git a/arch/um/configs/x86_64_defconfig b/arch/um/configs/x86_64_defconfig new file mode 100644 index 00000000000..3aab117bd55 --- /dev/null +++ b/arch/um/configs/x86_64_defconfig @@ -0,0 +1,75 @@ +# CONFIG_COMPACTION is not set +CONFIG_BINFMT_MISC=m +CONFIG_HOSTFS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CGROUPS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_CGROUP_SCHED=y +CONFIG_BLK_CGROUP=y +# CONFIG_PID_NS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_IOSCHED_CFQ=m +CONFIG_SSL=y +CONFIG_NULL_CHAN=y +CONFIG_PORT_CHAN=y +CONFIG_PTY_CHAN=y +CONFIG_TTY_CHAN=y +CONFIG_XTERM_CHAN=y +CONFIG_CON_CHAN="pts" +CONFIG_SSL_CHAN="pts" +CONFIG_UML_SOUND=m +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_BLK_DEV_UBD=y +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_DUMMY=m +CONFIG_TUN=m +CONFIG_PPP=m +CONFIG_SLIP=m +CONFIG_LEGACY_PTY_COUNT=32 +# CONFIG_HW_RANDOM is not set +CONFIG_UML_RANDOM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_UML_NET=y +CONFIG_UML_NET_ETHERTAP=y +CONFIG_UML_NET_TUNTAP=y +CONFIG_UML_NET_SLIP=y +CONFIG_UML_NET_DAEMON=y +CONFIG_UML_NET_MCAST=y +CONFIG_UML_NET_SLIRP=y +CONFIG_EXT4_FS=y +CONFIG_REISERFS_FS=y +CONFIG_QUOTA=y +CONFIG_AUTOFS4_FS=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_NLS=y +CONFIG_DEBUG_INFO=y +CONFIG_FRAME_WARN=1024 +CONFIG_DEBUG_KERNEL=y diff --git a/arch/um/defconfig b/arch/um/defconfig deleted file mode 100644 index 6bd456f96f9..00000000000 --- a/arch/um/defconfig +++ /dev/null @@ -1,617 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.24 -# Thu Feb 7 11:48:55 2008 -# -CONFIG_DEFCONFIG_LIST="arch/$ARCH/defconfig" -CONFIG_GENERIC_HARDIRQS=y -CONFIG_UML=y -CONFIG_MMU=y -CONFIG_NO_IOMEM=y -# CONFIG_TRACE_IRQFLAGS_SUPPORT is not set -CONFIG_LOCKDEP_SUPPORT=y -# CONFIG_STACKTRACE_SUPPORT is not set -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_BUG=y -CONFIG_GENERIC_TIME=y -CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_IRQ_RELEASE_METHOD=y -CONFIG_HZ=100 - -# -# UML-specific options -# -# CONFIG_STATIC_LINK is not set - -# -# 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_MVIAC7 is not set -# CONFIG_MPSC is not set -# CONFIG_MCORE2 is not set -# CONFIG_GENERIC_CPU is not set -# CONFIG_X86_GENERIC is not set -CONFIG_X86_CMPXCHG=y -CONFIG_X86_L1_CACHE_SHIFT=5 -CONFIG_X86_XADD=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_GOOD_APIC=y -CONFIG_X86_USE_PPRO_CHECKSUM=y -CONFIG_X86_TSC=y -CONFIG_X86_CMOV=y -CONFIG_X86_MINIMUM_CPU_FAMILY=4 -CONFIG_X86_DEBUGCTLMSR=y -CONFIG_UML_X86=y -CONFIG_X86_32=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -# CONFIG_64BIT is not set -CONFIG_SEMAPHORE_SLEEPERS=y -# CONFIG_3_LEVEL_PGTABLES is not set -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_SPARSEMEM_VMEMMAP_ENABLE is not set -CONFIG_SPLIT_PTLOCK_CPUS=4 -# CONFIG_RESOURCES_64BIT is not set -CONFIG_ZONE_DMA_FLAG=0 -CONFIG_VIRT_TO_BUS=y -CONFIG_TICK_ONESHOT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -CONFIG_LD_SCRIPT_DYN=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_AOUT is not set -CONFIG_BINFMT_MISC=m -CONFIG_HOSTFS=y -# CONFIG_HPPFS is not set -CONFIG_MCONSOLE=y -CONFIG_MAGIC_SYSRQ=y -# CONFIG_HIGHMEM is not set -CONFIG_KERNEL_STACK_ORDER=0 - -# -# General setup -# -CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=128 -CONFIG_LOCALVERSION="" -CONFIG_LOCALVERSION_AUTO=y -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_SYSVIPC_SYSCTL=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set -# CONFIG_TASKSTATS is not set -# CONFIG_USER_NS is not set -# CONFIG_PID_NS is not set -# CONFIG_AUDIT is not set -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_CGROUPS is not set -CONFIG_FAIR_GROUP_SCHED=y -CONFIG_FAIR_USER_SCHED=y -# CONFIG_FAIR_CGROUP_SCHED is not set -CONFIG_SYSFS_DEPRECATED=y -# CONFIG_RELAY is not set -# CONFIG_BLK_DEV_INITRD is not set -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SYSCTL=y -# CONFIG_EMBEDDED is not set -CONFIG_UID16=y -CONFIG_SYSCTL_SYSCALL=y -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_ANON_INODES=y -CONFIG_EPOLL=y -CONFIG_SIGNALFD=y -CONFIG_TIMERFD=y -CONFIG_EVENTFD=y -CONFIG_SHMEM=y -CONFIG_VM_EVENT_COUNTERS=y -CONFIG_SLAB=y -# CONFIG_SLUB is not set -# CONFIG_SLOB is not set -# CONFIG_PROFILING is not set -# CONFIG_MARKERS is not set -# CONFIG_HAVE_OPROFILE is not set -# CONFIG_HAVE_KPROBES is not set -CONFIG_PROC_PAGE_MONITOR=y -CONFIG_SLABINFO=y -CONFIG_RT_MUTEXES=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 -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 -CONFIG_BLOCK=y -# CONFIG_LBD is not set -# CONFIG_BLK_DEV_IO_TRACE is not set -# CONFIG_LSF is not set -# CONFIG_BLK_DEV_BSG 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" -CONFIG_CLASSIC_RCU=y -# CONFIG_PREEMPT_RCU is not set -CONFIG_BLK_DEV=y -CONFIG_BLK_DEV_UBD=y -# CONFIG_BLK_DEV_UBD_SYNC is not set -CONFIG_BLK_DEV_COW_COMMON=y -CONFIG_BLK_DEV_LOOP=m -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -CONFIG_BLK_DEV_NBD=m -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_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="pts" -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -# CONFIG_RAW_DRIVER is not set -CONFIG_LEGACY_PTY_COUNT=32 -# CONFIG_WATCHDOG is not set -CONFIG_UML_SOUND=m -CONFIG_SOUND=m -CONFIG_HOSTAUDIO=m -# CONFIG_HW_RANDOM is not set -CONFIG_UML_RANDOM=y -# CONFIG_MMAPPER is not set - -# -# Generic Driver Options -# -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set -# CONFIG_DEBUG_DRIVER is not set -# CONFIG_DEBUG_DEVRES is not set -# CONFIG_SYS_HYPERVISOR is not set - -# -# Networking -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -CONFIG_XFRM=y -# CONFIG_XFRM_USER is not set -# CONFIG_XFRM_SUB_POLICY is not set -# CONFIG_XFRM_MIGRATE is not set -# CONFIG_XFRM_STATISTICS is not set -# 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_XFRM_MODE_TRANSPORT=y -CONFIG_INET_XFRM_MODE_TUNNEL=y -CONFIG_INET_XFRM_MODE_BEET=y -# CONFIG_INET_LRO is not set -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_CUBIC=y -CONFIG_DEFAULT_TCP_CONG="cubic" -# CONFIG_TCP_MD5SIG is not set -# CONFIG_IPV6 is not set -# CONFIG_INET6_XFRM_TUNNEL is not set -# CONFIG_INET6_TUNNEL is not set -# CONFIG_NETWORK_SECMARK is not set -# CONFIG_NETFILTER is not set -# CONFIG_IP_DCCP is not set -# CONFIG_IP_SCTP is not set -# 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_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_HAMRADIO is not set -# CONFIG_CAN is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -# CONFIG_AF_RXRPC is not set - -# -# Wireless -# -# CONFIG_CFG80211 is not set -# CONFIG_WIRELESS_EXT is not set -# CONFIG_MAC80211 is not set -# CONFIG_IEEE80211 is not set -# CONFIG_RFKILL is not set -# CONFIG_NET_9P 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_VDE is not set -CONFIG_UML_NET_MCAST=y -# CONFIG_UML_NET_PCAP is not set -CONFIG_UML_NET_SLIRP=y -CONFIG_NETDEVICES=y -# CONFIG_NETDEVICES_MULTIQUEUE is not set -CONFIG_DUMMY=m -# CONFIG_BONDING is not set -# CONFIG_MACVLAN is not set -# CONFIG_EQUALIZER is not set -CONFIG_TUN=m -# CONFIG_VETH is not set - -# -# Wireless LAN -# -# CONFIG_WLAN_PRE80211 is not set -# CONFIG_WLAN_80211 is not set -# 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_PPPOL2TP is not set -CONFIG_SLIP=m -# CONFIG_SLIP_COMPRESSED is not set -CONFIG_SLHC=m -# CONFIG_SLIP_SMART is not set -# CONFIG_SLIP_MODE_SLIP6 is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# 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_EXT4DEV_FS is not set -CONFIG_JBD=y -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_GFS2_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_INOTIFY_USER=y -CONFIG_QUOTA=y -# CONFIG_QUOTA_NETLINK_INTERFACE is not set -CONFIG_PRINT_QUOTA_WARNING=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_PROC_SYSCTL=y -CONFIG_SYSFS=y -CONFIG_TMPFS=y -# CONFIG_TMPFS_POSIX_ACL is not set -# CONFIG_HUGETLB_PAGE is not set -# 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 -CONFIG_NETWORK_FILESYSTEMS=y -# 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 - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -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 -# CONFIG_DLM is not set - -# -# Security options -# -# CONFIG_KEYS is not set -# CONFIG_SECURITY is not set -# CONFIG_SECURITY_FILE_CAPABILITIES is not set -CONFIG_CRYPTO=y -# CONFIG_CRYPTO_SEQIV is not set -# CONFIG_CRYPTO_MANAGER is not set -# CONFIG_CRYPTO_HMAC is not set -# CONFIG_CRYPTO_XCBC is not set -# CONFIG_CRYPTO_NULL is not set -# CONFIG_CRYPTO_MD4 is not set -# CONFIG_CRYPTO_MD5 is not set -# CONFIG_CRYPTO_SHA1 is not set -# CONFIG_CRYPTO_SHA256 is not set -# CONFIG_CRYPTO_SHA512 is not set -# CONFIG_CRYPTO_WP512 is not set -# CONFIG_CRYPTO_TGR192 is not set -# CONFIG_CRYPTO_GF128MUL is not set -# CONFIG_CRYPTO_ECB is not set -# CONFIG_CRYPTO_CBC is not set -# CONFIG_CRYPTO_PCBC is not set -# CONFIG_CRYPTO_LRW is not set -# CONFIG_CRYPTO_XTS is not set -# CONFIG_CRYPTO_CTR is not set -# CONFIG_CRYPTO_GCM is not set -# CONFIG_CRYPTO_CCM is not set -# CONFIG_CRYPTO_CRYPTD is not set -# CONFIG_CRYPTO_DES is not set -# CONFIG_CRYPTO_FCRYPT is not set -# CONFIG_CRYPTO_BLOWFISH is not set -# CONFIG_CRYPTO_TWOFISH is not set -# CONFIG_CRYPTO_TWOFISH_586 is not set -# CONFIG_CRYPTO_SERPENT is not set -# CONFIG_CRYPTO_AES is not set -# CONFIG_CRYPTO_AES_586 is not set -# CONFIG_CRYPTO_CAST5 is not set -# CONFIG_CRYPTO_CAST6 is not set -# CONFIG_CRYPTO_TEA is not set -# CONFIG_CRYPTO_ARC4 is not set -# CONFIG_CRYPTO_KHAZAD is not set -# CONFIG_CRYPTO_ANUBIS is not set -# CONFIG_CRYPTO_SEED is not set -# CONFIG_CRYPTO_SALSA20 is not set -# CONFIG_CRYPTO_SALSA20_586 is not set -# CONFIG_CRYPTO_DEFLATE is not set -# CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_CRC32C is not set -# CONFIG_CRYPTO_CAMELLIA is not set -# CONFIG_CRYPTO_TEST is not set -# CONFIG_CRYPTO_AUTHENC is not set -# CONFIG_CRYPTO_LZO is not set -CONFIG_CRYPTO_HW=y - -# -# Library routines -# -CONFIG_BITREVERSE=m -# CONFIG_CRC_CCITT is not set -# CONFIG_CRC16 is not set -# CONFIG_CRC_ITU_T is not set -CONFIG_CRC32=m -# CONFIG_CRC7 is not set -# CONFIG_LIBCRC32C is not set -CONFIG_PLIST=y -CONFIG_HAS_DMA=y - -# -# SCSI device support -# -# CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set -# CONFIG_SCSI_DMA is not set -# CONFIG_SCSI_NETLINK is not set -# CONFIG_MD is not set -# CONFIG_INPUT is not set - -# -# Kernel hacking -# -# CONFIG_PRINTK_TIME is not set -CONFIG_ENABLE_WARN_DEPRECATED=y -CONFIG_ENABLE_MUST_CHECK=y -# CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SHIRQ is not set -CONFIG_DETECT_SOFTLOCKUP=y -CONFIG_SCHED_DEBUG=y -# CONFIG_SCHEDSTATS is not set -# CONFIG_TIMER_STATS is not set -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_RT_MUTEX_TESTER is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -# CONFIG_DEBUG_KOBJECT is not set -CONFIG_DEBUG_BUGVERBOSE=y -CONFIG_DEBUG_INFO=y -# CONFIG_DEBUG_VM is not set -# CONFIG_DEBUG_LIST is not set -# CONFIG_DEBUG_SG is not set -CONFIG_FRAME_POINTER=y -CONFIG_FORCED_INLINING=y -# CONFIG_BOOT_PRINTK_DELAY is not set -# CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_BACKTRACE_SELF_TEST is not set -# CONFIG_FAULT_INJECTION is not set -# CONFIG_SAMPLES is not set -# CONFIG_GPROF is not set -# CONFIG_GCOV is not set -# CONFIG_DEBUG_STACK_USAGE is not set diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index d283e7b022a..e7582e1d248 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile @@ -9,7 +9,7 @@ slip-objs := slip_kern.o slip_user.o slirp-objs := slirp_kern.o slirp_user.o daemon-objs := daemon_kern.o daemon_user.o -mcast-objs := mcast_kern.o mcast_user.o +umcast-objs := umcast_kern.o umcast_user.o net-objs := net_kern.o net_user.o mconsole-objs := mconsole_kern.o mconsole_user.o hostaudio-objs := hostaudio_kern.o @@ -44,7 +44,7 @@ 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_VDE) += vde.o -obj-$(CONFIG_UML_NET_MCAST) += mcast.o +obj-$(CONFIG_UML_NET_MCAST) += umcast.o obj-$(CONFIG_UML_NET_PCAP) += pcap.o obj-$(CONFIG_UML_NET) += net.o obj-$(CONFIG_MCONSOLE) += mconsole.o @@ -62,5 +62,6 @@ 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 vde_user.o +CFLAGS_null.o = -DDEV_NULL=$(DEV_NULL_PATH) include arch/um/scripts/Makefile.rules diff --git a/arch/um/include/chan_kern.h b/arch/um/drivers/chan.h index 624b5100a3c..c512b0306dd 100644 --- a/arch/um/include/chan_kern.h +++ b/arch/um/drivers/chan.h @@ -6,9 +6,9 @@ #ifndef __CHAN_KERN_H__ #define __CHAN_KERN_H__ -#include "linux/tty.h" -#include "linux/list.h" -#include "linux/console.h" +#include <linux/tty.h> +#include <linux/list.h> +#include <linux/console.h> #include "chan_user.h" #include "line.h" @@ -27,26 +27,23 @@ struct chan { void *data; }; -extern void chan_interrupt(struct list_head *chans, struct delayed_work *task, - struct tty_struct *tty, int irq); +extern void chan_interrupt(struct line *line, int irq); extern int parse_chan_pair(char *str, struct line *line, int device, const struct chan_opts *opts, char **error_out); -extern int open_chan(struct list_head *chans); -extern int write_chan(struct list_head *chans, const char *buf, int len, +extern int write_chan(struct chan *chan, const char *buf, int len, int write_irq); -extern int console_write_chan(struct list_head *chans, const char *buf, +extern int console_write_chan(struct chan *chan, const char *buf, int len); extern int console_open_chan(struct line *line, struct console *co); -extern void deactivate_chan(struct 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 deactivate_chan(struct chan *chan, int irq); +extern void reactivate_chan(struct chan *chan, int irq); +extern void chan_enable_winch(struct chan *chan, struct tty_port *port); extern int enable_chan(struct line *line); -extern void close_chan(struct list_head *chans, int delay_free_irq); -extern int chan_window_size(struct list_head *chans, +extern void close_chan(struct line *line); +extern int chan_window_size(struct line *line, unsigned short *rows_out, unsigned short *cols_out); -extern int chan_out_fd(struct list_head *chans); -extern int chan_config_string(struct list_head *chans, char *str, int size, +extern int chan_config_string(struct line *line, char *str, int size, char **error_out); #endif diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index db3082b4da4..acbe6c67afb 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -6,8 +6,9 @@ #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include "chan_kern.h" -#include "os.h" +#include "chan.h" +#include <os.h> +#include <irq_kern.h> #ifdef CONFIG_NOCONFIG_CHAN static void *not_configged_init(char *str, int device, @@ -80,25 +81,6 @@ static const struct chan_ops not_configged_ops = { }; #endif /* CONFIG_NOCONFIG_CHAN */ -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, err; @@ -125,7 +107,7 @@ static int open_one_chan(struct chan *chan) return 0; } -int open_chan(struct list_head *chans) +static int open_chan(struct list_head *chans) { struct list_head *ele; struct chan *chan; @@ -140,18 +122,18 @@ int open_chan(struct list_head *chans) return err; } -void chan_enable_winch(struct list_head *chans, struct tty_struct *tty) +void chan_enable_winch(struct chan *chan, struct tty_port *port) { - struct list_head *ele; - struct chan *chan; + if (chan && chan->primary && chan->ops->winch) + register_winch(chan->fd, port); +} - 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; - } - } +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, line->driver->read_irq); } int enable_chan(struct line *line) @@ -160,6 +142,8 @@ int enable_chan(struct line *line) struct chan *chan; int err; + INIT_DELAYED_WORK(&line->task, line_timer_cb); + list_for_each(ele, &line->chan_list) { chan = list_entry(ele, struct chan, list); err = open_one_chan(chan); @@ -183,7 +167,7 @@ int enable_chan(struct line *line) return 0; out_close: - close_chan(&line->chan_list, 0); + close_chan(line); return err; } @@ -210,10 +194,10 @@ void free_irqs(void) 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); + if (chan->input && chan->enabled) + um_free_irq(chan->line->driver->read_irq, chan); + if (chan->output && chan->enabled) + um_free_irq(chan->line->driver->write_irq, chan); chan->enabled = 0; } } @@ -231,10 +215,10 @@ static void close_one_chan(struct chan *chan, int delay_free_irq) 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); + if (chan->input && chan->enabled) + um_free_irq(chan->line->driver->read_irq, chan); + if (chan->output && chan->enabled) + um_free_irq(chan->line->driver->write_irq, chan); chan->enabled = 0; } if (chan->ops->close != NULL) @@ -244,7 +228,7 @@ static void close_one_chan(struct chan *chan, int delay_free_irq) chan->fd = -1; } -void close_chan(struct list_head *chans, int delay_free_irq) +void close_chan(struct line *line) { struct chan *chan; @@ -253,77 +237,50 @@ void close_chan(struct list_head *chans, int delay_free_irq) * 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); + list_for_each_entry_reverse(chan, &line->chan_list, list) { + close_one_chan(chan, 0); } } -void deactivate_chan(struct list_head *chans, int irq) +void deactivate_chan(struct chan *chan, 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); - } + if (chan && chan->enabled) + deactivate_fd(chan->fd, irq); } -void reactivate_chan(struct list_head *chans, int irq) +void reactivate_chan(struct chan *chan, 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); - } + if (chan && chan->enabled) + reactivate_fd(chan->fd, irq); } -int write_chan(struct list_head *chans, const char *buf, int len, +int write_chan(struct chan *chan, const char *buf, int len, int write_irq) { - struct list_head *ele; - struct chan *chan = NULL; int n, ret = 0; - if (len == 0) + if (len == 0 || !chan || !chan->ops->write) return 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); - } + 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) +int console_write_chan(struct chan *chan, const char *buf, int len) { - struct list_head *ele; - struct chan *chan; int n, ret = 0; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->output || (chan->ops->console_write == NULL)) - continue; + if (!chan || !chan->ops->console_write) + return 0; - n = chan->ops->console_write(chan->fd, buf, len); - if (chan->primary) - ret = n; - } + n = chan->ops->console_write(chan->fd, buf, len); + if (chan->primary) + ret = n; return ret; } @@ -340,29 +297,33 @@ int console_open_chan(struct line *line, struct console *co) return 0; } -int chan_window_size(struct list_head *chans, unsigned short *rows_out, +int chan_window_size(struct line *line, unsigned short *rows_out, unsigned short *cols_out) { - struct list_head *ele; struct chan *chan; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (chan->primary) { - if (chan->ops->window_size == NULL) - return 0; - return chan->ops->window_size(chan->fd, chan->data, - rows_out, cols_out); - } + chan = line->chan_in; + if (chan && chan->primary) { + if (chan->ops->window_size == NULL) + return 0; + return chan->ops->window_size(chan->fd, chan->data, + rows_out, cols_out); + } + chan = line->chan_out; + if (chan && chan->primary) { + if (chan->ops->window_size == NULL) + return 0; + return chan->ops->window_size(chan->fd, chan->data, + rows_out, cols_out); } return 0; } -static void free_one_chan(struct chan *chan, int delay_free_irq) +static void free_one_chan(struct chan *chan) { list_del(&chan->list); - close_one_chan(chan, delay_free_irq); + close_one_chan(chan, 0); if (chan->ops->free != NULL) (*chan->ops->free)(chan->data); @@ -372,14 +333,14 @@ static void free_one_chan(struct chan *chan, int delay_free_irq) kfree(chan); } -static void free_chan(struct list_head *chans, int delay_free_irq) +static void free_chan(struct list_head *chans) { 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); + free_one_chan(chan); } } @@ -429,21 +390,15 @@ static int chan_pair_config_string(struct chan *in, struct chan *out, return n; } -int chan_config_string(struct list_head *chans, char *str, int size, +int chan_config_string(struct line *line, char *str, int size, char **error_out) { - struct list_head *ele; - struct chan *chan, *in = NULL, *out = NULL; + struct chan *in = line->chan_in, *out = line->chan_out; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->primary) - continue; - if (chan->input) - in = chan; - if (chan->output) - out = chan; - } + if (in && !in->primary) + in = NULL; + if (out && !out->primary) + out = NULL; return chan_pair_config_string(in, out, str, size, error_out); } @@ -543,15 +498,18 @@ 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; + struct chan *new; char *in, *out; if (!list_empty(chans)) { - chan = list_entry(chans->next, struct chan, list); - free_chan(chans, 0); + line->chan_in = line->chan_out = NULL; + free_chan(chans); INIT_LIST_HEAD(chans); } + if (!str) + return 0; + out = strchr(str, ','); if (out != NULL) { in = str; @@ -563,6 +521,7 @@ int parse_chan_pair(char *str, struct line *line, int device, new->input = 1; list_add(&new->list, chans); + line->chan_in = new; new = parse_chan(line, out, device, opts, error_out); if (new == NULL) @@ -570,6 +529,7 @@ int parse_chan_pair(char *str, struct line *line, int device, list_add(&new->list, chans); new->output = 1; + line->chan_out = new; } else { new = parse_chan(line, str, device, opts, error_out); @@ -579,58 +539,43 @@ int parse_chan_pair(char *str, struct line *line, int device, list_add(&new->list, chans); new->input = 1; new->output = 1; + line->chan_in = line->chan_out = new; } return 0; } -int chan_out_fd(struct list_head *chans) -{ - struct list_head *ele; - struct chan *chan; - - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (chan->primary && chan->output) - return chan->fd; - } - return -1; -} - -void chan_interrupt(struct list_head *chans, struct delayed_work *task, - struct tty_struct *tty, int irq) +void chan_interrupt(struct line *line, int irq) { - struct list_head *ele, *next; - struct chan *chan; + struct tty_port *port = &line->port; + struct chan *chan = line->chan_in; int err; char c; - list_for_each_safe(ele, next, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->input || (chan->ops->read == NULL)) - continue; - do { - if (tty && !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); + if (!chan || !chan->ops->read) + goto out; + + do { + if (!tty_buffer_request_room(port, 1)) { + schedule_delayed_work(&line->task, 1); + goto out; + } + err = chan->ops->read(chan->fd, &c, chan->data); + if (err > 0) + tty_insert_flip_char(port, c, TTY_NORMAL); + } while (err > 0); + + if (err == 0) + reactivate_fd(chan->fd, irq); + if (err == -EIO) { + if (chan->primary) { + tty_port_tty_hangup(&line->port, false); + if (line->chan_out != chan) + close_one_chan(line->chan_out, 1); } + close_one_chan(chan, 1); + if (chan->primary) + return; } out: - if (tty) - tty_flip_buffer_push(tty); + tty_flip_buffer_push(port); } diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 025764089ac..3fd7c3efdb1 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -11,9 +11,8 @@ #include <termios.h> #include <sys/ioctl.h> #include "chan_user.h" -#include "os.h" -#include "um_malloc.h" -#include "user.h" +#include <os.h> +#include <um_malloc.h> void generic_close(int fd, void *unused) { @@ -217,7 +216,7 @@ static int winch_thread(void *arg) } } -static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out, +static int winch_tramp(int fd, struct tty_port *port, int *fd_out, unsigned long *stack_out) { struct winch_data data; @@ -272,7 +271,7 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out, return err; } -void register_winch(int fd, struct tty_struct *tty) +void register_winch(int fd, struct tty_port *port) { unsigned long stack; int pid, thread, count, thread_fd = -1; @@ -282,12 +281,17 @@ void register_winch(int fd, struct tty_struct *tty) return; pid = tcgetpgrp(fd); - if (!is_skas_winch(pid, fd, tty) && (pid == -1)) { - thread = winch_tramp(fd, tty, &thread_fd, &stack); + if (is_skas_winch(pid, fd, port)) { + register_winch_irq(-1, fd, -1, port, 0); + return; + } + + if (pid == -1) { + thread = winch_tramp(fd, port, &thread_fd, &stack); if (thread < 0) return; - register_winch_irq(thread_fd, fd, thread, tty, stack); + register_winch_irq(thread_fd, fd, thread, port, stack); count = write(thread_fd, &c, sizeof(c)); if (count != sizeof(c)) diff --git a/arch/um/include/chan_user.h b/arch/um/drivers/chan_user.h index 9b9ced85b70..03f1b565c5f 100644 --- a/arch/um/include/chan_user.h +++ b/arch/um/drivers/chan_user.h @@ -6,7 +6,7 @@ #ifndef __CHAN_USER_H__ #define __CHAN_USER_H__ -#include "init.h" +#include <init.h> struct chan_opts { void (*const announce)(char *dev_name, int dev); @@ -14,8 +14,6 @@ struct chan_opts { const int raw; }; -enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; - struct chan_ops { char *type; void *(*init)(char *, int, const struct chan_opts *); @@ -40,10 +38,10 @@ 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); +struct tty_port; +extern void register_winch(int fd, struct tty_port *port); extern void register_winch_irq(int fd, int tty_fd, int pid, - struct tty_struct *tty, unsigned long stack); + struct tty_port *port, unsigned long stack); #define __channel_help(fn, prefix) \ __uml_help(fn, prefix "[0-9]*=<channel description>\n" \ diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h index dc36b222100..6673508f342 100644 --- a/arch/um/drivers/cow.h +++ b/arch/um/drivers/cow.h @@ -3,41 +3,6 @@ #include <asm/types.h> -#if defined(__KERNEL__) - -# include <asm/byteorder.h> - -# if defined(__BIG_ENDIAN) -# define ntohll(x) (x) -# define htonll(x) (x) -# elif defined(__LITTLE_ENDIAN) -# define ntohll(x) be64_to_cpu(x) -# define htonll(x) cpu_to_be64(x) -# else -# error "Could not determine byte order" -# endif - -#else -/* For the definition of ntohl, htonl and __BYTE_ORDER */ -#include <endian.h> -#include <netinet/in.h> -#if defined(__BYTE_ORDER) - -# if __BYTE_ORDER == __BIG_ENDIAN -# define ntohll(x) (x) -# define htonll(x) (x) -# elif __BYTE_ORDER == __LITTLE_ENDIAN -# define ntohll(x) bswap_64(x) -# define htonll(x) bswap_64(x) -# else -# error "Could not determine byte order: __BYTE_ORDER uncorrectly defined" -# endif - -#else /* ! defined(__BYTE_ORDER) */ -# error "Could not determine byte order: __BYTE_ORDER not defined" -#endif -#endif /* ! defined(__KERNEL__) */ - extern int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out); diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h index ca8c9e11a39..67cbee63e70 100644 --- a/arch/um/drivers/cow_sys.h +++ b/arch/um/drivers/cow_sys.h @@ -1,14 +1,13 @@ #ifndef __COW_SYS_H__ #define __COW_SYS_H__ -#include "kern_util.h" -#include "os.h" -#include "user.h" -#include "um_malloc.h" +#include <kern_util.h> +#include <os.h> +#include <um_malloc.h> static inline void *cow_malloc(int size) { - return kmalloc(size, UM_GFP_KERNEL); + return uml_kmalloc(size, UM_GFP_KERNEL); } static inline void cow_free(void *ptr) diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index 93f227a25ba..0ee9cc6cc4c 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c @@ -8,11 +8,10 @@ * that. */ #include <unistd.h> -#include <byteswap.h> #include <errno.h> #include <string.h> #include <arpa/inet.h> -#include <asm/types.h> +#include <endian.h> #include "cow.h" #include "cow_sys.h" @@ -186,7 +185,11 @@ static int absolutize(char *to, int size, char *from) strcat(to, "/"); strcat(to, from); } - chdir(save_cwd); + if (chdir(save_cwd)) { + cow_printf("absolutize : Can't cd to '%s' - " + "errno = %d\n", save_cwd, errno); + return -1; + } return 0; } @@ -210,8 +213,8 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, "header\n"); goto out; } - header->magic = htonl(COW_MAGIC); - header->version = htonl(COW_VERSION); + header->magic = htobe32(COW_MAGIC); + header->version = htobe32(COW_VERSION); err = -EINVAL; if (strlen(backing_file) > sizeof(header->backing_file) - 1) { @@ -242,10 +245,10 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, goto out_free; } - header->mtime = htonl(modtime); - header->size = htonll(*size); - header->sectorsize = htonl(sectorsize); - header->alignment = htonl(alignment); + header->mtime = htobe32(modtime); + header->size = htobe64(*size); + header->sectorsize = htobe32(sectorsize); + header->alignment = htobe32(alignment); header->cow_format = COW_BITMAP; err = cow_write_file(fd, header, sizeof(*header)); @@ -297,8 +300,8 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, magic = header->v1.magic; if (magic == COW_MAGIC) version = header->v1.version; - else if (magic == ntohl(COW_MAGIC)) - version = ntohl(header->v1.version); + else if (magic == be32toh(COW_MAGIC)) + version = be32toh(header->v1.version); /* No error printed because the non-COW case comes through here */ else goto out; @@ -323,9 +326,9 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, "header\n"); goto out; } - *mtime_out = ntohl(header->v2.mtime); - *size_out = ntohll(header->v2.size); - *sectorsize_out = ntohl(header->v2.sectorsize); + *mtime_out = be32toh(header->v2.mtime); + *size_out = be64toh(header->v2.size); + *sectorsize_out = be32toh(header->v2.sectorsize); *bitmap_offset_out = sizeof(header->v2); *align_out = *sectorsize_out; file = header->v2.backing_file; @@ -337,10 +340,10 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, "header\n"); goto out; } - *mtime_out = ntohl(header->v3.mtime); - *size_out = ntohll(header->v3.size); - *sectorsize_out = ntohl(header->v3.sectorsize); - *align_out = ntohl(header->v3.alignment); + *mtime_out = be32toh(header->v3.mtime); + *size_out = be64toh(header->v3.size); + *sectorsize_out = be32toh(header->v3.sectorsize); + *align_out = be32toh(header->v3.alignment); if (*align_out == 0) { cow_printf("read_cow_header - invalid COW header, " "align == 0\n"); @@ -362,16 +365,16 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, * 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 + * Additionally, we must use be32toh() instead of be64toh(), since * the program used to use the former (tested - I got mtime * mismatch "0 vs whatever"). * * Ever heard about bug-to-bug-compatibility ? ;-) */ - *mtime_out = (time32_t) ntohl(header->v3_b.mtime); + *mtime_out = (time32_t) be32toh(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); + *size_out = be64toh(header->v3_b.size); + *sectorsize_out = be32toh(header->v3_b.sectorsize); + *align_out = be32toh(header->v3_b.alignment); if (*align_out == 0) { cow_printf("read_cow_header - invalid COW header, " "align == 0\n"); diff --git a/arch/um/drivers/daemon.h b/arch/um/drivers/daemon.h index 6e0e891f8a0..c2dd1951559 100644 --- a/arch/um/drivers/daemon.h +++ b/arch/um/drivers/daemon.h @@ -6,7 +6,7 @@ #ifndef __DAEMON_H__ #define __DAEMON_H__ -#include "net_user.h" +#include <net_user.h> #define SWITCH_VERSION 3 diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c index d53ff52bb40..7568cc2f3cd 100644 --- a/arch/um/drivers/daemon_kern.c +++ b/arch/um/drivers/daemon_kern.c @@ -6,9 +6,9 @@ * Licensed under the GPL. */ -#include "linux/init.h" +#include <linux/init.h> #include <linux/netdevice.h> -#include "net_kern.h" +#include <net_kern.h> #include "daemon.h" struct daemon_init { @@ -22,7 +22,7 @@ static void daemon_init(struct net_device *dev, void *data) struct daemon_data *dpri; struct daemon_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); dpri = (struct daemon_data *) pri->user; dpri->sock_type = init->sock_type; dpri->ctl_sock = init->ctl_sock; diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c index f23c109a055..8813c10d017 100644 --- a/arch/um/drivers/daemon_user.c +++ b/arch/um/drivers/daemon_user.c @@ -14,10 +14,9 @@ #include <sys/time.h> #include <sys/un.h> #include "daemon.h" -#include "net_user.h" -#include "os.h" -#include "um_malloc.h" -#include "user.h" +#include <net_user.h> +#include <os.h> +#include <um_malloc.h> enum request_type { REQ_NEW_CONTROL }; @@ -34,7 +33,7 @@ static struct sockaddr_un *new_addr(void *name, int len) { struct sockaddr_un *sun; - sun = kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); + sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); if (sun == NULL) { printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un " "failed\n"); @@ -83,7 +82,7 @@ static int connect_to_switch(struct daemon_data *pri) goto out_close; } - sun = kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); + sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); if (sun == NULL) { printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un " "failed\n"); diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index 0a2bb5b64b8..a13a427b996 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -9,10 +9,8 @@ #include <errno.h> #include <termios.h> #include "chan_user.h" -#include "kern_constants.h" -#include "os.h" -#include "um_malloc.h" -#include "user.h" +#include <os.h> +#include <um_malloc.h> struct fd_chan { int fd; @@ -40,7 +38,7 @@ static void *fd_init(char *str, int device, const struct chan_opts *opts) return NULL; } - data = kmalloc(sizeof(*data), UM_GFP_KERNEL); + data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); if (data == NULL) return NULL; diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index a9ad4bd6d95..2d0266d0254 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c @@ -42,7 +42,7 @@ #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/reboot.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/init.h> #include <linux/spinlock.h> #include <asm/uaccess.h> @@ -50,6 +50,7 @@ MODULE_LICENSE("GPL"); +static DEFINE_MUTEX(harddog_mutex); static DEFINE_SPINLOCK(lock); static int timer_alive; static int harddog_in_fd = -1; @@ -66,6 +67,7 @@ static int harddog_open(struct inode *inode, struct file *file) int err = -EBUSY; char *sock = NULL; + mutex_lock(&harddog_mutex); spin_lock(&lock); if(timer_alive) goto err; @@ -82,9 +84,11 @@ static int harddog_open(struct inode *inode, struct file *file) timer_alive = 1; spin_unlock(&lock); + mutex_unlock(&harddog_mutex); return nonseekable_open(inode, file); err: spin_unlock(&lock); + mutex_unlock(&harddog_mutex); return err; } @@ -121,8 +125,8 @@ static ssize_t harddog_write(struct file *file, const char __user *data, size_t return 0; } -static int harddog_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int harddog_ioctl_unlocked(struct file *file, + unsigned int cmd, unsigned long arg) { void __user *argp= (void __user *)arg; static struct watchdog_info ident = { @@ -145,12 +149,25 @@ static int harddog_ioctl(struct inode *inode, struct file *file, } } +static long harddog_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + + mutex_lock(&harddog_mutex); + ret = harddog_ioctl_unlocked(file, cmd, arg); + mutex_unlock(&harddog_mutex); + + return ret; +} + static const struct file_operations harddog_fops = { .owner = THIS_MODULE, .write = harddog_write, - .ioctl = harddog_ioctl, + .unlocked_ioctl = harddog_ioctl, .open = harddog_open, .release = harddog_release, + .llseek = no_llseek, }; static struct miscdevice harddog_miscdev = { diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index b56f8e0196a..f99b32a4dbf 100644 --- a/arch/um/drivers/harddog_user.c +++ b/arch/um/drivers/harddog_user.c @@ -6,8 +6,7 @@ #include <stdio.h> #include <unistd.h> #include <errno.h> -#include "os.h" -#include "user.h" +#include <os.h> struct dog_data { int stdin; @@ -32,7 +31,7 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) { struct dog_data data; int in_fds[2], out_fds[2], pid, n, err; - char pid_buf[sizeof("nnnnn\0")], c; + char pid_buf[sizeof("nnnnnnn\0")], c; char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL }; char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, NULL }; diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index ff1b22b69e9..9b90fdc4b15 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -3,14 +3,15 @@ * Licensed under the GPL */ -#include "linux/fs.h" -#include "linux/module.h" -#include "linux/slab.h" -#include "linux/sound.h" -#include "linux/soundcard.h" -#include "asm/uaccess.h" -#include "init.h" -#include "os.h" +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/sound.h> +#include <linux/soundcard.h> +#include <linux/mutex.h> +#include <asm/uaccess.h> +#include <init.h> +#include <os.h> struct hostaudio_state { int fd; @@ -39,6 +40,11 @@ static char *mixer = HOSTAUDIO_DEV_MIXER; " This is used to specify the host mixer device to the hostaudio driver.\n"\ " The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n" +module_param(dsp, charp, 0644); +MODULE_PARM_DESC(dsp, DSP_HELP); +module_param(mixer, charp, 0644); +MODULE_PARM_DESC(mixer, MIXER_HELP); + #ifndef MODULE static int set_dsp(char *name, int *add) { @@ -55,17 +61,10 @@ static int set_mixer(char *name, int *add) } __uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP); - -#else /*MODULE*/ - -module_param(dsp, charp, 0644); -MODULE_PARM_DESC(dsp, DSP_HELP); - -module_param(mixer, charp, 0644); -MODULE_PARM_DESC(mixer, MIXER_HELP); - #endif +static DEFINE_MUTEX(hostaudio_mutex); + /* /dev/dsp file operations */ static ssize_t hostaudio_read(struct file *file, char __user *buffer, @@ -136,7 +135,7 @@ static unsigned int hostaudio_poll(struct file *file, return mask; } -static int hostaudio_ioctl(struct inode *inode, struct file *file, +static long hostaudio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct hostaudio_state *state = file->private_data; @@ -154,7 +153,7 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_SETFRAGMENT: if (get_user(data, (int __user *) arg)) - return EFAULT; + return -EFAULT; break; default: break; @@ -186,7 +185,9 @@ static int hostaudio_open(struct inode *inode, struct file *file) int ret; #ifdef DEBUG + kparam_block_sysfs_write(dsp); printk(KERN_DEBUG "hostaudio: open called (host: %s)\n", dsp); + kparam_unblock_sysfs_write(dsp); #endif state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); @@ -198,7 +199,12 @@ static int hostaudio_open(struct inode *inode, struct file *file) if (file->f_mode & FMODE_WRITE) w = 1; + kparam_block_sysfs_write(dsp); + mutex_lock(&hostaudio_mutex); ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); + mutex_unlock(&hostaudio_mutex); + kparam_unblock_sysfs_write(dsp); + if (ret < 0) { kfree(state); return ret; @@ -223,7 +229,7 @@ static int hostaudio_release(struct inode *inode, struct file *file) /* /dev/mixer file operations */ -static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, +static long hostmixer_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) { struct hostmixer_state *state = file->private_data; @@ -254,11 +260,17 @@ static int hostmixer_open_mixdev(struct inode *inode, struct file *file) if (file->f_mode & FMODE_WRITE) w = 1; + kparam_block_sysfs_write(mixer); + mutex_lock(&hostaudio_mutex); ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); + mutex_unlock(&hostaudio_mutex); + kparam_unblock_sysfs_write(mixer); if (ret < 0) { + kparam_block_sysfs_write(dsp); printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', " "err = %d\n", dsp, -ret); + kparam_unblock_sysfs_write(dsp); kfree(state); return ret; } @@ -289,7 +301,7 @@ static const struct file_operations hostaudio_fops = { .read = hostaudio_read, .write = hostaudio_write, .poll = hostaudio_poll, - .ioctl = hostaudio_ioctl, + .unlocked_ioctl = hostaudio_ioctl, .mmap = NULL, .open = hostaudio_open, .release = hostaudio_release, @@ -298,7 +310,7 @@ static const struct file_operations hostaudio_fops = { static const struct file_operations hostmixer_fops = { .owner = THIS_MODULE, .llseek = no_llseek, - .ioctl = hostmixer_ioctl_mixdev, + .unlocked_ioctl = hostmixer_ioctl_mixdev, .open = hostmixer_open_mixdev, .release = hostmixer_release, }; @@ -314,8 +326,10 @@ MODULE_LICENSE("GPL"); static int __init hostaudio_init_module(void) { + __kernel_param_lock(); printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", dsp, mixer); + __kernel_param_unlock(); module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); if (module_data.dev_audio < 0) { diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 2c898c4d6b6..8035145f043 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -3,13 +3,15 @@ * Licensed under the GPL */ -#include "linux/irqreturn.h" -#include "linux/kd.h" -#include "chan_kern.h" -#include "irq_kern.h" -#include "irq_user.h" -#include "kern_util.h" -#include "os.h" +#include <linux/irqreturn.h> +#include <linux/kd.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include "chan.h" +#include <irq_kern.h> +#include <irq_user.h> +#include <kern_util.h> +#include <os.h> #define LINE_BUFSIZE 4096 @@ -17,20 +19,11 @@ 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; -} + chan_interrupt(line, irq); -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); + return IRQ_HANDLED; } /* @@ -144,7 +137,7 @@ static int flush_buffer(struct line *line) /* line->buffer + LINE_BUFSIZE is the end of the buffer! */ count = line->buffer + LINE_BUFSIZE - line->head; - n = write_chan(&line->chan_list, line->head, count, + n = write_chan(line->chan_out, line->head, count, line->driver->write_irq); if (n < 0) return n; @@ -161,7 +154,7 @@ static int flush_buffer(struct line *line) } count = line->tail - line->head; - n = write_chan(&line->chan_list, line->head, count, + n = write_chan(line->chan_out, line->head, count, line->driver->write_irq); if (n < 0) @@ -175,10 +168,9 @@ void line_flush_buffer(struct tty_struct *tty) { struct line *line = tty->driver_data; unsigned long flags; - int err; spin_lock_irqsave(&line->lock, flags); - err = flush_buffer(line); + flush_buffer(line); spin_unlock_irqrestore(&line->lock, flags); } @@ -191,9 +183,9 @@ void line_flush_chars(struct tty_struct *tty) line_flush_buffer(tty); } -void line_put_char(struct tty_struct *tty, unsigned char ch) +int line_put_char(struct tty_struct *tty, unsigned char ch) { - line_write(tty, &ch, sizeof(ch)); + return line_write(tty, &ch, sizeof(ch)); } int line_write(struct tty_struct *tty, const unsigned char *buf, int len) @@ -206,7 +198,7 @@ int line_write(struct tty_struct *tty, const unsigned char *buf, int len) if (line->head != line->tail) ret = buffer_data(line, buf, len); else { - n = write_chan(&line->chan_list, buf, len, + n = write_chan(line->chan_out, buf, len, line->driver->write_irq); if (n < 0) { ret = n; @@ -228,95 +220,11 @@ 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)) { - 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); + deactivate_chan(line->chan_in, line->driver->read_irq); line->throttled = 1; } @@ -325,8 +233,7 @@ 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); + chan_interrupt(line, line->driver->read_irq); /* * Maybe there is enough stuff pending that calling the interrupt @@ -334,24 +241,24 @@ void line_unthrottle(struct tty_struct *tty) * again and we shouldn't turn the interrupt back on. */ if (!line->throttled) - reactivate_chan(&line->chan_list, line->driver->read_irq); + reactivate_chan(line->chan_in, line->driver->read_irq); } static irqreturn_t line_write_interrupt(int irq, void *data) { struct chan *chan = data; struct line *line = chan->line; - struct tty_struct *tty = line->tty; int err; /* - * Interrupts are disabled here because we registered the interrupt with - * IRQF_DISABLED (see line_setup_irq). + * Interrupts are disabled here because genirq keep irqs disabled when + * calling the action handler. */ spin_lock(&line->lock); err = flush_buffer(line); if (err == 0) { + spin_unlock(&line->lock); return IRQ_NONE; } else if (err < 0) { line->head = line->buffer; @@ -359,137 +266,100 @@ static irqreturn_t line_write_interrupt(int irq, void *data) } 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); + tty_port_tty_wakeup(&line->port); - /* - * 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; + int err = 0; if (input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, - line_interrupt, flags, - driver->read_irq_name, data); + line_interrupt, IRQF_SHARED, + driver->read_irq_name, data); if (err) return err; if (output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, - line_write_interrupt, flags, - driver->write_irq_name, data); - line->have_irq = 1; + line_write_interrupt, IRQF_SHARED, + driver->write_irq_name, data); 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) +static int line_activate(struct tty_port *port, 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; - - err = enable_chan(line); - if (err) - return err; + int ret; + struct line *line = tty->driver_data; - INIT_DELAYED_WORK(&line->task, line_timer_cb); + ret = enable_chan(line); + if (ret) + return ret; if (!line->sigio) { - chan_enable_winch(&line->chan_list, tty); + chan_enable_winch(line->chan_out, port); line->sigio = 1; } - chan_window_size(&line->chan_list, &tty->winsize.ws_row, - &tty->winsize.ws_col); - - return err; + chan_window_size(line, &tty->winsize.ws_row, + &tty->winsize.ws_col); -out_unlock: - spin_unlock(&line->count_lock); - return err; + return 0; } static void unregister_winch(struct tty_struct *tty); -void line_close(struct tty_struct *tty, struct file * filp) +static void line_destruct(struct tty_port *port) { + struct tty_struct *tty = tty_port_tty_get(port); 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; + if (line->sigio) { + unregister_winch(tty); + line->sigio = 0; + } +} - /* We ignore the error anyway! */ - flush_buffer(line); +static const struct tty_port_operations line_port_ops = { + .activate = line_activate, + .destruct = line_destruct, +}; - spin_lock(&line->count_lock); - if (!line->valid) - goto out_unlock; +int line_open(struct tty_struct *tty, struct file *filp) +{ + struct line *line = tty->driver_data; - if (tty->count > 1) - goto out_unlock; + return tty_port_open(&line->port, tty, filp); +} - spin_unlock(&line->count_lock); +int line_install(struct tty_driver *driver, struct tty_struct *tty, + struct line *line) +{ + int ret; - line->tty = NULL; - tty->driver_data = NULL; + ret = tty_standard_install(driver, tty); + if (ret) + return ret; - if (line->sigio) { - unregister_winch(tty); - line->sigio = 0; - } + tty->driver_data = line; - return; + return 0; +} + +void line_close(struct tty_struct *tty, struct file * filp) +{ + struct line *line = tty->driver_data; + + tty_port_close(&line->port, tty, filp); +} + +void line_hangup(struct tty_struct *tty) +{ + struct line *line = tty->driver_data; -out_unlock: - spin_unlock(&line->count_lock); + tty_port_hangup(&line->port); } void close_lines(struct line *lines, int nlines) @@ -497,34 +367,58 @@ void close_lines(struct line *lines, int nlines) int i; for(i = 0; i < nlines; i++) - close_chan(&lines[i].chan_list, 0); + close_chan(&lines[i]); } -static int setup_one_line(struct line *lines, int n, char *init, int init_prio, - char **error_out) +int setup_one_line(struct line *lines, int n, char *init, + const struct chan_opts *opts, char **error_out) { struct line *line = &lines[n]; + struct tty_driver *driver = line->driver->driver; int err = -EINVAL; - spin_lock(&line->count_lock); - - if (line->tty != NULL) { + if (line->port.count) { *error_out = "Device is already open"; goto out; } - if (line->init_pri <= init_prio) { - line->init_pri = init_prio; - if (!strcmp(init, "none")) + if (!strcmp(init, "none")) { + if (line->valid) { + line->valid = 0; + kfree(line->init_str); + tty_unregister_device(driver, n); + parse_chan_pair(NULL, line, n, opts, error_out); + err = 0; + } + } else { + char *new = kstrdup(init, GFP_KERNEL); + if (!new) { + *error_out = "Failed to allocate memory"; + return -ENOMEM; + } + if (line->valid) { + tty_unregister_device(driver, n); + kfree(line->init_str); + } + line->init_str = new; + line->valid = 1; + err = parse_chan_pair(new, line, n, opts, error_out); + if (!err) { + struct device *d = tty_port_register_device(&line->port, + driver, n, NULL); + if (IS_ERR(d)) { + *error_out = "Failed to register device"; + err = PTR_ERR(d); + parse_chan_pair(NULL, line, n, opts, error_out); + } + } + if (err) { + line->init_str = NULL; line->valid = 0; - else { - line->init_str = init; - line->valid = 1; + kfree(new); } } - err = 0; out: - spin_unlock(&line->count_lock); return err; } @@ -535,54 +429,43 @@ out: * @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 line_setup(char **conf, unsigned int num, char **def, + char *init, char *name) { - int i, n, err; - char *end; + char *error; 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); + *def = init + 1; + } else { + char *end; + unsigned n = simple_strtoul(init, &end, 0); + if (*end != '=') { - *error_out = "Couldn't parse device number"; - return -EINVAL; + error = "Couldn't parse device number"; + goto out; } - 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; + if (n >= num) { + error = "Device number out of range"; + goto out; } + conf[n] = end + 1; } - return n == -1 ? num : n; + return 0; + +out: + printk(KERN_ERR "Failed to set up %s with " + "configuration string \"%s\" : %s\n", name, init, error); + return -EINVAL; } int line_config(struct line *lines, unsigned int num, char *str, const struct chan_opts *opts, char **error_out) { - struct line *line; - char *new; + char *end; int n; if (*str == '=') { @@ -590,17 +473,17 @@ int line_config(struct line *lines, unsigned int num, char *str, return -EINVAL; } - new = kstrdup(str, GFP_KERNEL); - if (new == NULL) { - *error_out = "Failed to allocate memory"; - return -ENOMEM; + n = simple_strtoul(str, &end, 0); + if (*end++ != '=') { + *error_out = "Couldn't parse device number"; + return -EINVAL; + } + if (n >= num) { + *error_out = "Device number out of range"; + return -EINVAL; } - 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); + return setup_one_line(lines, n, end, opts, error_out); } int line_get_config(char *name, struct line *lines, unsigned int num, char *str, @@ -623,13 +506,17 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, 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); + else { + struct tty_struct *tty = tty_port_tty_get(&line->port); + if (tty == NULL) { + CONFIG_CHUNK(str, size, n, line->init_str, 1); + } else { + n = chan_config_string(line, str, size, error_out); + tty_kref_put(tty); + } + } return n; } @@ -651,25 +538,23 @@ int line_id(char **str, int *start_out, int *end_out) 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; + if (n >= num) { + *error_out = "Device number out of range"; + return -EINVAL; + } + return setup_one_line(lines, n, "none", NULL, error_out); } -struct tty_driver *register_lines(struct line_driver *line_driver, - const struct tty_operations *ops, - struct line *lines, int nlines) +int register_lines(struct line_driver *line_driver, + const struct tty_operations *ops, + struct line *lines, int nlines) { - int i; struct tty_driver *driver = alloc_tty_driver(nlines); + int err; + int i; if (!driver) - return NULL; + return -ENOMEM; driver->driver_name = line_driver->name; driver->name = line_driver->device_name; @@ -677,108 +562,104 @@ struct tty_driver *register_lines(struct line_driver *line_driver, driver->minor_start = line_driver->minor_start; driver->type = line_driver->type; driver->subtype = line_driver->subtype; - driver->flags = TTY_DRIVER_REAL_RAW; + driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; driver->init_termios = tty_std_termios; + + for (i = 0; i < nlines; i++) { + tty_port_init(&lines[i].port); + lines[i].port.ops = &line_port_ops; + spin_lock_init(&lines[i].lock); + lines[i].driver = line_driver; + INIT_LIST_HEAD(&lines[i].chan_list); + } tty_set_operations(driver, ops); - if (tty_register_driver(driver)) { + err = tty_register_driver(driver); + if (err) { printk(KERN_ERR "register_lines : can't register %s driver\n", line_driver->name); put_tty_driver(driver); - return NULL; - } - - for(i = 0; i < nlines; i++) { - if (!lines[i].valid) - tty_unregister_device(driver, i); + for (i = 0; i < nlines; i++) + tty_port_destroy(&lines[i].port); + return err; } + line_driver->driver = driver; mconsole_register_dev(&line_driver->mc); - return driver; + return 0; } static 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(KERN_ERR "lines_init - kstrdup returned NULL\n"); - - if (parse_chan_pair(line->init_str, line, i, opts, &error)) { - printk(KERN_ERR "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; + struct tty_port *port; unsigned long stack; + struct work_struct work; }; -static void free_winch(struct winch *winch, int free_irq_ok) +static void __free_winch(struct work_struct *work) { - list_del(&winch->list); + struct winch *winch = container_of(work, struct winch, work); + um_free_irq(WINCH_IRQ, winch); if (winch->pid != -1) os_kill_process(winch->pid, 1); - if (winch->fd != -1) - os_close_file(winch->fd); if (winch->stack != 0) free_stack(winch->stack, 0); - if (free_irq_ok) - free_irq(WINCH_IRQ, winch); kfree(winch); } +static void free_winch(struct winch *winch) +{ + int fd = winch->fd; + winch->fd = -1; + if (fd != -1) + os_close_file(fd); + list_del(&winch->list); + __free_winch(&winch->work); +} + static irqreturn_t winch_interrupt(int irq, void *data) { struct winch *winch = data; struct tty_struct *tty; struct line *line; + int fd = winch->fd; int err; char c; - if (winch->fd != -1) { - err = generic_read(winch->fd, &c, NULL); + if (fd != -1) { + err = generic_read(fd, &c, NULL); if (err < 0) { if (err != -EAGAIN) { + winch->fd = -1; + list_del(&winch->list); + os_close_file(fd); printk(KERN_ERR "winch_interrupt : " "read failed, errno = %d\n", -err); printk(KERN_ERR "fd %d is losing SIGWINCH " "support\n", winch->tty_fd); - free_winch(winch, 0); + INIT_WORK(&winch->work, __free_winch); + schedule_work(&winch->work); return IRQ_HANDLED; } goto out; } } - tty = winch->tty; + tty = tty_port_tty_get(winch->port); if (tty != NULL) { line = tty->driver_data; if (line != NULL) { - chan_window_size(&line->chan_list, &tty->winsize.ws_row, + chan_window_size(line, &tty->winsize.ws_row, &tty->winsize.ws_col); kill_pgrp(tty->pgrp, SIGWINCH, 1); } + tty_kref_put(tty); } out: if (winch->fd != -1) @@ -786,7 +667,7 @@ static irqreturn_t winch_interrupt(int irq, void *data) return IRQ_HANDLED; } -void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty, +void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port, unsigned long stack) { struct winch *winch; @@ -801,12 +682,11 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty, .fd = fd, .tty_fd = tty_fd, .pid = pid, - .tty = tty, + .port = port, .stack = stack }); if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, - "winch", winch) < 0) { + IRQF_SHARED, "winch", winch) < 0) { printk(KERN_ERR "register_winch_irq - failed to register " "IRQ\n"); goto out_free; @@ -829,17 +709,20 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty, static void unregister_winch(struct tty_struct *tty) { - struct list_head *ele; + struct list_head *ele, *next; struct winch *winch; + struct tty_struct *wtty; spin_lock(&winch_handler_lock); - list_for_each(ele, &winch_handlers) { + list_for_each_safe(ele, next, &winch_handlers) { winch = list_entry(ele, struct winch, list); - if (winch->tty == tty) { - free_winch(winch, 1); + wtty = tty_port_tty_get(winch->port); + if (wtty == tty) { + free_winch(winch); break; } + tty_kref_put(wtty); } spin_unlock(&winch_handler_lock); } @@ -853,7 +736,7 @@ static void winch_cleanup(void) list_for_each_safe(ele, next, &winch_handlers) { winch = list_entry(ele, struct winch, list); - free_winch(winch, 1); + free_winch(winch); } spin_unlock(&winch_handler_lock); diff --git a/arch/um/include/line.h b/arch/um/drivers/line.h index 1223f2c844b..138a14526d9 100644 --- a/arch/um/include/line.h +++ b/arch/um/drivers/line.h @@ -6,16 +6,16 @@ #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 <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 */ +/* There's only two modifiable fields in this - .mc.list and .driver */ struct line_driver { const char *name; const char *device_name; @@ -28,16 +28,16 @@ struct line_driver { const int write_irq; const char *write_irq_name; struct mc_device mc; + struct tty_driver *driver; }; struct line { - struct tty_struct *tty; - spinlock_t count_lock; + struct tty_port port; int valid; char *init_str; - int init_pri; struct list_head chan_list; + struct chan *chan_in, *chan_out; /*This lock is actually, mostly, local to*/ spinlock_t lock; @@ -54,31 +54,24 @@ struct line { 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_open(struct tty_struct *tty, struct file *filp); +extern int line_install(struct tty_driver *driver, struct tty_struct *tty, + struct line *line); +extern void line_cleanup(struct tty_struct *tty); +extern void line_hangup(struct tty_struct *tty); +extern int line_setup(char **conf, unsigned nlines, char **def, + char *init, char *name); extern int line_write(struct tty_struct *tty, const unsigned char *buf, int len); -extern void line_put_char(struct tty_struct *tty, unsigned char ch); +extern int line_put_char(struct tty_struct *tty, unsigned char ch); extern void line_set_termios(struct tty_struct *tty, struct ktermios * old); extern int line_chars_in_buffer(struct tty_struct *tty); extern void line_flush_buffer(struct tty_struct *tty); extern void line_flush_chars(struct tty_struct *tty); extern int line_write_room(struct tty_struct *tty); -extern 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); @@ -86,10 +79,11 @@ 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 int register_lines(struct line_driver *line_driver, + const struct tty_operations *driver, + struct line *lines, int nlines); +extern int setup_one_line(struct line *lines, int n, char *init, + const struct chan_opts *opts, char **error_out); extern void close_lines(struct line *lines, int nlines); extern int line_config(struct line *lines, unsigned int sizeof_lines, diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h deleted file mode 100644 index 6fa282e896b..00000000000 --- a/arch/um/drivers/mcast.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#ifndef __DRIVERS_MCAST_H -#define __DRIVERS_MCAST_H - -#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); - -#endif diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c deleted file mode 100644 index 822092f149b..00000000000 --- a/arch/um/drivers/mcast_kern.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * user-mode-linux networking multicast transport - * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> - * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * - * based on the existing uml-networking code, which is - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and - * James Leu (jleu@mindspring.net). - * Copyright (C) 2001 by various other people who didn't put their name here. - * - * Licensed under the GPL. - */ - -#include "linux/init.h" -#include <linux/netdevice.h> -#include "mcast.h" -#include "net_kern.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 multicast address: %s:%u, TTL:%u\n", - dpri->addr, dpri->port, dpri->ttl); -} - -static int mcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) -{ - return net_recvfrom(fd, skb_mac_header(skb), - skb->dev->mtu + ETH_HEADER_OTHER); -} - -static int 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); diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c deleted file mode 100644 index 5f647d7a729..00000000000 --- a/arch/um/drivers/mcast_user.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * user-mode-linux networking multicast transport - * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> - * - * based on the existing uml-networking code, which is - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and - * James Leu (jleu@mindspring.net). - * Copyright (C) 2001 by various other people who didn't put their name here. - * - * Licensed under the GPL. - * - */ - -#include <unistd.h> -#include <errno.h> -#include <netinet/in.h> -#include "mcast.h" -#include "net_user.h" -#include "um_malloc.h" -#include "user.h" - -static struct sockaddr_in *new_addr(char *addr, unsigned short port) -{ - struct sockaddr_in *sin; - - sin = kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL); - if (sin == NULL) { - printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in " - "failed\n"); - return NULL; - } - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = in_aton(addr); - sin->sin_port = htons(port); - return sin; -} - -static int mcast_user_init(void *data, void *dev) -{ - struct mcast_data *pri = data; - - pri->mcast_addr = new_addr(pri->addr, pri->port); - pri->dev = dev; - return 0; -} - -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(UM_KERN_ERR "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(UM_KERN_ERR "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(UM_KERN_ERR "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(UM_KERN_ERR "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(UM_KERN_ERR "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(UM_KERN_ERR "mcast_open: IP_ADD_MEMBERSHIP failed, " - "error = %d\n", errno); - printk(UM_KERN_ERR "There appears not to be a multicast-" - "capable network interface on the host.\n"); - printk(UM_KERN_ERR "eth0 should be configured in order to use " - "the multicast transport.\n"); - goto out_close; - } - - return fd; - - out_close: - close(fd); - out: - return err; -} - -static void 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(UM_KERN_ERR "mcast_open: IP_DROP_MEMBERSHIP failed, " - "error = %d\n", errno); - } - - close(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)); -} - -const struct net_user_info mcast_user_info = { - .init = mcast_user_init, - .open = mcast_open, - .close = mcast_close, - .remove = mcast_remove, - .add_address = NULL, - .delete_address = NULL, - .mtu = ETH_MAX_PACKET, - .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, -}; diff --git a/arch/um/include/mconsole.h b/arch/um/drivers/mconsole.h index c139ae1d682..8b22535c62c 100644 --- a/arch/um/include/mconsole.h +++ b/arch/um/drivers/mconsole.h @@ -12,7 +12,7 @@ #define u32 uint32_t #endif -#include "sysdep/ptrace.h" +#include <sysdep/ptrace.h> #define MCONSOLE_MAGIC (0xcafebabe) #define MCONSOLE_MAX_DATA (512) diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 19d579d74d2..29880c9b324 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -6,6 +6,7 @@ #include <linux/console.h> #include <linux/ctype.h> +#include <linux/string.h> #include <linux/interrupt.h> #include <linux/list.h> #include <linux/mm.h> @@ -16,17 +17,23 @@ #include <linux/slab.h> #include <linux/syscalls.h> #include <linux/utsname.h> +#include <linux/socket.h> +#include <linux/un.h> #include <linux/workqueue.h> #include <linux/mutex.h> +#include <linux/fs.h> +#include <linux/mount.h> +#include <linux/file.h> #include <asm/uaccess.h> +#include <asm/switch_to.h> -#include "init.h" -#include "irq_kern.h" -#include "irq_user.h" -#include "kern_util.h" +#include <init.h> +#include <irq_kern.h> +#include <irq_user.h> +#include <kern_util.h> #include "mconsole.h" #include "mconsole_kern.h" -#include "os.h" +#include <os.h> static int do_unlink_socket(struct notifier_block *notifier, unsigned long what, void *data) @@ -114,120 +121,38 @@ void mconsole_log(struct mc_request *req) 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.path.dentry = super->s_root; - nd.path.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.path.dentry, nd.path.mnt, O_RDONLY); - if (IS_ERR(file)) { - mconsole_reply(req, "Failed to open file", 1, 0); - goto out_kill; - } - /*END*/ - - buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (buf == NULL) { - mconsole_reply(req, "Failed to allocate buffer", 1, 0); - goto out_fput; - } - - if ((file->f_op != NULL) && (file->f_op->read != NULL)) { - do { - n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1, - &file->f_pos); - if (n >= 0) { - buf[n] = '\0'; - mconsole_reply(req, buf, 0, (n > 0)); - } - else { - mconsole_reply(req, "Read of file failed", - 1, 0); - goto out_free; - } - } while (n > 0); - } - else mconsole_reply(req, "", 0, 0); - - out_free: - kfree(buf); - out_fput: - fput(file); - out_kill: - deactivate_super(super); - out: ; -} -#endif - -void mconsole_proc(struct mc_request *req) -{ - char path[64]; + struct vfsmount *mnt = task_active_pid_ns(current)->proc_mnt; char *buf; int len; - int fd; + struct file *file; int first_chunk = 1; char *ptr = req->request.data; ptr += strlen("proc"); - while (isspace(*ptr)) - ptr++; - snprintf(path, sizeof(path), "/proc/%s", ptr); + ptr = skip_spaces(ptr); - fd = sys_open(path, 0, 0); - if (fd < 0) { + file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY); + if (IS_ERR(file)) { mconsole_reply(req, "Failed to open file", 1, 0); - printk(KERN_ERR "open %s: %d\n",path,fd); + printk(KERN_ERR "open /proc/%s: %ld\n", ptr, PTR_ERR(file)); goto out; } buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (buf == NULL) { mconsole_reply(req, "Failed to allocate buffer", 1, 0); - goto out_close; + goto out_fput; } - for (;;) { - len = sys_read(fd, buf, PAGE_SIZE-1); + do { + loff_t pos = file->f_pos; + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + len = vfs_read(file, buf, PAGE_SIZE - 1, &pos); + set_fs(old_fs); + file->f_pos = pos; if (len < 0) { mconsole_reply(req, "Read of file failed", 1, 0); goto out_free; @@ -237,22 +162,14 @@ void mconsole_proc(struct mc_request *req) mconsole_reply(req, "\n", 0, 1); first_chunk = 0; } - if (len == PAGE_SIZE-1) { - buf[len] = '\0'; - mconsole_reply(req, buf, 0, 1); - } else { - buf[len] = '\0'; - mconsole_reply(req, buf, 0, 0); - break; - } - } - + buf[len] = '\0'; + mconsole_reply(req, buf, 0, (len > 0)); + } while (len > 0); out_free: kfree(buf); - out_close: - sys_close(fd); - out: - /* nothing */; + out_fput: + fput(file); + out: ; } #define UML_MCONSOLE_HELPTEXT \ @@ -557,8 +474,7 @@ void mconsole_config(struct mc_request *req) int err; ptr += strlen("config"); - while (isspace(*ptr)) - ptr++; + ptr = skip_spaces(ptr); dev = mconsole_find_dev(ptr); if (dev == NULL) { mconsole_reply(req, "Bad configuration option", 1, 0); @@ -585,7 +501,7 @@ void mconsole_remove(struct mc_request *req) int err, start, end, n; ptr += strlen("remove"); - while (isspace(*ptr)) ptr++; + ptr = skip_spaces(ptr); dev = mconsole_find_dev(ptr); if (dev == NULL) { mconsole_reply(req, "Bad remove option", 1, 0); @@ -701,7 +617,7 @@ static void with_console(struct mc_request *req, void (*proc)(void *), static void sysrq_proc(void *arg) { char *op = arg; - handle_sysrq(*op, NULL); + handle_sysrq(*op); } void mconsole_sysrq(struct mc_request *req) @@ -709,7 +625,7 @@ void mconsole_sysrq(struct mc_request *req) char *ptr = req->request.data; ptr += strlen("sysrq"); - while (isspace(*ptr)) ptr++; + ptr = skip_spaces(ptr); /* * With 'b', the system will shut down without a chance to reply, @@ -729,10 +645,9 @@ void mconsole_sysrq(struct mc_request *req) static void stack_proc(void *arg) { - struct task_struct *from = current, *to = arg; + struct task_struct *task = arg; - to->thread.saved_task = from; - switch_to(from, to, from); + show_stack(task, NULL); } /* @@ -754,8 +669,7 @@ void mconsole_stack(struct mc_request *req) */ ptr += strlen("stack"); - while (isspace(*ptr)) - ptr++; + ptr = skip_spaces(ptr); /* * Should really check for multiple pids or reject bad args here @@ -785,7 +699,7 @@ static int __init mconsole_init(void) /* long to avoid size mismatch warnings from gcc */ long sock; int err; - char file[256]; + char file[UNIX_PATH_MAX]; if (umid_file_name("mconsole", file, sizeof(file))) return -1; @@ -802,8 +716,7 @@ static int __init mconsole_init(void) 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); + IRQF_SHARED, "mconsole", (void *)sock); if (err) { printk(KERN_ERR "Failed to get IRQ for management console\n"); goto out; @@ -830,8 +743,8 @@ static int __init mconsole_init(void) __initcall(mconsole_init); -static int write_proc_mconsole(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static ssize_t mconsole_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) { char *buf; @@ -852,6 +765,12 @@ static int write_proc_mconsole(struct file *file, const char __user *buffer, return count; } +static const struct file_operations mconsole_proc_fops = { + .owner = THIS_MODULE, + .write = mconsole_proc_write, + .llseek = noop_llseek, +}; + static int create_proc_mconsole(void) { struct proc_dir_entry *ent; @@ -859,15 +778,11 @@ static int create_proc_mconsole(void) if (notify_socket == NULL) return 0; - ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL); + ent = proc_create("mconsole", 0200, NULL, &mconsole_proc_fops); if (ent == NULL) { - printk(KERN_INFO "create_proc_mconsole : create_proc_entry " - "failed\n"); + printk(KERN_INFO "create_proc_mconsole : proc_create failed\n"); return 0; } - - ent->read_proc = NULL; - ent->write_proc = write_proc_mconsole; return 0; } diff --git a/arch/um/include/mconsole_kern.h b/arch/um/drivers/mconsole_kern.h index d2fe07e7895..7a0c6a1ad1d 100644 --- a/arch/um/include/mconsole_kern.h +++ b/arch/um/drivers/mconsole_kern.h @@ -6,7 +6,7 @@ #ifndef __MCONSOLE_KERN_H__ #define __MCONSOLE_KERN_H__ -#include "linux/list.h" +#include <linux/list.h> #include "mconsole.h" struct mconsole_entry { diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c index 13af2f03ed8..99209826adb 100644 --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c @@ -10,9 +10,7 @@ #include <sys/socket.h> #include <sys/uio.h> #include <sys/un.h> -#include "kern_constants.h" #include "mconsole.h" -#include "user.h" static struct mconsole_command commands[] = { /* @@ -39,7 +37,7 @@ static struct mconsole_command commands[] = { /* Initialized in mconsole_init, which is an initcall */ char mconsole_socket_name[256]; -int mconsole_reply_v0(struct mc_request *req, char *reply) +static int mconsole_reply_v0(struct mc_request *req, char *reply) { struct iovec iov; struct msghdr msg; diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c index 67b2f55a602..62145c27616 100644 --- a/arch/um/drivers/mmapper_kern.c +++ b/arch/um/drivers/mmapper_kern.c @@ -16,8 +16,9 @@ #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/mm.h> + #include <asm/uaccess.h> -#include "mem_user.h" +#include <mem_user.h> /* These are set in mmapper_init, which is called at boot time */ static unsigned long mmapper_size; @@ -36,17 +37,10 @@ static ssize_t mmapper_write(struct file *file, const char __user *buf, if (*ppos > mmapper_size) return -EINVAL; - if (count > mmapper_size - *ppos) - count = mmapper_size - *ppos; - - if (copy_from_user(&v_buf[*ppos], buf, count)) - return -EFAULT; - - return count; + return simple_write_to_buffer(v_buf, mmapper_size, ppos, buf, count); } -static int mmapper_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long mmapper_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return -ENOIOCTLCMD; } @@ -89,10 +83,11 @@ static const struct file_operations mmapper_fops = { .owner = THIS_MODULE, .read = mmapper_read, .write = mmapper_write, - .ioctl = mmapper_ioctl, + .unlocked_ioctl = mmapper_ioctl, .mmap = mmapper_mmap, .open = mmapper_open, .release = mmapper_release, + .llseek = default_llseek, }; /* @@ -113,18 +108,16 @@ static int __init mmapper_init(void) v_buf = (char *) find_iomem("mmapper", &mmapper_size); if (mmapper_size == 0) { printk(KERN_ERR "mmapper_init - find_iomem failed\n"); - goto out; + return -ENODEV; } + p_buf = __pa(v_buf); err = misc_register(&mmapper_dev); if (err) { printk(KERN_ERR "mmapper - misc_register failed, err = %d\n", err); - goto out; + return err; } - - p_buf = __pa(v_buf); -out: return 0; } @@ -138,3 +131,4 @@ module_exit(mmapper_exit); MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>"); MODULE_DESCRIPTION("DSPLinux simulator mmapper driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 1d43bdfc20c..7d26d9c0b2f 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -16,18 +16,14 @@ #include <linux/platform_device.h> #include <linux/rtnetlink.h> #include <linux/skbuff.h> +#include <linux/slab.h> #include <linux/spinlock.h> -#include "init.h" -#include "irq_kern.h" -#include "irq_user.h" +#include <init.h> +#include <irq_kern.h> +#include <irq_user.h> #include "mconsole_kern.h" -#include "net_kern.h" -#include "net_user.h" - -static inline void set_ether_mac(struct net_device *dev, unsigned char *addr) -{ - memcpy(dev->dev_addr, addr, ETH_ALEN); -} +#include <net_kern.h> +#include <net_user.h> #define DRIVER_NAME "uml-netdev" @@ -76,7 +72,7 @@ out: static int uml_net_rx(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int pkt_len; struct sk_buff *skb; @@ -86,7 +82,7 @@ static int uml_net_rx(struct net_device *dev) drop_skb->dev = dev; /* Read a packet into drop_skb and don't do anything with it. */ (*lp->read)(lp->fd, drop_skb, lp); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; return 0; } @@ -99,8 +95,8 @@ static int uml_net_rx(struct net_device *dev) skb_trim(skb, pkt_len); skb->protocol = (*lp->protocol)(skb); - lp->stats.rx_bytes += skb->len; - lp->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; netif_rx(skb); return pkt_len; } @@ -116,10 +112,10 @@ static void uml_dev_close(struct work_struct *work) dev_close(lp->dev); } -irqreturn_t uml_net_interrupt(int irq, void *dev_id) +static irqreturn_t uml_net_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int err; if (!netif_running(dev)) @@ -150,7 +146,7 @@ out: static int uml_net_open(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int err; if (lp->fd >= 0) { @@ -165,7 +161,7 @@ static int uml_net_open(struct net_device *dev) } err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt, - IRQF_DISABLED | IRQF_SHARED, dev->name, dev); + IRQF_SHARED, dev->name, dev); if (err != 0) { printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err); err = -ENETUNREACH; @@ -195,11 +191,11 @@ out: static int uml_net_close(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); netif_stop_queue(dev); - free_irq(dev->irq, dev); + um_free_irq(dev->irq, dev); if (lp->close != NULL) (*lp->close)(lp->fd, &lp->user); lp->fd = -1; @@ -213,7 +209,7 @@ static int uml_net_close(struct net_device *dev) static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); unsigned long flags; int len; @@ -222,10 +218,11 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); len = (*lp->write)(lp->fd, skb, lp); + skb_tx_timestamp(skb); if (len == skb->len) { - lp->stats.tx_packets++; - lp->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; dev->trans_start = jiffies; netif_start_queue(dev); @@ -234,7 +231,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) } else if (len == 0) { netif_start_queue(dev); - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; } else { netif_start_queue(dev); @@ -243,15 +240,9 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); - dev_kfree_skb(skb); + dev_consume_skb_any(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; + return NETDEV_TX_OK; } static void uml_net_set_multicast_list(struct net_device *dev) @@ -265,38 +256,36 @@ static void uml_net_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int uml_net_set_mac(struct net_device *dev, void *addr) +static int uml_net_change_mtu(struct net_device *dev, int new_mtu) { - struct uml_net_private *lp = dev->priv; - struct sockaddr *hwaddr = addr; - - spin_lock_irq(&lp->lock); - set_ether_mac(dev, hwaddr->sa_data); - spin_unlock_irq(&lp->lock); + dev->mtu = new_mtu; return 0; } -static int uml_net_change_mtu(struct net_device *dev, int new_mtu) +#ifdef CONFIG_NET_POLL_CONTROLLER +static void uml_net_poll_controller(struct net_device *dev) { - dev->mtu = new_mtu; - - return 0; + disable_irq(dev->irq); + uml_net_interrupt(dev->irq, dev); + enable_irq(dev->irq); } +#endif static void uml_net_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - strcpy(info->driver, DRIVER_NAME); - strcpy(info->version, "42"); + strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); + strlcpy(info->version, "42", sizeof(info->version)); } -static struct ethtool_ops uml_net_ethtool_ops = { +static const struct ethtool_ops uml_net_ethtool_ops = { .get_drvinfo = uml_net_get_drvinfo, .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, }; -void uml_net_user_timer_expire(unsigned long _conn) +static void uml_net_user_timer_expire(unsigned long _conn) { #ifdef undef struct connection *conn = (struct connection *)_conn; @@ -306,8 +295,9 @@ void uml_net_user_timer_expire(unsigned long _conn) #endif } -static void setup_etheraddr(char *str, unsigned char *addr, char *name) +static void setup_etheraddr(struct net_device *dev, char *str) { + unsigned char *addr = dev->dev_addr; char *end; int i; @@ -351,8 +341,8 @@ static void setup_etheraddr(char *str, unsigned char *addr, char *name) random: printk(KERN_INFO - "Choosing a random ethernet address for device %s\n", name); - random_ether_addr(addr); + "Choosing a random ethernet address for device %s\n", dev->name); + eth_hw_addr_random(dev); } static DEFINE_SPINLOCK(devices_lock); @@ -366,9 +356,9 @@ static struct platform_driver uml_net_driver = { static void net_device_release(struct device *dev) { - struct uml_net *device = dev->driver_data; + struct uml_net *device = dev_get_drvdata(dev); struct net_device *netdev = device->dev; - struct uml_net_private *lp = netdev->priv; + struct uml_net_private *lp = netdev_priv(netdev); if (lp->remove != NULL) (*lp->remove)(&lp->user); @@ -377,6 +367,20 @@ static void net_device_release(struct device *dev) free_netdev(netdev); } +static const struct net_device_ops uml_netdev_ops = { + .ndo_open = uml_net_open, + .ndo_stop = uml_net_close, + .ndo_start_xmit = uml_net_start_xmit, + .ndo_set_rx_mode = uml_net_set_multicast_list, + .ndo_tx_timeout = uml_net_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = uml_net_change_mtu, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = uml_net_poll_controller, +#endif +}; + /* * Ensures that platform_driver_register is called only once by * eth_configure. Will be set in an initcall. @@ -416,16 +420,11 @@ static void eth_configure(int n, void *init, char *mac, */ snprintf(dev->name, sizeof(dev->name), "eth%d", n); - setup_etheraddr(mac, device->mac, dev->name); + setup_etheraddr(dev, 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(": "); + printk(KERN_INFO "Netdevice %d (%pM) : ", n, dev->dev_addr); - lp = dev->priv; + lp = netdev_priv(dev); /* This points to the transport private data. It's still clear, but we * must memset it to 0 *now*. Let's help the drivers. */ memset(lp, 0, size); @@ -439,7 +438,7 @@ static void eth_configure(int n, void *init, char *mac, device->pdev.id = n; device->pdev.name = DRIVER_NAME; device->pdev.dev.release = net_device_release; - device->pdev.dev.driver_data = device; + dev_set_drvdata(&device->pdev.dev, device); if (platform_device_register(&device->pdev)) goto out_free_netdev; SET_NETDEV_DEV(dev,&device->pdev.dev); @@ -470,22 +469,14 @@ static void eth_configure(int n, void *init, char *mac, 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)); + memcpy(lp->mac, dev->dev_addr, sizeof(lp->mac)); if ((transport->user->init != NULL) && ((*transport->user->init)(&lp->user, dev) != 0)) goto out_unregister; - set_ether_mac(dev, device->mac); dev->mtu = transport->user->mtu; - 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->netdev_ops = ¨_netdev_ops; dev->ethtool_ops = ¨_net_ethtool_ops; dev->watchdog_timeo = (HZ >> 1); dev->irq = UM_ETH_IRQ; @@ -539,7 +530,7 @@ static int eth_parse(char *str, int *index_out, char **str_out, char **error_out) { char *end; - int n, err = -EINVAL;; + int n, err = -EINVAL; n = simple_strtoul(str, &end, 0); if (end == str) { @@ -735,7 +726,7 @@ static int net_remove(int n, char **error_out) return -ENODEV; dev = device->dev; - lp = dev->priv; + lp = netdev_priv(dev); if (lp->fd > 0) return -EBUSY; unregister_netdev(dev); @@ -763,10 +754,10 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, void (*proc)(unsigned char *, unsigned char *, void *); unsigned char addr_buf[4], netmask_buf[4]; - if (dev->open != uml_net_open) + if (dev->netdev_ops->ndo_open != uml_net_open) return NOTIFY_DONE; - lp = dev->priv; + lp = netdev_priv(dev); proc = NULL; switch (event) { @@ -786,7 +777,7 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, } /* uml_net_init shouldn't be called twice on two CPUs at the same time */ -struct notifier_block uml_inetaddr_notifier = { +static struct notifier_block uml_inetaddr_notifier = { .notifier_call = uml_inetaddr_event, }; @@ -840,7 +831,7 @@ static void close_devices(void) 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); + um_free_irq(lp->dev->irq, lp->dev); if ((lp->close != NULL) && (lp->fd >= 0)) (*lp->close)(lp->fd, &lp->user); if (lp->remove != NULL) diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index abf2653f551..cd14157b556 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -11,11 +11,9 @@ #include <string.h> #include <sys/socket.h> #include <sys/wait.h> -#include "net_user.h" -#include "kern_constants.h" -#include "os.h" -#include "um_malloc.h" -#include "user.h" +#include <net_user.h> +#include <os.h> +#include <um_malloc.h> int tap_open_common(void *dev, char *gate_addr) { @@ -222,13 +220,16 @@ static void change(char *dev, char *what, unsigned char *addr, netmask[2], netmask[3]); output_len = UM_KERN_PAGE_SIZE; - output = kmalloc(output_len, UM_GFP_KERNEL); + output = uml_kmalloc(output_len, UM_GFP_KERNEL); if (output == NULL) printk(UM_KERN_ERR "change : failed to allocate output " "buffer\n"); pid = change_tramp(argv, output, output_len); - if (pid < 0) return; + if (pid < 0) { + kfree(output); + return; + } if (output != NULL) { printk("%s", output); diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c index 2b45a1446c8..10495747ce8 100644 --- a/arch/um/drivers/null.c +++ b/arch/um/drivers/null.c @@ -7,7 +7,7 @@ #include <errno.h> #include <fcntl.h> #include "chan_user.h" -#include "os.h" +#include <os.h> /* This address is used only as a unique identifier */ static int null_chan; diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c index 3a750dd39be..be0fb57bd1d 100644 --- a/arch/um/drivers/pcap_kern.c +++ b/arch/um/drivers/pcap_kern.c @@ -3,9 +3,9 @@ * Licensed under the GPL. */ -#include "linux/init.h" +#include <linux/init.h> #include <linux/netdevice.h> -#include "net_kern.h" +#include <net_kern.h> #include "pcap_user.h" struct pcap_init { @@ -21,7 +21,7 @@ void pcap_init(struct net_device *dev, void *data) struct pcap_data *ppri; struct pcap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); ppri = (struct pcap_data *) pri->user; ppri->host_if = init->host_if; ppri->promisc = init->promisc; diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c index e9809356c53..c07b9c752c8 100644 --- a/arch/um/drivers/pcap_user.c +++ b/arch/um/drivers/pcap_user.c @@ -7,11 +7,9 @@ #include <pcap.h> #include <string.h> #include <asm/types.h> -#include "net_user.h" +#include <net_user.h> #include "pcap_user.h" -#include "kern_constants.h" -#include "um_malloc.h" -#include "user.h" +#include <um_malloc.h> #define PCAP_FD(p) (*(int *)(p)) @@ -50,7 +48,7 @@ static int pcap_open(void *data) return -EIO; } - pri->compiled = kmalloc(sizeof(struct bpf_program), + pri->compiled = uml_kmalloc(sizeof(struct bpf_program), UM_GFP_KERNEL); if (pri->compiled == NULL) { printk(UM_KERN_ERR "pcap_open : kmalloc failed\n"); diff --git a/arch/um/drivers/pcap_user.h b/arch/um/drivers/pcap_user.h index 96b80b565ee..1ca7c764cc6 100644 --- a/arch/um/drivers/pcap_user.h +++ b/arch/um/drivers/pcap_user.h @@ -3,7 +3,7 @@ * Licensed under the GPL */ -#include "net_user.h" +#include <net_user.h> struct pcap_data { char *host_if; @@ -19,13 +19,3 @@ extern const struct net_user_info pcap_user_info; extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/port.h b/arch/um/drivers/port.h index 9117609a575..372a80c0556 100644 --- a/arch/um/drivers/port.h +++ b/arch/um/drivers/port.h @@ -18,13 +18,3 @@ extern void port_remove_dev(void *d); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 19930081d3d..40ca5cc275e 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -3,14 +3,16 @@ * Licensed under the GPL */ -#include "linux/completion.h" -#include "linux/interrupt.h" -#include "linux/list.h" -#include "linux/mutex.h" -#include "asm/atomic.h" -#include "init.h" -#include "irq_kern.h" -#include "os.h" +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <asm/atomic.h> +#include <init.h> +#include <irq_kern.h> +#include <os.h> #include "port.h" struct port_list { @@ -98,8 +100,7 @@ static int port_accept(struct port_list *port) .port = port }); if (um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, - "telnetd", conn)) { + IRQF_SHARED, "telnetd", conn)) { printk(KERN_ERR "port_accept : failed to get IRQ for " "telnetd\n"); goto out_free; @@ -182,8 +183,7 @@ void *port_data(int port_num) } if (um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, - "port", port)) { + IRQF_SHARED, "port", port)) { printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num); goto out_close; } @@ -252,7 +252,7 @@ int port_wait(void *data) * connection. Then we loop here throwing out failed * connections until a good one is found. */ - free_irq(TELNETD_IRQ, conn); + um_free_irq(TELNETD_IRQ, conn); if (conn->fd >= 0) break; diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index addd7590265..9a8e1b64c22 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -10,11 +10,9 @@ #include <unistd.h> #include <netinet/in.h> #include "chan_user.h" -#include "kern_constants.h" -#include "os.h" +#include <os.h> #include "port.h" -#include "um_malloc.h" -#include "user.h" +#include <um_malloc.h> struct port_chan { int raw; @@ -47,7 +45,7 @@ static void *port_init(char *str, int device, const struct chan_opts *opts) if (kern_data == NULL) return NULL; - data = kmalloc(sizeof(*data), UM_GFP_KERNEL); + data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); if (data == NULL) goto err; @@ -153,7 +151,7 @@ struct port_pre_exec_data { int pipe_fd; }; -void port_pre_exec(void *arg) +static void port_pre_exec(void *arg) { struct port_pre_exec_data *data = arg; diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index 49c79dda604..f1fcc2cedb5 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -12,10 +12,8 @@ #include <termios.h> #include <sys/stat.h> #include "chan_user.h" -#include "kern_constants.h" -#include "os.h" -#include "um_malloc.h" -#include "user.h" +#include <os.h> +#include <um_malloc.h> struct pty_chan { void (*announce)(char *dev_name, int dev); @@ -29,7 +27,7 @@ static void *pty_chan_init(char *str, int device, const struct chan_opts *opts) { struct pty_chan *data; - data = kmalloc(sizeof(*data), UM_GFP_KERNEL); + data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); if (data == NULL) return NULL; diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index 71f0959c153..9e3a7220582 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2005 Jeff Dike <jdike@addtoit.com> */ +/* Copyright (C) 2005 - 2008 Jeff Dike <jdike@{linux.intel,addtoit}.com> */ + /* Much of this ripped from drivers/char/hw_random.c, see there for other * copyright. * @@ -8,16 +9,18 @@ #include <linux/sched.h> #include <linux/module.h> #include <linux/fs.h> +#include <linux/interrupt.h> #include <linux/miscdevice.h> #include <linux/delay.h> #include <asm/uaccess.h> -#include "os.h" +#include <irq_kern.h> +#include <os.h> /* * core module and version information */ #define RNG_VERSION "1.0.0" -#define RNG_MODULE_NAME "random" +#define RNG_MODULE_NAME "hw_random" #define RNG_MISCDEV_MINOR 183 /* official */ @@ -26,47 +29,67 @@ * protects against a module being loaded twice at the same time. */ static int random_fd = -1; +static DECLARE_WAIT_QUEUE_HEAD(host_read_wait); static int rng_dev_open (struct inode *inode, struct file *filp) { /* enforce read-only access to this chrdev */ if ((filp->f_mode & FMODE_READ) == 0) return -EINVAL; - if (filp->f_mode & FMODE_WRITE) + if ((filp->f_mode & FMODE_WRITE) != 0) return -EINVAL; return 0; } +static atomic_t host_sleep_count = ATOMIC_INIT(0); + static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, - loff_t * offp) + loff_t *offp) { - u32 data; - int n, ret = 0, have_data; - - while(size){ - n = os_read_file(random_fd, &data, sizeof(data)); - if(n > 0){ - have_data = n; - while (have_data && size) { - if (put_user((u8)data, buf++)) { - ret = ret ? : -EFAULT; - break; - } - size--; - ret++; - have_data--; - data>>=8; - } - } - else if(n == -EAGAIN){ - if (filp->f_flags & O_NONBLOCK) - return ret ? : -EAGAIN; - - if(need_resched()) - schedule_timeout_interruptible(1); - } - else return n; + u32 data; + int n, ret = 0, have_data; + + while (size) { + n = os_read_file(random_fd, &data, sizeof(data)); + if (n > 0) { + have_data = n; + while (have_data && size) { + if (put_user((u8) data, buf++)) { + ret = ret ? : -EFAULT; + break; + } + size--; + ret++; + have_data--; + data >>= 8; + } + } + else if (n == -EAGAIN) { + DECLARE_WAITQUEUE(wait, current); + + if (filp->f_flags & O_NONBLOCK) + return ret ? : -EAGAIN; + + atomic_inc(&host_sleep_count); + reactivate_fd(random_fd, RANDOM_IRQ); + add_sigio_fd(random_fd); + + add_wait_queue(&host_read_wait, &wait); + set_task_state(current, TASK_INTERRUPTIBLE); + + schedule(); + set_task_state(current, TASK_RUNNING); + remove_wait_queue(&host_read_wait, &wait); + + if (atomic_dec_and_test(&host_sleep_count)) { + ignore_sigio_fd(random_fd); + deactivate_fd(random_fd, RANDOM_IRQ); + } + } + else + return n; + if (signal_pending (current)) return ret ? : -ERESTARTSYS; } @@ -77,6 +100,7 @@ static const struct file_operations rng_chrdev_ops = { .owner = THIS_MODULE, .open = rng_dev_open, .read = rng_dev_read, + .llseek = noop_llseek, }; /* rng_init shouldn't be called more than once at boot time */ @@ -86,6 +110,13 @@ static struct miscdevice rng_miscdev = { &rng_chrdev_ops, }; +static irqreturn_t random_interrupt(int irq, void *data) +{ + wake_up(&host_read_wait); + + return IRQ_HANDLED; +} + /* * rng_init - initialize RNG module */ @@ -93,28 +124,32 @@ static int __init rng_init (void) { int err; - err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0); - if(err < 0) - goto out; + err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0); + if (err < 0) + goto out; - random_fd = err; + random_fd = err; - err = os_set_fd_block(random_fd, 0); - if(err) + err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt, + 0, "random", NULL); + if (err) goto err_out_cleanup_hw; + sigio_broken(random_fd, 1); + err = misc_register (&rng_miscdev); if (err) { - printk (KERN_ERR RNG_MODULE_NAME ": misc device register failed\n"); + printk (KERN_ERR RNG_MODULE_NAME ": misc device register " + "failed\n"); goto err_out_cleanup_hw; } +out: + return err; - out: - return err; - - err_out_cleanup_hw: - random_fd = -1; - goto out; +err_out_cleanup_hw: + os_close_file(random_fd); + random_fd = -1; + goto out; } /* @@ -122,6 +157,7 @@ static int __init rng_init (void) */ static void __exit rng_cleanup (void) { + os_close_file(random_fd); misc_deregister (&rng_miscdev); } diff --git a/arch/um/drivers/slip_common.c b/arch/um/drivers/slip_common.c index e89cfc68fc3..f597fa7c91d 100644 --- a/arch/um/drivers/slip_common.c +++ b/arch/um/drivers/slip_common.c @@ -1,6 +1,6 @@ #include <string.h> #include "slip_common.h" -#include "net_user.h" +#include <net_user.h> int slip_proto_read(int fd, void *buf, int len, struct slip_proto *slip) { diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index 6b4a0f9e38d..ed5249fc057 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c @@ -6,20 +6,20 @@ #include <linux/if_arp.h> #include <linux/init.h> #include <linux/netdevice.h> -#include "net_kern.h" +#include <net_kern.h> #include "slip.h" struct slip_init { char *gate_addr; }; -void slip_init(struct net_device *dev, void *data) +static void slip_init(struct net_device *dev, void *data) { struct uml_net_private *private; struct slip_data *spri; struct slip_init *init = data; - private = dev->priv; + private = netdev_priv(dev); spri = (struct slip_data *) private->user; memset(spri->name, 0, sizeof(spri->name)); @@ -30,7 +30,6 @@ void slip_init(struct net_device *dev, void *data) slip_proto_init(&spri->slip); - dev->init = NULL; dev->hard_header_len = 0; dev->header_ops = NULL; dev->addr_len = 0; @@ -57,7 +56,7 @@ static int slip_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) (struct slip_data *) &lp->user); } -const struct net_kern_info slip_kern_info = { +static const struct net_kern_info slip_kern_info = { .init = slip_init, .protocol = slip_protocol, .read = slip_read, diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index 8b80505a3fb..55c290d925f 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -11,12 +11,10 @@ #include <string.h> #include <sys/termios.h> #include <sys/wait.h> -#include "kern_constants.h" -#include "net_user.h" -#include "os.h" +#include <net_user.h> +#include <os.h> #include "slip.h" -#include "um_malloc.h" -#include "user.h" +#include <um_malloc.h> static int slip_user_init(void *data, void *dev) { @@ -96,13 +94,13 @@ static int slip_tramp(char **argv, int fd) pid = err; output_len = UM_KERN_PAGE_SIZE; - output = kmalloc(output_len, UM_GFP_KERNEL); + output = uml_kmalloc(output_len, UM_GFP_KERNEL); if (output == NULL) { printk(UM_KERN_ERR "slip_tramp : failed to allocate output " "buffer\n"); os_kill_process(pid, 1); err = -ENOMEM; - goto out_free; + goto out_close; } close(fds[1]); @@ -112,7 +110,6 @@ static int slip_tramp(char **argv, int fd) err = helper_wait(pid); close(fds[0]); -out_free: kfree(output); return err; diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c index d987af277db..4ef11ca7cac 100644 --- a/arch/um/drivers/slirp_kern.c +++ b/arch/um/drivers/slirp_kern.c @@ -4,11 +4,11 @@ */ #include <linux/if_arp.h> -#include "linux/init.h" +#include <linux/init.h> #include <linux/netdevice.h> #include <linux/string.h> -#include "net_kern.h" -#include "net_user.h" +#include <net_kern.h> +#include <net_user.h> #include "slirp.h" struct slirp_init { @@ -22,7 +22,7 @@ void slirp_init(struct net_device *dev, void *data) struct slirp_init *init = data; int i; - private = dev->priv; + private = netdev_priv(dev); spri = (struct slirp_data *) private->user; spri->argw = init->argw; @@ -32,7 +32,6 @@ void slirp_init(struct net_device *dev, void *data) slip_proto_init(&spri->slip); - dev->init = NULL; dev->hard_header_len = 0; dev->header_ops = NULL; dev->addr_len = 0; diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index a0ada8fec72..c999d187abb 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -7,11 +7,9 @@ #include <errno.h> #include <string.h> #include <sys/wait.h> -#include "kern_constants.h" -#include "net_user.h" -#include "os.h" +#include <net_user.h> +#include <os.h> #include "slirp.h" -#include "user.h" static int slirp_user_init(void *data, void *dev) { diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index f1786e64607..b8d14fa5205 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -3,31 +3,23 @@ * 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 <linux/fs.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/major.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/console.h> +#include <asm/termbits.h> +#include <asm/irq.h> #include "ssl.h" -#include "chan_kern.h" -#include "kern.h" -#include "init.h" -#include "irq_user.h" +#include "chan.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) @@ -73,8 +65,9 @@ static struct line_driver driver = { /* 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 char *conf[NR_PORTS]; +static char *def_conf = CONFIG_SSL_CHAN; +static struct line serial_lines[NR_PORTS]; static int ssl_config(char *str, char **error_out) { @@ -94,40 +87,13 @@ static int ssl_remove(int n, char **error_out) error_out); } -static int ssl_open(struct tty_struct *tty, struct file *filp) -{ - int err = line_open(serial_lines, tty); - - if (err) - printk(KERN_ERR "Failed to open serial line %d, err = %d\n", - tty->index, err); - - return err; -} - -#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) +static int ssl_install(struct tty_driver *driver, struct tty_struct *tty) { - printk(KERN_ERR "Someone should implement ssl_start\n"); + return line_install(driver, tty, &serial_lines[tty->index]); } -void ssl_hangup(struct tty_struct *tty) -{ -} -#endif - static const struct tty_operations ssl_ops = { - .open = ssl_open, + .open = line_open, .close = line_close, .write = line_write, .put_char = line_put_char, @@ -136,14 +102,10 @@ static const struct tty_operations ssl_ops = { .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 + .install = ssl_install, + .hangup = line_hangup, }; /* Changed by ssl_init and referenced by ssl_exit, which are both serialized @@ -158,14 +120,14 @@ static void ssl_console_write(struct console *c, const char *string, unsigned long flags; spin_lock_irqsave(&line->lock, flags); - console_write_chan(&line->chan_list, string, len); + console_write_chan(line->chan_out, string, len); spin_unlock_irqrestore(&line->lock, flags); } static struct tty_driver *ssl_console_device(struct console *c, int *index) { *index = c->index; - return ssl_driver; + return driver.driver; } static int ssl_console_setup(struct console *co, char *options) @@ -188,17 +150,30 @@ static struct console ssl_cons = { static int ssl_init(void) { char *new_title; + int err; + int i; printk(KERN_INFO "Initializing software serial port version %d\n", ssl_version); - ssl_driver = register_lines(&driver, &ssl_ops, serial_lines, + + err = register_lines(&driver, &ssl_ops, serial_lines, ARRAY_SIZE(serial_lines)); + if (err) + return err; new_title = add_xterm_umid(opts.xterm_title); if (new_title != NULL) opts.xterm_title = new_title; - lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts); + for (i = 0; i < NR_PORTS; i++) { + char *error; + char *s = conf[i]; + if (!s) + s = def_conf; + if (setup_one_line(serial_lines, i, s, &opts, &error)) + printk(KERN_ERR "setup_one_line failed for " + "device %d : %s\n", i, error); + } ssl_init_done = 1; register_console(&ssl_cons); @@ -216,14 +191,7 @@ __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); - + line_setup(conf, NR_PORTS, &def_conf, str, "serial line"); return 1; } diff --git a/arch/um/drivers/ssl.h b/arch/um/drivers/ssl.h index 98412aa6660..314d17725ce 100644 --- a/arch/um/drivers/ssl.h +++ b/arch/um/drivers/ssl.h @@ -11,13 +11,3 @@ extern void ssl_receive_char(int line, char ch); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index cec0c33cdd3..7b361f36ca9 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -3,38 +3,31 @@ * 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 <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 "irq_user.h" +#include "chan.h" +#include <irq_user.h> #include "mconsole_kern.h" -#include "init.h" +#include <init.h> #define MAX_TTYS (16) -/* Referenced only by tty_driver below - presumably it's locked correctly - * by the tty driver. - */ - -static struct tty_driver *console_driver; - -void stdio_announce(char *dev_name, int dev) +static void stdio_announce(char *dev_name, int dev) { printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev, dev_name); @@ -77,9 +70,9 @@ static struct line_driver driver = { /* 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 char *vt_conf[MAX_TTYS]; +static char *def_conf; +static struct line vts[MAX_TTYS]; static int con_config(char *str, char **error_out) { @@ -96,21 +89,17 @@ 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) -{ - int err = line_open(vts, tty); - if (err) - printk(KERN_ERR "Failed to open console %d, err = %d\n", - tty->index, err); - - return err; -} - /* Set in an initcall, checked in an exitcall */ static int con_init_done = 0; +static int con_install(struct tty_driver *driver, struct tty_struct *tty) +{ + return line_install(driver, tty, &vts[tty->index]); +} + static const struct tty_operations console_ops = { - .open = con_open, + .open = line_open, + .install = con_install, .close = line_close, .write = line_write, .put_char = line_put_char, @@ -119,9 +108,9 @@ static const struct tty_operations console_ops = { .flush_buffer = line_flush_buffer, .flush_chars = line_flush_chars, .set_termios = line_set_termios, - .ioctl = line_ioctl, .throttle = line_throttle, .unthrottle = line_unthrottle, + .hangup = line_hangup, }; static void uml_console_write(struct console *console, const char *string, @@ -131,14 +120,14 @@ static void uml_console_write(struct console *console, const char *string, unsigned long flags; spin_lock_irqsave(&line->lock, flags); - console_write_chan(&line->chan_list, string, len); + console_write_chan(line->chan_out, string, len); spin_unlock_irqrestore(&line->lock, flags); } static struct tty_driver *uml_console_device(struct console *c, int *index) { *index = c->index; - return console_driver; + return driver.driver; } static int uml_console_setup(struct console *co, char *options) @@ -158,21 +147,34 @@ static struct console stdiocons = { .index = -1, }; -int stdio_init(void) +static int stdio_init(void) { char *new_title; + int err; + int i; - console_driver = register_lines(&driver, &console_ops, vts, + err = register_lines(&driver, &console_ops, vts, ARRAY_SIZE(vts)); - if (console_driver == NULL) - return -1; + if (err) + return err; + printk(KERN_INFO "Initialized stdio console driver\n"); new_title = add_xterm_umid(opts.xterm_title); if(new_title != NULL) opts.xterm_title = new_title; - lines_init(vts, ARRAY_SIZE(vts), &opts); + for (i = 0; i < MAX_TTYS; i++) { + char *error; + char *s = vt_conf[i]; + if (!s) + s = def_conf; + if (!s) + s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN; + if (setup_one_line(vts, i, s, &opts, &error)) + printk(KERN_ERR "setup_one_line failed for " + "device %d : %s\n", i, error); + } con_init_done = 1; register_console(&stdiocons); @@ -190,14 +192,7 @@ __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); - + line_setup(vt_conf, MAX_TTYS, &def_conf, str, "console"); return 1; } __setup("con", console_chan_setup); diff --git a/arch/um/drivers/stdio_console.h b/arch/um/drivers/stdio_console.h index 505a3d5bea5..6d8275f71fd 100644 --- a/arch/um/drivers/stdio_console.h +++ b/arch/um/drivers/stdio_console.h @@ -9,13 +9,3 @@ extern void save_console_flags(void); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c index c930fedc517..eaa201bca5e 100644 --- a/arch/um/drivers/tty.c +++ b/arch/um/drivers/tty.c @@ -7,10 +7,8 @@ #include <fcntl.h> #include <termios.h> #include "chan_user.h" -#include "kern_constants.h" -#include "os.h" -#include "um_malloc.h" -#include "user.h" +#include <os.h> +#include <um_malloc.h> struct tty_chan { char *dev; @@ -29,7 +27,7 @@ static void *tty_chan_init(char *str, int device, const struct chan_opts *opts) } str++; - data = kmalloc(sizeof(*data), UM_GFP_KERNEL); + data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); if (data == NULL) return NULL; *data = ((struct tty_chan) { .dev = str, diff --git a/arch/um/drivers/ubd.h b/arch/um/drivers/ubd.h new file mode 100644 index 00000000000..3b48cd2081e --- /dev/null +++ b/arch/um/drivers/ubd.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com) + * Licensed under the GPL + */ + +#ifndef __UM_UBD_USER_H +#define __UM_UBD_USER_H + +extern int start_io_thread(unsigned long sp, int *fds_out); +extern int io_thread(void *arg); +extern int kernel_fd; + +#endif + diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index be3a2797dac..3716e695255 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -17,45 +17,31 @@ * James McMechan */ -#define MAJOR_NR UBD_MAJOR #define UBD_SHIFT 4 -#include "linux/kernel.h" -#include "linux/module.h" -#include "linux/blkdev.h" -#include "linux/hdreg.h" -#include "linux/init.h" -#include "linux/cdrom.h" -#include "linux/proc_fs.h" -#include "linux/ctype.h" -#include "linux/capability.h" -#include "linux/mm.h" -#include "linux/vmalloc.h" -#include "linux/blkpg.h" -#include "linux/genhd.h" -#include "linux/spinlock.h" -#include "linux/platform_device.h" -#include "linux/scatterlist.h" -#include "asm/segment.h" -#include "asm/uaccess.h" -#include "asm/irq.h" -#include "asm/types.h" -#include "asm/tlbflush.h" -#include "mem_user.h" -#include "kern_util.h" -#include "kern.h" +#include <linux/module.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <linux/ata.h> +#include <linux/hdreg.h> +#include <linux/cdrom.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/ctype.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/platform_device.h> +#include <linux/scatterlist.h> +#include <asm/tlbflush.h> +#include <kern_util.h> #include "mconsole_kern.h" -#include "init.h" -#include "irq_user.h" -#include "irq_kern.h" -#include "ubd_user.h" -#include "kern_util.h" -#include "os.h" -#include "mem.h" -#include "mem_kern.h" +#include <init.h> +#include <irq_kern.h> +#include "ubd.h" +#include <os.h> #include "cow.h" -enum ubd_req { UBD_READ, UBD_WRITE }; +enum ubd_req { UBD_READ, UBD_WRITE, UBD_FLUSH }; struct io_thread_req { struct request *req; @@ -72,18 +58,6 @@ struct io_thread_req { int error; }; -extern int open_ubd_file(char *file, struct openflags *openflags, int shared, - char **backing_file_out, int *bitmap_offset_out, - unsigned long *bitmap_len_out, int *data_offset_out, - int *create_cow_out); -extern int create_cow_file(char *cow_file, char *backing_file, - struct openflags flags, int sectorsize, - int alignment, int *bitmap_offset_out, - unsigned long *bitmap_len_out, - int *data_offset_out); -extern int read_cow_bitmap(int fd, void *buf, int offset, int len); -extern void do_io(struct io_thread_req *req); - static inline int ubd_test_bit(__u64 bit, unsigned char *data) { __u64 n; @@ -110,16 +84,17 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data) #define DRIVER_NAME "uml-blkdev" static DEFINE_MUTEX(ubd_lock); +static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */ -static int ubd_open(struct inode * inode, struct file * filp); -static int ubd_release(struct inode * inode, struct file * file); -static int ubd_ioctl(struct inode * inode, struct file * file, +static int ubd_open(struct block_device *bdev, fmode_t mode); +static void ubd_release(struct gendisk *disk, fmode_t mode); +static int ubd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg); static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo); #define MAX_DEV (16) -static struct block_device_operations ubd_blops = { +static const struct block_device_operations ubd_blops = { .owner = THIS_MODULE, .open = ubd_open, .release = ubd_release, @@ -128,7 +103,7 @@ static struct block_device_operations ubd_blops = { }; /* Protected by ubd_lock */ -static int fake_major = MAJOR_NR; +static int fake_major = UBD_MAJOR; static struct gendisk *ubd_gendisk[MAX_DEV]; static struct gendisk *fake_gendisk[MAX_DEV]; @@ -173,6 +148,7 @@ struct ubd { struct scatterlist sg[MAX_SG]; struct request *request; int start_sg, end_sg; + sector_t rq_pos; }; #define DEFAULT_COW { \ @@ -193,14 +169,15 @@ struct ubd { .no_cow = 0, \ .shared = 0, \ .cow = DEFAULT_COW, \ - .lock = SPIN_LOCK_UNLOCKED, \ + .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \ .request = NULL, \ .start_sg = 0, \ .end_sg = 0, \ + .rq_pos = 0, \ } /* Protected by ubd_lock */ -struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; +static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD }; /* Only changed by fake_ide_setup which is a setup */ static int fake_ide = 0; @@ -213,23 +190,25 @@ static void make_proc_ide(void) proc_ide = proc_mkdir("ide0", proc_ide_root); } -static int proc_ide_read_media(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int fake_ide_media_proc_show(struct seq_file *m, void *v) { - int len; - - strcpy(page, "disk\n"); - len = strlen("disk\n"); - len -= off; - if (len < count){ - *eof = 1; - if (len <= 0) return 0; - } - else len = count; - *start = page + off; - return len; + seq_puts(m, "disk\n"); + return 0; +} + +static int fake_ide_media_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, fake_ide_media_proc_show, NULL); } +static const struct file_operations fake_ide_media_proc_fops = { + .owner = THIS_MODULE, + .open = fake_ide_media_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static void make_ide_entries(const char *dev_name) { struct proc_dir_entry *dir, *ent; @@ -240,11 +219,8 @@ static void make_ide_entries(const char *dev_name) dir = proc_mkdir(dev_name, proc_ide); if(!dir) return; - ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir); + ent = proc_create("media", S_IRUGO, dir, &fake_ide_media_proc_fops); if(!ent) return; - ent->data = NULL; - ent->read_proc = proc_ide_read_media; - ent->write_proc = NULL; snprintf(name, sizeof(name), "ide0/%s", dev_name); proc_symlink(dev_name, proc_ide_root, name); } @@ -312,7 +288,7 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out) } mutex_lock(&ubd_lock); - if(fake_major != MAJOR_NR){ + if (fake_major != UBD_MAJOR) { *error_out = "Can't assign a fake major twice"; goto out1; } @@ -463,24 +439,7 @@ __uml_help(udb_setup, static void do_ubd_request(struct request_queue * q); /* Only changed by ubd_init, which is an initcall. */ -int thread_fd = -1; - -static void ubd_end_request(struct request *req, int bytes, int error) -{ - blk_end_request(req, error, bytes); -} - -/* Callable only from interrupt context - otherwise you need to do - * spin_lock_irq()/spin_lock_irqsave() */ -static inline void ubd_finish(struct request *req, int bytes) -{ - if(bytes < 0){ - ubd_end_request(req, 0, -EIO); - return; - } - ubd_end_request(req, bytes, 0); -} - +static int thread_fd = -1; static LIST_HEAD(restart); /* XXX - move this inside ubd_intr. */ @@ -488,7 +447,6 @@ static LIST_HEAD(restart); static void ubd_handler(void) { struct io_thread_req *req; - struct request *rq; struct ubd *ubd; struct list_head *list, *next_ele; unsigned long flags; @@ -505,10 +463,7 @@ static void ubd_handler(void) return; } - rq = req->req; - rq->nr_sectors -= req->length >> 9; - if(rq->nr_sectors == 0) - ubd_finish(rq, rq->hard_nr_sectors << 9); + blk_end_request(req->req, 0, req->length); kfree(req); } reactivate_fd(thread_fd, UBD_IRQ); @@ -531,7 +486,7 @@ static irqreturn_t ubd_intr(int irq, void *dev) /* Only changed by ubd_init, which is an initcall. */ static int io_pid = -1; -void kill_io_thread(void) +static void kill_io_thread(void) { if(io_pid != -1) os_kill_process(io_pid, 1); @@ -542,11 +497,226 @@ __uml_exitcall(kill_io_thread); static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out) { char *file; + int fd; + int err; - file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file; + __u32 version; + __u32 align; + char *backing_file; + time_t mtime; + unsigned long long size; + int sector_size; + int bitmap_offset; + + if (ubd_dev->file && ubd_dev->cow.file) { + file = ubd_dev->cow.file; + + goto out; + } + + fd = os_open_file(ubd_dev->file, of_read(OPENFLAGS()), 0); + if (fd < 0) + return fd; + + err = read_cow_header(file_reader, &fd, &version, &backing_file, \ + &mtime, &size, §or_size, &align, &bitmap_offset); + os_close_file(fd); + + if(err == -EINVAL) + file = ubd_dev->file; + else + file = backing_file; + +out: return os_file_size(file, size_out); } +static int read_cow_bitmap(int fd, void *buf, int offset, int len) +{ + int err; + + err = os_seek_file(fd, offset); + if (err < 0) + return err; + + err = os_read_file(fd, buf, len); + if (err < 0) + return err; + + return 0; +} + +static int backing_file_mismatch(char *file, __u64 size, time_t mtime) +{ + unsigned long modtime; + unsigned long long actual; + int err; + + err = os_file_modtime(file, &modtime); + if (err < 0) { + printk(KERN_ERR "Failed to get modification time of backing " + "file \"%s\", err = %d\n", file, -err); + return err; + } + + err = os_file_size(file, &actual); + if (err < 0) { + printk(KERN_ERR "Failed to get size of backing file \"%s\", " + "err = %d\n", file, -err); + return err; + } + + if (actual != size) { + /*__u64 can be a long on AMD64 and with %lu GCC complains; so + * the typecast.*/ + printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header " + "vs backing file\n", (unsigned long long) size, actual); + return -EINVAL; + } + if (modtime != mtime) { + printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs " + "backing file\n", mtime, modtime); + return -EINVAL; + } + return 0; +} + +static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow) +{ + struct uml_stat buf1, buf2; + int err; + + if (from_cmdline == NULL) + return 0; + if (!strcmp(from_cmdline, from_cow)) + return 0; + + err = os_stat_file(from_cmdline, &buf1); + if (err < 0) { + printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline, + -err); + return 0; + } + err = os_stat_file(from_cow, &buf2); + if (err < 0) { + printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow, + -err); + return 1; + } + if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) + return 0; + + printk(KERN_ERR "Backing file mismatch - \"%s\" requested, " + "\"%s\" specified in COW header of \"%s\"\n", + from_cmdline, from_cow, cow); + return 1; +} + +static int open_ubd_file(char *file, struct openflags *openflags, int shared, + char **backing_file_out, int *bitmap_offset_out, + unsigned long *bitmap_len_out, int *data_offset_out, + int *create_cow_out) +{ + time_t mtime; + unsigned long long size; + __u32 version, align; + char *backing_file; + int fd, err, sectorsize, asked_switch, mode = 0644; + + fd = os_open_file(file, *openflags, mode); + if (fd < 0) { + if ((fd == -ENOENT) && (create_cow_out != NULL)) + *create_cow_out = 1; + if (!openflags->w || + ((fd != -EROFS) && (fd != -EACCES))) + return fd; + openflags->w = 0; + fd = os_open_file(file, *openflags, mode); + if (fd < 0) + return fd; + } + + if (shared) + printk(KERN_INFO "Not locking \"%s\" on the host\n", file); + else { + err = os_lock_file(fd, openflags->w); + if (err < 0) { + printk(KERN_ERR "Failed to lock '%s', err = %d\n", + file, -err); + goto out_close; + } + } + + /* Successful return case! */ + if (backing_file_out == NULL) + return fd; + + err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, + &size, §orsize, &align, bitmap_offset_out); + if (err && (*backing_file_out != NULL)) { + printk(KERN_ERR "Failed to read COW header from COW file " + "\"%s\", errno = %d\n", file, -err); + goto out_close; + } + if (err) + return fd; + + asked_switch = path_requires_switch(*backing_file_out, backing_file, + file); + + /* Allow switching only if no mismatch. */ + if (asked_switch && !backing_file_mismatch(*backing_file_out, size, + mtime)) { + printk(KERN_ERR "Switching backing file to '%s'\n", + *backing_file_out); + err = write_cow_header(file, fd, *backing_file_out, + sectorsize, align, &size); + if (err) { + printk(KERN_ERR "Switch failed, errno = %d\n", -err); + goto out_close; + } + } else { + *backing_file_out = backing_file; + err = backing_file_mismatch(*backing_file_out, size, mtime); + if (err) + goto out_close; + } + + cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, + bitmap_len_out, data_offset_out); + + return fd; + out_close: + os_close_file(fd); + return err; +} + +static int create_cow_file(char *cow_file, char *backing_file, + struct openflags flags, + int sectorsize, int alignment, int *bitmap_offset_out, + unsigned long *bitmap_len_out, int *data_offset_out) +{ + int err, fd; + + flags.c = 1; + fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL); + if (fd < 0) { + err = fd; + printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n", + cow_file, -err); + goto out; + } + + err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, + bitmap_offset_out, bitmap_len_out, + data_offset_out); + if (!err) + return fd; + os_close_file(fd); + out: + return err; +} + static void ubd_close_dev(struct ubd *ubd_dev) { os_close_file(ubd_dev->fd); @@ -595,7 +765,7 @@ static int ubd_open_dev(struct ubd *ubd_dev) ubd_dev->fd = fd; if(ubd_dev->cow.file != NULL){ - blk_queue_max_sectors(ubd_dev->queue, 8 * sizeof(long)); + blk_queue_max_hw_sectors(ubd_dev->queue, 8 * sizeof(long)); err = -ENOMEM; ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len); @@ -626,7 +796,7 @@ static int ubd_open_dev(struct ubd *ubd_dev) static void ubd_device_release(struct device *dev) { - struct ubd *ubd_dev = dev->driver_data; + struct ubd *ubd_dev = dev_get_drvdata(dev); blk_cleanup_queue(ubd_dev->queue); *ubd_dev = ((struct ubd) DEFAULT_UBD); @@ -645,17 +815,17 @@ static int ubd_disk_register(int major, u64 size, int unit, disk->first_minor = unit << UBD_SHIFT; disk->fops = &ubd_blops; set_capacity(disk, size / 512); - if(major == MAJOR_NR) + if (major == UBD_MAJOR) sprintf(disk->disk_name, "ubd%c", 'a' + unit); else sprintf(disk->disk_name, "ubd_fake%d", unit); /* sysfs register (not for ide fake devices) */ - if (major == MAJOR_NR) { + if (major == UBD_MAJOR) { ubd_devs[unit].pdev.id = unit; ubd_devs[unit].pdev.name = DRIVER_NAME; ubd_devs[unit].pdev.dev.release = ubd_device_release; - ubd_devs[unit].pdev.dev.driver_data = &ubd_devs[unit]; + dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]); platform_device_register(&ubd_devs[unit].pdev); disk->driverfs_dev = &ubd_devs[unit].pdev.dev; } @@ -696,15 +866,16 @@ static int ubd_add(int n, char **error_out) goto out; } ubd_dev->queue->queuedata = ubd_dev; + blk_queue_flush(ubd_dev->queue, REQ_FLUSH); - blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG); - err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); + blk_queue_max_segments(ubd_dev->queue, MAX_SG); + err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]); if(err){ *error_out = "Failed to register device"; goto out_cleanup; } - if(fake_major != MAJOR_NR) + if (fake_major != UBD_MAJOR) ubd_disk_register(fake_major, ubd_dev->size, n, &fake_gendisk[n]); @@ -886,10 +1057,10 @@ static int __init ubd_init(void) char *error; int i, err; - if (register_blkdev(MAJOR_NR, "ubd")) + if (register_blkdev(UBD_MAJOR, "ubd")) return -1; - if (fake_major != MAJOR_NR) { + if (fake_major != UBD_MAJOR) { char name[sizeof("ubd_nnn\0")]; snprintf(name, sizeof(name), "ubd_%d", fake_major); @@ -931,7 +1102,7 @@ static int __init ubd_driver_init(void){ return 0; } err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, - IRQF_DISABLED, "ubd", ubd_devs); + 0, "ubd", ubd_devs); if(err != 0) printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); return 0; @@ -939,12 +1110,13 @@ static int __init ubd_driver_init(void){ device_initcall(ubd_driver_init); -static int ubd_open(struct inode *inode, struct file *filp) +static int ubd_open(struct block_device *bdev, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct ubd *ubd_dev = disk->private_data; int err = 0; + mutex_lock(&ubd_mutex); if(ubd_dev->count == 0){ err = ubd_open_dev(ubd_dev); if(err){ @@ -958,22 +1130,23 @@ static int ubd_open(struct inode *inode, struct file *filp) /* This should no more be needed. And it didn't work anyway to exclude * read-write remounting of filesystems.*/ - /*if((filp->f_mode & FMODE_WRITE) && !ubd_dev->openflags.w){ + /*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){ if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev); err = -EROFS; }*/ - out: +out: + mutex_unlock(&ubd_mutex); return err; } -static int ubd_release(struct inode * inode, struct file * file) +static void ubd_release(struct gendisk *disk, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *ubd_dev = disk->private_data; + mutex_lock(&ubd_mutex); if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev); - return 0; + mutex_unlock(&ubd_mutex); } static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, @@ -1004,8 +1177,8 @@ static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, * by one word. Thanks to Lynn Kerby for the fix and James McMechan * for the original diagnosis. */ - if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / - sizeof(unsigned long) - 1)) + if (*cow_offset == (DIV_ROUND_UP(bitmap_len, + sizeof(unsigned long)) - 1)) (*cow_offset)--; bitmap_words[0] = bitmap[*cow_offset]; @@ -1067,31 +1240,71 @@ static void prepare_request(struct request *req, struct io_thread_req *io_req, } /* Called with dev->lock held */ +static void prepare_flush_request(struct request *req, + struct io_thread_req *io_req) +{ + struct gendisk *disk = req->rq_disk; + struct ubd *ubd_dev = disk->private_data; + + io_req->req = req; + io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : + ubd_dev->fd; + io_req->op = UBD_FLUSH; +} + +static bool submit_request(struct io_thread_req *io_req, struct ubd *dev) +{ + int n = os_write_file(thread_fd, &io_req, + sizeof(io_req)); + if (n != sizeof(io_req)) { + if (n != -EAGAIN) + printk("write to io thread failed, " + "errno = %d\n", -n); + else if (list_empty(&dev->restart)) + list_add(&dev->restart, &restart); + + kfree(io_req); + return false; + } + return true; +} + +/* Called with dev->lock held */ static void do_ubd_request(struct request_queue *q) { struct io_thread_req *io_req; struct request *req; - int n, last_sectors; while(1){ struct ubd *dev = q->queuedata; if(dev->end_sg == 0){ - struct request *req = elv_next_request(q); + struct request *req = blk_fetch_request(q); if(req == NULL) return; dev->request = req; - blkdev_dequeue_request(req); + dev->rq_pos = blk_rq_pos(req); dev->start_sg = 0; dev->end_sg = blk_rq_map_sg(q, req, dev->sg); } req = dev->request; - last_sectors = 0; + + if (req->cmd_flags & REQ_FLUSH) { + io_req = kmalloc(sizeof(struct io_thread_req), + GFP_ATOMIC); + if (io_req == NULL) { + if (list_empty(&dev->restart)) + list_add(&dev->restart, &restart); + return; + } + prepare_flush_request(req, io_req); + submit_request(io_req, dev); + } + while(dev->start_sg < dev->end_sg){ struct scatterlist *sg = &dev->sg[dev->start_sg]; - req->sector += last_sectors; io_req = kmalloc(sizeof(struct io_thread_req), GFP_ATOMIC); if(io_req == NULL){ @@ -1100,22 +1313,13 @@ static void do_ubd_request(struct request_queue *q) return; } prepare_request(req, io_req, - (unsigned long long) req->sector << 9, + (unsigned long long)dev->rq_pos << 9, sg->offset, sg->length, sg_page(sg)); - last_sectors = sg->length >> 9; - n = os_write_file(thread_fd, &io_req, - sizeof(struct io_thread_req *)); - if(n != sizeof(struct io_thread_req *)){ - if(n != -EAGAIN) - printk("write to io thread failed, " - "errno = %d\n", -n); - else if(list_empty(&dev->restart)) - list_add(&dev->restart, &restart); - kfree(io_req); + if (submit_request(io_req, dev) == false) return; - } + dev->rq_pos += sg->length >> 9; dev->start_sg++; } dev->end_sg = 0; @@ -1133,20 +1337,19 @@ static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo) return 0; } -static int ubd_ioctl(struct inode * inode, struct file * file, +static int ubd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct ubd *ubd_dev = inode->i_bdev->bd_disk->private_data; - struct hd_driveid ubd_id = { - .cyls = 0, - .heads = 128, - .sectors = 32, - }; + struct ubd *ubd_dev = bdev->bd_disk->private_data; + u16 ubd_id[ATA_ID_WORDS]; switch (cmd) { struct cdrom_volctrl volume; case HDIO_GET_IDENTITY: - ubd_id.cyls = ubd_dev->size / (128 * 32 * 512); + memset(&ubd_id, 0, ATA_ID_WORDS * 2); + ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512); + ubd_id[ATA_ID_HEADS] = 128; + ubd_id[ATA_ID_SECTORS] = 32; if(copy_to_user((char __user *) arg, (char *) &ubd_id, sizeof(ubd_id))) return -EFAULT; @@ -1166,185 +1369,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file, return -EINVAL; } -static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow) -{ - struct uml_stat buf1, buf2; - int err; - - if(from_cmdline == NULL) - return 0; - if(!strcmp(from_cmdline, from_cow)) - return 0; - - err = os_stat_file(from_cmdline, &buf1); - if(err < 0){ - printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err); - return 0; - } - err = os_stat_file(from_cow, &buf2); - if(err < 0){ - printk("Couldn't stat '%s', err = %d\n", from_cow, -err); - return 1; - } - if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) - return 0; - - printk("Backing file mismatch - \"%s\" requested,\n" - "\"%s\" specified in COW header of \"%s\"\n", - from_cmdline, from_cow, cow); - return 1; -} - -static int backing_file_mismatch(char *file, __u64 size, time_t mtime) -{ - unsigned long modtime; - unsigned long long actual; - int err; - - err = os_file_modtime(file, &modtime); - if(err < 0){ - printk("Failed to get modification time of backing file " - "\"%s\", err = %d\n", file, -err); - return err; - } - - err = os_file_size(file, &actual); - if(err < 0){ - printk("Failed to get size of backing file \"%s\", " - "err = %d\n", file, -err); - return err; - } - - if(actual != size){ - /*__u64 can be a long on AMD64 and with %lu GCC complains; so - * the typecast.*/ - printk("Size mismatch (%llu vs %llu) of COW header vs backing " - "file\n", (unsigned long long) size, actual); - return -EINVAL; - } - if(modtime != mtime){ - printk("mtime mismatch (%ld vs %ld) of COW header vs backing " - "file\n", mtime, modtime); - return -EINVAL; - } - return 0; -} - -int read_cow_bitmap(int fd, void *buf, int offset, int len) -{ - int err; - - err = os_seek_file(fd, offset); - if(err < 0) - return err; - - err = os_read_file(fd, buf, len); - if(err < 0) - return err; - - return 0; -} - -int open_ubd_file(char *file, struct openflags *openflags, int shared, - char **backing_file_out, int *bitmap_offset_out, - unsigned long *bitmap_len_out, int *data_offset_out, - int *create_cow_out) -{ - time_t mtime; - unsigned long long size; - __u32 version, align; - char *backing_file; - int fd, err, sectorsize, asked_switch, mode = 0644; - - fd = os_open_file(file, *openflags, mode); - if (fd < 0) { - if ((fd == -ENOENT) && (create_cow_out != NULL)) - *create_cow_out = 1; - if (!openflags->w || - ((fd != -EROFS) && (fd != -EACCES))) - return fd; - openflags->w = 0; - fd = os_open_file(file, *openflags, mode); - if (fd < 0) - return fd; - } - - if(shared) - printk("Not locking \"%s\" on the host\n", file); - else { - err = os_lock_file(fd, openflags->w); - if(err < 0){ - printk("Failed to lock '%s', err = %d\n", file, -err); - goto out_close; - } - } - - /* Successful return case! */ - if(backing_file_out == NULL) - return fd; - - err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, - &size, §orsize, &align, bitmap_offset_out); - if(err && (*backing_file_out != NULL)){ - printk("Failed to read COW header from COW file \"%s\", " - "errno = %d\n", file, -err); - goto out_close; - } - if(err) - return fd; - - asked_switch = path_requires_switch(*backing_file_out, backing_file, file); - - /* Allow switching only if no mismatch. */ - if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) { - printk("Switching backing file to '%s'\n", *backing_file_out); - err = write_cow_header(file, fd, *backing_file_out, - sectorsize, align, &size); - if (err) { - printk("Switch failed, errno = %d\n", -err); - goto out_close; - } - } else { - *backing_file_out = backing_file; - err = backing_file_mismatch(*backing_file_out, size, mtime); - if (err) - goto out_close; - } - - cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, - bitmap_len_out, data_offset_out); - - return fd; - out_close: - os_close_file(fd); - return err; -} - -int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, - int sectorsize, int alignment, int *bitmap_offset_out, - unsigned long *bitmap_len_out, int *data_offset_out) -{ - int err, fd; - - flags.c = 1; - fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL); - if(fd < 0){ - err = fd; - printk("Open of COW file '%s' failed, errno = %d\n", cow_file, - -err); - goto out; - } - - err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, - bitmap_offset_out, bitmap_len_out, - data_offset_out); - if(!err) - return fd; - os_close_file(fd); - out: - return err; -} - static int update_bitmap(struct io_thread_req *req) { int n; @@ -1369,7 +1393,7 @@ static int update_bitmap(struct io_thread_req *req) return 0; } -void do_io(struct io_thread_req *req) +static void do_io(struct io_thread_req *req) { char *buf; unsigned long len; @@ -1377,6 +1401,17 @@ void do_io(struct io_thread_req *req) int err; __u64 off; + if (req->op == UBD_FLUSH) { + /* fds[0] is always either the rw image or our cow file */ + n = os_sync_file(req->fds[0]); + if (n != 0) { + printk("do_io - sync failed err = %d " + "fd = %d\n", -n, req->fds[0]); + req->error = 1; + } + return; + } + nsectors = req->length / req->sectorsize; start = 0; do { @@ -1441,7 +1476,8 @@ int io_thread(void *arg) struct io_thread_req *req; int n; - ignore_sigwinch_sig(); + os_fix_helper_signals(); + while(1){ n = os_read_file(kernel_fd, &req, sizeof(struct io_thread_req *)); diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index b591bb9c41d..e376f9b9c68 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -15,19 +15,11 @@ #include <sys/socket.h> #include <sys/mman.h> #include <sys/param.h> -#include "asm/types.h" -#include "user.h" -#include "ubd_user.h" -#include "os.h" -#include "cow.h" - #include <endian.h> #include <byteswap.h> -void ignore_sigwinch_sig(void) -{ - signal(SIGWINCH, SIG_IGN); -} +#include "ubd.h" +#include <os.h> int start_io_thread(unsigned long sp, int *fd_out) { diff --git a/arch/um/drivers/umcast.h b/arch/um/drivers/umcast.h new file mode 100644 index 00000000000..c190c644091 --- /dev/null +++ b/arch/um/drivers/umcast.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __DRIVERS_UMCAST_H +#define __DRIVERS_UMCAST_H + +#include <net_user.h> + +struct umcast_data { + char *addr; + unsigned short lport; + unsigned short rport; + void *listen_addr; + void *remote_addr; + int ttl; + int unicast; + void *dev; +}; + +extern const struct net_user_info umcast_user_info; + +extern int umcast_user_write(int fd, void *buf, int len, + struct umcast_data *pri); + +#endif diff --git a/arch/um/drivers/umcast_kern.c b/arch/um/drivers/umcast_kern.c new file mode 100644 index 00000000000..f5ba6e37791 --- /dev/null +++ b/arch/um/drivers/umcast_kern.c @@ -0,0 +1,188 @@ +/* + * user-mode-linux networking multicast transport + * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * + * based on the existing uml-networking code, which is + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * + * Licensed under the GPL. + */ + +#include <linux/init.h> +#include <linux/netdevice.h> +#include "umcast.h" +#include <net_kern.h> + +struct umcast_init { + char *addr; + int lport; + int rport; + int ttl; + bool unicast; +}; + +static void umcast_init(struct net_device *dev, void *data) +{ + struct uml_net_private *pri; + struct umcast_data *dpri; + struct umcast_init *init = data; + + pri = netdev_priv(dev); + dpri = (struct umcast_data *) pri->user; + dpri->addr = init->addr; + dpri->lport = init->lport; + dpri->rport = init->rport; + dpri->unicast = init->unicast; + dpri->ttl = init->ttl; + dpri->dev = dev; + + if (dpri->unicast) { + printk(KERN_INFO "ucast backend address: %s:%u listen port: " + "%u\n", dpri->addr, dpri->rport, dpri->lport); + } else { + printk(KERN_INFO "mcast backend multicast address: %s:%u, " + "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl); + } +} + +static int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp) +{ + return net_recvfrom(fd, skb_mac_header(skb), + skb->dev->mtu + ETH_HEADER_OTHER); +} + +static int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp) +{ + return umcast_user_write(fd, skb->data, skb->len, + (struct umcast_data *) &lp->user); +} + +static const struct net_kern_info umcast_kern_info = { + .init = umcast_init, + .protocol = eth_protocol, + .read = umcast_read, + .write = umcast_write, +}; + +static int mcast_setup(char *str, char **mac_out, void *data) +{ + struct umcast_init *init = data; + char *port_str = NULL, *ttl_str = NULL, *remain; + char *last; + + *init = ((struct umcast_init) + { .addr = "239.192.168.1", + .lport = 1102, + .ttl = 1 }); + + remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str, + NULL); + if (remain != NULL) { + printk(KERN_ERR "mcast_setup - Extra garbage on " + "specification : '%s'\n", remain); + return 0; + } + + if (port_str != NULL) { + init->lport = simple_strtoul(port_str, &last, 10); + if ((*last != '\0') || (last == port_str)) { + printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", + port_str); + return 0; + } + } + + if (ttl_str != NULL) { + init->ttl = simple_strtoul(ttl_str, &last, 10); + if ((*last != '\0') || (last == ttl_str)) { + printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", + ttl_str); + return 0; + } + } + + init->unicast = false; + init->rport = init->lport; + + printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr, + init->lport, init->ttl); + + return 1; +} + +static int ucast_setup(char *str, char **mac_out, void *data) +{ + struct umcast_init *init = data; + char *lport_str = NULL, *rport_str = NULL, *remain; + char *last; + + *init = ((struct umcast_init) + { .addr = "", + .lport = 1102, + .rport = 1102 }); + + remain = split_if_spec(str, mac_out, &init->addr, + &lport_str, &rport_str, NULL); + if (remain != NULL) { + printk(KERN_ERR "ucast_setup - Extra garbage on " + "specification : '%s'\n", remain); + return 0; + } + + if (lport_str != NULL) { + init->lport = simple_strtoul(lport_str, &last, 10); + if ((*last != '\0') || (last == lport_str)) { + printk(KERN_ERR "ucast_setup - Bad listen port : " + "'%s'\n", lport_str); + return 0; + } + } + + if (rport_str != NULL) { + init->rport = simple_strtoul(rport_str, &last, 10); + if ((*last != '\0') || (last == rport_str)) { + printk(KERN_ERR "ucast_setup - Bad remote port : " + "'%s'\n", rport_str); + return 0; + } + } + + init->unicast = true; + + printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n", + init->lport, init->addr, init->rport); + + return 1; +} + +static struct transport mcast_transport = { + .list = LIST_HEAD_INIT(mcast_transport.list), + .name = "mcast", + .setup = mcast_setup, + .user = &umcast_user_info, + .kern = &umcast_kern_info, + .private_size = sizeof(struct umcast_data), + .setup_size = sizeof(struct umcast_init), +}; + +static struct transport ucast_transport = { + .list = LIST_HEAD_INIT(ucast_transport.list), + .name = "ucast", + .setup = ucast_setup, + .user = &umcast_user_info, + .kern = &umcast_kern_info, + .private_size = sizeof(struct umcast_data), + .setup_size = sizeof(struct umcast_init), +}; + +static int register_umcast(void) +{ + register_transport(&mcast_transport); + register_transport(&ucast_transport); + return 0; +} + +late_initcall(register_umcast); diff --git a/arch/um/drivers/umcast_user.c b/arch/um/drivers/umcast_user.c new file mode 100644 index 00000000000..6074184bb51 --- /dev/null +++ b/arch/um/drivers/umcast_user.c @@ -0,0 +1,184 @@ +/* + * user-mode-linux networking multicast transport + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org> + * + * based on the existing uml-networking code, which is + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * James Leu (jleu@mindspring.net). + * Copyright (C) 2001 by various other people who didn't put their name here. + * + * Licensed under the GPL. + * + */ + +#include <unistd.h> +#include <errno.h> +#include <netinet/in.h> +#include "umcast.h" +#include <net_user.h> +#include <um_malloc.h> + +static struct sockaddr_in *new_addr(char *addr, unsigned short port) +{ + struct sockaddr_in *sin; + + sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL); + if (sin == NULL) { + printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in " + "failed\n"); + return NULL; + } + sin->sin_family = AF_INET; + if (addr) + sin->sin_addr.s_addr = in_aton(addr); + else + sin->sin_addr.s_addr = INADDR_ANY; + sin->sin_port = htons(port); + return sin; +} + +static int umcast_user_init(void *data, void *dev) +{ + struct umcast_data *pri = data; + + pri->remote_addr = new_addr(pri->addr, pri->rport); + if (pri->unicast) + pri->listen_addr = new_addr(NULL, pri->lport); + else + pri->listen_addr = pri->remote_addr; + pri->dev = dev; + return 0; +} + +static void umcast_remove(void *data) +{ + struct umcast_data *pri = data; + + kfree(pri->listen_addr); + if (pri->unicast) + kfree(pri->remote_addr); + pri->listen_addr = pri->remote_addr = NULL; +} + +static int umcast_open(void *data) +{ + struct umcast_data *pri = data; + struct sockaddr_in *lsin = pri->listen_addr; + struct sockaddr_in *rsin = pri->remote_addr; + struct ip_mreq mreq; + int fd, yes = 1, err = -EINVAL; + + + if ((!pri->unicast && lsin->sin_addr.s_addr == 0) || + (rsin->sin_addr.s_addr == 0) || + (lsin->sin_port == 0) || (rsin->sin_port == 0)) + goto out; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + + if (fd < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open : data socket failed, " + "errno = %d\n", errno); + goto out; + } + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open: SO_REUSEADDR failed, " + "errno = %d\n", errno); + goto out_close; + } + + if (!pri->unicast) { + /* set ttl according to config */ + if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl, + sizeof(pri->ttl)) < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_TTL " + "failed, error = %d\n", errno); + goto out_close; + } + + /* set LOOP, so data does get fed back to local sockets */ + if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, + &yes, sizeof(yes)) < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_LOOP " + "failed, error = %d\n", errno); + goto out_close; + } + } + + /* bind socket to the address */ + if (bind(fd, (struct sockaddr *) lsin, sizeof(*lsin)) < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open : data bind failed, " + "errno = %d\n", errno); + goto out_close; + } + + if (!pri->unicast) { + /* subscribe to the multicast group */ + mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr; + mreq.imr_interface.s_addr = 0; + if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, + &mreq, sizeof(mreq)) < 0) { + err = -errno; + printk(UM_KERN_ERR "umcast_open: IP_ADD_MEMBERSHIP " + "failed, error = %d\n", errno); + printk(UM_KERN_ERR "There appears not to be a " + "multicast-capable network interface on the " + "host.\n"); + printk(UM_KERN_ERR "eth0 should be configured in order " + "to use the multicast transport.\n"); + goto out_close; + } + } + + return fd; + + out_close: + close(fd); + out: + return err; +} + +static void umcast_close(int fd, void *data) +{ + struct umcast_data *pri = data; + + if (!pri->unicast) { + struct ip_mreq mreq; + struct sockaddr_in *lsin = pri->listen_addr; + + mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr; + mreq.imr_interface.s_addr = 0; + if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, + &mreq, sizeof(mreq)) < 0) { + printk(UM_KERN_ERR "umcast_close: IP_DROP_MEMBERSHIP " + "failed, error = %d\n", errno); + } + } + + close(fd); +} + +int umcast_user_write(int fd, void *buf, int len, struct umcast_data *pri) +{ + struct sockaddr_in *data_addr = pri->remote_addr; + + return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)); +} + +const struct net_user_info umcast_user_info = { + .init = umcast_user_init, + .open = umcast_open, + .close = umcast_close, + .remove = umcast_remove, + .add_address = NULL, + .delete_address = NULL, + .mtu = ETH_MAX_PACKET, + .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, +}; diff --git a/arch/um/drivers/vde_kern.c b/arch/um/drivers/vde_kern.c index add7e722def..6a365fadc7c 100644 --- a/arch/um/drivers/vde_kern.c +++ b/arch/um/drivers/vde_kern.c @@ -7,10 +7,10 @@ * */ -#include "linux/init.h" +#include <linux/init.h> #include <linux/netdevice.h> -#include "net_kern.h" -#include "net_user.h" +#include <net_kern.h> +#include <net_user.h> #include "vde.h" static void vde_init(struct net_device *dev, void *data) @@ -19,7 +19,7 @@ static void vde_init(struct net_device *dev, void *data) struct uml_net_private *pri; struct vde_data *vpri; - pri = dev->priv; + pri = netdev_priv(dev); vpri = (struct vde_data *) pri->user; vpri->vde_switch = init->vde_switch; diff --git a/arch/um/drivers/vde_user.c b/arch/um/drivers/vde_user.c index 56533db2534..64cb630d115 100644 --- a/arch/um/drivers/vde_user.c +++ b/arch/um/drivers/vde_user.c @@ -6,10 +6,8 @@ #include <stddef.h> #include <errno.h> #include <libvdeplug.h> -#include "kern_constants.h" -#include "net_user.h" -#include "um_malloc.h" -#include "user.h" +#include <net_user.h> +#include <um_malloc.h> #include "vde.h" static int vde_user_init(void *data, void *dev) @@ -78,7 +76,7 @@ void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init) { struct vde_open_args *args; - vpri->args = kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL); + vpri->args = uml_kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL); if (vpri->args == NULL) { printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args " "allocation failed"); @@ -91,8 +89,8 @@ void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init) args->group = init->group; args->mode = init->mode ? init->mode : 0700; - args->port ? printk(UM_KERN_INFO "port %d", args->port) : - printk(UM_KERN_INFO "undefined port"); + args->port ? printk("port %d", args->port) : + printk("undefined port"); } int vde_user_read(void *conn, void *buf, int len) diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index 8a1c18a9b24..20e30be4479 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -11,10 +11,8 @@ #include <string.h> #include <termios.h> #include "chan_user.h" -#include "kern_constants.h" -#include "os.h" -#include "um_malloc.h" -#include "user.h" +#include <os.h> +#include <um_malloc.h> #include "xterm.h" struct xterm_chan { @@ -30,7 +28,7 @@ static void *xterm_init(char *str, int device, const struct chan_opts *opts) { struct xterm_chan *data; - data = kmalloc(sizeof(*data), UM_GFP_KERNEL); + data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); if (data == NULL) return NULL; *data = ((struct xterm_chan) { .pid = -1, @@ -90,7 +88,7 @@ static int xterm_open(int input, int output, int primary, void *d, 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", + OS_LIB_PATH "/uml/port-helper", "-uml-socket", file, NULL }; if (access(argv[4], X_OK) < 0) @@ -123,6 +121,7 @@ static int xterm_open(int input, int output, int primary, void *d, err = -errno; printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n", errno); + close(fd); return err; } close(fd); diff --git a/arch/um/drivers/xterm.h b/arch/um/drivers/xterm.h index f33a6e77b18..56b9c4aba42 100644 --- a/arch/um/drivers/xterm.h +++ b/arch/um/drivers/xterm.h @@ -10,13 +10,3 @@ extern int xterm_fd(int socket, int *pid_out); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c index b646bccef37..e8f9957bfbf 100644 --- a/arch/um/drivers/xterm_kern.c +++ b/arch/um/drivers/xterm_kern.c @@ -7,8 +7,8 @@ #include <linux/completion.h> #include <linux/irqreturn.h> #include <asm/irq.h> -#include "irq_kern.h" -#include "os.h" +#include <irq_kern.h> +#include <os.h> struct xterm_wait { struct completion ready; @@ -50,8 +50,7 @@ int xterm_fd(int socket, int *pid_out) init_completion(&data->ready); err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, - "xterm", data); + IRQF_SHARED, "xterm", data); if (err) { printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, " "err = %d\n", err); @@ -65,7 +64,7 @@ int xterm_fd(int socket, int *pid_out) * isn't set) this will hang... */ wait_for_completion(&data->ready); - free_irq(XTERM_IRQ, data); + um_free_irq(XTERM_IRQ, data); ret = data->new_fd; *pid_out = data->pid; diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild new file mode 100644 index 00000000000..a5e4b606821 --- /dev/null +++ b/arch/um/include/asm/Kbuild @@ -0,0 +1,28 @@ +generic-y += barrier.h +generic-y += bug.h +generic-y += clkdev.h +generic-y += cputime.h +generic-y += current.h +generic-y += delay.h +generic-y += device.h +generic-y += emergency-restart.h +generic-y += exec.h +generic-y += ftrace.h +generic-y += futex.h +generic-y += hardirq.h +generic-y += hash.h +generic-y += hw_irq.h +generic-y += io.h +generic-y += irq_regs.h +generic-y += kdebug.h +generic-y += mcs_spinlock.h +generic-y += mutex.h +generic-y += param.h +generic-y += pci.h +generic-y += percpu.h +generic-y += preempt.h +generic-y += sections.h +generic-y += switch_to.h +generic-y += topology.h +generic-y += trace_clock.h +generic-y += xor.h diff --git a/arch/um/include/asm/a.out-core.h b/arch/um/include/asm/a.out-core.h new file mode 100644 index 00000000000..995643b1830 --- /dev/null +++ b/arch/um/include/asm/a.out-core.h @@ -0,0 +1,27 @@ +/* a.out coredump register dumper + * + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef __UM_A_OUT_CORE_H +#define __UM_A_OUT_CORE_H + +#ifdef __KERNEL__ + +#include <linux/user.h> + +/* + * fill in the user structure for an a.out core dump + */ +static inline void aout_dump_thread(struct pt_regs *regs, struct user *u) +{ +} + +#endif /* __KERNEL__ */ +#endif /* __UM_A_OUT_CORE_H */ diff --git a/arch/um/include/asm/bugs.h b/arch/um/include/asm/bugs.h new file mode 100644 index 00000000000..6a72e240d5f --- /dev/null +++ b/arch/um/include/asm/bugs.h @@ -0,0 +1,6 @@ +#ifndef __UM_BUGS_H +#define __UM_BUGS_H + +void check_bugs(void); + +#endif diff --git a/arch/um/include/asm/cache.h b/arch/um/include/asm/cache.h new file mode 100644 index 00000000000..19e1bdd6741 --- /dev/null +++ b/arch/um/include/asm/cache.h @@ -0,0 +1,17 @@ +#ifndef __UM_CACHE_H +#define __UM_CACHE_H + + +#if defined(CONFIG_UML_X86) && !defined(CONFIG_64BIT) +# define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) +#elif defined(CONFIG_UML_X86) /* 64-bit */ +# define L1_CACHE_SHIFT 6 /* Should be 7 on Intel */ +#else +/* XXX: this was taken from x86, now it's completely random. Luckily only + * affects SMP padding. */ +# define L1_CACHE_SHIFT 5 +#endif + +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + +#endif diff --git a/arch/um/include/asm/common.lds.S b/arch/um/include/asm/common.lds.S new file mode 100644 index 00000000000..1dd5bd8a8c5 --- /dev/null +++ b/arch/um/include/asm/common.lds.S @@ -0,0 +1,107 @@ +#include <asm-generic/vmlinux.lds.h> + + .fini : { *(.fini) } =0x9090 + _etext = .; + PROVIDE (etext = .); + + . = ALIGN(4096); + _sdata = .; + PROVIDE (sdata = .); + + RODATA + + .unprotected : { *(.unprotected) } + . = ALIGN(4096); + PROVIDE (_unprotected_end = .); + + . = ALIGN(4096); + .note : { *(.note.*) } + EXCEPTION_TABLE(0) + + BUG_TABLE + + .uml.setup.init : { + __uml_setup_start = .; + *(.uml.setup.init) + __uml_setup_end = .; + } + + .uml.help.init : { + __uml_help_start = .; + *(.uml.help.init) + __uml_help_end = .; + } + + .uml.postsetup.init : { + __uml_postsetup_start = .; + *(.uml.postsetup.init) + __uml_postsetup_end = .; + } + + .init.setup : { + INIT_SETUP(0) + } + + PERCPU_SECTION(32) + + .initcall.init : { + INIT_CALLS + } + + .con_initcall.init : { + CON_INITCALL + } + + .uml.initcall.init : { + __uml_initcall_start = .; + *(.uml.initcall.init) + __uml_initcall_end = .; + } + + SECURITY_INIT + + .exitcall : { + __exitcall_begin = .; + *(.exitcall.exit) + __exitcall_end = .; + } + + .uml.exitcall : { + __uml_exitcall_begin = .; + *(.uml.exitcall.exit) + __uml_exitcall_end = .; + } + + . = ALIGN(4); + .altinstructions : { + __alt_instructions = .; + *(.altinstructions) + __alt_instructions_end = .; + } + .altinstr_replacement : { *(.altinstr_replacement) } + /* .exit.text is discard at runtime, not link time, to deal with references + from .altinstructions and .eh_frame */ + .exit.text : { *(.exit.text) } + .exit.data : { *(.exit.data) } + + .preinit_array : { + __preinit_array_start = .; + *(.preinit_array) + __preinit_array_end = .; + } + .init_array : { + __init_array_start = .; + *(.init_array) + __init_array_end = .; + } + .fini_array : { + __fini_array_start = .; + *(.fini_array) + __fini_array_end = .; + } + + . = ALIGN(4096); + .init.ramfs : { + INIT_RAM_FS + } + diff --git a/arch/um/include/asm/dma.h b/arch/um/include/asm/dma.h new file mode 100644 index 00000000000..f88c5860520 --- /dev/null +++ b/arch/um/include/asm/dma.h @@ -0,0 +1,10 @@ +#ifndef __UM_DMA_H +#define __UM_DMA_H + +#include <asm/io.h> + +extern unsigned long uml_physmem; + +#define MAX_DMA_ADDRESS (uml_physmem) + +#endif diff --git a/arch/um/include/asm/fixmap.h b/arch/um/include/asm/fixmap.h new file mode 100644 index 00000000000..3094ea3c73b --- /dev/null +++ b/arch/um/include/asm/fixmap.h @@ -0,0 +1,60 @@ +#ifndef __UM_FIXMAP_H +#define __UM_FIXMAP_H + +#include <asm/processor.h> +#include <asm/kmap_types.h> +#include <asm/archparam.h> +#include <asm/page.h> +#include <linux/threads.h> + +/* + * Here we define all the compile-time 'special' virtual + * addresses. The point is to have a constant address at + * compile time, but to set the physical address only + * in the boot process. We allocate these special addresses + * from the end of virtual memory (0xfffff000) backwards. + * Also this lets us do fail-safe vmalloc(), we + * can guarantee that these special addresses and + * vmalloc()-ed addresses never overlap. + * + * these 'compile-time allocated' memory buffers are + * fixed-size 4k pages. (or larger if used with an increment + * highger than 1) use fixmap_set(idx,phys) to associate + * physical memory with fixmap indices. + * + * TLB entries of such buffers will not be flushed across + * task switches. + */ + +/* + * on UP currently we will have no trace of the fixmap mechanizm, + * no page table allocations, etc. This might change in the + * future, say framebuffers for the console driver(s) could be + * fix-mapped? + */ +enum fixed_addresses { +#ifdef CONFIG_HIGHMEM + FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ + FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, +#endif + __end_of_fixed_addresses +}; + +extern void __set_fixmap (enum fixed_addresses idx, + unsigned long phys, pgprot_t flags); + +/* + * used by vmalloc.c. + * + * Leave one empty page between vmalloc'ed areas and + * the start of the fixmap, and leave one page empty + * at the top of mem.. + */ + +#define FIXADDR_TOP (TASK_SIZE - 2 * PAGE_SIZE) +#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) +#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) + +#include <asm-generic/fixmap.h> + +#endif diff --git a/arch/um/include/asm/irq.h b/arch/um/include/asm/irq.h new file mode 100644 index 00000000000..4a2037f8204 --- /dev/null +++ b/arch/um/include/asm/irq.h @@ -0,0 +1,23 @@ +#ifndef __UM_IRQ_H +#define __UM_IRQ_H + +#define TIMER_IRQ 0 +#define UMN_IRQ 1 +#define CONSOLE_IRQ 2 +#define CONSOLE_WRITE_IRQ 3 +#define UBD_IRQ 4 +#define UM_ETH_IRQ 5 +#define SSL_IRQ 6 +#define SSL_WRITE_IRQ 7 +#define ACCEPT_IRQ 8 +#define MCONSOLE_IRQ 9 +#define WINCH_IRQ 10 +#define SIGIO_WRITE_IRQ 11 +#define TELNETD_IRQ 12 +#define XTERM_IRQ 13 +#define RANDOM_IRQ 14 + +#define LAST_IRQ RANDOM_IRQ +#define NR_IRQS (LAST_IRQ + 1) + +#endif diff --git a/arch/um/include/asm/irqflags.h b/arch/um/include/asm/irqflags.h new file mode 100644 index 00000000000..c780d8a1677 --- /dev/null +++ b/arch/um/include/asm/irqflags.h @@ -0,0 +1,42 @@ +#ifndef __UM_IRQFLAGS_H +#define __UM_IRQFLAGS_H + +extern int get_signals(void); +extern int set_signals(int enable); +extern void block_signals(void); +extern void unblock_signals(void); + +static inline unsigned long arch_local_save_flags(void) +{ + return get_signals(); +} + +static inline void arch_local_irq_restore(unsigned long flags) +{ + set_signals(flags); +} + +static inline void arch_local_irq_enable(void) +{ + unblock_signals(); +} + +static inline void arch_local_irq_disable(void) +{ + block_signals(); +} + +static inline unsigned long arch_local_irq_save(void) +{ + unsigned long flags; + flags = arch_local_save_flags(); + arch_local_irq_disable(); + return flags; +} + +static inline bool arch_irqs_disabled(void) +{ + return arch_local_save_flags() == 0; +} + +#endif diff --git a/arch/um/include/asm/kmap_types.h b/arch/um/include/asm/kmap_types.h new file mode 100644 index 00000000000..2e0a6b1d830 --- /dev/null +++ b/arch/um/include/asm/kmap_types.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __UM_KMAP_TYPES_H +#define __UM_KMAP_TYPES_H + +/* No more #include "asm/arch/kmap_types.h" ! */ + +#define KM_TYPE_NR 14 + +#endif diff --git a/arch/um/include/asm/kvm_para.h b/arch/um/include/asm/kvm_para.h new file mode 100644 index 00000000000..14fab8f0b95 --- /dev/null +++ b/arch/um/include/asm/kvm_para.h @@ -0,0 +1 @@ +#include <asm-generic/kvm_para.h> diff --git a/arch/um/include/um_mmu.h b/arch/um/include/asm/mmu.h index f575ff91f2a..da705448590 100644 --- a/arch/um/include/um_mmu.h +++ b/arch/um/include/asm/mmu.h @@ -6,14 +6,13 @@ #ifndef __ARCH_UM_MMU_H #define __ARCH_UM_MMU_H -#include "uml-config.h" -#include "mm_id.h" -#include "asm/ldt.h" +#include <mm_id.h> +#include <asm/mm_context.h> typedef struct mm_context { struct mm_id id; - struct uml_ldt ldt; - struct page **stub_pages; + struct uml_arch_mm_context arch; + struct page *stub_pages[2]; } mm_context_t; extern void __switch_mm(struct mm_id * mm_idp); diff --git a/arch/um/include/asm/mmu_context.h b/arch/um/include/asm/mmu_context.h new file mode 100644 index 00000000000..aa4a743dc4a --- /dev/null +++ b/arch/um/include/asm/mmu_context.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __UM_MMU_CONTEXT_H +#define __UM_MMU_CONTEXT_H + +#include <linux/sched.h> +#include <asm/mmu.h> + +extern void uml_setup_stubs(struct mm_struct *mm); +extern void arch_exit_mmap(struct mm_struct *mm); + +#define deactivate_mm(tsk,mm) do { } while (0) + +extern void force_flush_all(void); + +static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) +{ + /* + * This is called by fs/exec.c and sys_unshare() + * when the new ->mm is used for the first time. + */ + __switch_mm(&new->context.id); + down_write(&new->mmap_sem); + uml_setup_stubs(new); + up_write(&new->mmap_sem); +} + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ + unsigned cpu = smp_processor_id(); + + if(prev != next){ + cpumask_clear_cpu(cpu, mm_cpumask(prev)); + cpumask_set_cpu(cpu, mm_cpumask(next)); + if(next != &init_mm) + __switch_mm(&next->context.id); + } +} + +static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) +{ + uml_setup_stubs(mm); +} + +static inline void enter_lazy_tlb(struct mm_struct *mm, + struct task_struct *tsk) +{ +} + +extern int init_new_context(struct task_struct *task, struct mm_struct *mm); + +extern void destroy_context(struct mm_struct *mm); + +#endif diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h new file mode 100644 index 00000000000..5ff53d9185f --- /dev/null +++ b/arch/um/include/asm/page.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright 2003 PathScale, Inc. + * Licensed under the GPL + */ + +#ifndef __UM_PAGE_H +#define __UM_PAGE_H + +#include <linux/const.h> + +/* PAGE_SHIFT determines the page size */ +#define PAGE_SHIFT 12 +#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#ifndef __ASSEMBLY__ + +struct page; + +#include <linux/types.h> +#include <asm/vm-flags.h> + +/* + * These are used to make use of C type-checking.. + */ + +#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) +#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) + +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +#if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64BIT) + +typedef struct { unsigned long pte_low, pte_high; } pte_t; +typedef struct { unsigned long pmd; } pmd_t; +typedef struct { unsigned long pgd; } pgd_t; +#define pte_val(x) ((x).pte_low | ((unsigned long long) (x).pte_high << 32)) + +#define pte_get_bits(pte, bits) ((pte).pte_low & (bits)) +#define pte_set_bits(pte, bits) ((pte).pte_low |= (bits)) +#define pte_clear_bits(pte, bits) ((pte).pte_low &= ~(bits)) +#define pte_copy(to, from) ({ (to).pte_high = (from).pte_high; \ + smp_wmb(); \ + (to).pte_low = (from).pte_low; }) +#define pte_is_zero(pte) (!((pte).pte_low & ~_PAGE_NEWPAGE) && !(pte).pte_high) +#define pte_set_val(pte, phys, prot) \ + ({ (pte).pte_high = (phys) >> 32; \ + (pte).pte_low = (phys) | pgprot_val(prot); }) + +#define pmd_val(x) ((x).pmd) +#define __pmd(x) ((pmd_t) { (x) } ) + +typedef unsigned long long pfn_t; +typedef unsigned long long phys_t; + +#else + +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pgd; } pgd_t; + +#ifdef CONFIG_3_LEVEL_PGTABLES +typedef struct { unsigned long pmd; } pmd_t; +#define pmd_val(x) ((x).pmd) +#define __pmd(x) ((pmd_t) { (x) } ) +#endif + +#define pte_val(x) ((x).pte) + + +#define pte_get_bits(p, bits) ((p).pte & (bits)) +#define pte_set_bits(p, bits) ((p).pte |= (bits)) +#define pte_clear_bits(p, bits) ((p).pte &= ~(bits)) +#define pte_copy(to, from) ((to).pte = (from).pte) +#define pte_is_zero(p) (!((p).pte & ~_PAGE_NEWPAGE)) +#define pte_set_val(p, phys, prot) (p).pte = (phys | pgprot_val(prot)) + +typedef unsigned long pfn_t; +typedef unsigned long phys_t; + +#endif + +typedef struct { unsigned long pgprot; } pgprot_t; + +typedef struct page *pgtable_t; + +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +extern unsigned long uml_physmem; + +#define PAGE_OFFSET (uml_physmem) +#define KERNELBASE PAGE_OFFSET + +#define __va_space (8*1024*1024) + +#include <mem.h> + +/* Cast to unsigned long before casting to void * to avoid a warning from + * mmap_kmem about cutting a long long down to a void *. Not sure that + * casting is the right thing, but 32-bit UML can't have 64-bit virtual + * addresses + */ +#define __pa(virt) to_phys((void *) (unsigned long) (virt)) +#define __va(phys) to_virt((unsigned long) (phys)) + +#define phys_to_pfn(p) ((pfn_t) ((p) >> PAGE_SHIFT)) +#define pfn_to_phys(pfn) ((phys_t) ((pfn) << PAGE_SHIFT)) + +#define pfn_valid(pfn) ((pfn) < max_mapnr) +#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v))) + +#include <asm-generic/memory_model.h> +#include <asm-generic/getorder.h> + +#endif /* __ASSEMBLY__ */ +#endif /* __UM_PAGE_H */ diff --git a/arch/um/include/asm/pgalloc.h b/arch/um/include/asm/pgalloc.h new file mode 100644 index 00000000000..bf90b2aa200 --- /dev/null +++ b/arch/um/include/asm/pgalloc.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. + * Derived from include/asm-i386/pgalloc.h and include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGALLOC_H +#define __UM_PGALLOC_H + +#include <linux/mm.h> + +#define pmd_populate_kernel(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte))) + +#define pmd_populate(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + \ + ((unsigned long long)page_to_pfn(pte) << \ + (unsigned long long) PAGE_SHIFT))) +#define pmd_pgtable(pmd) pmd_page(pmd) + +/* + * Allocate and free page tables. + */ +extern pgd_t *pgd_alloc(struct mm_struct *); +extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); + +extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long); +extern pgtable_t pte_alloc_one(struct mm_struct *, unsigned long); + +static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) +{ + free_page((unsigned long) pte); +} + +static inline void pte_free(struct mm_struct *mm, pgtable_t pte) +{ + pgtable_page_dtor(pte); + __free_page(pte); +} + +#define __pte_free_tlb(tlb,pte, address) \ +do { \ + pgtable_page_dtor(pte); \ + tlb_remove_page((tlb),(pte)); \ +} while (0) + +#ifdef CONFIG_3_LEVEL_PGTABLES + +static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) +{ + free_page((unsigned long)pmd); +} + +#define __pmd_free_tlb(tlb,x, address) tlb_remove_page((tlb),virt_to_page(x)) +#endif + +#define check_pgt_cache() do { } while (0) + +#endif + diff --git a/arch/um/include/asm/pgtable-2level.h b/arch/um/include/asm/pgtable-2level.h new file mode 100644 index 00000000000..f534b73e753 --- /dev/null +++ b/arch/um/include/asm/pgtable-2level.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright 2003 PathScale, Inc. + * Derived from include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGTABLE_2LEVEL_H +#define __UM_PGTABLE_2LEVEL_H + +#include <asm-generic/pgtable-nopmd.h> + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ + +#define PGDIR_SHIFT 22 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * entries per page directory level: the i386 is two-level, so + * we don't really have any PMD directory physically. + */ +#define PTRS_PER_PTE 1024 +#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE) +#define PTRS_PER_PGD 1024 +#define FIRST_USER_ADDRESS 0 + +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %p(%08lx).\n", __FILE__, __LINE__, &(e), \ + pte_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %p(%08lx).\n", __FILE__, __LINE__, &(e), \ + pgd_val(e)) + +static inline int pgd_newpage(pgd_t pgd) { return 0; } +static inline void pgd_mkuptodate(pgd_t pgd) { } + +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval)) + +#define pte_pfn(x) phys_to_pfn(pte_val(x)) +#define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot)) +#define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot)) + +/* + * Bits 0 through 4 are taken + */ +#define PTE_FILE_MAX_BITS 27 + +#define pte_to_pgoff(pte) (pte_val(pte) >> 5) + +#define pgoff_to_pte(off) ((pte_t) { ((off) << 5) + _PAGE_FILE }) + +#endif diff --git a/arch/um/include/asm/pgtable-3level.h b/arch/um/include/asm/pgtable-3level.h new file mode 100644 index 00000000000..0032f9212e7 --- /dev/null +++ b/arch/um/include/asm/pgtable-3level.h @@ -0,0 +1,136 @@ +/* + * Copyright 2003 PathScale Inc + * Derived from include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGTABLE_3LEVEL_H +#define __UM_PGTABLE_3LEVEL_H + +#include <asm-generic/pgtable-nopud.h> + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ + +#ifdef CONFIG_64BIT +#define PGDIR_SHIFT 30 +#else +#define PGDIR_SHIFT 31 +#endif +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* PMD_SHIFT determines the size of the area a second-level page table can + * map + */ + +#define PMD_SHIFT 21 +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* + * entries per page directory level + */ + +#define PTRS_PER_PTE 512 +#ifdef CONFIG_64BIT +#define PTRS_PER_PMD 512 +#define PTRS_PER_PGD 512 +#else +#define PTRS_PER_PMD 1024 +#define PTRS_PER_PGD 1024 +#endif + +#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE) +#define FIRST_USER_ADDRESS 0 + +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pte_val(e)) +#define pmd_ERROR(e) \ + printk("%s:%d: bad pmd %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pmd_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pgd_val(e)) + +#define pud_none(x) (!(pud_val(x) & ~_PAGE_NEWPAGE)) +#define pud_bad(x) ((pud_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) +#define pud_present(x) (pud_val(x) & _PAGE_PRESENT) +#define pud_populate(mm, pud, pmd) \ + set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd))) + +#ifdef CONFIG_64BIT +#define set_pud(pudptr, pudval) set_64bit((u64 *) (pudptr), pud_val(pudval)) +#else +#define set_pud(pudptr, pudval) (*(pudptr) = (pudval)) +#endif + +static inline int pgd_newpage(pgd_t pgd) +{ + return(pgd_val(pgd) & _PAGE_NEWPAGE); +} + +static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; } + +#ifdef CONFIG_64BIT +#define set_pmd(pmdptr, pmdval) set_64bit((u64 *) (pmdptr), pmd_val(pmdval)) +#else +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval)) +#endif + +struct mm_struct; +extern pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address); + +static inline void pud_clear (pud_t *pud) +{ + set_pud(pud, __pud(_PAGE_NEWPAGE)); +} + +#define pud_page(pud) phys_to_page(pud_val(pud) & PAGE_MASK) +#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PAGE_MASK)) + +/* Find an entry in the second-level page table.. */ +#define pmd_offset(pud, address) ((pmd_t *) pud_page_vaddr(*(pud)) + \ + pmd_index(address)) + +static inline unsigned long pte_pfn(pte_t pte) +{ + return phys_to_pfn(pte_val(pte)); +} + +static inline pte_t pfn_pte(pfn_t page_nr, pgprot_t pgprot) +{ + pte_t pte; + phys_t phys = pfn_to_phys(page_nr); + + pte_set_val(pte, phys, pgprot); + return pte; +} + +static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot) +{ + return __pmd((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); +} + +/* + * Bits 0 through 3 are taken in the low part of the pte, + * put the 32 bits of offset into the high part. + */ +#define PTE_FILE_MAX_BITS 32 + +#ifdef CONFIG_64BIT + +#define pte_to_pgoff(p) ((p).pte >> 32) + +#define pgoff_to_pte(off) ((pte_t) { ((off) << 32) | _PAGE_FILE }) + +#else + +#define pte_to_pgoff(pte) ((pte).pte_high) + +#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) }) + +#endif + +#endif + diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h new file mode 100644 index 00000000000..bf974f712af --- /dev/null +++ b/arch/um/include/asm/pgtable.h @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright 2003 PathScale, Inc. + * Derived from include/asm-i386/pgtable.h + * Licensed under the GPL + */ + +#ifndef __UM_PGTABLE_H +#define __UM_PGTABLE_H + +#include <asm/fixmap.h> + +#define _PAGE_PRESENT 0x001 +#define _PAGE_NEWPAGE 0x002 +#define _PAGE_NEWPROT 0x004 +#define _PAGE_RW 0x020 +#define _PAGE_USER 0x040 +#define _PAGE_ACCESSED 0x080 +#define _PAGE_DIRTY 0x100 +/* If _PAGE_PRESENT is clear, we use these: */ +#define _PAGE_FILE 0x008 /* nonlinear file mapping, saved PTE; unset:swap */ +#define _PAGE_PROTNONE 0x010 /* if the user mapped it with PROT_NONE; + pte_present gives true */ + +#ifdef CONFIG_3_LEVEL_PGTABLES +#include <asm/pgtable-3level.h> +#else +#include <asm/pgtable-2level.h> +#endif + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +/* zero page used for uninitialized stuff */ +extern unsigned long *empty_zero_page; + +#define pgtable_cache_init() do ; while (0) + +/* Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ + +extern unsigned long end_iomem; + +#define VMALLOC_OFFSET (__va_space) +#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define PKMAP_BASE ((FIXADDR_START - LAST_PKMAP * PAGE_SIZE) & PMD_MASK) +#ifdef CONFIG_HIGHMEM +# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) +#else +# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) +#endif +#define MODULES_VADDR VMALLOC_START +#define MODULES_END VMALLOC_END +#define MODULES_LEN (MODULES_VADDR - MODULES_END) + +#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) +#define __PAGE_KERNEL_EXEC \ + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) +#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) + +/* + * The i386 can't do page protection for execute, and considers that the same + * are read. + * Also, write permissions imply read permissions. This is the closest we can + * get.. + */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY +#define __P101 PAGE_READONLY +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY +#define __S101 PAGE_READONLY +#define __S110 PAGE_SHARED +#define __S111 PAGE_SHARED + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) + +#define pte_clear(mm,addr,xp) pte_set_val(*(xp), (phys_t) 0, __pgprot(_PAGE_NEWPAGE)) + +#define pmd_none(x) (!((unsigned long)pmd_val(x) & ~_PAGE_NEWPAGE)) +#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) + +#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) +#define pmd_clear(xp) do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0) + +#define pmd_newpage(x) (pmd_val(x) & _PAGE_NEWPAGE) +#define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEWPAGE) + +#define pud_newpage(x) (pud_val(x) & _PAGE_NEWPAGE) +#define pud_mkuptodate(x) (pud_val(x) &= ~_PAGE_NEWPAGE) + +#define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK) + +#define pte_page(x) pfn_to_page(pte_pfn(x)) + +#define pte_present(x) pte_get_bits(x, (_PAGE_PRESENT | _PAGE_PROTNONE)) + +/* + * ================================= + * Flags checking section. + * ================================= + */ + +static inline int pte_none(pte_t pte) +{ + return pte_is_zero(pte); +} + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +static inline int pte_read(pte_t pte) +{ + return((pte_get_bits(pte, _PAGE_USER)) && + !(pte_get_bits(pte, _PAGE_PROTNONE))); +} + +static inline int pte_exec(pte_t pte){ + return((pte_get_bits(pte, _PAGE_USER)) && + !(pte_get_bits(pte, _PAGE_PROTNONE))); +} + +static inline int pte_write(pte_t pte) +{ + return((pte_get_bits(pte, _PAGE_RW)) && + !(pte_get_bits(pte, _PAGE_PROTNONE))); +} + +/* + * The following only works if pte_present() is not true. + */ +static inline int pte_file(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_FILE); +} + +static inline int pte_dirty(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_DIRTY); +} + +static inline int pte_young(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_ACCESSED); +} + +static inline int pte_newpage(pte_t pte) +{ + return pte_get_bits(pte, _PAGE_NEWPAGE); +} + +static inline int pte_newprot(pte_t pte) +{ + return(pte_present(pte) && (pte_get_bits(pte, _PAGE_NEWPROT))); +} + +static inline int pte_special(pte_t pte) +{ + return 0; +} + +/* + * ================================= + * Flags setting section. + * ================================= + */ + +static inline pte_t pte_mknewprot(pte_t pte) +{ + pte_set_bits(pte, _PAGE_NEWPROT); + return(pte); +} + +static inline pte_t pte_mkclean(pte_t pte) +{ + pte_clear_bits(pte, _PAGE_DIRTY); + return(pte); +} + +static inline pte_t pte_mkold(pte_t pte) +{ + pte_clear_bits(pte, _PAGE_ACCESSED); + return(pte); +} + +static inline pte_t pte_wrprotect(pte_t pte) +{ + pte_clear_bits(pte, _PAGE_RW); + return(pte_mknewprot(pte)); +} + +static inline pte_t pte_mkread(pte_t pte) +{ + pte_set_bits(pte, _PAGE_USER); + return(pte_mknewprot(pte)); +} + +static inline pte_t pte_mkdirty(pte_t pte) +{ + pte_set_bits(pte, _PAGE_DIRTY); + return(pte); +} + +static inline pte_t pte_mkyoung(pte_t pte) +{ + pte_set_bits(pte, _PAGE_ACCESSED); + return(pte); +} + +static inline pte_t pte_mkwrite(pte_t pte) +{ + pte_set_bits(pte, _PAGE_RW); + return(pte_mknewprot(pte)); +} + +static inline pte_t pte_mkuptodate(pte_t pte) +{ + pte_clear_bits(pte, _PAGE_NEWPAGE); + if(pte_present(pte)) + pte_clear_bits(pte, _PAGE_NEWPROT); + return(pte); +} + +static inline pte_t pte_mknewpage(pte_t pte) +{ + pte_set_bits(pte, _PAGE_NEWPAGE); + return(pte); +} + +static inline pte_t pte_mkspecial(pte_t pte) +{ + return(pte); +} + +static inline void set_pte(pte_t *pteptr, pte_t pteval) +{ + pte_copy(*pteptr, pteval); + + /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so + * fix_range knows to unmap it. _PAGE_NEWPROT is specific to + * mapped pages. + */ + + *pteptr = pte_mknewpage(*pteptr); + if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr); +} +#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) + +#define __HAVE_ARCH_PTE_SAME +static inline int pte_same(pte_t pte_a, pte_t pte_b) +{ + return !((pte_val(pte_a) ^ pte_val(pte_b)) & ~_PAGE_NEWPAGE); +} + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ + +#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys)) +#define __virt_to_page(virt) phys_to_page(__pa(virt)) +#define page_to_phys(page) pfn_to_phys((pfn_t) page_to_pfn(page)) +#define virt_to_page(addr) __virt_to_page((const unsigned long) addr) + +#define mk_pte(page, pgprot) \ + ({ pte_t pte; \ + \ + pte_set_val(pte, page_to_phys(page), (pgprot)); \ + if (pte_present(pte)) \ + pte_mknewprot(pte_mknewpage(pte)); \ + pte;}) + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + pte_set_val(pte, (pte_val(pte) & _PAGE_CHG_MASK), newprot); + return pte; +} + +/* + * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD] + * + * this macro returns the index of the entry in the pgd page which would + * control the given virtual address + */ +#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) + +/* + * pgd_offset() returns a (pgd_t *) + * pgd_index() is used get the offset into the pgd page's array of pgd_t's; + */ +#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) + +/* + * a shortcut which implies the use of the kernel's pgd, instead + * of a process's + */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +/* + * the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD] + * + * this macro returns the index of the entry in the pmd page which would + * control the given virtual address + */ +#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) +#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) + +#define pmd_page_vaddr(pmd) \ + ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) + +/* + * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] + * + * this macro returns the index of the entry in the pte page which would + * control the given virtual address + */ +#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset_kernel(dir, address) \ + ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address)) +#define pte_offset_map(dir, address) \ + ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address)) +#define pte_unmap(pte) do { } while (0) + +struct mm_struct; +extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr); + +#define update_mmu_cache(vma,address,ptep) do ; while (0) + +/* Encode and de-code a swap entry */ +#define __swp_type(x) (((x).val >> 5) & 0x1f) +#define __swp_offset(x) ((x).val >> 11) + +#define __swp_entry(type, offset) \ + ((swp_entry_t) { ((type) << 5) | ((offset) << 11) }) +#define __pte_to_swp_entry(pte) \ + ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +#define kern_addr_valid(addr) (1) + +#include <asm-generic/pgtable.h> + +/* Clear a kernel PTE and flush it from the TLB */ +#define kpte_clear_flush(ptep, vaddr) \ +do { \ + pte_clear(&init_mm, (vaddr), (ptep)); \ + __flush_tlb_one((vaddr)); \ +} while (0) + +#endif diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h new file mode 100644 index 00000000000..cbc5edd5a90 --- /dev/null +++ b/arch/um/include/asm/processor-generic.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __UM_PROCESSOR_GENERIC_H +#define __UM_PROCESSOR_GENERIC_H + +struct pt_regs; + +struct task_struct; + +#include <asm/ptrace.h> +#include <registers.h> +#include <sysdep/archsetjmp.h> + +#include <linux/prefetch.h> + +struct mm_struct; + +struct thread_struct { + struct pt_regs regs; + struct pt_regs *segv_regs; + int singlestep_syscall; + void *fault_addr; + jmp_buf *fault_catcher; + struct task_struct *prev_sched; + struct arch_thread arch; + jmp_buf switch_buf; + struct { + int op; + union { + struct { + int pid; + } fork, exec; + struct { + int (*proc)(void *); + void *arg; + } thread; + struct { + void (*proc)(void *); + void *arg; + } cb; + } u; + } request; +}; + +#define INIT_THREAD \ +{ \ + .regs = EMPTY_REGS, \ + .fault_addr = NULL, \ + .prev_sched = NULL, \ + .arch = INIT_ARCH_THREAD, \ + .request = { 0 } \ +} + +static inline void release_thread(struct task_struct *task) +{ +} + +extern unsigned long thread_saved_pc(struct task_struct *t); + +static inline void mm_copy_segments(struct mm_struct *from_mm, + struct mm_struct *new_mm) +{ +} + +#define init_stack (init_thread_union.stack) + +/* + * User space process size: 3GB (default). + */ +extern unsigned long task_size; + +#define TASK_SIZE (task_size) + +#undef STACK_TOP +#undef STACK_TOP_MAX + +extern unsigned long stacksizelim; + +#define STACK_ROOM (stacksizelim) +#define STACK_TOP (TASK_SIZE - 2 * PAGE_SIZE) +#define STACK_TOP_MAX STACK_TOP + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (0x40000000) + +extern void start_thread(struct pt_regs *regs, unsigned long entry, + unsigned long stack); + +struct cpuinfo_um { + unsigned long loops_per_jiffy; + int ipi_pipe[2]; +}; + +extern struct cpuinfo_um boot_cpu_data; + +#define my_cpu_data cpu_data[smp_processor_id()] + +#ifdef CONFIG_SMP +extern struct cpuinfo_um cpu_data[]; +#define current_cpu_data cpu_data[smp_processor_id()] +#else +#define cpu_data (&boot_cpu_data) +#define current_cpu_data boot_cpu_data +#endif + + +#define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf) +extern unsigned long get_wchan(struct task_struct *p); + +#endif diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h new file mode 100644 index 00000000000..cb9b3c47ca8 --- /dev/null +++ b/arch/um/include/asm/ptrace-generic.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __UM_PTRACE_GENERIC_H +#define __UM_PTRACE_GENERIC_H + +#ifndef __ASSEMBLY__ + +#include <asm/ptrace-abi.h> +#include <sysdep/ptrace.h> + +struct pt_regs { + struct uml_pt_regs regs; +}; + +#define arch_has_single_step() (1) + +#define EMPTY_REGS { .regs = EMPTY_UML_PT_REGS } + +#define PT_REGS_IP(r) UPT_IP(&(r)->regs) +#define PT_REGS_SP(r) UPT_SP(&(r)->regs) + +#define PT_REGS_RESTART_SYSCALL(r) UPT_RESTART_SYSCALL(&(r)->regs) + +#define PT_REGS_SYSCALL_NR(r) UPT_SYSCALL_NR(&(r)->regs) + +#define instruction_pointer(regs) PT_REGS_IP(regs) + +struct task_struct; + +extern long subarch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data); +extern unsigned long getreg(struct task_struct *child, int regno); +extern int putreg(struct task_struct *child, int regno, unsigned long value); + +extern int arch_copy_tls(struct task_struct *new); +extern void clear_flushed_tls(struct task_struct *task); +extern void syscall_trace_enter(struct pt_regs *regs); +extern void syscall_trace_leave(struct pt_regs *regs); + +#endif + +#endif diff --git a/arch/um/include/asm/setup.h b/arch/um/include/asm/setup.h new file mode 100644 index 00000000000..99f086301f4 --- /dev/null +++ b/arch/um/include/asm/setup.h @@ -0,0 +1,10 @@ +#ifndef SETUP_H_INCLUDED +#define SETUP_H_INCLUDED + +/* POSIX mandated with _POSIX_ARG_MAX that we can rely on 4096 chars in the + * command line, so this choice is ok. + */ + +#define COMMAND_LINE_SIZE 4096 + +#endif /* SETUP_H_INCLUDED */ diff --git a/arch/um/include/asm/smp.h b/arch/um/include/asm/smp.h new file mode 100644 index 00000000000..e4507938d8c --- /dev/null +++ b/arch/um/include/asm/smp.h @@ -0,0 +1,32 @@ +#ifndef __UM_SMP_H +#define __UM_SMP_H + +#ifdef CONFIG_SMP + +#include <linux/bitops.h> +#include <asm/current.h> +#include <linux/cpumask.h> + +#define raw_smp_processor_id() (current_thread->cpu) + +#define cpu_logical_map(n) (n) +#define cpu_number_map(n) (n) +extern int hard_smp_processor_id(void); +#define NO_PROC_ID -1 + +extern int ncpus; + + +static inline void smp_cpus_done(unsigned int maxcpus) +{ +} + +extern struct task_struct *idle_threads[NR_CPUS]; + +#else + +#define hard_smp_processor_id() 0 + +#endif + +#endif diff --git a/arch/um/include/sysrq.h b/arch/um/include/asm/sysrq.h index c8d332b56b9..c8d332b56b9 100644 --- a/arch/um/include/sysrq.h +++ b/arch/um/include/asm/sysrq.h diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h new file mode 100644 index 00000000000..1c5b2a83046 --- /dev/null +++ b/arch/um/include/asm/thread_info.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __UM_THREAD_INFO_H +#define __UM_THREAD_INFO_H + +#ifndef __ASSEMBLY__ + +#include <asm/types.h> +#include <asm/page.h> +#include <asm/uaccess.h> + +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + __u32 cpu; /* current CPU */ + int preempt_count; /* 0 => preemptable, + <0 => BUG */ + mm_segment_t addr_limit; /* thread address space: + 0-0xBFFFFFFF for user + 0-0xFFFFFFFF for kernel */ + struct restart_block restart_block; + struct thread_info *real_thread; /* Points to non-IRQ stack */ +}; + +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = INIT_PREEMPT_COUNT, \ + .addr_limit = KERNEL_DS, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ + .real_thread = NULL, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + +#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE) +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + struct thread_info *ti; + unsigned long mask = THREAD_SIZE - 1; + void *p; + + asm volatile ("" : "=r" (p) : "0" (&ti)); + ti = (struct thread_info *) (((unsigned long)p) & ~mask); + return ti; +} + +#define THREAD_SIZE_ORDER CONFIG_KERNEL_STACK_ORDER + +#endif + +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_SIGPENDING 1 /* signal pending */ +#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ +#define TIF_RESTART_BLOCK 4 +#define TIF_MEMDIE 5 /* is terminating due to OOM killer */ +#define TIF_SYSCALL_AUDIT 6 +#define TIF_RESTORE_SIGMASK 7 +#define TIF_NOTIFY_RESUME 8 + +#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_MEMDIE (1 << TIF_MEMDIE) +#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) + +#endif diff --git a/arch/um/include/asm/timex.h b/arch/um/include/asm/timex.h new file mode 100644 index 00000000000..0f4ada08f74 --- /dev/null +++ b/arch/um/include/asm/timex.h @@ -0,0 +1,13 @@ +#ifndef __UM_TIMEX_H +#define __UM_TIMEX_H + +typedef unsigned long cycles_t; + +static inline cycles_t get_cycles (void) +{ + return 0; +} + +#define CLOCK_TICK_RATE (HZ) + +#endif diff --git a/arch/um/include/asm/tlb.h b/arch/um/include/asm/tlb.h new file mode 100644 index 00000000000..16eb63fac57 --- /dev/null +++ b/arch/um/include/asm/tlb.h @@ -0,0 +1,134 @@ +#ifndef __UM_TLB_H +#define __UM_TLB_H + +#include <linux/pagemap.h> +#include <linux/swap.h> +#include <asm/percpu.h> +#include <asm/pgalloc.h> +#include <asm/tlbflush.h> + +#define tlb_start_vma(tlb, vma) do { } while (0) +#define tlb_end_vma(tlb, vma) do { } while (0) +#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) + +/* struct mmu_gather is an opaque type used by the mm code for passing around + * any data needed by arch specific code for tlb_remove_page. + */ +struct mmu_gather { + struct mm_struct *mm; + unsigned int need_flush; /* Really unmapped some ptes? */ + unsigned long start; + unsigned long end; + unsigned int fullmm; /* non-zero means full mm flush */ +}; + +static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, + unsigned long address) +{ + if (tlb->start > address) + tlb->start = address; + if (tlb->end < address + PAGE_SIZE) + tlb->end = address + PAGE_SIZE; +} + +static inline void init_tlb_gather(struct mmu_gather *tlb) +{ + tlb->need_flush = 0; + + tlb->start = TASK_SIZE; + tlb->end = 0; + + if (tlb->fullmm) { + tlb->start = 0; + tlb->end = TASK_SIZE; + } +} + +static inline void +tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end) +{ + tlb->mm = mm; + tlb->start = start; + tlb->end = end; + tlb->fullmm = !(start | (end+1)); + + init_tlb_gather(tlb); +} + +extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, + unsigned long end); + +static inline void +tlb_flush_mmu_tlbonly(struct mmu_gather *tlb) +{ + flush_tlb_mm_range(tlb->mm, tlb->start, tlb->end); +} + +static inline void +tlb_flush_mmu_free(struct mmu_gather *tlb) +{ + init_tlb_gather(tlb); +} + +static inline void +tlb_flush_mmu(struct mmu_gather *tlb) +{ + if (!tlb->need_flush) + return; + + tlb_flush_mmu_tlbonly(tlb); + tlb_flush_mmu_free(tlb); +} + +/* tlb_finish_mmu + * Called at the end of the shootdown operation to free up any resources + * that were required. + */ +static inline void +tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) +{ + tlb_flush_mmu(tlb); + + /* keep the page table cache within bounds */ + check_pgt_cache(); +} + +/* tlb_remove_page + * Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), + * while handling the additional races in SMP caused by other CPUs + * caching valid mappings in their TLBs. + */ +static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) +{ + tlb->need_flush = 1; + free_page_and_swap_cache(page); + return 1; /* avoid calling tlb_flush_mmu */ +} + +static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) +{ + __tlb_remove_page(tlb, page); +} + +/** + * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation. + * + * Record the fact that pte's were really umapped in ->need_flush, so we can + * later optimise away the tlb invalidate. This helps when userspace is + * unmapping already-unmapped pages, which happens quite a lot. + */ +#define tlb_remove_tlb_entry(tlb, ptep, address) \ + do { \ + tlb->need_flush = 1; \ + __tlb_remove_tlb_entry(tlb, ptep, address); \ + } while (0) + +#define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr) + +#define pud_free_tlb(tlb, pudp, addr) __pud_free_tlb(tlb, pudp, addr) + +#define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr) + +#define tlb_migrate_finish(mm) do {} while (0) + +#endif diff --git a/arch/um/include/asm/tlbflush.h b/arch/um/include/asm/tlbflush.h new file mode 100644 index 00000000000..614f2c09117 --- /dev/null +++ b/arch/um/include/asm/tlbflush.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __UM_TLBFLUSH_H +#define __UM_TLBFLUSH_H + +#include <linux/mm.h> + +/* + * TLB flushing: + * + * - flush_tlb() flushes the current mm struct TLBs + * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_kernel_vm() flushes the kernel vm area + * - flush_tlb_range(vma, start, end) flushes a range of pages + */ + +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long address); +extern void flush_tlb_kernel_vm(void); +extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); +extern void __flush_tlb_one(unsigned long addr); + +#endif diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/asm/uaccess.h index 2b6fc8e0f07..3f22fbf7ca1 100644 --- a/arch/um/include/um_uaccess.h +++ b/arch/um/include/asm/uaccess.h @@ -1,14 +1,42 @@ /* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -#ifndef __ARCH_UM_UACCESS_H -#define __ARCH_UM_UACCESS_H +#ifndef __UM_UACCESS_H +#define __UM_UACCESS_H +/* thread_info has a mm_segment_t in it, so put the definition up here */ +typedef struct { + unsigned long seg; +} mm_segment_t; + +#include <linux/thread_info.h> +#include <linux/errno.h> +#include <asm/processor.h> #include <asm/elf.h> -#include <asm/fixmap.h> -#include "sysdep/archsetjmp.h" + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons, these macros are grossly misnamed. + */ + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) + +#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) +#define USER_DS MAKE_MM_SEG(TASK_SIZE) + +#define get_ds() (KERNEL_DS) +#define get_fs() (current_thread_info()->addr_limit) +#define set_fs(x) (current_thread_info()->addr_limit = (x)) + +#define segment_eq(a, b) ((a).seg == (b).seg) #define __under_task_size(addr, size) \ (((unsigned long) (addr) < TASK_SIZE) && \ @@ -32,10 +60,6 @@ extern int copy_from_user(void *to, const void __user *from, int n); extern int copy_to_user(void __user *to, const void *from, int n); -extern int __do_copy_to_user(void *to, const void *from, int n, - void **fault_addr, jmp_buf **fault_catcher); -extern void __do_copy(void *to, const void *from, int n); - /* * strncpy_from_user: - Copy a NUL terminated string from userspace. * @dst: Destination address, in kernel space. This buffer must be at @@ -95,4 +119,60 @@ extern int clear_user(void __user *mem, int len); */ extern int strnlen_user(const void __user *str, int len); +#define __copy_from_user(to, from, n) copy_from_user(to, from, n) + +#define __copy_to_user(to, from, n) copy_to_user(to, from, n) + +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + +#define __get_user(x, ptr) \ +({ \ + const __typeof__(*(ptr)) __user *__private_ptr = (ptr); \ + __typeof__(x) __private_val; \ + int __private_ret = -EFAULT; \ + (x) = (__typeof__(*(__private_ptr)))0; \ + if (__copy_from_user((__force void *)&__private_val, (__private_ptr),\ + sizeof(*(__private_ptr))) == 0) { \ + (x) = (__typeof__(*(__private_ptr))) __private_val; \ + __private_ret = 0; \ + } \ + __private_ret; \ +}) + +#define get_user(x, ptr) \ +({ \ + const __typeof__((*(ptr))) __user *private_ptr = (ptr); \ + (access_ok(VERIFY_READ, private_ptr, sizeof(*private_ptr)) ? \ + __get_user(x, private_ptr) : ((x) = (__typeof__(*ptr))0, -EFAULT)); \ +}) + +#define __put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) __user *__private_ptr = ptr; \ + __typeof__(*(__private_ptr)) __private_val; \ + int __private_ret = -EFAULT; \ + __private_val = (__typeof__(*(__private_ptr))) (x); \ + if (__copy_to_user((__private_ptr), &__private_val, \ + sizeof(*(__private_ptr))) == 0) { \ + __private_ret = 0; \ + } \ + __private_ret; \ +}) + +#define put_user(x, ptr) \ +({ \ + __typeof__(*(ptr)) __user *private_ptr = (ptr); \ + (access_ok(VERIFY_WRITE, private_ptr, sizeof(*private_ptr)) ? \ + __put_user(x, private_ptr) : -EFAULT); \ +}) + +#define strlen_user(str) strnlen_user(str, ~0U >> 1) + +struct exception_table_entry +{ + unsigned long insn; + unsigned long fixup; +}; + #endif diff --git a/arch/um/include/frame_kern.h b/arch/um/include/frame_kern.h deleted file mode 100644 index ce9514f5721..00000000000 --- a/arch/um/include/frame_kern.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __FRAME_KERN_H_ -#define __FRAME_KERN_H_ - -#define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) - -extern int setup_signal_stack_sc(unsigned long stack_top, int sig, - struct k_sigaction *ka, - struct pt_regs *regs, - sigset_t *mask); -extern int setup_signal_stack_si(unsigned long stack_top, int sig, - struct k_sigaction *ka, - struct pt_regs *regs, siginfo_t *info, - sigset_t *mask); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/initrd.h b/arch/um/include/initrd.h deleted file mode 100644 index 439b9a81498..00000000000 --- a/arch/um/include/initrd.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __INITRD_USER_H__ -#define __INITRD_USER_H__ - -extern int load_initrd(char *filename, void *buf, int size); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h deleted file mode 100644 index 4f775597fd5..00000000000 --- a/arch/um/include/irq_kern.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __IRQ_KERN_H__ -#define __IRQ_KERN_H__ - -#include "linux/interrupt.h" -#include "asm/ptrace.h" - -extern int um_request_irq(unsigned int irq, int fd, int type, - 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: - */ diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h deleted file mode 100644 index 4ce3fc650e5..00000000000 --- a/arch/um/include/kern.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __KERN_H__ -#define __KERN_H__ - -/* These are all user-mode things which are convenient to call directly - * from kernel code and for which writing a wrapper is too much of a pain. - * The regular include files can't be included because this file is included - * only into kernel code, and user-space includes conflict with kernel - * includes. - */ - -extern int errno; - -extern int clone(int (*proc)(void *), void *sp, int flags, void *data); -extern int sleep(int); -extern int printf(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 - diff --git a/arch/um/include/mem_kern.h b/arch/um/include/mem_kern.h deleted file mode 100644 index cb7e196d366..00000000000 --- a/arch/um/include/mem_kern.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#ifndef __MEM_KERN_H__ -#define __MEM_KERN_H__ - -#include "linux/list.h" -#include "linux/types.h" - -struct remapper { - struct list_head list; - int (*proc)(int, unsigned long, int, __u64); -}; - -extern void register_remapper(struct remapper *info); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/process.h b/arch/um/include/process.h deleted file mode 100644 index 5af9157ff54..00000000000 --- a/arch/um/include/process.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __PROCESS_H__ -#define __PROCESS_H__ - -#include <signal.h> - -extern void sig_handler(int sig, struct sigcontext sc); -extern void alarm_handler(int sig, struct sigcontext sc); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/aio.h b/arch/um/include/shared/aio.h index 423bae9153f..423bae9153f 100644 --- a/arch/um/include/aio.h +++ b/arch/um/include/shared/aio.h diff --git a/arch/um/include/arch.h b/arch/um/include/shared/arch.h index 2de92a08a76..4f46abda060 100644 --- a/arch/um/include/arch.h +++ b/arch/um/include/shared/arch.h @@ -6,7 +6,7 @@ #ifndef __ARCH_H__ #define __ARCH_H__ -#include "sysdep/ptrace.h" +#include <sysdep/ptrace.h> extern void arch_check_bugs(void); extern int arch_fixup(unsigned long address, struct uml_pt_regs *regs); diff --git a/arch/um/include/as-layout.h b/arch/um/include/shared/as-layout.h index cac542d8ff7..41c8c774ec1 100644 --- a/arch/um/include/as-layout.h +++ b/arch/um/include/shared/as-layout.h @@ -6,8 +6,7 @@ #ifndef __START_H__ #define __START_H__ -#include "uml-config.h" -#include "kern_constants.h" +#include <generated/asm-offsets.h> /* * Stolen from linux/const.h, which can't be directly included since @@ -23,20 +22,20 @@ */ #ifdef __ASSEMBLY__ -#define _AC(X, Y) (Y) +#define _UML_AC(X, Y) (Y) #else -#define __AC(X, Y) (X (Y)) -#define _AC(X, Y) __AC(X, Y) +#define __UML_AC(X, Y) (X(Y)) +#define _UML_AC(X, Y) __UML_AC(X, Y) #endif -#define STUB_START _AC(, 0x100000) -#define STUB_CODE _AC((unsigned long), STUB_START) -#define STUB_DATA _AC((unsigned long), STUB_CODE + UM_KERN_PAGE_SIZE) -#define STUB_END _AC((unsigned long), STUB_DATA + UM_KERN_PAGE_SIZE) +#define STUB_START _UML_AC(, 0x100000) +#define STUB_CODE _UML_AC((unsigned long), STUB_START) +#define STUB_DATA _UML_AC((unsigned long), STUB_CODE + UM_KERN_PAGE_SIZE) +#define STUB_END _UML_AC((unsigned long), STUB_DATA + UM_KERN_PAGE_SIZE) #ifndef __ASSEMBLY__ -#include "sysdep/ptrace.h" +#include <sysdep/ptrace.h> struct cpu_task { int pid; @@ -45,7 +44,6 @@ struct cpu_task { extern struct cpu_task cpu_tasks[]; -extern unsigned long low_physmem; extern unsigned long high_physmem; extern unsigned long uml_physmem; extern unsigned long uml_reserved; @@ -53,15 +51,14 @@ extern unsigned long end_vm; extern unsigned long start_vm; extern unsigned long long highmem; -extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; -extern unsigned long _unprotected_end; extern unsigned long brk_start; extern unsigned long host_task_size; extern int linux_main(int argc, char **argv); -extern void (*sig_info[])(int, struct uml_pt_regs *); +struct siginfo; +extern void (*sig_info[])(int, struct siginfo *si, struct uml_pt_regs *); #endif diff --git a/arch/um/include/common-offsets.h b/arch/um/include/shared/common-offsets.h index b54bd35585c..c9230680902 100644 --- a/arch/um/include/common-offsets.h +++ b/arch/um/include/shared/common-offsets.h @@ -2,24 +2,11 @@ DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE); -OFFSET(HOST_TASK_REGS, task_struct, thread.regs); -OFFSET(HOST_TASK_PID, task_struct, pid); - DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE); DEFINE(UM_KERN_PAGE_MASK, PAGE_MASK); DEFINE(UM_KERN_PAGE_SHIFT, PAGE_SHIFT); DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC); -DEFINE_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_STR(UM_KERN_CONT, KERN_CONT); - DEFINE(UM_ELF_CLASS, ELF_CLASS); DEFINE(UM_ELFCLASS32, ELFCLASS32); DEFINE(UM_ELFCLASS64, ELFCLASS64); @@ -39,3 +26,16 @@ DEFINE(UM_HZ, HZ); DEFINE(UM_USEC_PER_SEC, USEC_PER_SEC); DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC); DEFINE(UM_NSEC_PER_USEC, NSEC_PER_USEC); + +#ifdef CONFIG_PRINTK +DEFINE(UML_CONFIG_PRINTK, CONFIG_PRINTK); +#endif +#ifdef CONFIG_NO_HZ_COMMON +DEFINE(UML_CONFIG_NO_HZ_COMMON, CONFIG_NO_HZ_COMMON); +#endif +#ifdef CONFIG_UML_X86 +DEFINE(UML_CONFIG_UML_X86, CONFIG_UML_X86); +#endif +#ifdef CONFIG_64BIT +DEFINE(UML_CONFIG_64BIT, CONFIG_64BIT); +#endif diff --git a/arch/um/include/elf_user.h b/arch/um/include/shared/elf_user.h index 53516b63727..53516b63727 100644 --- a/arch/um/include/elf_user.h +++ b/arch/um/include/shared/elf_user.h diff --git a/arch/um/include/shared/frame_kern.h b/arch/um/include/shared/frame_kern.h new file mode 100644 index 00000000000..f2ca5702a4e --- /dev/null +++ b/arch/um/include/shared/frame_kern.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __FRAME_KERN_H_ +#define __FRAME_KERN_H_ + +extern int setup_signal_stack_sc(unsigned long stack_top, int sig, + struct k_sigaction *ka, + struct pt_regs *regs, + sigset_t *mask); +extern int setup_signal_stack_si(unsigned long stack_top, int sig, + struct k_sigaction *ka, + struct pt_regs *regs, struct siginfo *info, + sigset_t *mask); + +#endif + diff --git a/arch/um/include/init.h b/arch/um/include/shared/init.h index b00a95741d4..b3906f860a8 100644 --- a/arch/um/include/init.h +++ b/arch/um/include/shared/init.h @@ -27,7 +27,7 @@ * sign followed by value, e.g.: * * static int init_variable __initdata = 0; - * static char linux_logo[] __initdata = { 0x32, 0x36, ... }; + * static const char linux_logo[] __initconst = { 0x32, 0x36, ... }; * * Don't forget to initialize data not at file scope, i.e. within a function, * as gcc otherwise puts the data into the bss section and not into the init @@ -45,6 +45,8 @@ typedef void (*exitcall_t)(void); # define __section(S) __attribute__ ((__section__(#S))) #endif +#if __GNUC__ == 3 + #if __GNUC_MINOR__ >= 3 # define __used __attribute__((__used__)) #else @@ -52,6 +54,12 @@ typedef void (*exitcall_t)(void); #endif #else +#if __GNUC__ == 4 +# define __used __attribute__((__used__)) +#endif +#endif + +#else #include <linux/compiler.h> #endif /* These are for everybody (although not all archs will actually diff --git a/arch/um/include/shared/irq_kern.h b/arch/um/include/shared/irq_kern.h new file mode 100644 index 00000000000..e05bd667de1 --- /dev/null +++ b/arch/um/include/shared/irq_kern.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __IRQ_KERN_H__ +#define __IRQ_KERN_H__ + +#include <linux/interrupt.h> +#include <asm/ptrace.h> + +extern int um_request_irq(unsigned int irq, int fd, int type, + irq_handler_t handler, + unsigned long irqflags, const char * devname, + void *dev_id); +void um_free_irq(unsigned int irq, void *dev); +#endif + diff --git a/arch/um/include/irq_user.h b/arch/um/include/shared/irq_user.h index e60b31873de..df563305395 100644 --- a/arch/um/include/irq_user.h +++ b/arch/um/include/shared/irq_user.h @@ -6,7 +6,7 @@ #ifndef __IRQ_USER_H__ #define __IRQ_USER_H__ -#include "sysdep/ptrace.h" +#include <sysdep/ptrace.h> struct irq_fd { struct irq_fd *next; @@ -20,9 +20,8 @@ struct irq_fd { enum { IRQ_READ, IRQ_WRITE }; -extern void sigio_handler(int sig, struct 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); +struct siginfo; +extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); extern void free_irq_by_fd(int fd); extern void reactivate_fd(int fd, int irqnum); extern void deactivate_fd(int fd, int irqnum); diff --git a/arch/um/include/shared/kern.h b/arch/um/include/shared/kern.h new file mode 100644 index 00000000000..6cd01240bbf --- /dev/null +++ b/arch/um/include/shared/kern.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __KERN_H__ +#define __KERN_H__ + +/* These are all user-mode things which are convenient to call directly + * from kernel code and for which writing a wrapper is too much of a pain. + * The regular include files can't be included because this file is included + * only into kernel code, and user-space includes conflict with kernel + * includes. + */ + +extern int printf(const char *fmt, ...); +extern void *sbrk(int increment); +extern int pause(void); +extern void exit(int); + +#endif + diff --git a/arch/um/include/kern_util.h b/arch/um/include/shared/kern_util.h index 3c341222d25..83a91f97633 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/shared/kern_util.h @@ -6,8 +6,10 @@ #ifndef __KERN_UTIL_H__ #define __KERN_UTIL_H__ -#include "sysdep/ptrace.h" -#include "sysdep/faultinfo.h" +#include <sysdep/ptrace.h> +#include <sysdep/faultinfo.h> + +struct siginfo; extern int uml_exitcode; @@ -21,9 +23,8 @@ extern unsigned long alloc_stack(int order, int atomic); extern void free_stack(unsigned long stack, int order); extern int do_signal(void); -extern void copy_sc(struct uml_pt_regs *regs, void *from); extern void interrupt_end(void); -extern void relay_signal(int sig, struct uml_pt_regs *regs); +extern void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs); extern unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, struct uml_pt_regs *regs); @@ -34,9 +35,8 @@ extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs); extern int smp_sigio_handler(void); extern void initial_thread_cb(void (*proc)(void *), void *arg); extern int is_syscall(unsigned long addr); -extern void timer_handler(int sig, struct uml_pt_regs *regs); -extern void timer_handler(int sig, struct uml_pt_regs *regs); +extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); extern int start_uml(void); extern void paging_init(void); @@ -49,7 +49,7 @@ extern void do_uml_exitcalls(void); * GFP_ATOMIC. */ extern int __cant_sleep(void); -extern void *get_current(void); +extern int get_current_pid(void); extern int copy_from_user_proc(void *to, void *from, int size); extern int cpu(void); extern char *uml_strdup(const char *string); @@ -60,9 +60,9 @@ extern unsigned long from_irq_stack(int nested); extern void syscall_trace(struct uml_pt_regs *regs, int entryexit); extern int singlestepping(void *t); -extern void segv_handler(int sig, struct uml_pt_regs *regs); -extern void bus_handler(int sig, struct uml_pt_regs *regs); -extern void winch(int sig, struct uml_pt_regs *regs); +extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); +extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs); +extern void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); extern void fatal_sigsegv(void) __attribute__ ((noreturn)); diff --git a/arch/um/include/longjmp.h b/arch/um/include/shared/longjmp.h index e860bc5848e..9bdddf4c405 100644 --- a/arch/um/include/longjmp.h +++ b/arch/um/include/shared/longjmp.h @@ -1,8 +1,8 @@ #ifndef __UML_LONGJMP_H #define __UML_LONGJMP_H -#include "sysdep/archsetjmp.h" -#include "os.h" +#include <sysdep/archsetjmp.h> +#include <os.h> extern int setjmp(jmp_buf); extern void longjmp(jmp_buf, int); diff --git a/arch/um/include/mem.h b/arch/um/include/shared/mem.h index 5cd40e99e8d..5cd40e99e8d 100644 --- a/arch/um/include/mem.h +++ b/arch/um/include/shared/mem.h diff --git a/arch/um/include/mem_user.h b/arch/um/include/shared/mem_user.h index 46384acd547..46384acd547 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/shared/mem_user.h diff --git a/arch/um/include/net_kern.h b/arch/um/include/shared/net_kern.h index d843c7924a7..012ac87d490 100644 --- a/arch/um/include/net_kern.h +++ b/arch/um/include/shared/net_kern.h @@ -18,7 +18,6 @@ struct uml_net { struct net_device *dev; struct platform_device pdev; int index; - unsigned char mac[ETH_ALEN]; }; struct uml_net_private { @@ -26,7 +25,7 @@ struct uml_net_private { spinlock_t lock; struct net_device *dev; struct timer_list tl; - struct net_device_stats stats; + struct work_struct work; int fd; unsigned char mac[ETH_ALEN]; diff --git a/arch/um/include/net_user.h b/arch/um/include/shared/net_user.h index 63bee158cd8..3dabbe128e4 100644 --- a/arch/um/include/net_user.h +++ b/arch/um/include/shared/net_user.h @@ -8,7 +8,7 @@ #define ETH_ADDR_LEN (6) #define ETH_HEADER_ETHERTAP (16) -#define ETH_HEADER_OTHER (14) +#define ETH_HEADER_OTHER (26) /* 14 for ethernet + VLAN + MPLS for crazy people */ #define ETH_MAX_PACKET (1500) #define UML_NET_VERSION (4) diff --git a/arch/um/include/os.h b/arch/um/include/shared/os.h index 32c799e3a49..08eec0b691b 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/shared/os.h @@ -7,11 +7,9 @@ #define __OS_H__ #include <stdarg.h> -#include "irq_user.h" -#include "longjmp.h" -#include "mm_id.h" -#include "sysdep/tls.h" -#include "../os/include/file.h" +#include <irq_user.h> +#include <longjmp.h> +#include <mm_id.h> #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) @@ -30,6 +28,12 @@ #define OS_ACC_R_OK 4 /* Test for read permission. */ #define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ +#ifdef CONFIG_64BIT +#define OS_LIB_PATH "/usr/lib64/" +#else +#define OS_LIB_PATH "/usr/lib/" +#endif + /* * types taken from stat_file() in hostfs_user.c * (if they are wrong here, they are wrong there...). @@ -132,11 +136,13 @@ extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); extern int os_get_ifname(int fd, char *namebuf); extern int os_set_slip(int fd); extern int os_mode_fd(int fd, int mode); +extern int os_fsync_file(int fd); extern int os_seek_file(int fd, unsigned long long offset); extern int os_open_file(const char *file, struct openflags flags, int mode); extern int os_read_file(int fd, void *buf, int len); extern int os_write_file(int fd, const void *buf, int count); +extern int os_sync_file(int fd); extern int os_file_size(const char *file, unsigned long long *size_out); extern int os_file_modtime(const char *file, unsigned long *modtime); extern int os_pipe(int *fd, int stream, int close_on_exec); @@ -162,6 +168,9 @@ extern int os_stat_filesystem(char *path, long *bsize_out, long *spare_out); extern int os_change_dir(char *dir); extern int os_fchange_dir(int fd); +extern unsigned os_major(unsigned long long dev); +extern unsigned os_minor(unsigned long long dev); +extern unsigned long long os_makedev(unsigned major, unsigned minor); /* start_up.c */ extern void os_early_checks(void); @@ -184,7 +193,6 @@ extern int os_getpid(void); extern int os_getpgrp(void); extern void init_new_thread_signals(void); -extern int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr); extern int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, int r, int w, int x); @@ -194,12 +202,7 @@ 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); - -/* uaccess.c */ -extern unsigned long __do_user_copy(void *to, const void *from, int n, - void **fault_addr, jmp_buf **fault_catcher, - void (*op)(void *to, const void *from, - int n), int *faulted_out); +extern int os_mincore(void *addr, unsigned long len); /* execvp.c */ extern int execvp_noalloc(char *buf, const char *file, char *const argv[]); @@ -210,10 +213,6 @@ extern int run_helper_thread(int (*proc)(void *), void *arg, 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); @@ -223,12 +222,13 @@ extern char *get_umid(void); extern void timer_init(void); extern void set_sigstack(void *sig_stack, int size); extern void remove_sigstack(void); -extern void set_handler(int sig, void (*handler)(int), int flags, ...); +extern void set_handler(int sig); extern int change_sig(int signal, int on); extern void block_signals(void); extern void unblock_signals(void); extern int get_signals(void); extern int set_signals(int enable); +extern int os_is_signal_stack(void); /* util.c */ extern void stack_protections(unsigned long address); @@ -236,6 +236,8 @@ extern int raw(int fd); extern void setup_machinename(char *machine_out); extern void setup_hostinfo(char *buf, int len); extern void os_dump_core(void) __attribute__ ((noreturn)); +extern void um_early_printk(const char *s, unsigned int n); +extern void os_fix_helper_signals(void); /* time.c */ extern void idle_sleep(unsigned long long nsecs); @@ -290,6 +292,7 @@ extern void os_set_ioignore(void); extern int add_sigio_fd(int fd); extern int ignore_sigio_fd(int fd); extern void maybe_sigio_broken(int fd, int read); +extern void sigio_broken(int fd, int read); /* sys-x86_64/prctl.c */ extern int os_arch_prctl(int pid, int code, unsigned long *addr); @@ -298,6 +301,6 @@ extern int os_arch_prctl(int pid, int code, unsigned long *addr); extern int get_pty(void); /* sys-$ARCH/task_size.c */ -extern unsigned long os_get_task_size(void); +extern unsigned long os_get_top_address(void); #endif diff --git a/arch/um/include/ptrace_user.h b/arch/um/include/shared/ptrace_user.h index 4bce6e01288..56b2f284b10 100644 --- a/arch/um/include/ptrace_user.h +++ b/arch/um/include/shared/ptrace_user.h @@ -6,7 +6,8 @@ #ifndef __PTRACE_USER_H__ #define __PTRACE_USER_H__ -#include "sysdep/ptrace_user.h" +#include <sys/ptrace.h> +#include <sysdep/ptrace_user.h> extern int ptrace_getregs(long pid, unsigned long *regs_out); extern int ptrace_setregs(long pid, unsigned long *regs_in); @@ -29,7 +30,7 @@ extern int ptrace_setregs(long pid, unsigned long *regs_in); * recompilation. So, we use PTRACE_OLDSETOPTIONS in UML. * We also want to be able to build the kernel on 2.4, which doesn't * have PTRACE_OLDSETOPTIONS. So, if it is missing, we declare - * PTRACE_OLDSETOPTIONS to to be the same as PTRACE_SETOPTIONS. + * PTRACE_OLDSETOPTIONS to be the same as PTRACE_SETOPTIONS. * * On architectures, that start to support PTRACE_O_TRACESYSGOOD on * linux 2.6, PTRACE_OLDSETOPTIONS never is defined, and also isn't diff --git a/arch/um/include/registers.h b/arch/um/include/shared/registers.h index b0b4589e0eb..f5b76355ad7 100644 --- a/arch/um/include/registers.h +++ b/arch/um/include/shared/registers.h @@ -6,8 +6,8 @@ #ifndef __REGISTERS_H #define __REGISTERS_H -#include "sysdep/ptrace.h" -#include "sysdep/archsetjmp.h" +#include <sysdep/ptrace.h> +#include <sysdep/archsetjmp.h> extern int save_fp_registers(int pid, unsigned long *fp_regs); extern int restore_fp_registers(int pid, unsigned long *fp_regs); @@ -16,7 +16,7 @@ extern int restore_fpx_registers(int pid, unsigned long *fp_regs); extern int save_registers(int pid, struct uml_pt_regs *regs); extern int restore_registers(int pid, struct uml_pt_regs *regs); extern int init_registers(int pid); -extern void get_safe_registers(unsigned long *regs); +extern void get_safe_registers(unsigned long *regs, unsigned long *fp_regs); extern unsigned long get_thread_reg(int reg, jmp_buf *buf); extern int get_fp_registers(int pid, unsigned long *regs); extern int put_fp_registers(int pid, unsigned long *regs); diff --git a/arch/um/include/sigio.h b/arch/um/include/shared/sigio.h index 434f1a9ae4b..434f1a9ae4b 100644 --- a/arch/um/include/sigio.h +++ b/arch/um/include/shared/sigio.h diff --git a/arch/um/include/skas/mm_id.h b/arch/um/include/shared/skas/mm_id.h index 48dd0989dda..48dd0989dda 100644 --- a/arch/um/include/skas/mm_id.h +++ b/arch/um/include/shared/skas/mm_id.h diff --git a/arch/um/include/skas/proc_mm.h b/arch/um/include/shared/skas/proc_mm.h index 90280920960..90280920960 100644 --- a/arch/um/include/skas/proc_mm.h +++ b/arch/um/include/shared/skas/proc_mm.h diff --git a/arch/um/include/skas/skas.h b/arch/um/include/shared/skas/skas.h index b073f8a86bd..c45df961c87 100644 --- a/arch/um/include/skas/skas.h +++ b/arch/um/include/shared/skas/skas.h @@ -6,7 +6,7 @@ #ifndef __SKAS_H #define __SKAS_H -#include "sysdep/ptrace.h" +#include <sysdep/ptrace.h> extern int userspace_pid[]; extern int proc_mm, ptrace_faultinfo, ptrace_ldt; @@ -16,7 +16,6 @@ extern int user_thread(unsigned long stack, int flags); extern void new_thread_handler(void); extern void handle_syscall(struct uml_pt_regs *regs); extern int new_mm(unsigned long stack); -extern void get_skas_faultinfo(int pid, struct faultinfo * fi); extern long execute_syscall_skas(void *r); extern unsigned long current_stub_stack(void); diff --git a/arch/um/include/skas/stub-data.h b/arch/um/include/shared/skas/stub-data.h index f6ed92c3727..f6ed92c3727 100644 --- a/arch/um/include/skas/stub-data.h +++ b/arch/um/include/shared/skas/stub-data.h diff --git a/arch/um/include/shared/skas_ptrace.h b/arch/um/include/shared/skas_ptrace.h new file mode 100644 index 00000000000..630a9c92b93 --- /dev/null +++ b/arch/um/include/shared/skas_ptrace.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_PTRACE_H +#define __SKAS_PTRACE_H + +#define PTRACE_FAULTINFO 52 +#define PTRACE_SWITCH_MM 55 + +#include <sysdep/skas_ptrace.h> + +#endif diff --git a/arch/um/include/um_malloc.h b/arch/um/include/shared/um_malloc.h index 0ad17cb83d9..6395fef6b69 100644 --- a/arch/um/include/um_malloc.h +++ b/arch/um/include/shared/um_malloc.h @@ -6,17 +6,14 @@ #ifndef __UM_MALLOC_H__ #define __UM_MALLOC_H__ -#include "kern_constants.h" - -extern void *__kmalloc(int size, int flags); -static inline void *kmalloc(int size, int flags) -{ - return __kmalloc(size, flags); -} +#include <generated/asm-offsets.h> +extern void *uml_kmalloc(int size, int flags); extern void kfree(const void *ptr); extern void *vmalloc(unsigned long size); extern void vfree(void *ptr); #endif /* __UM_MALLOC_H__ */ + + diff --git a/arch/um/include/user.h b/arch/um/include/shared/user.h index 1723fac6f40..cef06856333 100644 --- a/arch/um/include/user.h +++ b/arch/um/include/shared/user.h @@ -6,7 +6,7 @@ #ifndef __USER_H__ #define __USER_H__ -#include "uml-config.h" +#include <generated/asm-offsets.h> /* * The usual definition - copied here because the kernel provides its own, @@ -26,6 +26,17 @@ extern void panic(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +/* Requires preincluding include/linux/kern_levels.h */ +#define UM_KERN_EMERG KERN_EMERG +#define UM_KERN_ALERT KERN_ALERT +#define UM_KERN_CRIT KERN_CRIT +#define UM_KERN_ERR KERN_ERR +#define UM_KERN_WARNING KERN_WARNING +#define UM_KERN_NOTICE KERN_NOTICE +#define UM_KERN_INFO KERN_INFO +#define UM_KERN_DEBUG KERN_DEBUG +#define UM_KERN_CONT KERN_CONT + #ifdef UML_CONFIG_PRINTK extern int printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); @@ -36,10 +47,11 @@ static inline int printk(const char *fmt, ...) } #endif -extern void schedule(void); extern int in_aton(char *str); -extern int open_gdb_chan(void); extern size_t strlcpy(char *, const char *, size_t); extern size_t strlcat(char *, const char *, size_t); +/* Copied from linux/compiler-gcc.h since we can't include it directly */ +#define barrier() __asm__ __volatile__("": : :"memory") + #endif diff --git a/arch/um/include/sigcontext.h b/arch/um/include/sigcontext.h deleted file mode 100644 index 59816ca7a8d..00000000000 --- a/arch/um/include/sigcontext.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __UML_SIGCONTEXT_H__ -#define __UML_SIGCONTEXT_H__ - -#include "sysdep/sigcontext.h" - -extern int sc_size(void *data); -extern void sc_to_sc(void *to_ptr, void *from_ptr); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/skas_ptrace.h b/arch/um/include/skas_ptrace.h deleted file mode 100644 index cd2327d09c8..00000000000 --- a/arch/um/include/skas_ptrace.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SKAS_PTRACE_H -#define __SKAS_PTRACE_H - -#define PTRACE_FAULTINFO 52 -#define PTRACE_SWITCH_MM 55 - -#include "sysdep/skas_ptrace.h" - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/skas_ptregs.h b/arch/um/include/skas_ptregs.h deleted file mode 100644 index 73db19e9c07..00000000000 --- a/arch/um/include/skas_ptregs.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __SKAS_PT_REGS_ -#define __SKAS_PT_REGS_ - -#include <user_constants.h> - -#endif diff --git a/arch/um/include/syscall.h b/arch/um/include/syscall.h deleted file mode 100644 index dda1df901a0..00000000000 --- a/arch/um/include/syscall.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSCALL_USER_H -#define __SYSCALL_USER_H - -extern int record_syscall_start(int syscall); -extern void record_syscall_end(int index, long result); - -#endif diff --git a/arch/um/include/sysdep-i386/archsetjmp.h b/arch/um/include/sysdep-i386/archsetjmp.h deleted file mode 100644 index 0f312085ce1..00000000000 --- a/arch/um/include/sysdep-i386/archsetjmp.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * arch/um/include/sysdep-i386/archsetjmp.h - */ - -#ifndef _KLIBC_ARCHSETJMP_H -#define _KLIBC_ARCHSETJMP_H - -struct __jmp_buf { - unsigned int __ebx; - unsigned int __esp; - unsigned int __ebp; - unsigned int __esi; - unsigned int __edi; - unsigned int __eip; -}; - -typedef struct __jmp_buf jmp_buf[1]; - -#define JB_IP __eip -#define JB_SP __esp - -#endif /* _SETJMP_H */ diff --git a/arch/um/include/sysdep-i386/barrier.h b/arch/um/include/sysdep-i386/barrier.h deleted file mode 100644 index b58d52c5b2f..00000000000 --- a/arch/um/include/sysdep-i386/barrier.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __SYSDEP_I386_BARRIER_H -#define __SYSDEP_I386_BARRIER_H - -/* Copied from include/asm-i386 for use by userspace. i386 has the option - * of using mfence, but I'm just using this, which works everywhere, for now. - */ -#define mb() asm volatile("lock; addl $0,0(%esp)") - -#endif diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h deleted file mode 100644 index 0cb4645cbeb..00000000000 --- a/arch/um/include/sysdep-i386/checksum.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Licensed under the GPL - */ - -#ifndef __UM_SYSDEP_CHECKSUM_H -#define __UM_SYSDEP_CHECKSUM_H - -#include "linux/in6.h" -#include "linux/string.h" - -/* - * computes the checksum of a memory block at buff, length len, - * and adds in "sum" (32-bit) - * - * returns a 32-bit number suitable for feeding into itself - * or csum_tcpudp_magic - * - * this function must be called with even lengths, except - * for the last fragment, which may be odd - * - * it's best to have buff aligned on a 32-bit boundary - */ -__wsum csum_partial(const void *buff, int len, __wsum sum); - -/* - * Note: when you get a NULL pointer exception here this means someone - * passed in an incorrect kernel address to one of these functions. - * - * If you use these functions directly please don't forget the - * access_ok(). - */ - -static __inline__ -__wsum csum_partial_copy_nocheck(const void *src, void *dst, - int len, __wsum sum) -{ - memcpy(dst, src, len); - return csum_partial(dst, len, sum); -} - -/* - * the same as csum_partial, but copies from src while it - * checksums, and handles user-space pointer exceptions correctly, when needed. - * - * here even more important to align src and dst on a 32-bit (or even - * better 64-bit) boundary - */ - -static __inline__ -__wsum csum_partial_copy_from_user(const void __user *src, void *dst, - int len, __wsum sum, int *err_ptr) -{ - if (copy_from_user(dst, src, len)) { - *err_ptr = -EFAULT; - return (__force __wsum)-1; - } - - return csum_partial(dst, len, sum); -} - -/* - * This is a version of ip_compute_csum() optimized for IP headers, - * which always checksum on 4 octet boundaries. - * - * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by - * Arnt Gulbrandsen. - */ -static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) -{ - unsigned int sum; - - __asm__ __volatile__( - "movl (%1), %0 ;\n" - "subl $4, %2 ;\n" - "jbe 2f ;\n" - "addl 4(%1), %0 ;\n" - "adcl 8(%1), %0 ;\n" - "adcl 12(%1), %0 ;\n" -"1: adcl 16(%1), %0 ;\n" - "lea 4(%1), %1 ;\n" - "decl %2 ;\n" - "jne 1b ;\n" - "adcl $0, %0 ;\n" - "movl %0, %2 ;\n" - "shrl $16, %0 ;\n" - "addw %w2, %w0 ;\n" - "adcl $0, %0 ;\n" - "notl %0 ;\n" -"2: ;\n" - /* Since the input registers which are loaded with iph and ipl - are modified, we must also specify them as outputs, or gcc - will assume they contain their original values. */ - : "=r" (sum), "=r" (iph), "=r" (ihl) - : "1" (iph), "2" (ihl) - : "memory"); - return (__force __sum16)sum; -} - -/* - * Fold a partial checksum - */ - -static inline __sum16 csum_fold(__wsum sum) -{ - __asm__( - "addl %1, %0 ;\n" - "adcl $0xffff, %0 ;\n" - : "=r" (sum) - : "r" ((__force u32)sum << 16), - "0" ((__force u32)sum & 0xffff0000) - ); - return (__force __sum16)(~(__force u32)sum >> 16); -} - -static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, - unsigned short len, - unsigned short proto, - __wsum sum) -{ - __asm__( - "addl %1, %0 ;\n" - "adcl %2, %0 ;\n" - "adcl %3, %0 ;\n" - "adcl $0, %0 ;\n" - : "=r" (sum) - : "g" (daddr), "g"(saddr), "g"((len + proto) << 8), "0"(sum)); - return sum; -} - -/* - * computes the checksum of the TCP/UDP pseudo-header - * returns a 16-bit checksum, already complemented - */ -static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, - unsigned short len, - unsigned short proto, - __wsum sum) -{ - return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); -} - -/* - * this routine is used for miscellaneous IP-like checksums, mainly - * in icmp.c - */ - -static inline __sum16 ip_compute_csum(const void *buff, int len) -{ - return csum_fold (csum_partial(buff, len, 0)); -} - -#define _HAVE_ARCH_IPV6_CSUM -static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, - const struct in6_addr *daddr, - __u32 len, unsigned short proto, - __wsum sum) -{ - __asm__( - "addl 0(%1), %0 ;\n" - "adcl 4(%1), %0 ;\n" - "adcl 8(%1), %0 ;\n" - "adcl 12(%1), %0 ;\n" - "adcl 0(%2), %0 ;\n" - "adcl 4(%2), %0 ;\n" - "adcl 8(%2), %0 ;\n" - "adcl 12(%2), %0 ;\n" - "adcl %3, %0 ;\n" - "adcl %4, %0 ;\n" - "adcl $0, %0 ;\n" - : "=&r" (sum) - : "r" (saddr), "r" (daddr), - "r"(htonl(len)), "r"(htonl(proto)), "0"(sum)); - - return csum_fold(sum); -} - -/* - * Copy and checksum to user - */ -#define HAVE_CSUM_COPY_USER -static __inline__ __wsum csum_and_copy_to_user(const void *src, - void __user *dst, - int len, __wsum sum, int *err_ptr) -{ - if (access_ok(VERIFY_WRITE, dst, len)) { - if (copy_to_user(dst, src, len)) { - *err_ptr = -EFAULT; - return (__force __wsum)-1; - } - - return csum_partial(src, len, sum); - } - - if (len) - *err_ptr = -EFAULT; - - return (__force __wsum)-1; /* invalid checksum */ -} - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-i386/faultinfo.h b/arch/um/include/sysdep-i386/faultinfo.h deleted file mode 100644 index db437cc373b..00000000000 --- a/arch/um/include/sysdep-i386/faultinfo.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2004 Fujitsu Siemens Computers GmbH - * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com> - * Licensed under the GPL - */ - -#ifndef __FAULTINFO_I386_H -#define __FAULTINFO_I386_H - -/* this structure contains the full arch-specific faultinfo - * from the traps. - * On i386, ptrace_faultinfo unfortunately doesn't provide - * all the info, since trap_no is missing. - * All common elements are defined at the same position in - * both structures, thus making it easy to copy the - * contents without knowledge about the structure elements. - */ -struct faultinfo { - int error_code; /* in ptrace_faultinfo misleadingly called is_write */ - unsigned long cr2; /* in ptrace_faultinfo called addr */ - int trap_no; /* missing in ptrace_faultinfo */ -}; - -#define FAULT_WRITE(fi) ((fi).error_code & 2) -#define FAULT_ADDRESS(fi) ((fi).cr2) - -#define PTRACE_FULL_FAULTINFO 0 - -#endif diff --git a/arch/um/include/sysdep-i386/kernel-offsets.h b/arch/um/include/sysdep-i386/kernel-offsets.h deleted file mode 100644 index 5868526b5ee..00000000000 --- a/arch/um/include/sysdep-i386/kernel-offsets.h +++ /dev/null @@ -1,21 +0,0 @@ -#include <linux/stddef.h> -#include <linux/sched.h> -#include <linux/elf.h> -#include <linux/crypto.h> -#include <asm/mman.h> - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define STR(x) #x -#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " STR(val) " " #val: : ) - -#define BLANK() asm volatile("\n->" : : ) - -#define OFFSET(sym, str, mem) \ - DEFINE(sym, offsetof(struct str, mem)); - -void foo(void) -{ -#include <common-offsets.h> -} diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h deleted file mode 100644 index 11c08969d13..00000000000 --- a/arch/um/include/sysdep-i386/ptrace.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_I386_PTRACE_H -#define __SYSDEP_I386_PTRACE_H - -#include "uml-config.h" -#include "user_constants.h" -#include "sysdep/faultinfo.h" - -#define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long)) -#define MAX_REG_OFFSET (UM_FRAME_SIZE) - -static inline void update_debugregs(int seq) {} - -/* syscall emulation path in ptrace */ - -#ifndef PTRACE_SYSEMU -#define PTRACE_SYSEMU 31 -#endif - -void set_using_sysemu(int value); -int get_using_sysemu(void); -extern int sysemu_supported; - -#include "skas_ptregs.h" - -#define REGS_IP(r) ((r)[HOST_IP]) -#define REGS_SP(r) ((r)[HOST_SP]) -#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS]) -#define REGS_EAX(r) ((r)[HOST_EAX]) -#define REGS_EBX(r) ((r)[HOST_EBX]) -#define REGS_ECX(r) ((r)[HOST_ECX]) -#define REGS_EDX(r) ((r)[HOST_EDX]) -#define REGS_ESI(r) ((r)[HOST_ESI]) -#define REGS_EDI(r) ((r)[HOST_EDI]) -#define REGS_EBP(r) ((r)[HOST_EBP]) -#define REGS_CS(r) ((r)[HOST_CS]) -#define REGS_SS(r) ((r)[HOST_SS]) -#define REGS_DS(r) ((r)[HOST_DS]) -#define REGS_ES(r) ((r)[HOST_ES]) -#define REGS_FS(r) ((r)[HOST_FS]) -#define REGS_GS(r) ((r)[HOST_GS]) - -#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res) - -#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) - -#ifndef PTRACE_SYSEMU_SINGLESTEP -#define PTRACE_SYSEMU_SINGLESTEP 32 -#endif - -struct uml_pt_regs { - unsigned long gp[MAX_REG_NR]; - struct faultinfo faultinfo; - long syscall; - int is_user; -}; - -#define EMPTY_UML_PT_REGS { } - -#define UPT_IP(r) REGS_IP((r)->gp) -#define UPT_SP(r) REGS_SP((r)->gp) -#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp) -#define UPT_EAX(r) REGS_EAX((r)->gp) -#define UPT_EBX(r) REGS_EBX((r)->gp) -#define UPT_ECX(r) REGS_ECX((r)->gp) -#define UPT_EDX(r) REGS_EDX((r)->gp) -#define UPT_ESI(r) REGS_ESI((r)->gp) -#define UPT_EDI(r) REGS_EDI((r)->gp) -#define UPT_EBP(r) REGS_EBP((r)->gp) -#define UPT_ORIG_EAX(r) ((r)->syscall) -#define UPT_CS(r) REGS_CS((r)->gp) -#define UPT_SS(r) REGS_SS((r)->gp) -#define UPT_DS(r) REGS_DS((r)->gp) -#define UPT_ES(r) REGS_ES((r)->gp) -#define UPT_FS(r) REGS_FS((r)->gp) -#define UPT_GS(r) REGS_GS((r)->gp) - -#define UPT_SYSCALL_ARG1(r) UPT_EBX(r) -#define UPT_SYSCALL_ARG2(r) UPT_ECX(r) -#define UPT_SYSCALL_ARG3(r) UPT_EDX(r) -#define UPT_SYSCALL_ARG4(r) UPT_ESI(r) -#define UPT_SYSCALL_ARG5(r) UPT_EDI(r) -#define UPT_SYSCALL_ARG6(r) UPT_EBP(r) - -extern int user_context(unsigned long sp); - -#define UPT_IS_USER(r) ((r)->is_user) - -struct syscall_args { - unsigned long args[6]; -}; - -#define SYSCALL_ARGS(r) ((struct syscall_args) \ - { .args = { UPT_SYSCALL_ARG1(r), \ - UPT_SYSCALL_ARG2(r), \ - UPT_SYSCALL_ARG3(r), \ - UPT_SYSCALL_ARG4(r), \ - UPT_SYSCALL_ARG5(r), \ - UPT_SYSCALL_ARG6(r) } } ) - -#define UPT_REG(regs, reg) \ - ({ unsigned long val; \ - switch(reg){ \ - case EIP: val = UPT_IP(regs); break; \ - case UESP: val = UPT_SP(regs); break; \ - case EAX: val = UPT_EAX(regs); break; \ - case EBX: val = UPT_EBX(regs); break; \ - case ECX: val = UPT_ECX(regs); break; \ - case EDX: val = UPT_EDX(regs); break; \ - case ESI: val = UPT_ESI(regs); break; \ - case EDI: val = UPT_EDI(regs); break; \ - case EBP: val = UPT_EBP(regs); break; \ - case ORIG_EAX: val = UPT_ORIG_EAX(regs); break; \ - case CS: val = UPT_CS(regs); break; \ - case SS: val = UPT_SS(regs); break; \ - case DS: val = UPT_DS(regs); break; \ - case ES: val = UPT_ES(regs); break; \ - case FS: val = UPT_FS(regs); break; \ - case GS: val = UPT_GS(regs); break; \ - case EFL: val = UPT_EFLAGS(regs); break; \ - default : \ - panic("Bad register in UPT_REG : %d\n", reg); \ - val = -1; \ - } \ - val; \ - }) - -#define UPT_SET(regs, reg, val) \ - do { \ - switch(reg){ \ - case EIP: UPT_IP(regs) = val; break; \ - case UESP: UPT_SP(regs) = val; break; \ - case EAX: UPT_EAX(regs) = val; break; \ - case EBX: UPT_EBX(regs) = val; break; \ - case ECX: UPT_ECX(regs) = val; break; \ - case EDX: UPT_EDX(regs) = val; break; \ - case ESI: UPT_ESI(regs) = val; break; \ - case EDI: UPT_EDI(regs) = val; break; \ - case EBP: UPT_EBP(regs) = val; break; \ - case ORIG_EAX: UPT_ORIG_EAX(regs) = val; break; \ - case CS: UPT_CS(regs) = val; break; \ - case SS: UPT_SS(regs) = val; break; \ - case DS: UPT_DS(regs) = val; break; \ - case ES: UPT_ES(regs) = val; break; \ - case FS: UPT_FS(regs) = val; break; \ - case GS: UPT_GS(regs) = val; break; \ - case EFL: UPT_EFLAGS(regs) = val; break; \ - default : \ - panic("Bad register in UPT_SET : %d\n", reg); \ - break; \ - } \ - } while (0) - -#define UPT_SET_SYSCALL_RETURN(r, res) \ - REGS_SET_SYSCALL_RETURN((r)->regs, (res)) - -#define UPT_RESTART_SYSCALL(r) REGS_RESTART_SYSCALL((r)->gp) - -#define UPT_ORIG_SYSCALL(r) UPT_EAX(r) -#define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r) -#define UPT_SYSCALL_RET(r) UPT_EAX(r) - -#define UPT_FAULTINFO(r) (&(r)->faultinfo) - -extern void arch_init_registers(int pid); - -#endif diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h deleted file mode 100644 index 75650723c38..00000000000 --- a/arch/um/include/sysdep-i386/ptrace_user.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_I386_PTRACE_USER_H__ -#define __SYSDEP_I386_PTRACE_USER_H__ - -#include <sys/ptrace.h> -#include <linux/ptrace.h> -#include <asm/ptrace.h> -#include "user_constants.h" - -#define PT_OFFSET(r) ((r) * sizeof(long)) - -#define PT_SYSCALL_NR(regs) ((regs)[ORIG_EAX]) -#define PT_SYSCALL_NR_OFFSET PT_OFFSET(ORIG_EAX) - -#define PT_SYSCALL_ARG1_OFFSET PT_OFFSET(EBX) -#define PT_SYSCALL_ARG2_OFFSET PT_OFFSET(ECX) -#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX) -#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI) -#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI) -#define PT_SYSCALL_ARG6_OFFSET PT_OFFSET(EBP) - -#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX) - -#define REGS_SYSCALL_NR EAX /* This is used before a system call */ -#define REGS_SYSCALL_ARG1 EBX -#define REGS_SYSCALL_ARG2 ECX -#define REGS_SYSCALL_ARG3 EDX -#define REGS_SYSCALL_ARG4 ESI -#define REGS_SYSCALL_ARG5 EDI -#define REGS_SYSCALL_ARG6 EBP - -#define REGS_IP_INDEX EIP -#define REGS_SP_INDEX UESP - -#define PT_IP_OFFSET PT_OFFSET(EIP) -#define PT_IP(regs) ((regs)[EIP]) -#define PT_SP_OFFSET PT_OFFSET(UESP) -#define PT_SP(regs) ((regs)[UESP]) - -#define FP_SIZE ((HOST_XFP_SIZE > HOST_FP_SIZE) ? HOST_XFP_SIZE : HOST_FP_SIZE) - -#ifndef FRAME_SIZE -#define FRAME_SIZE (17) -#endif -#define FRAME_SIZE_OFFSET (FRAME_SIZE * sizeof(unsigned long)) - -#define FP_FRAME_SIZE (27) -#define FPX_FRAME_SIZE (128) - -#ifdef PTRACE_GETREGS -#define UM_HAVE_GETREGS -#endif - -#ifdef PTRACE_SETREGS -#define UM_HAVE_SETREGS -#endif - -#ifdef PTRACE_GETFPREGS -#define UM_HAVE_GETFPREGS -#endif - -#ifdef PTRACE_SETFPREGS -#define UM_HAVE_SETFPREGS -#endif - -#ifdef PTRACE_GETFPXREGS -#define UM_HAVE_GETFPXREGS -#endif - -#ifdef PTRACE_SETFPXREGS -#define UM_HAVE_SETFPXREGS -#endif - -#endif diff --git a/arch/um/include/sysdep-i386/sc.h b/arch/um/include/sysdep-i386/sc.h deleted file mode 100644 index c57d1780ad3..00000000000 --- a/arch/um/include/sysdep-i386/sc.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __SYSDEP_I386_SC_H -#define __SYSDEP_I386_SC_H - -#include <user_constants.h> - -#define SC_OFFSET(sc, field) \ - *((unsigned long *) &(((char *) (sc))[HOST_##field])) -#define SC_FP_OFFSET(sc, field) \ - *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[HOST_##field])) -#define SC_FP_OFFSET_PTR(sc, field, type) \ - ((type *) &(((char *) (SC_FPSTATE(sc)))[HOST_##field])) - -#define SC_IP(sc) SC_OFFSET(sc, SC_IP) -#define SC_SP(sc) SC_OFFSET(sc, SC_SP) -#define SC_FS(sc) SC_OFFSET(sc, SC_FS) -#define SC_GS(sc) SC_OFFSET(sc, SC_GS) -#define SC_DS(sc) SC_OFFSET(sc, SC_DS) -#define SC_ES(sc) SC_OFFSET(sc, SC_ES) -#define SC_SS(sc) SC_OFFSET(sc, SC_SS) -#define SC_CS(sc) SC_OFFSET(sc, SC_CS) -#define SC_EFLAGS(sc) SC_OFFSET(sc, SC_EFLAGS) -#define SC_EAX(sc) SC_OFFSET(sc, SC_EAX) -#define SC_EBX(sc) SC_OFFSET(sc, SC_EBX) -#define SC_ECX(sc) SC_OFFSET(sc, SC_ECX) -#define SC_EDX(sc) SC_OFFSET(sc, SC_EDX) -#define SC_EDI(sc) SC_OFFSET(sc, SC_EDI) -#define SC_ESI(sc) SC_OFFSET(sc, SC_ESI) -#define SC_EBP(sc) SC_OFFSET(sc, SC_EBP) -#define SC_TRAPNO(sc) SC_OFFSET(sc, SC_TRAPNO) -#define SC_ERR(sc) SC_OFFSET(sc, SC_ERR) -#define SC_CR2(sc) SC_OFFSET(sc, SC_CR2) -#define SC_FPSTATE(sc) SC_OFFSET(sc, SC_FPSTATE) -#define SC_SIGMASK(sc) SC_OFFSET(sc, SC_SIGMASK) -#define SC_FP_CW(sc) SC_FP_OFFSET(sc, SC_FP_CW) -#define SC_FP_SW(sc) SC_FP_OFFSET(sc, SC_FP_SW) -#define SC_FP_TAG(sc) SC_FP_OFFSET(sc, SC_FP_TAG) -#define SC_FP_IPOFF(sc) SC_FP_OFFSET(sc, SC_FP_IPOFF) -#define SC_FP_CSSEL(sc) SC_FP_OFFSET(sc, SC_FP_CSSEL) -#define SC_FP_DATAOFF(sc) SC_FP_OFFSET(sc, SC_FP_DATAOFF) -#define SC_FP_DATASEL(sc) SC_FP_OFFSET(sc, SC_FP_DATASEL) -#define SC_FP_ST(sc) SC_FP_OFFSET_PTR(sc, SC_FP_ST, struct _fpstate) -#define SC_FXSR_ENV(sc) SC_FP_OFFSET_PTR(sc, SC_FXSR_ENV, void) - -#endif diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h deleted file mode 100644 index 67e77122aa4..00000000000 --- a/arch/um/include/sysdep-i386/sigcontext.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#ifndef __SYS_SIGCONTEXT_I386_H -#define __SYS_SIGCONTEXT_I386_H - -#include "sysdep/sc.h" - -#define IP_RESTART_SYSCALL(ip) ((ip) -= 2) - -#define GET_FAULTINFO_FROM_SC(fi,sc) \ - { \ - (fi).cr2 = SC_CR2(sc); \ - (fi).error_code = SC_ERR(sc); \ - (fi).trap_no = SC_TRAPNO(sc); \ - } - -/* This is Page Fault */ -#define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) - -/* SKAS3 has no trap_no on i386, but get_skas_faultinfo() sets it to 0. */ -#define SEGV_MAYBE_FIXABLE(fi) ((fi)->trap_no == 0 && ptrace_faultinfo) - -#endif diff --git a/arch/um/include/sysdep-i386/skas_ptrace.h b/arch/um/include/sysdep-i386/skas_ptrace.h deleted file mode 100644 index e27b8a79177..00000000000 --- a/arch/um/include/sysdep-i386/skas_ptrace.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_I386_SKAS_PTRACE_H -#define __SYSDEP_I386_SKAS_PTRACE_H - -struct ptrace_faultinfo { - int is_write; - unsigned long addr; -}; - -struct ptrace_ldt { - int func; - void *ptr; - unsigned long bytecount; -}; - -#define PTRACE_LDT 54 - -#endif diff --git a/arch/um/include/sysdep-i386/stub.h b/arch/um/include/sysdep-i386/stub.h deleted file mode 100644 index 8c097b87fca..00000000000 --- a/arch/um/include/sysdep-i386/stub.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_STUB_H -#define __SYSDEP_STUB_H - -#include <sys/mman.h> -#include <asm/ptrace.h> -#include <asm/unistd.h> -#include "as-layout.h" -#include "stub-data.h" -#include "kern_constants.h" -#include "uml-config.h" - -extern void stub_segv_handler(int sig); -extern void stub_clone_handler(void); - -#define STUB_SYSCALL_RET EAX -#define STUB_MMAP_NR __NR_mmap2 -#define MMAP_OFFSET(o) ((o) >> UM_KERN_PAGE_SHIFT) - -static inline long stub_syscall0(long syscall) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall)); - - return ret; -} - -static inline long stub_syscall1(long syscall, long arg1) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1)); - - return ret; -} - -static inline long stub_syscall2(long syscall, long arg1, long arg2) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2)); - - return ret; -} - -static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2), "d" (arg3)); - - return ret; -} - -static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, - long arg4) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2), "d" (arg3), "S" (arg4)); - - return ret; -} - -static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, - long arg4, long arg5) -{ - long ret; - - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5)); - - return ret; -} - -static inline void trap_myself(void) -{ - __asm("int3"); -} - -static inline void remap_stack(int fd, unsigned long offset) -{ - __asm__ volatile ("movl %%eax,%%ebp ; movl %0,%%eax ; int $0x80 ;" - "movl %7, %%ebx ; movl %%eax, (%%ebx)" - : : "g" (STUB_MMAP_NR), "b" (STUB_DATA), - "c" (UM_KERN_PAGE_SIZE), - "d" (PROT_READ | PROT_WRITE), - "S" (MAP_FIXED | MAP_SHARED), "D" (fd), - "a" (offset), - "i" (&((struct stub_data *) STUB_DATA)->err) - : "memory"); -} - -#endif diff --git a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h deleted file mode 100644 index 905698197e3..00000000000 --- a/arch/um/include/sysdep-i386/syscalls.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2000 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include "asm/unistd.h" -#include "sysdep/ptrace.h" - -typedef long syscall_handler_t(struct pt_regs); - -/* Not declared on x86, incompatible declarations on x86_64, so these have - * to go here rather than in sys_call_table.c - */ -extern syscall_handler_t sys_rt_sigaction; - -extern syscall_handler_t old_mmap_i386; - -extern syscall_handler_t *sys_call_table[]; - -#define EXECUTE_SYSCALL(syscall, regs) \ - ((long (*)(struct syscall_args)) \ - (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) - -extern long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); diff --git a/arch/um/include/sysdep-i386/tls.h b/arch/um/include/sysdep-i386/tls.h deleted file mode 100644 index 918fd3c5ff9..00000000000 --- a/arch/um/include/sysdep-i386/tls.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _SYSDEP_TLS_H -#define _SYSDEP_TLS_H - -# ifndef __KERNEL__ - -/* Change name to avoid conflicts with the original one from <asm/ldt.h>, which - * may be named user_desc (but in 2.4 and in header matching its API was named - * modify_ldt_ldt_s). */ - -typedef struct um_dup_user_desc { - unsigned int entry_number; - unsigned int base_addr; - unsigned int limit; - unsigned int seg_32bit:1; - unsigned int contents:2; - unsigned int read_exec_only:1; - unsigned int limit_in_pages:1; - unsigned int seg_not_present:1; - unsigned int useable:1; -} user_desc_t; - -# else /* __KERNEL__ */ - -# include <asm/ldt.h> -typedef struct user_desc user_desc_t; - -# endif /* __KERNEL__ */ - -#define GDT_ENTRY_TLS_MIN_I386 6 -#define GDT_ENTRY_TLS_MIN_X86_64 12 - -#endif /* _SYSDEP_TLS_H */ diff --git a/arch/um/include/sysdep-ia64/ptrace.h b/arch/um/include/sysdep-ia64/ptrace.h deleted file mode 100644 index 42dd8fb6f2f..00000000000 --- a/arch/um/include/sysdep-ia64/ptrace.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_IA64_PTRACE_H -#define __SYSDEP_IA64_PTRACE_H - -struct sys_pt_regs { - int foo; -}; - -#define EMPTY_REGS { 0 } - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-ia64/sigcontext.h b/arch/um/include/sysdep-ia64/sigcontext.h deleted file mode 100644 index f15fb25260b..00000000000 --- a/arch/um/include/sysdep-ia64/sigcontext.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_IA64_SIGCONTEXT_H -#define __SYSDEP_IA64_SIGCONTEXT_H - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-ia64/syscalls.h b/arch/um/include/sysdep-ia64/syscalls.h deleted file mode 100644 index 4a1f46ef1eb..00000000000 --- a/arch/um/include/sysdep-ia64/syscalls.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_IA64_SYSCALLS_H -#define __SYSDEP_IA64_SYSCALLS_H - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-x86_64/archsetjmp.h b/arch/um/include/sysdep-x86_64/archsetjmp.h deleted file mode 100644 index 2af8f12ca16..00000000000 --- a/arch/um/include/sysdep-x86_64/archsetjmp.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * arch/um/include/sysdep-x86_64/archsetjmp.h - */ - -#ifndef _KLIBC_ARCHSETJMP_H -#define _KLIBC_ARCHSETJMP_H - -struct __jmp_buf { - unsigned long __rbx; - unsigned long __rsp; - unsigned long __rbp; - unsigned long __r12; - unsigned long __r13; - unsigned long __r14; - unsigned long __r15; - unsigned long __rip; -}; - -typedef struct __jmp_buf jmp_buf[1]; - -#define JB_IP __rip -#define JB_SP __rsp - -#endif /* _SETJMP_H */ diff --git a/arch/um/include/sysdep-x86_64/barrier.h b/arch/um/include/sysdep-x86_64/barrier.h deleted file mode 100644 index 7b610befdc8..00000000000 --- a/arch/um/include/sysdep-x86_64/barrier.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __SYSDEP_X86_64_BARRIER_H -#define __SYSDEP_X86_64_BARRIER_H - -/* Copied from include/asm-x86_64 for use by userspace. */ -#define mb() asm volatile("mfence":::"memory") - -#endif diff --git a/arch/um/include/sysdep-x86_64/checksum.h b/arch/um/include/sysdep-x86_64/checksum.h deleted file mode 100644 index a5be9031ea8..00000000000 --- a/arch/um/include/sysdep-x86_64/checksum.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed under the GPL - */ - -#ifndef __UM_SYSDEP_CHECKSUM_H -#define __UM_SYSDEP_CHECKSUM_H - -#include "linux/string.h" -#include "linux/in6.h" -#include "asm/uaccess.h" - -extern __wsum csum_partial(const void *buff, int len, __wsum sum); - -/* - * Note: when you get a NULL pointer exception here this means someone - * passed in an incorrect kernel address to one of these functions. - * - * If you use these functions directly please don't forget the - * access_ok(). - */ - -static __inline__ -__wsum csum_partial_copy_nocheck(const void *src, void *dst, - int len, __wsum sum) -{ - memcpy(dst, src, len); - return(csum_partial(dst, len, sum)); -} - -static __inline__ -__wsum csum_partial_copy_from_user(const void __user *src, - void *dst, int len, __wsum sum, - int *err_ptr) -{ - if (copy_from_user(dst, src, len)) { - *err_ptr = -EFAULT; - return (__force __wsum)-1; - } - return csum_partial(dst, len, sum); -} - -/** - * csum_fold - Fold and invert a 32bit checksum. - * sum: 32bit unfolded sum - * - * Fold a 32bit running checksum to 16bit and invert it. This is usually - * the last step before putting a checksum into a packet. - * Make sure not to mix with 64bit checksums. - */ -static inline __sum16 csum_fold(__wsum sum) -{ - __asm__( - " addl %1,%0\n" - " adcl $0xffff,%0" - : "=r" (sum) - : "r" ((__force u32)sum << 16), - "0" ((__force u32)sum & 0xffff0000) - ); - return (__force __sum16)(~(__force u32)sum >> 16); -} - -/** - * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum. - * @saddr: source address - * @daddr: destination address - * @len: length of packet - * @proto: ip protocol of packet - * @sum: initial sum to be added in (32bit unfolded) - * - * Returns the pseudo header checksum the input data. Result is - * 32bit unfolded. - */ -static inline __wsum -csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, - unsigned short proto, __wsum sum) -{ - asm(" addl %1, %0\n" - " adcl %2, %0\n" - " adcl %3, %0\n" - " adcl $0, %0\n" - : "=r" (sum) - : "g" (daddr), "g" (saddr), "g" ((len + proto) << 8), "0" (sum)); - return sum; -} - -/* - * computes the checksum of the TCP/UDP pseudo-header - * returns a 16-bit checksum, already complemented - */ -static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, - unsigned short len, - unsigned short proto, - __wsum sum) -{ - return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); -} - -/** - * ip_fast_csum - Compute the IPv4 header checksum efficiently. - * iph: ipv4 header - * ihl: length of header / 4 - */ -static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) -{ - unsigned int sum; - - asm( " movl (%1), %0\n" - " subl $4, %2\n" - " jbe 2f\n" - " addl 4(%1), %0\n" - " adcl 8(%1), %0\n" - " adcl 12(%1), %0\n" - "1: adcl 16(%1), %0\n" - " lea 4(%1), %1\n" - " decl %2\n" - " jne 1b\n" - " adcl $0, %0\n" - " movl %0, %2\n" - " shrl $16, %0\n" - " addw %w2, %w0\n" - " adcl $0, %0\n" - " notl %0\n" - "2:" - /* Since the input registers which are loaded with iph and ipl - are modified, we must also specify them as outputs, or gcc - will assume they contain their original values. */ - : "=r" (sum), "=r" (iph), "=r" (ihl) - : "1" (iph), "2" (ihl) - : "memory"); - return (__force __sum16)sum; -} - -static inline unsigned add32_with_carry(unsigned a, unsigned b) -{ - asm("addl %2,%0\n\t" - "adcl $0,%0" - : "=r" (a) - : "0" (a), "r" (b)); - return a; -} - -extern __sum16 ip_compute_csum(const void *buff, int len); - -#endif diff --git a/arch/um/include/sysdep-x86_64/faultinfo.h b/arch/um/include/sysdep-x86_64/faultinfo.h deleted file mode 100644 index cb917b0d566..00000000000 --- a/arch/um/include/sysdep-x86_64/faultinfo.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2004 Fujitsu Siemens Computers GmbH - * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com> - * Licensed under the GPL - */ - -#ifndef __FAULTINFO_X86_64_H -#define __FAULTINFO_X86_64_H - -/* this structure contains the full arch-specific faultinfo - * from the traps. - * On i386, ptrace_faultinfo unfortunately doesn't provide - * all the info, since trap_no is missing. - * All common elements are defined at the same position in - * both structures, thus making it easy to copy the - * contents without knowledge about the structure elements. - */ -struct faultinfo { - int error_code; /* in ptrace_faultinfo misleadingly called is_write */ - unsigned long cr2; /* in ptrace_faultinfo called addr */ - int trap_no; /* missing in ptrace_faultinfo */ -}; - -#define FAULT_WRITE(fi) ((fi).error_code & 2) -#define FAULT_ADDRESS(fi) ((fi).cr2) - -#define PTRACE_FULL_FAULTINFO 1 - -#endif diff --git a/arch/um/include/sysdep-x86_64/kernel-offsets.h b/arch/um/include/sysdep-x86_64/kernel-offsets.h deleted file mode 100644 index a307237b796..00000000000 --- a/arch/um/include/sysdep-x86_64/kernel-offsets.h +++ /dev/null @@ -1,23 +0,0 @@ -#include <linux/stddef.h> -#include <linux/sched.h> -#include <linux/time.h> -#include <linux/elf.h> -#include <linux/crypto.h> -#include <asm/page.h> -#include <asm/mman.h> - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define DEFINE_STR1(x) #x -#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " DEFINE_STR1(val) " " #val: : ) - -#define BLANK() asm volatile("\n->" : : ) - -#define OFFSET(sym, str, mem) \ - DEFINE(sym, offsetof(struct str, mem)); - -void foo(void) -{ -#include <common-offsets.h> -} diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h deleted file mode 100644 index 9ea44d111f3..00000000000 --- a/arch/um/include/sysdep-x86_64/ptrace.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_64_PTRACE_H -#define __SYSDEP_X86_64_PTRACE_H - -#include "uml-config.h" -#include "user_constants.h" -#include "sysdep/faultinfo.h" - -#define MAX_REG_OFFSET (UM_FRAME_SIZE) -#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long)) - -#include "skas_ptregs.h" - -#define REGS_IP(r) ((r)[HOST_IP]) -#define REGS_SP(r) ((r)[HOST_SP]) - -#define REGS_RBX(r) ((r)[HOST_RBX]) -#define REGS_RCX(r) ((r)[HOST_RCX]) -#define REGS_RDX(r) ((r)[HOST_RDX]) -#define REGS_RSI(r) ((r)[HOST_RSI]) -#define REGS_RDI(r) ((r)[HOST_RDI]) -#define REGS_RBP(r) ((r)[HOST_RBP]) -#define REGS_RAX(r) ((r)[HOST_RAX]) -#define REGS_R8(r) ((r)[HOST_R8]) -#define REGS_R9(r) ((r)[HOST_R9]) -#define REGS_R10(r) ((r)[HOST_R10]) -#define REGS_R11(r) ((r)[HOST_R11]) -#define REGS_R12(r) ((r)[HOST_R12]) -#define REGS_R13(r) ((r)[HOST_R13]) -#define REGS_R14(r) ((r)[HOST_R14]) -#define REGS_R15(r) ((r)[HOST_R15]) -#define REGS_CS(r) ((r)[HOST_CS]) -#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS]) -#define REGS_SS(r) ((r)[HOST_SS]) - -#define HOST_FS_BASE 21 -#define HOST_GS_BASE 22 -#define HOST_DS 23 -#define HOST_ES 24 -#define HOST_FS 25 -#define HOST_GS 26 - -/* Also defined in asm/ptrace-x86_64.h, but not in libc headers. So, these - * are already defined for kernel code, but not for userspace code. - */ -#ifndef FS_BASE -/* These aren't defined in ptrace.h, but exist in struct user_regs_struct, - * which is what x86_64 ptrace actually uses. - */ -#define FS_BASE (HOST_FS_BASE * sizeof(long)) -#define GS_BASE (HOST_GS_BASE * sizeof(long)) -#define DS (HOST_DS * sizeof(long)) -#define ES (HOST_ES * sizeof(long)) -#define FS (HOST_FS * sizeof(long)) -#define GS (HOST_GS * sizeof(long)) -#endif - -#define REGS_FS_BASE(r) ((r)[HOST_FS_BASE]) -#define REGS_GS_BASE(r) ((r)[HOST_GS_BASE]) -#define REGS_DS(r) ((r)[HOST_DS]) -#define REGS_ES(r) ((r)[HOST_ES]) -#define REGS_FS(r) ((r)[HOST_FS]) -#define REGS_GS(r) ((r)[HOST_GS]) - -#define REGS_ORIG_RAX(r) ((r)[HOST_ORIG_RAX]) - -#define REGS_SET_SYSCALL_RETURN(r, res) REGS_RAX(r) = (res) - -#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) - -#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type) - -#define REGS_FAULT_ADDR(r) ((r)->fault_addr) - -#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type) - -#define REGS_TRAP(r) ((r)->trap_type) - -#define REGS_ERR(r) ((r)->fault_type) - -struct uml_pt_regs { - unsigned long gp[MAX_REG_NR]; - struct faultinfo faultinfo; - long syscall; - int is_user; -}; - -#define EMPTY_UML_PT_REGS { } - -#define UPT_RBX(r) REGS_RBX((r)->gp) -#define UPT_RCX(r) REGS_RCX((r)->gp) -#define UPT_RDX(r) REGS_RDX((r)->gp) -#define UPT_RSI(r) REGS_RSI((r)->gp) -#define UPT_RDI(r) REGS_RDI((r)->gp) -#define UPT_RBP(r) REGS_RBP((r)->gp) -#define UPT_RAX(r) REGS_RAX((r)->gp) -#define UPT_R8(r) REGS_R8((r)->gp) -#define UPT_R9(r) REGS_R9((r)->gp) -#define UPT_R10(r) REGS_R10((r)->gp) -#define UPT_R11(r) REGS_R11((r)->gp) -#define UPT_R12(r) REGS_R12((r)->gp) -#define UPT_R13(r) REGS_R13((r)->gp) -#define UPT_R14(r) REGS_R14((r)->gp) -#define UPT_R15(r) REGS_R15((r)->gp) -#define UPT_CS(r) REGS_CS((r)->gp) -#define UPT_FS_BASE(r) REGS_FS_BASE((r)->gp) -#define UPT_FS(r) REGS_FS((r)->gp) -#define UPT_GS_BASE(r) REGS_GS_BASE((r)->gp) -#define UPT_GS(r) REGS_GS((r)->gp) -#define UPT_DS(r) REGS_DS((r)->gp) -#define UPT_ES(r) REGS_ES((r)->gp) -#define UPT_CS(r) REGS_CS((r)->gp) -#define UPT_SS(r) REGS_SS((r)->gp) -#define UPT_ORIG_RAX(r) REGS_ORIG_RAX((r)->gp) - -#define UPT_IP(r) REGS_IP((r)->gp) -#define UPT_SP(r) REGS_SP((r)->gp) - -#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp) -#define UPT_SYSCALL_NR(r) ((r)->syscall) -#define UPT_SYSCALL_RET(r) UPT_RAX(r) - -extern int user_context(unsigned long sp); - -#define UPT_IS_USER(r) ((r)->is_user) - -#define UPT_SYSCALL_ARG1(r) UPT_RDI(r) -#define UPT_SYSCALL_ARG2(r) UPT_RSI(r) -#define UPT_SYSCALL_ARG3(r) UPT_RDX(r) -#define UPT_SYSCALL_ARG4(r) UPT_R10(r) -#define UPT_SYSCALL_ARG5(r) UPT_R8(r) -#define UPT_SYSCALL_ARG6(r) UPT_R9(r) - -struct syscall_args { - unsigned long args[6]; -}; - -#define SYSCALL_ARGS(r) ((struct syscall_args) \ - { .args = { UPT_SYSCALL_ARG1(r), \ - UPT_SYSCALL_ARG2(r), \ - UPT_SYSCALL_ARG3(r), \ - UPT_SYSCALL_ARG4(r), \ - UPT_SYSCALL_ARG5(r), \ - UPT_SYSCALL_ARG6(r) } } ) - -#define UPT_REG(regs, reg) \ - ({ unsigned long val; \ - switch(reg){ \ - case R8: val = UPT_R8(regs); break; \ - case R9: val = UPT_R9(regs); break; \ - case R10: val = UPT_R10(regs); break; \ - case R11: val = UPT_R11(regs); break; \ - case R12: val = UPT_R12(regs); break; \ - case R13: val = UPT_R13(regs); break; \ - case R14: val = UPT_R14(regs); break; \ - case R15: val = UPT_R15(regs); break; \ - case RIP: val = UPT_IP(regs); break; \ - case RSP: val = UPT_SP(regs); break; \ - case RAX: val = UPT_RAX(regs); break; \ - case RBX: val = UPT_RBX(regs); break; \ - case RCX: val = UPT_RCX(regs); break; \ - case RDX: val = UPT_RDX(regs); break; \ - case RSI: val = UPT_RSI(regs); break; \ - case RDI: val = UPT_RDI(regs); break; \ - case RBP: val = UPT_RBP(regs); break; \ - case ORIG_RAX: val = UPT_ORIG_RAX(regs); break; \ - case CS: val = UPT_CS(regs); break; \ - case SS: val = UPT_SS(regs); break; \ - case FS_BASE: val = UPT_FS_BASE(regs); break; \ - case GS_BASE: val = UPT_GS_BASE(regs); break; \ - case DS: val = UPT_DS(regs); break; \ - case ES: val = UPT_ES(regs); break; \ - case FS : val = UPT_FS (regs); break; \ - case GS: val = UPT_GS(regs); break; \ - case EFLAGS: val = UPT_EFLAGS(regs); break; \ - default : \ - panic("Bad register in UPT_REG : %d\n", reg); \ - val = -1; \ - } \ - val; \ - }) - - -#define UPT_SET(regs, reg, val) \ - ({ unsigned long __upt_val = val; \ - switch(reg){ \ - case R8: UPT_R8(regs) = __upt_val; break; \ - case R9: UPT_R9(regs) = __upt_val; break; \ - case R10: UPT_R10(regs) = __upt_val; break; \ - case R11: UPT_R11(regs) = __upt_val; break; \ - case R12: UPT_R12(regs) = __upt_val; break; \ - case R13: UPT_R13(regs) = __upt_val; break; \ - case R14: UPT_R14(regs) = __upt_val; break; \ - case R15: UPT_R15(regs) = __upt_val; break; \ - case RIP: UPT_IP(regs) = __upt_val; break; \ - case RSP: UPT_SP(regs) = __upt_val; break; \ - case RAX: UPT_RAX(regs) = __upt_val; break; \ - case RBX: UPT_RBX(regs) = __upt_val; break; \ - case RCX: UPT_RCX(regs) = __upt_val; break; \ - case RDX: UPT_RDX(regs) = __upt_val; break; \ - case RSI: UPT_RSI(regs) = __upt_val; break; \ - case RDI: UPT_RDI(regs) = __upt_val; break; \ - case RBP: UPT_RBP(regs) = __upt_val; break; \ - case ORIG_RAX: UPT_ORIG_RAX(regs) = __upt_val; break; \ - case CS: UPT_CS(regs) = __upt_val; break; \ - case SS: UPT_SS(regs) = __upt_val; break; \ - case FS_BASE: UPT_FS_BASE(regs) = __upt_val; break; \ - case GS_BASE: UPT_GS_BASE(regs) = __upt_val; break; \ - case DS: UPT_DS(regs) = __upt_val; break; \ - case ES: UPT_ES(regs) = __upt_val; break; \ - case FS: UPT_FS(regs) = __upt_val; break; \ - case GS: UPT_GS(regs) = __upt_val; break; \ - case EFLAGS: UPT_EFLAGS(regs) = __upt_val; break; \ - default : \ - panic("Bad register in UPT_SET : %d\n", reg); \ - break; \ - } \ - __upt_val; \ - }) - -#define UPT_SET_SYSCALL_RETURN(r, res) \ - REGS_SET_SYSCALL_RETURN((r)->regs, (res)) - -#define UPT_RESTART_SYSCALL(r) REGS_RESTART_SYSCALL((r)->gp) - -#define UPT_SEGV_IS_FIXABLE(r) REGS_SEGV_IS_FIXABLE(&r->skas) - -#define UPT_FAULTINFO(r) (&(r)->faultinfo) - -static inline void arch_init_registers(int pid) -{ -} - -#endif diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h deleted file mode 100644 index 45c0bd881cb..00000000000 --- a/arch/um/include/sysdep-x86_64/ptrace_user.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_64_PTRACE_USER_H__ -#define __SYSDEP_X86_64_PTRACE_USER_H__ - -#define __FRAME_OFFSETS -#include <sys/ptrace.h> -#include <linux/ptrace.h> -#include <asm/ptrace.h> -#undef __FRAME_OFFSETS -#include "user_constants.h" - -#define PT_INDEX(off) ((off) / sizeof(unsigned long)) - -#define PT_SYSCALL_NR(regs) ((regs)[PT_INDEX(ORIG_RAX)]) -#define PT_SYSCALL_NR_OFFSET (ORIG_RAX) - -#define PT_SYSCALL_ARG1(regs) (((unsigned long *) (regs))[PT_INDEX(RDI)]) -#define PT_SYSCALL_ARG1_OFFSET (RDI) - -#define PT_SYSCALL_ARG2(regs) (((unsigned long *) (regs))[PT_INDEX(RSI)]) -#define PT_SYSCALL_ARG2_OFFSET (RSI) - -#define PT_SYSCALL_ARG3(regs) (((unsigned long *) (regs))[PT_INDEX(RDX)]) -#define PT_SYSCALL_ARG3_OFFSET (RDX) - -#define PT_SYSCALL_ARG4(regs) (((unsigned long *) (regs))[PT_INDEX(RCX)]) -#define PT_SYSCALL_ARG4_OFFSET (RCX) - -#define PT_SYSCALL_ARG5(regs) (((unsigned long *) (regs))[PT_INDEX(R8)]) -#define PT_SYSCALL_ARG5_OFFSET (R8) - -#define PT_SYSCALL_ARG6(regs) (((unsigned long *) (regs))[PT_INDEX(R9)]) -#define PT_SYSCALL_ARG6_OFFSET (R9) - -#define PT_SYSCALL_RET_OFFSET (RAX) - -#define PT_IP_OFFSET (RIP) -#define PT_IP(regs) ((regs)[PT_INDEX(RIP)]) - -#define PT_SP_OFFSET (RSP) -#define PT_SP(regs) ((regs)[PT_INDEX(RSP)]) - -#define PT_ORIG_RAX_OFFSET (ORIG_RAX) -#define PT_ORIG_RAX(regs) ((regs)[PT_INDEX(ORIG_RAX)]) - -/* x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though - * it's defined in the kernel's include/linux/ptrace.h. Additionally, use the - * 2.4 name and value for 2.4 host compatibility. - */ -#ifndef PTRACE_OLDSETOPTIONS -#define PTRACE_OLDSETOPTIONS 21 -#endif - -/* These are before the system call, so the system call number is RAX - * rather than ORIG_RAX, and arg4 is R10 rather than RCX - */ -#define REGS_SYSCALL_NR PT_INDEX(RAX) -#define REGS_SYSCALL_ARG1 PT_INDEX(RDI) -#define REGS_SYSCALL_ARG2 PT_INDEX(RSI) -#define REGS_SYSCALL_ARG3 PT_INDEX(RDX) -#define REGS_SYSCALL_ARG4 PT_INDEX(R10) -#define REGS_SYSCALL_ARG5 PT_INDEX(R8) -#define REGS_SYSCALL_ARG6 PT_INDEX(R9) - -#define REGS_IP_INDEX PT_INDEX(RIP) -#define REGS_SP_INDEX PT_INDEX(RSP) - -#define FP_SIZE (HOST_FP_SIZE) - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-x86_64/sc.h b/arch/um/include/sysdep-x86_64/sc.h deleted file mode 100644 index 8aee45b0743..00000000000 --- a/arch/um/include/sysdep-x86_64/sc.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __SYSDEP_X86_64_SC_H -#define __SYSDEP_X86_64_SC_H - -/* Copyright (C) 2003 - 2004 PathScale, Inc - * Released under the GPL - */ - -#include <user_constants.h> - -#define SC_OFFSET(sc, field) \ - *((unsigned long *) &(((char *) (sc))[HOST_##field])) - -#define SC_RBX(sc) SC_OFFSET(sc, SC_RBX) -#define SC_RCX(sc) SC_OFFSET(sc, SC_RCX) -#define SC_RDX(sc) SC_OFFSET(sc, SC_RDX) -#define SC_RSI(sc) SC_OFFSET(sc, SC_RSI) -#define SC_RDI(sc) SC_OFFSET(sc, SC_RDI) -#define SC_RBP(sc) SC_OFFSET(sc, SC_RBP) -#define SC_RAX(sc) SC_OFFSET(sc, SC_RAX) -#define SC_R8(sc) SC_OFFSET(sc, SC_R8) -#define SC_R9(sc) SC_OFFSET(sc, SC_R9) -#define SC_R10(sc) SC_OFFSET(sc, SC_R10) -#define SC_R11(sc) SC_OFFSET(sc, SC_R11) -#define SC_R12(sc) SC_OFFSET(sc, SC_R12) -#define SC_R13(sc) SC_OFFSET(sc, SC_R13) -#define SC_R14(sc) SC_OFFSET(sc, SC_R14) -#define SC_R15(sc) SC_OFFSET(sc, SC_R15) -#define SC_IP(sc) SC_OFFSET(sc, SC_IP) -#define SC_SP(sc) SC_OFFSET(sc, SC_SP) -#define SC_CR2(sc) SC_OFFSET(sc, SC_CR2) -#define SC_ERR(sc) SC_OFFSET(sc, SC_ERR) -#define SC_TRAPNO(sc) SC_OFFSET(sc, SC_TRAPNO) -#define SC_CS(sc) SC_OFFSET(sc, SC_CS) -#define SC_FS(sc) SC_OFFSET(sc, SC_FS) -#define SC_GS(sc) SC_OFFSET(sc, SC_GS) -#define SC_EFLAGS(sc) SC_OFFSET(sc, SC_EFLAGS) -#define SC_SIGMASK(sc) SC_OFFSET(sc, SC_SIGMASK) -#define SC_SS(sc) SC_OFFSET(sc, SC_SS) -#if 0 -#define SC_ORIG_RAX(sc) SC_OFFSET(sc, SC_ORIG_RAX) -#define SC_DS(sc) SC_OFFSET(sc, SC_DS) -#define SC_ES(sc) SC_OFFSET(sc, SC_ES) -#endif - -#endif diff --git a/arch/um/include/sysdep-x86_64/sigcontext.h b/arch/um/include/sysdep-x86_64/sigcontext.h deleted file mode 100644 index 0155133b145..00000000000 --- a/arch/um/include/sysdep-x86_64/sigcontext.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_64_SIGCONTEXT_H -#define __SYSDEP_X86_64_SIGCONTEXT_H - -#include <sysdep/sc.h> - -#define IP_RESTART_SYSCALL(ip) ((ip) -= 2) - -#define GET_FAULTINFO_FROM_SC(fi, sc) \ - { \ - (fi).cr2 = SC_CR2(sc); \ - (fi).error_code = SC_ERR(sc); \ - (fi).trap_no = SC_TRAPNO(sc); \ - } - -/* This is Page Fault */ -#define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) - -/* No broken SKAS API, which doesn't pass trap_no, here. */ -#define SEGV_MAYBE_FIXABLE(fi) 0 - -#endif diff --git a/arch/um/include/sysdep-x86_64/skas_ptrace.h b/arch/um/include/sysdep-x86_64/skas_ptrace.h deleted file mode 100644 index 95db4be786e..00000000000 --- a/arch/um/include/sysdep-x86_64/skas_ptrace.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_64_SKAS_PTRACE_H -#define __SYSDEP_X86_64_SKAS_PTRACE_H - -struct ptrace_faultinfo { - int is_write; - unsigned long addr; -}; - -struct ptrace_ldt { - int func; - void *ptr; - unsigned long bytecount; -}; - -#define PTRACE_LDT 54 - -#endif diff --git a/arch/um/include/sysdep-x86_64/stub.h b/arch/um/include/sysdep-x86_64/stub.h deleted file mode 100644 index 655f9c2de3a..00000000000 --- a/arch/um/include/sysdep-x86_64/stub.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#ifndef __SYSDEP_STUB_H -#define __SYSDEP_STUB_H - -#include <sys/mman.h> -#include <asm/unistd.h> -#include <sysdep/ptrace_user.h> -#include "as-layout.h" -#include "stub-data.h" -#include "kern_constants.h" -#include "uml-config.h" - -extern void stub_segv_handler(int sig); -extern void stub_clone_handler(void); - -#define STUB_SYSCALL_RET PT_INDEX(RAX) -#define STUB_MMAP_NR __NR_mmap -#define MMAP_OFFSET(o) (o) - -#define __syscall_clobber "r11","rcx","memory" -#define __syscall "syscall" - -static inline long stub_syscall0(long syscall) -{ - long ret; - - __asm__ volatile (__syscall - : "=a" (ret) - : "0" (syscall) : __syscall_clobber ); - - return ret; -} - -static inline long stub_syscall2(long syscall, long arg1, long arg2) -{ - long ret; - - __asm__ volatile (__syscall - : "=a" (ret) - : "0" (syscall), "D" (arg1), "S" (arg2) : __syscall_clobber ); - - return ret; -} - -static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) -{ - long ret; - - __asm__ volatile (__syscall - : "=a" (ret) - : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3) - : __syscall_clobber ); - - return ret; -} - -static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, - long arg4) -{ - long ret; - - __asm__ volatile ("movq %5,%%r10 ; " __syscall - : "=a" (ret) - : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3), - "g" (arg4) - : __syscall_clobber, "r10" ); - - return ret; -} - -static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, - long arg4, long arg5) -{ - long ret; - - __asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; " __syscall - : "=a" (ret) - : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3), - "g" (arg4), "g" (arg5) - : __syscall_clobber, "r10", "r8" ); - - return ret; -} - -static inline void trap_myself(void) -{ - __asm("int3"); -} - -static inline void remap_stack(long fd, unsigned long offset) -{ - __asm__ volatile ("movq %4,%%r10 ; movq %5,%%r8 ; " - "movq %6, %%r9; " __syscall "; movq %7, %%rbx ; " - "movq %%rax, (%%rbx)": - : "a" (STUB_MMAP_NR), "D" (STUB_DATA), - "S" (UM_KERN_PAGE_SIZE), - "d" (PROT_READ | PROT_WRITE), - "g" (MAP_FIXED | MAP_SHARED), "g" (fd), - "g" (offset), - "i" (&((struct stub_data *) STUB_DATA)->err) - : __syscall_clobber, "r10", "r8", "r9" ); -} - -#endif diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h deleted file mode 100644 index 7cfb0b08565..00000000000 --- a/arch/um/include/sysdep-x86_64/syscalls.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#ifndef __SYSDEP_X86_64_SYSCALLS_H__ -#define __SYSDEP_X86_64_SYSCALLS_H__ - -#include <linux/msg.h> -#include <linux/shm.h> -#include <kern_constants.h> - -typedef long syscall_handler_t(void); - -extern syscall_handler_t *sys_call_table[]; - -#define EXECUTE_SYSCALL(syscall, regs) \ - (((long (*)(long, long, long, long, long, long)) \ - (*sys_call_table[syscall]))(UPT_SYSCALL_ARG1(®s->regs), \ - UPT_SYSCALL_ARG2(®s->regs), \ - UPT_SYSCALL_ARG3(®s->regs), \ - UPT_SYSCALL_ARG4(®s->regs), \ - UPT_SYSCALL_ARG5(®s->regs), \ - UPT_SYSCALL_ARG6(®s->regs))) - -extern long old_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -extern syscall_handler_t sys_modify_ldt; -extern syscall_handler_t sys_arch_prctl; - -#endif diff --git a/arch/um/include/sysdep-x86_64/tls.h b/arch/um/include/sysdep-x86_64/tls.h deleted file mode 100644 index 35f19f25bd3..00000000000 --- a/arch/um/include/sysdep-x86_64/tls.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _SYSDEP_TLS_H -#define _SYSDEP_TLS_H - -# ifndef __KERNEL__ - -/* Change name to avoid conflicts with the original one from <asm/ldt.h>, which - * may be named user_desc (but in 2.4 and in header matching its API was named - * modify_ldt_ldt_s). */ - -typedef struct um_dup_user_desc { - unsigned int entry_number; - unsigned int base_addr; - unsigned int limit; - unsigned int seg_32bit:1; - unsigned int contents:2; - unsigned int read_exec_only:1; - unsigned int limit_in_pages:1; - unsigned int seg_not_present:1; - unsigned int useable:1; - unsigned int lm:1; -} user_desc_t; - -# else /* __KERNEL__ */ - -# include <asm/ldt.h> -typedef struct user_desc user_desc_t; - -# endif /* __KERNEL__ */ -#endif /* _SYSDEP_TLS_H */ diff --git a/arch/um/include/task.h b/arch/um/include/task.h deleted file mode 100644 index 3fe726b3cf4..00000000000 --- a/arch/um/include/task.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __TASK_H -#define __TASK_H - -#include <kern_constants.h> - -#define TASK_REGS(task) ((struct uml_pt_regs *) &(((char *) (task))[HOST_TASK_REGS])) -#define TASK_PID(task) *((int *) &(((char *) (task))[HOST_TASK_PID])) - -#endif diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h deleted file mode 100644 index ecd2265b301..00000000000 --- a/arch/um/include/tlb.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __TLB_H__ -#define __TLB_H__ - -#include "um_mmu.h" - -extern void force_flush_all(void); -extern int flush_tlb_kernel_range_common(unsigned long start, - unsigned long end); - -#endif diff --git a/arch/um/include/ubd_user.h b/arch/um/include/ubd_user.h deleted file mode 100644 index bb66517f073..00000000000 --- a/arch/um/include/ubd_user.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com) - * Licensed under the GPL - */ - -#ifndef __UM_UBD_USER_H -#define __UM_UBD_USER_H - -extern void ignore_sigwinch_sig(void); -extern int start_io_thread(unsigned long sp, int *fds_out); -extern int io_thread(void *arg); -extern int kernel_fd; - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 499e5e95e60..d8b78a03855 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -3,17 +3,22 @@ # Licensed under the GPL # +CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START) \ + -DELF_ARCH=$(LDS_ELF_ARCH) \ + -DELF_FORMAT=$(LDS_ELF_FORMAT) \ + $(LDS_EXTRA) extra-y := vmlinux.lds clean-files := -obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \ +obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \ physmem.o process.o ptrace.o reboot.o sigio.o \ - signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \ - um_arch.o umid.o skas/ + signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o \ + um_arch.o umid.o maccess.o skas/ obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o USER_OBJS := config.o @@ -28,7 +33,7 @@ $(obj)/config.tmp: $(objtree)/.config FORCE $(call if_changed,quote1) quiet_cmd_quote1 = QUOTE $@ - cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' \ + cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n",/' \ $< > $@ $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE @@ -36,9 +41,9 @@ $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE quiet_cmd_quote2 = QUOTE $@ cmd_quote2 = sed -e '/CONFIG/{' \ - -e 's/"CONFIG"\;/""/' \ + -e 's/"CONFIG"//' \ -e 'r $(obj)/config.tmp' \ -e 'a \' \ - -e '""\;' \ + -e '""' \ -e '}' \ $< > $@ diff --git a/arch/um/kernel/asm-offsets.c b/arch/um/kernel/asm-offsets.c index 91ea538e161..1fb12235ab9 100644 --- a/arch/um/kernel/asm-offsets.c +++ b/arch/um/kernel/asm-offsets.c @@ -1 +1 @@ -#include "sysdep/kernel-offsets.h" +#include <sysdep/kernel-offsets.h> diff --git a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in index c062cbfe386..972bf165956 100644 --- a/arch/um/kernel/config.c.in +++ b/arch/um/kernel/config.c.in @@ -5,13 +5,17 @@ #include <stdio.h> #include <stdlib.h> -#include "init.h" +#include <init.h> -static __initdata char *config = "CONFIG"; +static __initdata const char *config[] = { +"CONFIG" +}; static int __init print_config(char *line, int *add) { - printf("%s", config); + int i; + for (i = 0; i < sizeof(config)/sizeof(config[0]); i++) + printf("%s", config[i]); exit(0); } @@ -20,13 +24,3 @@ __uml_setup("--showconfig", print_config, " Prints the config file that this UML binary was generated from.\n\n" ); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index 26090b7f323..adde088aeef 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -1,4 +1,5 @@ #include <asm-generic/vmlinux.lds.h> +#include <asm/page.h> OUTPUT_FORMAT(ELF_FORMAT) OUTPUT_ARCH(ELF_ARCH) @@ -13,15 +14,9 @@ SECTIONS __binary_start = .; . = ALIGN(4096); /* Init code and data */ _text = .; - _stext = .; - __init_begin = .; - .init.text : { - _sinittext = .; - INIT_TEXT - _einittext = .; - } + INIT_TEXT_SECTION(PAGE_SIZE) - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); /* Read-only sections, merged into text segment: */ .hash : { *(.hash) } @@ -53,13 +48,24 @@ SECTIONS .rela.got : { *(.rela.got) } .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } + .rel.plt : { + *(.rel.plt) + PROVIDE_HIDDEN(__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN(__rel_iplt_end = .); + } + .rela.plt : { + *(.rela.plt) + PROVIDE_HIDDEN(__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN(__rela_iplt_end = .); + } .init : { KEEP (*(.init)) } =0x90909090 .plt : { *(.plt) } .text : { + _stext = .; TEXT_TEXT SCHED_TEXT LOCK_TEXT @@ -68,9 +74,9 @@ SECTIONS /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); } =0x90909090 - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); .syscall_stub : { __syscall_stub_start = .; *(.__syscall_stub*) @@ -82,9 +88,11 @@ SECTIONS .kstrtab : { *(.kstrtab) } - #include "asm/common.lds.S" + #include <asm/common.lds.S> + __init_begin = .; init.data : { INIT_DATA } + __init_end = .; /* Ensure the __preinit_array_start label is properly aligned. We could instead move the label definition inside the section, but @@ -95,10 +103,9 @@ SECTIONS .init_array : { *(.init_array) } .fini_array : { *(.fini_array) } .data : { - . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ - *(.data.init_task) + INIT_TASK_DATA(KERNEL_STACK_SIZE) . = ALIGN(KERNEL_STACK_SIZE); - *(.data.init_irqstack) + *(.data..init_irqstack) DATA_DATA *(.data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) @@ -149,10 +156,13 @@ SECTIONS . = ALIGN(32 / 8); . = ALIGN(32 / 8); } + __bss_stop = .; _end = .; PROVIDE (end = .); STABS_DEBUG DWARF_DEBUG + + DISCARDS } diff --git a/arch/um/kernel/early_printk.c b/arch/um/kernel/early_printk.c new file mode 100644 index 00000000000..4a0800bc37b --- /dev/null +++ b/arch/um/kernel/early_printk.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/console.h> +#include <linux/init.h> +#include <os.h> + +static void early_console_write(struct console *con, const char *s, unsigned int n) +{ + um_early_printk(s, n); +} + +static struct console early_console_dev = { + .name = "earlycon", + .write = early_console_write, + .flags = CON_BOOT, + .index = -1, +}; + +static int __init setup_early_printk(char *buf) +{ + if (!early_console) { + early_console = &early_console_dev; + register_console(&early_console_dev); + } + return 0; +} + +early_param("earlyprintk", setup_early_printk); diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index f5d7f4569ba..0d7103c9eff 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c @@ -3,18 +3,19 @@ * Licensed under the GPL */ -#include "linux/stddef.h" -#include "linux/fs.h" -#include "linux/smp_lock.h" -#include "linux/ptrace.h" -#include "linux/sched.h" -#include "asm/current.h" -#include "asm/processor.h" -#include "asm/uaccess.h" -#include "as-layout.h" -#include "mem_user.h" -#include "skas.h" -#include "os.h" +#include <linux/stddef.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <asm/current.h> +#include <asm/processor.h> +#include <asm/uaccess.h> +#include <as-layout.h> +#include <mem_user.h> +#include <skas.h> +#include <os.h> void flush_thread(void) { @@ -31,69 +32,19 @@ void flush_thread(void) "err = %d\n", ret); force_sig(SIGKILL, current); } + get_safe_registers(current_pt_regs()->regs.gp, + current_pt_regs()->regs.fp); __switch_mm(¤t->mm->context.id); } void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) { - set_fs(USER_DS); PT_REGS_IP(regs) = eip; PT_REGS_SP(regs) = esp; -} - -#ifdef CONFIG_TTY_LOG -extern void log_exec(char **argv, void *tty); -#endif - -static long execve1(char *file, char __user * __user *argv, - char __user *__user *env) -{ - long error; -#ifdef CONFIG_TTY_LOG - struct tty_struct *tty; - - mutex_lock(&tty_mutex); - tty = get_current_tty(); - if (tty) - log_exec(argv, tty); - mutex_unlock(&tty_mutex); -#endif - error = do_execve(file, argv, env, ¤t->thread.regs); - if (error == 0) { - task_lock(current); - current->ptrace &= ~PT_DTRACE; + current->ptrace &= ~PT_DTRACE; #ifdef SUBARCH_EXECVE1 - SUBARCH_EXECVE1(¤t->thread.regs.regs); + SUBARCH_EXECVE1(regs->regs); #endif - task_unlock(current); - } - return error; -} - -long um_execve(char *file, char __user *__user *argv, char __user *__user *env) -{ - long err; - - err = execve1(file, argv, env); - if (!err) - UML_LONGJMP(current->thread.exec_buf, 1); - return err; -} - -long sys_execve(char __user *file, char __user *__user *argv, - char __user *__user *env) -{ - long error; - char *filename; - - lock_kernel(); - filename = getname(file); - error = PTR_ERR(filename); - if (IS_ERR(filename)) goto out; - error = execve1(filename, argv, env); - putname(filename); - out: - unlock_kernel(); - return error; } +EXPORT_SYMBOL(start_thread); diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index 984f80e668c..41ebbfebb33 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -6,7 +6,9 @@ #include <linux/ctype.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/types.h> #include <asm/uaccess.h> @@ -16,35 +18,33 @@ */ int uml_exitcode = 0; -static int read_proc_exitcode(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int exitcode_proc_show(struct seq_file *m, void *v) { - int len, val; + int val; /* * Save uml_exitcode in a local so that we don't need to guarantee * that sprintf accesses it atomically. */ val = uml_exitcode; - len = sprintf(page, "%d\n", val); - len -= off; - if (len <= off+count) - *eof = 1; - *start = page + off; - if (len > count) - len = count; - if (len < 0) - len = 0; - return len; + seq_printf(m, "%d\n", val); + return 0; +} + +static int exitcode_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, exitcode_proc_show, NULL); } -static int write_proc_exitcode(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static ssize_t exitcode_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) { char *end, buf[sizeof("nnnnn\0")]; + size_t size; int tmp; - if (copy_from_user(buf, buffer, count)) + size = min(count, sizeof(buf)); + if (copy_from_user(buf, buffer, size)) return -EFAULT; tmp = simple_strtol(buf, &end, 0); @@ -55,20 +55,25 @@ static int write_proc_exitcode(struct file *file, const char __user *buffer, return count; } +static const struct file_operations exitcode_proc_fops = { + .owner = THIS_MODULE, + .open = exitcode_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = exitcode_proc_write, +}; + static int make_proc_exitcode(void) { struct proc_dir_entry *ent; - ent = create_proc_entry("exitcode", 0600, &proc_root); + ent = proc_create("exitcode", 0600, NULL, &exitcode_proc_fops); if (ent == NULL) { printk(KERN_WARNING "make_proc_exitcode : Failed to register " "/proc/exitcode\n"); return 0; } - - ent->read_proc = read_proc_exitcode; - ent->write_proc = write_proc_exitcode; - return 0; } diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c index 72eccd2a411..1bf61266da8 100644 --- a/arch/um/kernel/gmon_syms.c +++ b/arch/um/kernel/gmon_syms.c @@ -3,22 +3,7 @@ * Licensed under the GPL */ -#include "linux/module.h" +#include <linux/module.h> extern void __bb_init_func(void *) __attribute__((weak)); EXPORT_SYMBOL(__bb_init_func); - -/* - * This is defined (and referred to in profiling stub code) only by some GCC - * versions in libgcov. - * - * Since SuSE backported the fix, we cannot handle it depending on GCC version. - * So, unconditionally export it. But also give it a weak declaration, which - * will be overridden by any other one. - */ - -extern void __gcov_init(void *) __attribute__((weak)); -EXPORT_SYMBOL(__gcov_init); - -extern void __gcov_merge_add(void *) __attribute__((weak)); -EXPORT_SYMBOL(__gcov_merge_add); diff --git a/arch/um/kernel/gprof_syms.c b/arch/um/kernel/gprof_syms.c index e2f043d0de6..74ddb44288a 100644 --- a/arch/um/kernel/gprof_syms.c +++ b/arch/um/kernel/gprof_syms.c @@ -3,7 +3,7 @@ * Licensed under the GPL */ -#include "linux/module.h" +#include <linux/module.h> extern void mcount(void); EXPORT_SYMBOL(mcount); diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c deleted file mode 100644 index dcfceca9505..00000000000 --- a/arch/um/kernel/init_task.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,intel.linux}.com) - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "linux/init_task.h" -#include "linux/fs.h" -#include "linux/module.h" -#include "linux/mqueue.h" -#include "asm/uaccess.h" - -static struct fs_struct init_fs = INIT_FS; -struct mm_struct init_mm = INIT_MM(init_mm); -static struct files_struct init_files = INIT_FILES; -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -EXPORT_SYMBOL(init_mm); - -/* - * Initial task structure. - * - * All other task structs will be allocated on slabs in fork.c - */ - -struct task_struct init_task = INIT_TASK(init_task); - -EXPORT_SYMBOL(init_task); - -/* - * Initial thread structure. - * - * We need to make sure that this is aligned due to the - * way process stacks are handled. This is done by having a special - * "init_task" linker map entry.. - */ - -union thread_union init_thread_union - __attribute__((__section__(".data.init_task"))) = - { INIT_THREAD_INFO(init_task) }; - -union thread_union cpu0_irqstack - __attribute__((__section__(".data.init_irqstack"))) = - { INIT_THREAD_INFO(init_task) }; diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c index d386c75c88e..55cead809b1 100644 --- a/arch/um/kernel/initrd.c +++ b/arch/um/kernel/initrd.c @@ -3,16 +3,16 @@ * Licensed under the GPL */ -#include "linux/init.h" -#include "linux/bootmem.h" -#include "linux/initrd.h" -#include "asm/types.h" -#include "initrd.h" -#include "init.h" -#include "os.h" +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/initrd.h> +#include <asm/types.h> +#include <init.h> +#include <os.h> /* Changed by uml_initrd_setup, which is a setup */ static char *initrd __initdata = NULL; +static int load_initrd(char *filename, void *buf, int size); static int __init read_initrd(void) { @@ -62,7 +62,7 @@ __uml_setup("initrd=", uml_initrd_setup, " name of the file containing the image.\n\n" ); -int load_initrd(char *filename, void *buf, int size) +static int load_initrd(char *filename, void *buf, int size) { int fd, n; diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 91587f8db34..1d8505b1e29 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -5,59 +5,17 @@ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar */ -#include "linux/cpumask.h" -#include "linux/hardirq.h" -#include "linux/interrupt.h" -#include "linux/kernel_stat.h" -#include "linux/module.h" -#include "linux/seq_file.h" -#include "as-layout.h" -#include "kern_util.h" -#include "os.h" - -/* - * Generic, controller-independent functions: - */ - -int show_interrupts(struct seq_file *p, void *v) -{ - int i = *(loff_t *) v, j; - struct irqaction * action; - unsigned long flags; - - if (i == 0) { - seq_printf(p, " "); - for_each_online_cpu(j) - seq_printf(p, "CPU%d ",j); - seq_putc(p, '\n'); - } - - if (i < NR_IRQS) { - spin_lock_irqsave(&irq_desc[i].lock, flags); - action = irq_desc[i].action; - if (!action) - goto skip; - seq_printf(p, "%3d: ",i); -#ifndef CONFIG_SMP - seq_printf(p, "%10u ", kstat_irqs(i)); -#else - for_each_online_cpu(j) - seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); -#endif - seq_printf(p, " %14s", irq_desc[i].chip->typename); - seq_printf(p, " %s", action->name); - - for (action=action->next; action; action = action->next) - seq_printf(p, ", %s", action->name); - - seq_putc(p, '\n'); -skip: - spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } else if (i == NR_IRQS) - seq_putc(p, '\n'); - - return 0; -} +#include <linux/cpumask.h> +#include <linux/hardirq.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> /* * This list is accessed under irq_lock, except in sigio_handler, @@ -72,7 +30,7 @@ static struct irq_fd **last_irq_ptr = &active_fds; extern void free_irqs(void); -void sigio_handler(int sig, struct uml_pt_regs *regs) +void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) { struct irq_fd *irq_fd; int n; @@ -102,7 +60,7 @@ void sigio_handler(int sig, struct uml_pt_regs *regs) static DEFINE_SPINLOCK(irq_lock); -int activate_fd(int irq, int fd, int type, void *dev_id) +static int activate_fd(int irq, int fd, int type, void *dev_id) { struct pollfd *tmp_pfd; struct irq_fd *new_fd, *irq_fd; @@ -216,7 +174,7 @@ static int same_irq_and_dev(struct irq_fd *irq, void *d) return ((irq->irq == data->irq) && (irq->id == data->dev)); } -void free_irq_by_irq_and_dev(unsigned int irq, void *dev) +static void free_irq_by_irq_and_dev(unsigned int irq, void *dev) { struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq, .dev = dev }); @@ -300,6 +258,7 @@ void deactivate_fd(int fd, int irqnum) ignore_sigio_fd(fd); } +EXPORT_SYMBOL(deactivate_fd); /* * Called just before shutdown in order to provide a clean exec @@ -332,12 +291,19 @@ unsigned int do_IRQ(int irq, struct uml_pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs); irq_enter(); - __do_IRQ(irq); + generic_handle_irq(irq); irq_exit(); set_irq_regs(old_regs); return 1; } +void um_free_irq(unsigned int irq, void *dev) +{ + free_irq_by_irq_and_dev(irq, dev); + free_irq(irq, dev); +} +EXPORT_SYMBOL(um_free_irq); + int um_request_irq(unsigned int irq, int fd, int type, irq_handler_t handler, unsigned long irqflags, const char * devname, @@ -358,80 +324,40 @@ EXPORT_SYMBOL(um_request_irq); EXPORT_SYMBOL(reactivate_fd); /* - * hw_interrupt_type must define (startup || enable) && - * (shutdown || disable) && end + * irq_chip must define at least enable/disable and ack when + * the edge handler is used. */ -static void dummy(unsigned int irq) +static void dummy(struct irq_data *d) { } /* This is used for everything else than the timer. */ -static struct hw_interrupt_type normal_irq_type = { - .typename = "SIGIO", - .release = free_irq_by_irq_and_dev, - .disable = dummy, - .enable = dummy, - .ack = dummy, - .end = dummy +static struct irq_chip normal_irq_type = { + .name = "SIGIO", + .irq_disable = dummy, + .irq_enable = dummy, + .irq_ack = dummy, + .irq_mask = dummy, + .irq_unmask = dummy, }; -static struct hw_interrupt_type SIGVTALRM_irq_type = { - .typename = "SIGVTALRM", - .release = free_irq_by_irq_and_dev, - .shutdown = dummy, /* never called */ - .disable = dummy, - .enable = dummy, - .ack = dummy, - .end = dummy +static struct irq_chip SIGVTALRM_irq_type = { + .name = "SIGVTALRM", + .irq_disable = dummy, + .irq_enable = dummy, + .irq_ack = dummy, + .irq_mask = dummy, + .irq_unmask = dummy, }; void __init init_IRQ(void) { int i; - irq_desc[TIMER_IRQ].status = IRQ_DISABLED; - irq_desc[TIMER_IRQ].action = NULL; - irq_desc[TIMER_IRQ].depth = 1; - irq_desc[TIMER_IRQ].chip = &SIGVTALRM_irq_type; - enable_irq(TIMER_IRQ); - for (i = 1; i < NR_IRQS; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = NULL; - irq_desc[i].depth = 1; - irq_desc[i].chip = &normal_irq_type; - enable_irq(i); - } -} + irq_set_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq); -int init_aio_irq(int irq, char *name, irq_handler_t handler) -{ - int fds[2], err; - - err = os_pipe(fds, 1, 1); - if (err) { - printk(KERN_ERR "init_aio_irq - os_pipe failed, err = %d\n", - -err); - goto out; - } - - err = um_request_irq(irq, fds[0], IRQ_READ, handler, - IRQF_DISABLED | IRQF_SAMPLE_RANDOM, name, - (void *) (long) fds[0]); - if (err) { - printk(KERN_ERR "init_aio_irq - : um_request_irq failed, " - "err = %d\n", - err); - goto out_close; - } - - err = fds[1]; - goto out; - - out_close: - os_close_file(fds[0]); - os_close_file(fds[1]); - out: - return err; + for (i = 1; i < NR_IRQS; i++) + irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq); } /* diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 66e2a305a8d..543c0475693 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -3,34 +3,11 @@ * Licensed under the GPL */ -#include "linux/module.h" -#include "linux/syscalls.h" -#include "asm/tlbflush.h" -#include "asm/uaccess.h" -#include "as-layout.h" -#include "kern_util.h" -#include "mem_user.h" -#include "os.h" +#include <linux/module.h> +#include <os.h> -EXPORT_SYMBOL(uml_physmem); EXPORT_SYMBOL(set_signals); EXPORT_SYMBOL(get_signals); -EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(sys_waitpid); -EXPORT_SYMBOL(flush_tlb_range); -EXPORT_SYMBOL(arch_validate); - -EXPORT_SYMBOL(high_physmem); -EXPORT_SYMBOL(empty_zero_page); -EXPORT_SYMBOL(handle_page_fault); -EXPORT_SYMBOL(find_iomem); - -EXPORT_SYMBOL(strnlen_user); -EXPORT_SYMBOL(strncpy_from_user); -EXPORT_SYMBOL(copy_to_user); -EXPORT_SYMBOL(copy_from_user); -EXPORT_SYMBOL(clear_user); -EXPORT_SYMBOL(uml_strdup); EXPORT_SYMBOL(os_stat_fd); EXPORT_SYMBOL(os_stat_file); @@ -58,16 +35,10 @@ EXPORT_SYMBOL(os_connect_socket); EXPORT_SYMBOL(os_accept_connection); EXPORT_SYMBOL(os_rcv_fd); EXPORT_SYMBOL(run_helper); -EXPORT_SYMBOL(start_thread); - -#ifdef CONFIG_SMP - -/* required for SMP */ - -extern void __write_lock_failed(rwlock_t *rw); -EXPORT_SYMBOL(__write_lock_failed); - -extern void __read_lock_failed(rwlock_t *rw); -EXPORT_SYMBOL(__read_lock_failed); +EXPORT_SYMBOL(os_major); +EXPORT_SYMBOL(os_minor); +EXPORT_SYMBOL(os_makedev); -#endif +EXPORT_SYMBOL(add_sigio_fd); +EXPORT_SYMBOL(ignore_sigio_fd); +EXPORT_SYMBOL(sigio_broken); diff --git a/arch/um/kernel/maccess.c b/arch/um/kernel/maccess.c new file mode 100644 index 00000000000..1f3d5c4910d --- /dev/null +++ b/arch/um/kernel/maccess.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 Richard Weinberger <richrd@nod.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/uaccess.h> +#include <linux/kernel.h> +#include <os.h> + +long probe_kernel_read(void *dst, const void *src, size_t size) +{ + void *psrc = (void *)rounddown((unsigned long)src, PAGE_SIZE); + + if ((unsigned long)src < PAGE_SIZE || size <= 0) + return -EFAULT; + + if (os_mincore(psrc, size + src - psrc) <= 0) + return -EFAULT; + + return __probe_kernel_read(dst, src, size); +} diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 2eea1ff235e..8636e905426 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -4,24 +4,26 @@ */ #include <linux/stddef.h> +#include <linux/module.h> #include <linux/bootmem.h> -#include <linux/gfp.h> #include <linux/highmem.h> #include <linux/mm.h> #include <linux/swap.h> +#include <linux/slab.h> #include <asm/fixmap.h> #include <asm/page.h> -#include "as-layout.h" -#include "init.h" -#include "kern.h" -#include "kern_util.h" -#include "mem_user.h" -#include "os.h" +#include <as-layout.h> +#include <init.h> +#include <kern.h> +#include <kern_util.h> +#include <mem_user.h> +#include <os.h> /* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */ unsigned long *empty_zero_page = NULL; +EXPORT_SYMBOL(empty_zero_page); /* allocated in paging_init and unchanged thereafter */ -unsigned long *empty_bad_page = NULL; +static unsigned long *empty_bad_page = NULL; /* * Initialized during boot, and readonly for initializing page tables @@ -40,17 +42,12 @@ static unsigned long brk_end; static void setup_highmem(unsigned long highmem_start, unsigned long highmem_len) { - struct page *page; unsigned long highmem_pfn; int i; highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT; - for (i = 0; i < highmem_len >> PAGE_SHIFT; i++) { - page = &mem_map[highmem_pfn + i]; - ClearPageReserved(page); - init_page_count(page); - __free_page(page); - } + for (i = 0; i < highmem_len >> PAGE_SHIFT; i++) + free_highmem_page(&mem_map[highmem_pfn + i]); } #endif @@ -68,21 +65,14 @@ void __init mem_init(void) uml_reserved = brk_end; /* this will put all low memory onto the freelists */ - totalram_pages = free_all_bootmem(); + free_all_bootmem(); max_low_pfn = totalram_pages; #ifdef CONFIG_HIGHMEM - totalhigh_pages = highmem >> PAGE_SHIFT; - totalram_pages += totalhigh_pages; + setup_highmem(end_iomem, highmem); #endif - num_physpages = totalram_pages; max_pfn = totalram_pages; - printk(KERN_INFO "Memory: %luk available\n", - (unsigned long) nr_free_pages() << (PAGE_SHIFT-10)); + mem_init_print_info(NULL); kmalloc_ok = 1; - -#ifdef CONFIG_HIGHMEM - setup_highmem(end_iomem, highmem); -#endif } /* @@ -240,37 +230,6 @@ void __init paging_init(void) #endif } -struct page *arch_validate(struct page *page, gfp_t mask, int order) -{ - unsigned long addr, zero = 0; - int i; - - again: - if (page == NULL) - return page; - if (PageHighMem(page)) - return page; - - addr = (unsigned long) page_address(page); - for (i = 0; i < (1 << order); i++) { - current->thread.fault_addr = (void *) addr; - if (__do_copy_to_user((void __user *) addr, &zero, - sizeof(zero), - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)) { - if (!(mask & __GFP_WAIT)) - return NULL; - else break; - } - addr += PAGE_SIZE; - } - - if (i == (1 << order)) - return page; - page = alloc_pages(mask, order); - goto again; -} - /* * This can't do anything because nothing in the kernel image can be freed * since it's not in kernel physical memory. @@ -283,49 +242,10 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - if (start < end) - printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", - (end - start) >> 10); - for (; start < end; start += PAGE_SIZE) { - ClearPageReserved(virt_to_page(start)); - init_page_count(virt_to_page(start)); - free_page(start); - totalram_pages++; - } + free_reserved_area((void *)start, (void *)end, -1, "initrd"); } #endif -void show_mem(void) -{ - int pfn, total = 0, reserved = 0; - int shared = 0, cached = 0; - int high_mem = 0; - struct page *page; - - printk(KERN_INFO "Mem-info:\n"); - show_free_areas(); - printk(KERN_INFO "Free swap: %6ldkB\n", - nr_swap_pages<<(PAGE_SHIFT-10)); - pfn = max_mapnr; - while (pfn-- > 0) { - page = pfn_to_page(pfn); - total++; - if (PageHighMem(page)) - high_mem++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page) - 1; - } - printk(KERN_INFO "%d pages of RAM\n", total); - printk(KERN_INFO "%d pages of HIGHMEM\n", high_mem); - printk(KERN_INFO "%d reserved pages\n", reserved); - printk(KERN_INFO "%d pages shared\n", shared); - printk(KERN_INFO "%d pages swap cached\n", cached); -} - /* Allocate and free page tables. */ pgd_t *pgd_alloc(struct mm_struct *mm) @@ -359,8 +279,12 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address) struct page *pte; pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); - if (pte) - pgtable_page_ctor(pte); + if (!pte) + return NULL; + if (!pgtable_page_ctor(pte)) { + __free_page(pte); + return NULL; + } return pte; } @@ -375,3 +299,8 @@ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) return pmd; } #endif + +void *uml_kmalloc(int size, int flags) +{ + return kmalloc(size, flags); +} diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index 9757085a022..30fdd5d0067 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -3,20 +3,22 @@ * Licensed under the GPL */ -#include "linux/bootmem.h" -#include "linux/mm.h" -#include "linux/pfn.h" -#include "asm/page.h" -#include "as-layout.h" -#include "init.h" -#include "kern.h" -#include "mem_user.h" -#include "os.h" +#include <linux/module.h> +#include <linux/bootmem.h> +#include <linux/mm.h> +#include <linux/pfn.h> +#include <asm/page.h> +#include <as-layout.h> +#include <init.h> +#include <kern.h> +#include <mem_user.h> +#include <os.h> static int physmem_fd = -1; /* Changed during early boot */ unsigned long high_physmem; +EXPORT_SYMBOL(high_physmem); extern unsigned long long physmem_size; @@ -101,6 +103,7 @@ void __init setup_physmem(unsigned long start, unsigned long reserve_end, */ os_seek_file(physmem_fd, __pa(&__syscall_stub_start)); os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE); + os_fsync_file(physmem_fd); bootmap_size = init_bootmem(pfn, pfn + delta); free_bootmem(__pa(reserve_end) + bootmap_size, @@ -184,8 +187,9 @@ unsigned long find_iomem(char *driver, unsigned long *len_out) return 0; } +EXPORT_SYMBOL(find_iomem); -int setup_iomem(void) +static int setup_iomem(void) { struct iomem_region *region = iomem_regions; unsigned long iomem_start = high_physmem + PAGE_SIZE; diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index e8cb9ff183e..f17bca8ed2c 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -7,23 +7,26 @@ #include <linux/stddef.h> #include <linux/err.h> #include <linux/hardirq.h> -#include <linux/gfp.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/personality.h> #include <linux/proc_fs.h> #include <linux/ptrace.h> #include <linux/random.h> +#include <linux/slab.h> #include <linux/sched.h> +#include <linux/seq_file.h> #include <linux/tick.h> #include <linux/threads.h> +#include <linux/tracehook.h> #include <asm/current.h> #include <asm/pgtable.h> +#include <asm/mmu_context.h> #include <asm/uaccess.h> -#include "as-layout.h" -#include "kern_util.h" -#include "os.h" -#include "skas.h" -#include "tlb.h" +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> +#include <skas.h> /* * This is a per-cpu array. A processor only modifies its entry and it only @@ -66,17 +69,6 @@ unsigned long alloc_stack(int order, int atomic) return page; } -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - int pid; - - current->thread.request.u.thread.proc = fn; - current->thread.request.u.thread.arg = arg; - pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, - ¤t->thread.regs, 0, NULL, NULL); - return pid; -} - static inline void set_current(struct task_struct *task) { cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) @@ -85,47 +77,34 @@ static inline void set_current(struct task_struct *task) extern void arch_switch_to(struct task_struct *to); -void *_switch_to(void *prev, void *next, void *last) +void *__switch_to(struct task_struct *from, struct task_struct *to) { - struct task_struct *from = prev; - struct task_struct *to = next; - to->thread.prev_sched = from; set_current(to); - do { - current->thread.saved_task = NULL; - - switch_threads(&from->thread.switch_buf, - &to->thread.switch_buf); - - arch_switch_to(current); - - if (current->thread.saved_task) - show_regs(&(current->thread.regs)); - to = current->thread.saved_task; - from = current; - } while (current->thread.saved_task); + switch_threads(&from->thread.switch_buf, &to->thread.switch_buf); + arch_switch_to(current); return current->thread.prev_sched; - } void interrupt_end(void) { if (need_resched()) schedule(); - if (test_tsk_thread_flag(current, TIF_SIGPENDING)) + if (test_thread_flag(TIF_SIGPENDING)) do_signal(); + if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) + tracehook_notify_resume(¤t->thread.regs); } void exit_thread(void) { } -void *get_current(void) +int get_current_pid(void) { - return current; + return task_pid_nr(current); } /* @@ -145,16 +124,10 @@ void new_thread_handler(void) arg = current->thread.request.u.thread.arg; /* - * The return value is 1 if the kernel thread execs a process, - * 0 if it just exits + * callback returns only if the kernel thread execs a process */ - n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); - if (n == 1) { - /* Handle any immediate reschedules or signals */ - interrupt_end(); - userspace(¤t->thread.regs.regs); - } - else do_exit(0); + n = fn(arg); + userspace(¤t->thread.regs.regs); } /* Called magically, see new_thread_handler above */ @@ -173,41 +146,38 @@ void fork_handler(void) current->thread.prev_sched = NULL; - /* Handle any immediate reschedules or signals */ - interrupt_end(); - userspace(¤t->thread.regs.regs); } -int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, - unsigned long stack_top, struct task_struct * p, - struct pt_regs *regs) +int copy_thread(unsigned long clone_flags, unsigned long sp, + unsigned long arg, struct task_struct * p) { void (*handler)(void); + int kthread = current->flags & PF_KTHREAD; int ret = 0; p->thread = (struct thread_struct) INIT_THREAD; - if (current->thread.forking) { - memcpy(&p->thread.regs.regs, ®s->regs, + if (!kthread) { + memcpy(&p->thread.regs.regs, current_pt_regs(), sizeof(p->thread.regs.regs)); - REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.gp, 0); + PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0); if (sp != 0) REGS_SP(p->thread.regs.regs.gp) = sp; handler = fork_handler; arch_copy_thread(¤t->thread.arch, &p->thread.arch); - } - else { - get_safe_registers(p->thread.regs.regs.gp); - p->thread.request.u.thread = current->thread.request.u.thread; + } else { + get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp); + p->thread.request.u.thread.proc = (int (*)(void *))sp; + p->thread.request.u.thread.arg = (void *)arg; handler = new_thread_handler; } new_thread(task_stack_page(p), &p->thread.switch_buf, handler); - if (current->thread.forking) { + if (!kthread) { clear_flushed_tls(p); /* @@ -229,31 +199,14 @@ void initial_thread_cb(void (*proc)(void *), void *arg) kmalloc_ok = save_kmalloc_ok; } -void default_idle(void) +void arch_cpu_idle(void) { unsigned long long nsecs; - while (1) { - /* endless idle loop with no priority at all */ - - /* - * although we are an idle CPU, we do not want to - * get into the scheduler unnecessarily. - */ - if (need_resched()) - schedule(); - - tick_nohz_stop_sched_tick(); - nsecs = disable_timer(); - idle_sleep(nsecs); - tick_nohz_restart_sched_tick(); - } -} - -void cpu_idle(void) -{ cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); - default_idle(); + nsecs = disable_timer(); + idle_sleep(nsecs); + local_irq_enable(); } int __cant_sleep(void) { @@ -284,6 +237,7 @@ char *uml_strdup(const char *string) { return kstrdup(string, GFP_KERNEL); } +EXPORT_SYMBOL(uml_strdup); int copy_to_user_proc(void __user *to, void *from, int size) { @@ -336,16 +290,19 @@ int get_using_sysemu(void) return atomic_read(&using_sysemu); } -static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data) +static int sysemu_proc_show(struct seq_file *m, void *v) { - if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) - /* No overflow */ - *eof = 1; + seq_printf(m, "%d\n", get_using_sysemu()); + return 0; +} - return strlen(buf); +static int sysemu_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, sysemu_proc_show, NULL); } -static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned long count,void *data) +static ssize_t sysemu_proc_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) { char tmp[2]; @@ -358,13 +315,22 @@ static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned return count; } +static const struct file_operations sysemu_proc_fops = { + .owner = THIS_MODULE, + .open = sysemu_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = sysemu_proc_write, +}; + int __init make_proc_sysemu(void) { struct proc_dir_entry *ent; if (!sysemu_supported) return 0; - ent = create_proc_entry("sysemu", 0600, &proc_root); + ent = proc_create("sysemu", 0600, NULL, &sysemu_proc_fops); if (ent == NULL) { @@ -372,9 +338,6 @@ int __init make_proc_sysemu(void) return 0; } - ent->read_proc = proc_read_sysemu; - ent->write_proc = proc_write_sysemu; - return 0; } @@ -396,7 +359,7 @@ int singlestepping(void * t) /* * Only x86 and x86_64 have an arch_align_stack(). * All other arches have "#define arch_align_stack(x) (x)" - * in their asm/system.h + * in their asm/exec.h * As this is included in UML from asm-um/system-generic.h, * we can use it to behave as the subarch does. */ diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 47b57b497d5..694d551c889 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -3,25 +3,32 @@ * Licensed under the GPL */ -#include "linux/audit.h" -#include "linux/ptrace.h" -#include "linux/sched.h" -#include "asm/uaccess.h" -#ifdef CONFIG_PROC_MM -#include "proc_mm.h" +#include <linux/audit.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/tracehook.h> +#include <asm/uaccess.h> +#include <skas_ptrace.h> + + + +void user_enable_single_step(struct task_struct *child) +{ + child->ptrace |= PT_DTRACE; + child->thread.singlestep_syscall = 0; + +#ifdef SUBARCH_SET_SINGLESTEPPING + SUBARCH_SET_SINGLESTEPPING(child, 1); #endif -#include "skas_ptrace.h" +} -static inline void set_singlestepping(struct task_struct *child, int on) +void user_disable_single_step(struct task_struct *child) { - if (on) - child->ptrace |= PT_DTRACE; - else - child->ptrace &= ~PT_DTRACE; + child->ptrace &= ~PT_DTRACE; child->thread.singlestep_syscall = 0; #ifdef SUBARCH_SET_SINGLESTEPPING - SUBARCH_SET_SINGLESTEPPING(child, on); + SUBARCH_SET_SINGLESTEPPING(child, 0); #endif } @@ -30,86 +37,34 @@ static inline void set_singlestepping(struct task_struct *child, int on) */ void ptrace_disable(struct task_struct *child) { - set_singlestepping(child,0); + user_disable_single_step(child); } extern int peek_user(struct task_struct * child, long addr, long data); extern int poke_user(struct task_struct * child, long addr, long data); -long arch_ptrace(struct task_struct *child, long request, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) { int i, ret; - unsigned long __user *p = (void __user *)(unsigned long)data; + unsigned long __user *p = (void __user *)data; + void __user *vp = p; switch (request) { - /* read word at location addr. */ - case PTRACE_PEEKTEXT: - case PTRACE_PEEKDATA: - ret = generic_ptrace_peekdata(child, addr, data); - break; - /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: ret = peek_user(child, addr, data); break; - /* write the word at location addr. */ - case PTRACE_POKETEXT: - case PTRACE_POKEDATA: - ret = generic_ptrace_pokedata(child, addr, data); - break; - /* write the word at location addr in the USER area */ case PTRACE_POKEUSR: ret = poke_user(child, addr, data); break; - /* continue and stop at next (return from) syscall */ - case PTRACE_SYSCALL: - /* restart after signal. */ - case PTRACE_CONT: { + case PTRACE_SYSEMU: + case PTRACE_SYSEMU_SINGLESTEP: ret = -EIO; - if (!valid_signal(data)) - break; - - set_singlestepping(child, 0); - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->exit_code = data; - wake_up_process(child); - ret = 0; - break; - } - -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - - set_singlestepping(child, 0); - child->exit_code = SIGKILL; - wake_up_process(child); - break; - } - - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - ret = -EIO; - if (!valid_signal(data)) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - set_singlestepping(child, 1); - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; break; - } #ifdef PTRACE_GETREGS case PTRACE_GETREGS: { /* Get all gp regs from the child. */ @@ -141,26 +96,12 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } #endif -#ifdef PTRACE_GETFPREGS - case PTRACE_GETFPREGS: /* Get the child FPU state. */ - ret = get_fpregs((struct user_i387_struct __user *) data, - child); - break; -#endif -#ifdef PTRACE_SETFPREGS - case PTRACE_SETFPREGS: /* Set the child FPU state. */ - ret = set_fpregs((struct user_i387_struct __user *) data, - child); - break; -#endif case PTRACE_GET_THREAD_AREA: - ret = ptrace_get_thread_area(child, addr, - (struct user_desc __user *) data); + ret = ptrace_get_thread_area(child, addr, vp); break; case PTRACE_SET_THREAD_AREA: - ret = ptrace_set_thread_area(child, addr, - (struct user_desc __user *) data); + ret = ptrace_set_thread_area(child, addr, vp); break; case PTRACE_FAULTINFO: { @@ -170,7 +111,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) * On i386, ptrace_faultinfo is smaller! */ ret = copy_to_user(p, &child->thread.arch.faultinfo, - sizeof(struct ptrace_faultinfo)); + sizeof(struct ptrace_faultinfo)) ? + -EIO : 0; break; } @@ -191,30 +133,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } #endif -#ifdef CONFIG_PROC_MM - case PTRACE_SWITCH_MM: { - struct mm_struct *old = child->mm; - struct mm_struct *new = proc_mm_get_mm(data); - - if (IS_ERR(new)) { - ret = PTR_ERR(new); - break; - } - - atomic_inc(&new->mm_users); - child->mm = new; - child->active_mm = new; - mmput(old); - ret = 0; - break; - } -#endif -#ifdef PTRACE_ARCH_PRCTL - case PTRACE_ARCH_PRCTL: - /* XXX Calls ptrace on the host - needs some SMP thinking */ - ret = arch_prctl(child, data, (void *) addr); - break; -#endif default: ret = ptrace_request(child, request, addr, data); if (ret == -EIO) @@ -225,7 +143,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return ret; } -void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs, +static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs, int error_code) { struct siginfo info; @@ -245,50 +163,36 @@ void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs, * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check */ -void syscall_trace(struct uml_pt_regs *regs, int entryexit) +void syscall_trace_enter(struct pt_regs *regs) { - int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit; - int tracesysgood; - - if (unlikely(current->audit_context)) { - if (!entryexit) - audit_syscall_entry(HOST_AUDIT_ARCH, - UPT_SYSCALL_NR(regs), - UPT_SYSCALL_ARG1(regs), - UPT_SYSCALL_ARG2(regs), - UPT_SYSCALL_ARG3(regs), - UPT_SYSCALL_ARG4(regs)); - else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), - UPT_SYSCALL_RET(regs)); - } - - /* Fake a debug trap */ - if (is_singlestep) - send_sigtrap(current, regs, 0); + audit_syscall_entry(HOST_AUDIT_ARCH, + UPT_SYSCALL_NR(®s->regs), + UPT_SYSCALL_ARG1(®s->regs), + UPT_SYSCALL_ARG2(®s->regs), + UPT_SYSCALL_ARG3(®s->regs), + UPT_SYSCALL_ARG4(®s->regs)); if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; - if (!(current->ptrace & PT_PTRACED)) - return; + tracehook_report_syscall_entry(regs); +} - /* - * the 0x80 provides a way for the tracing parent to distinguish - * between a syscall stop and SIGTRAP delivery - */ - tracesysgood = (current->ptrace & PT_TRACESYSGOOD); - ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0)); +void syscall_trace_leave(struct pt_regs *regs) +{ + int ptraced = current->ptrace; - if (entryexit) /* force do_signal() --> is_syscall() */ - set_thread_flag(TIF_SIGPENDING); + audit_syscall_exit(regs); - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } + /* Fake a debug trap */ + if (ptraced & PT_DTRACE) + send_sigtrap(current, ®s->regs, 0); + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + + tracehook_report_syscall_exit(regs, 0); + /* force do_signal() --> is_syscall() */ + if (ptraced & PT_PTRACED) + set_thread_flag(TIF_SIGPENDING); } diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 00197d3d21e..ced8903921a 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -3,10 +3,13 @@ * Licensed under the GPL */ -#include "linux/sched.h" -#include "kern_util.h" -#include "os.h" -#include "skas.h" +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/oom.h> +#include <kern_util.h> +#include <os.h> +#include <skas.h> void (*pm_power_off)(void); @@ -19,16 +22,20 @@ static void kill_off_processes(void) os_kill_ptraced_process(userspace_pid[0], 1); else { struct task_struct *p; - int pid, me; + int pid; - me = os_getpid(); + read_lock(&tasklist_lock); for_each_process(p) { - if (p->mm == NULL) - continue; + struct task_struct *t; - pid = p->mm->context.id.u.pid; + t = find_lock_task_mm(p); + if (!t) + continue; + pid = t->mm->context.id.u.pid; + task_unlock(t); os_kill_ptraced_process(pid, 1); } + read_unlock(&tasklist_lock); } } diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c index 2b272b63b51..b5e0cbb3438 100644 --- a/arch/um/kernel/sigio.c +++ b/arch/um/kernel/sigio.c @@ -4,9 +4,9 @@ */ #include <linux/interrupt.h> -#include "irq_kern.h" -#include "os.h" -#include "sigio.h" +#include <irq_kern.h> +#include <os.h> +#include <sigio.h> /* Protected by sigio_lock() called from write_sigio_workaround */ static int sigio_irq_fd = -1; @@ -25,8 +25,7 @@ int write_sigio_irq(int fd) int err; err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, - IRQF_DISABLED|IRQF_SAMPLE_RANDOM, "write sigio", - NULL); + 0, "write sigio", NULL); if (err) { printk(KERN_ERR "write_sigio_irq : um_request_irq failed, " "err = %d\n", err); diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c index b0fce720c4d..f57e02e7910 100644 --- a/arch/um/kernel/signal.c +++ b/arch/um/kernel/signal.c @@ -9,29 +9,25 @@ #include <asm/siginfo.h> #include <asm/signal.h> #include <asm/unistd.h> -#include "frame_kern.h" -#include "kern_util.h" -#include "sigcontext.h" +#include <frame_kern.h> +#include <kern_util.h> EXPORT_SYMBOL(block_signals); EXPORT_SYMBOL(unblock_signals); -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) - /* * OK, we're invoking a handler */ -static int handle_signal(struct pt_regs *regs, unsigned long signr, - struct k_sigaction *ka, siginfo_t *info, - sigset_t *oldset) +static void handle_signal(struct pt_regs *regs, unsigned long signr, + struct k_sigaction *ka, struct siginfo *info) { + sigset_t *oldset = sigmask_to_save(); + int singlestep = 0; unsigned long sp; int err; - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; + if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) + singlestep = 1; /* Did we come from a system call? */ if (PT_REGS_SYSCALL_NR(regs) >= 0) { @@ -66,51 +62,22 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, #endif err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset); - if (err) { - spin_lock_irq(¤t->sighand->siglock); - current->blocked = *oldset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + if (err) force_sigsegv(signr, current); - } else { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } - - return err; + else + signal_delivered(signr, info, ka, regs, singlestep); } static int kern_do_signal(struct pt_regs *regs) { struct k_sigaction ka_copy; - siginfo_t info; - sigset_t *oldset; + struct siginfo info; int sig, handled_sig = 0; - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - oldset = ¤t->saved_sigmask; - else - oldset = ¤t->blocked; - while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) { handled_sig = 1; /* Whee! Actually deliver the signal. */ - if (!handle_signal(regs, sig, &ka_copy, &info, oldset)) { - /* - * a signal was successfully delivered; the saved - * sigmask will have been stored in the signal frame, - * and will be restored by sigreturn, so we can simply - * clear the TIF_RESTORE_SIGMASK flag - */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); - break; - } + handle_signal(regs, sig, &ka_copy, &info); } /* Did we come from a system call? */ @@ -146,10 +113,8 @@ static int kern_do_signal(struct pt_regs *regs) * if there's no signal to deliver, we just put the saved sigmask * back */ - if (!handled_sig && test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); - sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); - } + if (!handled_sig) + restore_saved_sigmask(); return handled_sig; } @@ -157,26 +122,3 @@ int do_signal(void) { return kern_do_signal(¤t->thread.regs); } - -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -long sys_sigsuspend(int history0, int history1, old_sigset_t mask) -{ - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - current->saved_sigmask = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; -} - -long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) -{ - return do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs)); -} diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c index 2c8583c1a34..289771dadf8 100644 --- a/arch/um/kernel/skas/clone.c +++ b/arch/um/kernel/skas/clone.c @@ -7,11 +7,10 @@ #include <sched.h> #include <asm/unistd.h> #include <sys/time.h> -#include "as-layout.h" -#include "kern_constants.h" -#include "ptrace_user.h" -#include "stub-data.h" -#include "sysdep/stub.h" +#include <as-layout.h> +#include <ptrace_user.h> +#include <stub-data.h> +#include <sysdep/stub.h> /* * This is in a separate file because it needs to be compiled with any diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 0cd9a7a05e7..007d5503f49 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -3,13 +3,14 @@ * Licensed under the GPL */ -#include "linux/mm.h" -#include "linux/sched.h" -#include "asm/pgalloc.h" -#include "asm/pgtable.h" -#include "as-layout.h" -#include "os.h" -#include "skas.h" +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <asm/pgalloc.h> +#include <asm/pgtable.h> +#include <as-layout.h> +#include <os.h> +#include <skas.h> extern int __syscall_stub_start; @@ -30,7 +31,7 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc, if (!pmd) goto out_pmd; - pte = pte_alloc_map(mm, pmd, proc); + pte = pte_alloc_map(mm, NULL, pmd, proc); if (!pte) goto out_pte; @@ -38,10 +39,10 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc, *pte = pte_mkread(*pte); return 0; - out_pmd: - pud_free(mm, pud); out_pte: pmd_free(mm, pmd); + out_pmd: + pud_free(mm, pud); out: return -ENOMEM; } @@ -91,8 +92,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) goto out_free; } - to_mm->stub_pages = NULL; - return 0; out_free: @@ -102,9 +101,8 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) return ret; } -void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) +void uml_setup_stubs(struct mm_struct *mm) { - struct page **pages; int err, ret; if (!skas_needs_stub) @@ -119,29 +117,20 @@ void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) if (ret) goto out; - pages = kmalloc(2 * sizeof(struct page *), GFP_KERNEL); - if (pages == NULL) { - printk(KERN_ERR "arch_dup_mmap failed to allocate 2 page " - "pointers\n"); - goto out; - } - - pages[0] = virt_to_page(&__syscall_stub_start); - pages[1] = virt_to_page(mm->context.id.stack); - mm->context.stub_pages = pages; + mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start); + mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack); /* dup_mmap already holds mmap_sem */ err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START, VM_READ | VM_MAYREAD | VM_EXEC | - VM_MAYEXEC | VM_DONTCOPY, pages); + VM_MAYEXEC | VM_DONTCOPY | VM_PFNMAP, + mm->context.stub_pages); if (err) { printk(KERN_ERR "install_special_mapping returned %d\n", err); - goto out_free; + goto out; } return; -out_free: - kfree(pages); out: force_sigsegv(SIGSEGV, current); } @@ -150,8 +139,6 @@ void arch_exit_mmap(struct mm_struct *mm) { pte_t *pte; - if (mm->context.stub_pages != NULL) - kfree(mm->context.stub_pages); pte = virt_to_pte(mm, STUB_CODE); if (pte != NULL) pte_clear(mm, STUB_CODE, pte); diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 2e9852c0d48..4da11b3c8dd 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -3,12 +3,12 @@ * Licensed under the GPL */ -#include "linux/init.h" -#include "linux/sched.h" -#include "as-layout.h" -#include "kern.h" -#include "os.h" -#include "skas.h" +#include <linux/init.h> +#include <linux/sched.h> +#include <as-layout.h> +#include <kern.h> +#include <os.h> +#include <skas.h> int new_mm(unsigned long stack) { @@ -41,7 +41,7 @@ static int __init start_kernel_proc(void *unused) cpu_tasks[0].pid = pid; cpu_tasks[0].task = current; #ifdef CONFIG_SMP - cpu_online_map = cpumask_of_cpu(0); + init_cpu_online(get_cpu_mask(0)); #endif start_kernel(); return 0; diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index 4e3b820bd2b..c0681e09743 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -3,14 +3,14 @@ * Licensed under the GPL */ -#include "linux/kernel.h" -#include "linux/ptrace.h" -#include "kern_util.h" -#include "sysdep/ptrace.h" -#include "sysdep/syscalls.h" +#include <linux/kernel.h> +#include <linux/ptrace.h> +#include <kern_util.h> +#include <sysdep/ptrace.h> +#include <sysdep/syscalls.h> extern int syscall_table_size; -#define NR_syscalls (syscall_table_size / sizeof(void *)) +#define NR_SYSCALLS (syscall_table_size / sizeof(void *)) void handle_syscall(struct uml_pt_regs *r) { @@ -18,7 +18,7 @@ void handle_syscall(struct uml_pt_regs *r) long result; int syscall; - syscall_trace(r, 0); + syscall_trace_enter(regs); /* * This should go in the declaration of syscall, but when I do that, @@ -30,11 +30,11 @@ void handle_syscall(struct uml_pt_regs *r) * in case it's a compiler bug. */ syscall = UPT_SYSCALL_NR(r); - if ((syscall >= NR_syscalls) || (syscall < 0)) + if ((syscall >= NR_SYSCALLS) || (syscall < 0)) result = -ENOSYS; else result = EXECUTE_SYSCALL(syscall, regs); - REGS_SET_SYSCALL_RETURN(r->gp, result); + PT_REGS_SET_SYSCALL_RETURN(regs, result); - syscall_trace(r, 1); + syscall_trace_leave(regs); } diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index e22c96993db..4ffb644d6c0 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -6,12 +6,13 @@ #include <linux/err.h> #include <linux/highmem.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/sched.h> #include <asm/current.h> #include <asm/page.h> #include <asm/pgtable.h> -#include "kern_util.h" -#include "os.h" +#include <kern_util.h> +#include <os.h> pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr) { @@ -68,7 +69,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write, return -1; page = pte_page(*pte); - addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) + + addr = (unsigned long) kmap_atomic(page) + (addr & ~PAGE_MASK); current->thread.fault_catcher = &buf; @@ -81,7 +82,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write, current->thread.fault_catcher = NULL; - kunmap_atomic(page, KM_UML_USERCOPY); + kunmap_atomic((void *)addr); return n; } @@ -149,6 +150,7 @@ int copy_from_user(void *to, const void __user *from, int n) buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to): n; } +EXPORT_SYMBOL(copy_from_user); static int copy_chunk_to_user(unsigned long to, int len, void *arg) { @@ -170,6 +172,7 @@ int copy_to_user(void __user *to, const void *from, int n) buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) : n; } +EXPORT_SYMBOL(copy_to_user); static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) { @@ -204,6 +207,7 @@ int strncpy_from_user(char *dst, const char __user *src, int count) return -EFAULT; return strnlen(dst, count); } +EXPORT_SYMBOL(strncpy_from_user); static int clear_chunk(unsigned long addr, int len, void *unused) { @@ -226,6 +230,7 @@ int clear_user(void __user *mem, int len) return access_ok(VERIFY_WRITE, mem, len) ? buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len; } +EXPORT_SYMBOL(clear_user); static int strnlen_chunk(unsigned long str, int len, void *arg) { @@ -249,5 +254,6 @@ int strnlen_user(const void __user *str, int len) n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count); if (n == 0) return count + 1; - return -EFAULT; + return 0; } +EXPORT_SYMBOL(strnlen_user); diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index e1062ec36d4..5c8c3ea7db7 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -3,34 +3,24 @@ * Licensed under the GPL */ -#include "linux/percpu.h" -#include "asm/pgalloc.h" -#include "asm/tlb.h" - -/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */ -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); +#include <linux/percpu.h> +#include <asm/pgalloc.h> +#include <asm/tlb.h> #ifdef CONFIG_SMP -#include "linux/sched.h" -#include "linux/module.h" -#include "linux/threads.h" -#include "linux/interrupt.h" -#include "linux/err.h" -#include "linux/hardirq.h" -#include "asm/smp.h" -#include "asm/processor.h" -#include "asm/spinlock.h" -#include "kern.h" -#include "irq_user.h" -#include "os.h" - -/* CPU online map, set by smp_boot_cpus */ -cpumask_t cpu_online_map = CPU_MASK_NONE; -cpumask_t cpu_possible_map = CPU_MASK_NONE; - -EXPORT_SYMBOL(cpu_online_map); -EXPORT_SYMBOL(cpu_possible_map); +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/threads.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/hardirq.h> +#include <asm/smp.h> +#include <asm/processor.h> +#include <asm/spinlock.h> +#include <kern.h> +#include <irq_user.h> +#include <os.h> /* Per CPU bogomips and other parameters * The only piece used here is the ipi pipe, which is set before SMP is @@ -85,7 +75,8 @@ static int idle_proc(void *cpup) while (!cpu_isset(cpu, smp_commenced_mask)) cpu_relax(); - cpu_set(cpu, cpu_online_map); + notify_cpu_starting(cpu); + set_cpu_online(cpu, true); default_idle(); return 0; } @@ -117,10 +108,9 @@ void smp_prepare_cpus(unsigned int maxcpus) int i; for (i = 0; i < ncpus; ++i) - cpu_set(i, cpu_possible_map); + set_cpu_possible(i, true); - cpu_clear(me, cpu_online_map); - cpu_set(me, cpu_online_map); + set_cpu_online(me, true); cpu_set(me, cpu_callin_map); err = os_pipe(cpu_data[me].ipi_pipe, 1, 1); @@ -147,13 +137,13 @@ void smp_prepare_cpus(unsigned int maxcpus) void smp_prepare_boot_cpu(void) { - cpu_set(smp_processor_id(), cpu_online_map); + set_cpu_online(smp_processor_id(), true); } -int __cpu_up(unsigned int cpu) +int __cpu_up(unsigned int cpu, struct task_struct *tidle) { cpu_set(cpu, smp_commenced_mask); - while (!cpu_isset(cpu, cpu_online_map)) + while (!cpu_online(cpu)) mb(); return 0; } @@ -179,7 +169,7 @@ void IPI_handler(int cpu) break; case 'R': - set_tsk_need_resched(current); + scheduler_ipi(); break; case 'S': @@ -214,8 +204,7 @@ void smp_call_function_slave(int cpu) atomic_inc(&scf_finished); } -int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, - int wait) +int smp_call_function(void (*_func)(void *info), void *_info, int wait) { int cpus = num_online_cpus() - 1; int i; diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index 9cffc628a37..c1d0ae069b5 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -3,63 +3,16 @@ * Licensed under the GPL */ -#include "linux/file.h" -#include "linux/fs.h" -#include "linux/mm.h" -#include "linux/sched.h" -#include "linux/utsname.h" -#include "asm/current.h" -#include "asm/mman.h" -#include "asm/uaccess.h" -#include "asm/unistd.h" - -long sys_fork(void) -{ - long ret; - - current->thread.forking = 1; - ret = do_fork(SIGCHLD, UPT_SP(¤t->thread.regs.regs), - ¤t->thread.regs, 0, NULL, NULL); - current->thread.forking = 0; - return ret; -} - -long sys_vfork(void) -{ - long ret; - - current->thread.forking = 1; - ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, - UPT_SP(¤t->thread.regs.regs), - ¤t->thread.regs, 0, NULL, NULL); - current->thread.forking = 0; - return ret; -} - -/* common code for old and new mmaps */ -long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - long error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); - out: - return error; -} +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/utsname.h> +#include <linux/syscalls.h> +#include <asm/current.h> +#include <asm/mman.h> +#include <asm/uaccess.h> +#include <asm/unistd.h> long old_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, @@ -69,82 +22,7 @@ long old_mmap(unsigned long addr, unsigned long len, if (offset & ~PAGE_MASK) goto out; - err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + err = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); out: return err; } -/* - * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way unix traditionally does this, though. - */ -long sys_pipe(unsigned long __user * fildes) -{ - int fd[2]; - long error; - - error = do_pipe(fd); - if (!error) { - if (copy_to_user(fildes, fd, sizeof(fd))) - error = -EFAULT; - } - return error; -} - - -long sys_uname(struct old_utsname __user * name) -{ - long err; - if (!name) - return -EFAULT; - down_read(&uts_sem); - err = copy_to_user(name, utsname(), sizeof (*name)); - up_read(&uts_sem); - return err?-EFAULT:0; -} - -long sys_olduname(struct oldold_utsname __user * name) -{ - long error; - - if (!name) - return -EFAULT; - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) - return -EFAULT; - - down_read(&uts_sem); - - error = __copy_to_user(&name->sysname, &utsname()->sysname, - __OLD_UTS_LEN); - error |= __put_user(0, name->sysname + __OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename, &utsname()->nodename, - __OLD_UTS_LEN); - error |= __put_user(0, name->nodename + __OLD_UTS_LEN); - error |= __copy_to_user(&name->release, &utsname()->release, - __OLD_UTS_LEN); - error |= __put_user(0, name->release + __OLD_UTS_LEN); - error |= __copy_to_user(&name->version, &utsname()->version, - __OLD_UTS_LEN); - error |= __put_user(0, name->version + __OLD_UTS_LEN); - error |= __copy_to_user(&name->machine, &utsname()->machine, - __OLD_UTS_LEN); - error |= __put_user(0, name->machine + __OLD_UTS_LEN); - - up_read(&uts_sem); - - error = error ? -EFAULT : 0; - - return error; -} - -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) -{ - mm_segment_t fs; - int ret; - - fs = get_fs(); - set_fs(KERNEL_DS); - ret = um_execve(filename, argv, envp); - set_fs(fs); - - return ret; -} diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 56d43d0a396..799d7e413bf 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -1,78 +1,98 @@ /* * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL + * Copyright (C) 2013 Richard Weinberger <richrd@nod.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include <linux/kallsyms.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h> -#include "sysrq.h" +#include <asm/sysrq.h> +#include <os.h> -/* Catch non-i386 SUBARCH's. */ -#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT) -void show_trace(struct task_struct *task, unsigned long * stack) +struct stack_frame { + struct stack_frame *next_frame; + unsigned long return_address; +}; + +static void do_stack_trace(unsigned long *sp, unsigned long bp) { + int reliable; unsigned long addr; + struct stack_frame *frame = (struct stack_frame *)bp; - if (!stack) { - stack = (unsigned long*) &stack; - WARN_ON(1); - } - - printk(KERN_INFO "Call Trace: \n"); - while (((long) stack & (THREAD_SIZE-1)) != 0) { - addr = *stack; + printk(KERN_INFO "Call Trace:\n"); + while (((long) sp & (THREAD_SIZE-1)) != 0) { + addr = *sp; if (__kernel_text_address(addr)) { - printk(KERN_INFO "%08lx: [<%08lx>]", - (unsigned long) stack, addr); - print_symbol(KERN_CONT " %s", addr); + reliable = 0; + if ((unsigned long) sp == bp + sizeof(long)) { + frame = frame ? frame->next_frame : NULL; + bp = (unsigned long)frame; + reliable = 1; + } + + printk(KERN_INFO " [<%08lx>]", addr); + printk(KERN_CONT " %s", reliable ? "" : "? "); + print_symbol(KERN_CONT "%s", addr); printk(KERN_CONT "\n"); } - stack++; + sp++; } printk(KERN_INFO "\n"); } -#endif -/* - * stack dumps generator - this is used by arch-independent code. - * And this is identical to i386 currently. - */ -void dump_stack(void) +static unsigned long get_frame_pointer(struct task_struct *task, + struct pt_regs *segv_regs) { - unsigned long stack; - - show_trace(current, &stack); + if (!task || task == current) + return segv_regs ? PT_REGS_BP(segv_regs) : current_bp(); + else + return KSTK_EBP(task); } -EXPORT_SYMBOL(dump_stack); -/*Stolen from arch/i386/kernel/traps.c */ -static const int kstack_depth_to_print = 24; +static unsigned long *get_stack_pointer(struct task_struct *task, + struct pt_regs *segv_regs) +{ + if (!task || task == current) + return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp(); + else + return (unsigned long *)KSTK_ESP(task); +} -/* This recently started being used in arch-independent code too, as in - * kernel/sched.c.*/ -void show_stack(struct task_struct *task, unsigned long *esp) +void show_stack(struct task_struct *task, unsigned long *stack) { - unsigned long *stack; + unsigned long *sp = stack, bp = 0; + struct pt_regs *segv_regs = current->thread.segv_regs; int i; - if (esp == NULL) { - if (task != current && task != NULL) { - esp = (unsigned long *) KSTK_ESP(task); - } else { - esp = (unsigned long *) &esp; - } + if (!segv_regs && os_is_signal_stack()) { + printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler," + " aborting stack trace!\n"); + return; } - stack = esp; - for (i = 0; i < kstack_depth_to_print; i++) { +#ifdef CONFIG_FRAME_POINTER + bp = get_frame_pointer(task, segv_regs); +#endif + + if (!stack) + sp = get_stack_pointer(task, segv_regs); + + printk(KERN_INFO "Stack:\n"); + stack = sp; + for (i = 0; i < 3 * STACKSLOTS_PER_LINE; i++) { if (kstack_end(stack)) break; - if (i && ((i % 8) == 0)) - printk("\n" KERN_INFO " "); - printk("%08lx ", *stack++); + if (i && ((i % STACKSLOTS_PER_LINE) == 0)) + printk(KERN_CONT "\n"); + printk(KERN_CONT " %08lx", *stack++); } + printk(KERN_CONT "\n"); - show_trace(task, esp); + do_stack_trace(sp, bp); } diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index e066e84493b..117568d4f64 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -4,23 +4,16 @@ */ #include <linux/clockchips.h> +#include <linux/init.h> #include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/threads.h> #include <asm/irq.h> #include <asm/param.h> -#include "kern_util.h" -#include "os.h" +#include <kern_util.h> +#include <os.h> -/* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies_64 * (NSEC_PER_SEC / HZ); -} - -void timer_handler(int sig, struct uml_pt_regs *regs) +void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) { unsigned long flags; @@ -57,7 +50,7 @@ static int itimer_next_event(unsigned long delta, static struct clock_event_device itimer_clockevent = { .name = "itimer", .rating = 250, - .cpumask = CPU_MASK_ALL, + .cpumask = cpu_all_mask, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_mode = itimer_set_mode, .set_next_event = itimer_next_event, @@ -72,9 +65,9 @@ static irqreturn_t um_timer(int irq, void *dev) return IRQ_HANDLED; } -static cycle_t itimer_read(void) +static cycle_t itimer_read(struct clocksource *cs) { - return os_nsecs(); + return os_nsecs() / 1000; } static struct clocksource itimer_clocksource = { @@ -82,8 +75,6 @@ static struct clocksource itimer_clocksource = { .rating = 300, .read = itimer_read, .mask = CLOCKSOURCE_MASK(64), - .mult = 1, - .shift = 0, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -91,7 +82,7 @@ static void __init setup_itimer(void) { int err; - err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL); + err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL); if (err != 0) printk(KERN_ERR "register_timer : request_irq failed - " "errno = %d\n", -err); @@ -101,26 +92,24 @@ static void __init setup_itimer(void) clockevent_delta2ns(60 * HZ, &itimer_clockevent); itimer_clockevent.min_delta_ns = clockevent_delta2ns(1, &itimer_clockevent); - err = clocksource_register(&itimer_clocksource); + err = clocksource_register_hz(&itimer_clocksource, USEC_PER_SEC); if (err) { - printk(KERN_ERR "clocksource_register returned %d\n", err); + printk(KERN_ERR "clocksource_register_hz returned %d\n", err); return; } clockevents_register_device(&itimer_clockevent); } -extern void (*late_time_init)(void); +void read_persistent_clock(struct timespec *ts) +{ + long long nsecs = os_nsecs(); + + set_normalized_timespec(ts, nsecs / NSEC_PER_SEC, + nsecs % NSEC_PER_SEC); +} void __init time_init(void) { - long long nsecs; - timer_init(); - - nsecs = os_nsecs(); - set_normalized_timespec(&wall_to_monotonic, -nsecs / NSEC_PER_SEC, - -nsecs % NSEC_PER_SEC); - set_normalized_timespec(&xtime, nsecs / NSEC_PER_SEC, - nsecs % NSEC_PER_SEC); late_time_init = setup_itimer; } diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index d175d0566af..f1b3eb14b85 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -4,14 +4,15 @@ */ #include <linux/mm.h> +#include <linux/module.h> #include <linux/sched.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> -#include "as-layout.h" -#include "mem_user.h" -#include "os.h" -#include "skas.h" -#include "tlb.h" +#include <as-layout.h> +#include <mem_user.h> +#include <os.h> +#include <skas.h> +#include <kern_util.h> struct host_vm_change { struct host_vm_op { @@ -75,6 +76,7 @@ static int do_ops(struct host_vm_change *hvc, int end, default: printk(KERN_ERR "Unknown op type %d in do_ops\n", op->type); + BUG(); break; } } @@ -123,6 +125,9 @@ static int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *last; int ret = 0; + if ((addr >= STUB_START) && (addr < STUB_END)) + return -EINVAL; + if (hvc->index != 0) { last = &hvc->ops[hvc->index - 1]; if ((last->type == MUNMAP) && @@ -282,12 +287,15 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, /* This is not an else because ret is modified above */ if (ret) { printk(KERN_ERR "fix_range_common: failed, killing current " - "process\n"); + "process: %d\n", task_tgid_vnr(current)); + /* We are under mmap_sem, release it such that current can terminate */ + up_write(¤t->mm->mmap_sem); force_sig(SIGKILL, current); + do_signal(); } } -int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) +static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) { struct mm_struct *mm; pgd_t *pgd; @@ -499,6 +507,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, flush_tlb_kernel_range_common(start, end); else fix_range(vma->vm_mm, start, end, 0); } +EXPORT_SYMBOL(flush_tlb_range); void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, unsigned long end) diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 44e49041949..5678c3571e7 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -6,15 +6,15 @@ #include <linux/mm.h> #include <linux/sched.h> #include <linux/hardirq.h> +#include <linux/module.h> #include <asm/current.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> -#include "arch.h" -#include "as-layout.h" -#include "kern_util.h" -#include "os.h" -#include "skas.h" -#include "sysdep/sigcontext.h" +#include <arch.h> +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> +#include <skas.h> /* * Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by @@ -30,6 +30,7 @@ int handle_page_fault(unsigned long address, unsigned long ip, pmd_t *pmd; pte_t *pte; int err = -EFAULT; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; *code_out = SEGV_MAPERR; @@ -40,6 +41,9 @@ int handle_page_fault(unsigned long address, unsigned long ip, if (in_atomic()) goto out_nosemaphore; + if (is_user) + flags |= FAULT_FLAG_USER; +retry: down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) @@ -55,20 +59,26 @@ int handle_page_fault(unsigned long address, unsigned long ip, good_area: *code_out = SEGV_ACCERR; - if (is_write && !(vma->vm_flags & VM_WRITE)) - goto out; - - /* Don't require VM_READ|VM_EXEC for write faults! */ - if (!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC))) - goto out; + if (is_write) { + if (!(vma->vm_flags & VM_WRITE)) + goto out; + flags |= FAULT_FLAG_WRITE; + } else { + /* Don't require VM_READ|VM_EXEC for write faults! */ + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto out; + } do { int fault; -survive: - fault = handle_mm_fault(mm, vma, address, is_write); + + fault = handle_mm_fault(mm, vma, address, flags); + + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + goto out_nosemaphore; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) { - err = -ENOMEM; goto out_of_memory; } else if (fault & VM_FAULT_SIGBUS) { err = -EACCES; @@ -76,10 +86,18 @@ survive: } BUG(); } - if (fault & VM_FAULT_MAJOR) - current->maj_flt++; - else - current->min_flt++; + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) + current->maj_flt++; + else + current->min_flt++; + if (fault & VM_FAULT_RETRY) { + flags &= ~FAULT_FLAG_ALLOW_RETRY; + flags |= FAULT_FLAG_TRIED; + + goto retry; + } + } pgd = pgd_offset(mm, address); pud = pud_offset(pgd, address); @@ -104,18 +122,38 @@ out: out_nosemaphore: return err; -/* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ out_of_memory: - if (is_global_init(current)) { - up_read(&mm->mmap_sem); - yield(); - down_read(&mm->mmap_sem); - goto survive; - } - goto out; + /* + * We ran out of memory, call the OOM killer, and return the userspace + * (which will retry the fault, or kill us if we got oom-killed). + */ + up_read(&mm->mmap_sem); + if (!is_user) + goto out_nosemaphore; + pagefault_out_of_memory(); + return 0; +} +EXPORT_SYMBOL(handle_page_fault); + +static void show_segv_info(struct uml_pt_regs *regs) +{ + struct task_struct *tsk = current; + struct faultinfo *fi = UPT_FAULTINFO(regs); + + if (!unhandled_signal(tsk, SIGSEGV)) + return; + + if (!printk_ratelimit()) + return; + + printk("%s%s[%d]: segfault at %lx ip %p sp %p error %x", + task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, + tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi), + (void *)UPT_IP(regs), (void *)UPT_SP(regs), + fi->error_code); + + print_vma_addr(KERN_CONT " in ", UPT_IP(regs)); + printk(KERN_CONT "\n"); } static void bad_segv(struct faultinfo fi, unsigned long ip) @@ -141,11 +179,12 @@ void fatal_sigsegv(void) os_dump_core(); } -void segv_handler(int sig, struct uml_pt_regs *regs) +void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) { struct faultinfo * fi = UPT_FAULTINFO(regs); if (UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)) { + show_segv_info(regs); bad_segv(*fi, UPT_IP(regs)); return; } @@ -167,9 +206,12 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, int is_write = FAULT_WRITE(fi); unsigned long address = FAULT_ADDRESS(fi); + if (!is_user && regs) + current->thread.segv_regs = container_of(regs, struct pt_regs, regs); + if (!is_user && (address >= start_vm) && (address < end_vm)) { flush_tlb_kernel_vm(); - return 0; + goto out; } else if (current->mm == NULL) { show_regs(container_of(regs, struct pt_regs, regs)); @@ -191,7 +233,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, catcher = current->thread.fault_catcher; if (!err) - return 0; + goto out; else if (catcher != NULL) { current->thread.fault_addr = (void *) address; UML_LONGJMP(catcher, 1); @@ -199,7 +241,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, else if (current->thread.fault_addr != NULL) panic("fault_addr set but no fault catcher"); else if (!is_user && arch_fixup(ip, regs)) - return 0; + goto out; if (!is_user) { show_regs(container_of(regs, struct pt_regs, regs)); @@ -207,6 +249,8 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, address, ip); } + show_segv_info(regs); + if (err == -EACCES) { si.si_signo = SIGBUS; si.si_errno = 0; @@ -214,9 +258,6 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, si.si_addr = (void __user *)address; current->thread.arch.faultinfo = fi; force_sig_info(SIGBUS, &si, current); - } else if (err == -ENOMEM) { - printk(KERN_INFO "VM: killing process %s\n", current->comm); - do_exit(SIGKILL); } else { BUG_ON(err != -EFAULT); si.si_signo = SIGSEGV; @@ -224,11 +265,19 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, current->thread.arch.faultinfo = fi; force_sig_info(SIGSEGV, &si, current); } + +out: + if (regs) + current->thread.segv_regs = NULL; + return 0; } -void relay_signal(int sig, struct uml_pt_regs *regs) +void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs) { + struct faultinfo *fi; + struct siginfo clean_si; + if (!UPT_IS_USER(regs)) { if (sig == SIGBUS) printk(KERN_ERR "Bus error - the host /dev/shm or /tmp " @@ -238,18 +287,40 @@ void relay_signal(int sig, struct uml_pt_regs *regs) arch_examine_signal(sig, regs); - current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); - force_sig(sig, current); + memset(&clean_si, 0, sizeof(clean_si)); + clean_si.si_signo = si->si_signo; + clean_si.si_errno = si->si_errno; + clean_si.si_code = si->si_code; + switch (sig) { + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGTRAP: + fi = UPT_FAULTINFO(regs); + clean_si.si_addr = (void __user *) FAULT_ADDRESS(*fi); + current->thread.arch.faultinfo = *fi; +#ifdef __ARCH_SI_TRAPNO + clean_si.si_trapno = si->si_trapno; +#endif + break; + default: + printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d)\n", + sig, si->si_code); + } + + force_sig_info(sig, &clean_si, current); } -void bus_handler(int sig, struct uml_pt_regs *regs) +void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs) { if (current->thread.fault_catcher != NULL) UML_LONGJMP(current->thread.fault_catcher, 1); - else relay_signal(sig, regs); + else + relay_signal(sig, si, regs); } -void winch(int sig, struct uml_pt_regs *regs) +void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) { do_IRQ(WINCH_IRQ, regs); } diff --git a/arch/um/kernel/uaccess.c b/arch/um/kernel/uaccess.c deleted file mode 100644 index f0f4b040d7c..00000000000 --- a/arch/um/kernel/uaccess.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) - * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -/* - * These are here rather than tt/uaccess.c because skas mode needs them in - * order to do SIGBUS recovery when a tmpfs mount runs out of room. - */ - -#include <linux/string.h> -#include "os.h" - -void __do_copy(void *to, const void *from, int n) -{ - memcpy(to, from, n); -} - - -int __do_copy_to_user(void *to, const void *from, int n, - void **fault_addr, jmp_buf **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, - __do_copy, &faulted); - if (!faulted) - return 0; - else - return n - (fault - (unsigned long) to); -} diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index a6c1dd1cf5a..016adf0985d 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -10,16 +10,18 @@ #include <linux/seq_file.h> #include <linux/string.h> #include <linux/utsname.h> +#include <linux/sched.h> #include <asm/pgtable.h> #include <asm/processor.h> +#include <asm/sections.h> #include <asm/setup.h> -#include "as-layout.h" -#include "arch.h" -#include "init.h" -#include "kern.h" -#include "kern_util.h" -#include "mem_user.h" -#include "os.h" +#include <as-layout.h> +#include <arch.h> +#include <init.h> +#include <kern.h> +#include <kern_util.h> +#include <mem_user.h> +#include <os.h> #define DEFAULT_COMMAND_LINE "root=98:0" @@ -47,6 +49,10 @@ struct cpuinfo_um boot_cpu_data = { .ipi_pipe = { -1, -1 } }; +union thread_union cpu0_irqstack + __attribute__((__section__(".data..init_irqstack"))) = + { INIT_THREAD_INFO(init_task) }; + unsigned long thread_saved_pc(struct task_struct *task) { /* FIXME: Need to look up userspace_pid by cpu */ @@ -102,6 +108,8 @@ const struct seq_operations cpuinfo_op = { /* Set in linux_main */ unsigned long uml_physmem; +EXPORT_SYMBOL(uml_physmem); + unsigned long uml_reserved; /* Also modified in mem_init */ unsigned long start_vm; unsigned long end_vm; @@ -115,7 +123,7 @@ static int have_root __initdata = 0; /* Set in uml_mem_setup and modified in linux_main */ long long physmem_size = 32 * 1024 * 1024; -static char *usage_string = +static const char *usage_string = "User Mode Linux v%s\n" " available at http://user-mode-linux.sourceforge.net/\n\n"; @@ -150,7 +158,7 @@ __uml_setup("root=", uml_root_setup, static int __init no_skas_debug_setup(char *line, int *add) { printf("'debug' is not necessary to gdb UML in skas mode - run \n"); - printf("'gdb linux'"); + printf("'gdb linux'\n"); return 0; } @@ -202,7 +210,7 @@ static void __init uml_checksetup(char *line, int *add) p = &__uml_setup_start; while (p < &__uml_setup_end) { - int n; + size_t n; n = strlen(p->str); if (!strncmp(line, p->str, n) && p->setup_func(line + n, add)) @@ -227,7 +235,6 @@ static int panic_exit(struct notifier_block *self, unsigned long unused1, void *unused2) { bust_spinlocks(1); - show_regs(&(current->thread.regs)); bust_spinlocks(0); uml_exitcode = 1; os_dump_core(); @@ -258,7 +265,9 @@ int __init linux_main(int argc, char **argv) { unsigned long avail, diff; unsigned long virtmem_size, max_physmem; - unsigned int i, add; + unsigned long stack; + unsigned int i; + int add; char * mode; for (i = 1; i < argc; i++) { @@ -272,7 +281,7 @@ int __init linux_main(int argc, char **argv) if (have_root == 0) add_arg(DEFAULT_COMMAND_LINE); - host_task_size = os_get_task_size(); + host_task_size = os_get_top_address(); /* * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps * out @@ -347,7 +356,9 @@ int __init linux_main(int argc, char **argv) } virtmem_size = physmem_size; - avail = TASK_SIZE - start_vm; + stack = (unsigned long) argv; + stack &= ~(1024 * 1024 - 1); + avail = stack - start_vm; if (physmem_size > avail) virtmem_size = avail; end_vm = start_vm + virtmem_size; diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c index 81e07e2be3a..f6cc3bd6178 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -4,9 +4,9 @@ */ #include <asm/errno.h> -#include "init.h" -#include "kern.h" -#include "os.h" +#include <init.h> +#include <kern.h> +#include <os.h> /* Changed by set_umid_arg */ static int umid_inited = 0; diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index 5828c1d5450..6899195602b 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -1,4 +1,5 @@ #include <asm-generic/vmlinux.lds.h> +#include <asm/page.h> OUTPUT_FORMAT(ELF_FORMAT) OUTPUT_ARCH(ELF_ARCH) @@ -19,17 +20,12 @@ SECTIONS . = START + SIZEOF_HEADERS; _text = .; - _stext = .; - __init_begin = .; - .init.text : { - _sinittext = .; - INIT_TEXT - _einittext = .; - } - . = ALIGN(4096); + INIT_TEXT_SECTION(0) + . = ALIGN(PAGE_SIZE); .text : { + _stext = .; TEXT_TEXT SCHED_TEXT LOCK_TEXT @@ -39,22 +35,41 @@ SECTIONS *(.gnu.linkonce.t*) } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); .syscall_stub : { __syscall_stub_start = .; *(.__syscall_stub*) __syscall_stub_end = .; } - #include "asm/common.lds.S" + /* + * These are needed even in a static link, even if they wind up being empty. + * Newer glibc needs these __rel{,a}_iplt_{start,end} symbols. + */ + .rel.plt : { + *(.rel.plt) + PROVIDE_HIDDEN(__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN(__rel_iplt_end = .); + } + .rela.plt : { + *(.rela.plt) + PROVIDE_HIDDEN(__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN(__rela_iplt_end = .); + } + + #include <asm/common.lds.S> + __init_begin = .; init.data : { INIT_DATA } + __init_end = .; + .data : { - . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ - *(.data.init_task) + INIT_TASK_DATA(KERNEL_STACK_SIZE) . = ALIGN(KERNEL_STACK_SIZE); - *(.data.init_irqstack) + *(.data..init_irqstack) DATA_DATA *(.gnu.linkonce.d*) CONSTRUCTORS @@ -79,24 +94,18 @@ SECTIONS .sdata : { *(.sdata) } _edata = .; PROVIDE (edata = .); - . = ALIGN(0x1000); - .sbss : - { - __bss_start = .; - PROVIDE(_bss_start = .); - *(.sbss) - *(.scommon) - } - .bss : - { - *(.dynbss) - *(.bss) - *(COMMON) - } + . = ALIGN(PAGE_SIZE); + __bss_start = .; + PROVIDE(_bss_start = .); + SBSS(0) + BSS(0) + __bss_stop = .; _end = .; PROVIDE (end = .); STABS_DEBUG DWARF_DEBUG + + DISCARDS } diff --git a/arch/um/kernel/vmlinux.lds.S b/arch/um/kernel/vmlinux.lds.S index f8aeb448aab..16e49bfa2b4 100644 --- a/arch/um/kernel/vmlinux.lds.S +++ b/arch/um/kernel/vmlinux.lds.S @@ -1,3 +1,6 @@ + +KERNEL_STACK_SIZE = 4096 * (1 << CONFIG_KERNEL_STACK_ORDER); + #ifdef CONFIG_LD_SCRIPT_STATIC #include "uml.lds.S" #else diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 8a48d6a3006..08ff5094fcd 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -3,18 +3,15 @@ # Licensed under the GPL # -obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ - registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \ - umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/ +obj-y = aio.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ + registers.o sigio.o signal.o start_up.o time.o tty.o \ + umid.o user_syms.o util.o drivers/ skas/ -obj-$(CONFIG_TTY_LOG) += tty_log.o -user-objs-$(CONFIG_TTY_LOG) += tty_log.o +obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) += elf_aux.o USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \ main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \ - tty.o tls.o uaccess.o umid.o util.o - -CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) + tty.o umid.o util.o HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \ echo -DHAVE_AIO_ABI ) diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index 57e3d46c989..014eb35fd13 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c @@ -9,12 +9,10 @@ #include <errno.h> #include <sys/time.h> #include <asm/unistd.h> -#include "aio.h" -#include "init.h" -#include "kern_constants.h" -#include "kern_util.h" -#include "os.h" -#include "user.h" +#include <aio.h> +#include <init.h> +#include <kern_util.h> +#include <os.h> struct aio_thread_req { enum aio_type type; @@ -106,8 +104,7 @@ static int aio_thread(void *arg) struct io_event event; int err, n, reply_fd; - signal(SIGWINCH, SIG_IGN); - + os_fix_helper_signals(); while (1) { n = io_getevents(ctx, 1, 1, &event, NULL); if (n < 0) { @@ -175,7 +172,7 @@ static int not_aio_thread(void *arg) struct aio_thread_reply reply; int err; - signal(SIGWINCH, SIG_IGN); + os_fix_helper_signals(); while (1) { err = read(aio_req_fd_r, &req, sizeof(req)); if (err != sizeof(req)) { diff --git a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h index ddffd41c3f3..54183a679fd 100644 --- a/arch/um/os-Linux/drivers/etap.h +++ b/arch/um/os-Linux/drivers/etap.h @@ -6,7 +6,7 @@ #ifndef __DRIVERS_ETAP_H #define __DRIVERS_ETAP_H -#include "net_user.h" +#include <net_user.h> struct ethertap_data { char *dev_name; diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c index 046a131f610..f424600a583 100644 --- a/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/arch/um/os-Linux/drivers/ethertap_kern.c @@ -9,7 +9,7 @@ #include <linux/init.h> #include <linux/netdevice.h> #include "etap.h" -#include "net_kern.h" +#include <net_kern.h> struct ethertap_init { char *dev_name; @@ -22,7 +22,7 @@ static void etap_init(struct net_device *dev, void *data) struct ethertap_data *epri; struct ethertap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); epri = (struct ethertap_data *) pri->user; epri->dev_name = init->dev_name; epri->gate_addr = init->gate_addr; diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index 6fb0b174f53..b39b6696ac5 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -13,11 +13,9 @@ #include <sys/socket.h> #include <sys/wait.h> #include "etap.h" -#include "kern_constants.h" -#include "os.h" -#include "net_user.h" -#include "um_malloc.h" -#include "user.h" +#include <os.h> +#include <net_user.h> +#include <um_malloc.h> #define MAX_PACKET ETH_MAX_PACKET @@ -52,7 +50,7 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask, return; } - output = kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL); + output = uml_kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL); if (output == NULL) printk(UM_KERN_ERR "etap_change : Failed to allocate output " "buffer\n"); @@ -165,7 +163,7 @@ static int etap_open(void *data) err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], control_fds[1], data_fds[0], data_fds[1]); output_len = UM_KERN_PAGE_SIZE; - output = kmalloc(output_len, UM_GFP_KERNEL); + output = uml_kmalloc(output_len, UM_GFP_KERNEL); read_output(control_fds[0], output, output_len); if (output == NULL) diff --git a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h index f17c31586c8..7367354ac8d 100644 --- a/arch/um/os-Linux/drivers/tuntap.h +++ b/arch/um/os-Linux/drivers/tuntap.h @@ -6,7 +6,7 @@ #ifndef __UM_TUNTAP_H #define __UM_TUNTAP_H -#include "net_user.h" +#include <net_user.h> struct tuntap_data { char *dev_name; diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index 6b9e33d5de2..d9d56e5810f 100644 --- a/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/arch/um/os-Linux/drivers/tuntap_kern.c @@ -7,7 +7,7 @@ #include <linux/init.h> #include <linux/skbuff.h> #include <asm/errno.h> -#include "net_kern.h" +#include <net_kern.h> #include "tuntap.h" struct tuntap_init { @@ -21,7 +21,7 @@ static void tuntap_init(struct net_device *dev, void *data) struct tuntap_data *tpri; struct tuntap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); tpri = (struct tuntap_data *) pri->user; tpri->dev_name = init->dev_name; tpri->fixed_config = (init->dev_name != NULL); diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index 2448be03fd7..14126d9176a 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -13,11 +13,9 @@ #include <sys/socket.h> #include <sys/wait.h> #include <sys/uio.h> -#include "kern_constants.h" -#include "kern_util.h" -#include "os.h" +#include <kern_util.h> +#include <os.h> #include "tuntap.h" -#include "user.h" static int tuntap_user_init(void *data, void *dev) { diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 608784d4ec5..1a365ddc4d0 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c @@ -9,21 +9,15 @@ */ #include <elf.h> #include <stddef.h> -#include "init.h" -#include "elf_user.h" -#include "mem_user.h" -#include <kern_constants.h> +#include <init.h> +#include <elf_user.h> +#include <mem_user.h> -/* Use the one from the kernel - the host may miss it, if having old headers. */ -#if UM_ELF_CLASS == UM_ELFCLASS32 typedef Elf32_auxv_t elf_auxv_t; -#else -typedef Elf64_auxv_t elf_auxv_t; -#endif /* These are initialized very early in boot and never changed */ char * elf_aux_platform; -long elf_aux_hwcap; +extern long elf_aux_hwcap; unsigned long vsyscall_ehdr; unsigned long vsyscall_end; unsigned long __kernel_vsyscall; diff --git a/arch/um/os-Linux/execvp.c b/arch/um/os-Linux/execvp.c index 66e583a4031..8fb25ca07c4 100644 --- a/arch/um/os-Linux/execvp.c +++ b/arch/um/os-Linux/execvp.c @@ -27,12 +27,12 @@ #include <limits.h> #ifndef TEST -#include "um_malloc.h" +#include <um_malloc.h> #else #include <stdio.h> #define um_kmalloc malloc #endif -#include "os.h" +#include <os.h> /* Execute FILE, searching in the `PATH' environment variable if it contains no slashes, with arguments ARGV and environment from `environ'. */ diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index b5afcfd0f86..08d90fba952 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -13,9 +13,7 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/un.h> -#include "kern_constants.h" -#include "os.h" -#include "user.h" +#include <os.h> static void copy_stat(struct uml_stat *dst, const struct stat64 *src) { @@ -239,6 +237,12 @@ void os_close_file(int fd) { close(fd); } +int os_fsync_file(int fd) +{ + if (fsync(fd) < 0) + return -errno; + return 0; +} int os_seek_file(int fd, unsigned long long offset) { @@ -268,6 +272,15 @@ int os_write_file(int fd, const void *buf, int len) return n; } +int os_sync_file(int fd) +{ + int n = fsync(fd); + + if (n < 0) + return -errno; + return n; +} + int os_file_size(const char *file, unsigned long long *size_out) { struct uml_stat buf; @@ -561,3 +574,18 @@ int os_lock_file(int fd, int excl) out: return err; } + +unsigned os_major(unsigned long long dev) +{ + return major(dev); +} + +unsigned os_minor(unsigned long long dev) +{ + return minor(dev); +} + +unsigned long long os_makedev(unsigned major, unsigned minor) +{ + return makedev(major, minor); +} diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index f4bd349d441..e3ee4a51ef6 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -7,13 +7,12 @@ #include <unistd.h> #include <errno.h> #include <sched.h> +#include <linux/limits.h> #include <sys/socket.h> #include <sys/wait.h> -#include "kern_constants.h" -#include "kern_util.h" -#include "os.h" -#include "um_malloc.h" -#include "user.h" +#include <kern_util.h> +#include <os.h> +#include <um_malloc.h> struct helper_data { void (*pre_exec)(void*); @@ -27,14 +26,14 @@ static int helper_child(void *arg) { struct helper_data *data = arg; char **argv = data->argv; - int err; + int err, ret; if (data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); err = execvp_noalloc(data->buf, argv[0], argv); /* If the exec succeeds, we don't get here */ - write(data->fd, &err, sizeof(err)); + CATCH_EINTR(ret = write(data->fd, &err, sizeof(err))); return 0; } @@ -70,8 +69,8 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) data.pre_data = pre_data; data.argv = argv; data.fd = fds[1]; - data.buf = __cant_sleep() ? kmalloc(PATH_MAX, UM_GFP_ATOMIC) : - kmalloc(PATH_MAX, UM_GFP_KERNEL); + data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) : + uml_kmalloc(PATH_MAX, UM_GFP_KERNEL); pid = clone(helper_child, (void *) sp, CLONE_VM, &data); if (pid < 0) { ret = -errno; diff --git a/arch/um/os-Linux/include/file.h b/arch/um/os-Linux/include/file.h deleted file mode 100644 index fe71be24bd5..00000000000 --- a/arch/um/os-Linux/include/file.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#ifndef __OS_FILE_H__ -#define __OS_FILE_H__ - -#define DEV_NULL "/dev/null" - -#endif diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h new file mode 100644 index 00000000000..0dc2c9f135f --- /dev/null +++ b/arch/um/os-Linux/internal.h @@ -0,0 +1 @@ +void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc); diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c index 0348b975e81..b9afb74b79a 100644 --- a/arch/um/os-Linux/irq.c +++ b/arch/um/os-Linux/irq.c @@ -8,12 +8,9 @@ #include <poll.h> #include <signal.h> #include <string.h> -#include "irq_user.h" -#include "kern_constants.h" -#include "os.h" -#include "process.h" -#include "um_malloc.h" -#include "user.h" +#include <irq_user.h> +#include <os.h> +#include <um_malloc.h> /* * Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index abb9b0ffd96..df9191acd92 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -10,17 +10,18 @@ #include <signal.h> #include <string.h> #include <sys/resource.h> -#include "as-layout.h" -#include "init.h" -#include "kern_constants.h" -#include "kern_util.h" -#include "os.h" -#include "um_malloc.h" +#include <as-layout.h> +#include <init.h> +#include <kern_util.h> +#include <os.h> +#include <um_malloc.h> #define PGD_BOUND (4 * 1024 * 1024) #define STACKSIZE (8 * 1024 * 1024) #define THREAD_NAME_LEN (256) +long elf_aux_hwcap; + static void set_stklim(void) { struct rlimit lim; @@ -78,7 +79,7 @@ static void install_fatal_handler(int sig) } } -#define UML_LIB_PATH ":/usr/lib/uml" +#define UML_LIB_PATH ":" OS_LIB_PATH "/uml" static void setup_env_path(void) { @@ -122,6 +123,8 @@ int __init main(int argc, char **argv, char **envp) setup_env_path(); + setsid(); + new_argv = malloc((argc + 1) * sizeof(char *)); if (new_argv == NULL) { perror("Mallocing argv"); @@ -142,11 +145,13 @@ int __init main(int argc, char **argv, char **envp) */ install_fatal_handler(SIGINT); install_fatal_handler(SIGTERM); - install_fatal_handler(SIGHUP); +#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA scan_elf_aux(envp); +#endif do_uml_initcalls(); + change_sig(SIGPIPE, 0); ret = linux_main(argc, argv); /* @@ -199,7 +204,7 @@ void *__wrap_malloc(int size) return __real_malloc(size); else if (size <= UM_KERN_PAGE_SIZE) /* finding contiguous pages can be hard*/ - ret = kmalloc(size, UM_GFP_KERNEL); + ret = uml_kmalloc(size, UM_GFP_KERNEL); else ret = vmalloc(size); /* diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 93a11d7edfa..897e9ad0c10 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -10,206 +10,135 @@ #include <errno.h> #include <fcntl.h> #include <string.h> +#include <sys/stat.h> #include <sys/mman.h> -#include <sys/param.h> -#include "init.h" -#include "kern_constants.h" -#include "os.h" -#include "user.h" +#include <sys/vfs.h> +#include <linux/magic.h> +#include <init.h> +#include <os.h> -/* Modified by which_tmpdir, which is called during early boot */ -static char *default_tmpdir = "/tmp"; - -/* - * Modified when creating the physical memory file and when checking - * the tmp filesystem for usability, both happening during early boot. - */ +/* Set by make_tempfile() during early boot. */ static char *tempdir = NULL; -static void __init find_tempdir(void) +/* Check if dir is on tmpfs. Return 0 if yes, -1 if no or error. */ +static int __init check_tmpfs(const char *dir) { - const char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; - int i; - char *dir = NULL; - - if (tempdir != NULL) - /* We've already been called */ - return; - for (i = 0; dirs[i]; i++) { - dir = getenv(dirs[i]); - if ((dir != NULL) && (*dir != '\0')) - break; + struct statfs st; + + printf("Checking if %s is on tmpfs...", dir); + if (statfs(dir, &st) < 0) { + printf("%s\n", strerror(errno)); + } else if (st.f_type != TMPFS_MAGIC) { + printf("no\n"); + } else { + printf("OK\n"); + return 0; } - if ((dir == NULL) || (*dir == '\0')) - dir = default_tmpdir; - - tempdir = malloc(strlen(dir) + 2); - if (tempdir == NULL) { - fprintf(stderr, "Failed to malloc tempdir, " - "errno = %d\n", errno); - return; - } - strcpy(tempdir, dir); - strcat(tempdir, "/"); + return -1; } /* - * This will return 1, with the first character in buf being the - * character following the next instance of c in the file. This will - * read the file as needed. If there's an error, -errno is returned; - * if the end of the file is reached, 0 is returned. + * Choose the tempdir to use. We want something on tmpfs so that our memory is + * not subject to the host's vm.dirty_ratio. If a tempdir is specified in the + * environment, we use that even if it's not on tmpfs, but we warn the user. + * Otherwise, we try common tmpfs locations, and if no tmpfs directory is found + * then we fall back to /tmp. */ -static int next(int fd, char *buf, size_t size, char c) +static char * __init choose_tempdir(void) { - ssize_t n; - size_t len; - char *ptr; - - while ((ptr = strchr(buf, c)) == NULL) { - n = read(fd, buf, size - 1); - if (n == 0) - return 0; - else if (n < 0) - return -errno; - - buf[n] = '\0'; + static const char * const vars[] = { + "TMPDIR", + "TMP", + "TEMP", + NULL + }; + static const char fallback_dir[] = "/tmp"; + static const char * const tmpfs_dirs[] = { + "/dev/shm", + fallback_dir, + NULL + }; + int i; + const char *dir; + + printf("Checking environment variables for a tempdir..."); + for (i = 0; vars[i]; i++) { + dir = getenv(vars[i]); + if ((dir != NULL) && (*dir != '\0')) { + printf("%s\n", dir); + if (check_tmpfs(dir) >= 0) + goto done; + else + goto warn; + } } + printf("none found\n"); - ptr++; - len = strlen(ptr); - memmove(buf, ptr, len + 1); - - /* - * Refill the buffer so that if there's a partial string that we care - * about, it will be completed, and we can recognize it. - */ - n = read(fd, &buf[len], size - len - 1); - if (n < 0) - return -errno; + for (i = 0; tmpfs_dirs[i]; i++) { + dir = tmpfs_dirs[i]; + if (check_tmpfs(dir) >= 0) + goto done; + } - buf[len + n] = '\0'; - return 1; + dir = fallback_dir; +warn: + printf("Warning: tempdir %s is not on tmpfs\n", dir); +done: + /* Make a copy since getenv results may not remain valid forever. */ + return strdup(dir); } -/* which_tmpdir is called only during early boot */ -static int checked_tmpdir = 0; - /* - * Look for a tmpfs mounted at /dev/shm. I couldn't find a cleaner - * way to do this than to parse /proc/mounts. statfs will return the - * same filesystem magic number and fs id for both /dev and /dev/shm - * when they are both tmpfs, so you can't tell if they are different - * filesystems. Also, there seems to be no other way of finding the - * mount point of a filesystem from within it. - * - * If a /dev/shm tmpfs entry is found, then we switch to using it. - * Otherwise, we stay with the default /tmp. + * Create an unlinked tempfile in a suitable tempdir. template must be the + * basename part of the template with a leading '/'. */ -static void which_tmpdir(void) -{ - int fd, found; - char buf[128] = { '\0' }; - - if (checked_tmpdir) - return; - - checked_tmpdir = 1; - - printf("Checking for tmpfs mount on /dev/shm..."); - - fd = open("/proc/mounts", O_RDONLY); - if (fd < 0) { - printf("failed to open /proc/mounts, errno = %d\n", errno); - return; - } - - while (1) { - found = next(fd, buf, ARRAY_SIZE(buf), ' '); - if (found != 1) - break; - - if (!strncmp(buf, "/dev/shm", strlen("/dev/shm"))) - goto found; - - found = next(fd, buf, ARRAY_SIZE(buf), '\n'); - if (found != 1) - break; - } - -err: - if (found == 0) - printf("nothing mounted on /dev/shm\n"); - else if (found < 0) - printf("read returned errno %d\n", -found); - -out: - close(fd); - - return; - -found: - found = next(fd, buf, ARRAY_SIZE(buf), ' '); - if (found != 1) - goto err; - - if (strncmp(buf, "tmpfs", strlen("tmpfs"))) { - printf("not tmpfs\n"); - goto out; - } - - printf("OK\n"); - default_tmpdir = "/dev/shm"; - goto out; -} - -static int __init make_tempfile(const char *template, char **out_tempname, - int do_unlink) +static int __init make_tempfile(const char *template) { char *tempname; int fd; - which_tmpdir(); - tempname = malloc(MAXPATHLEN); - if (tempname == NULL) - return -1; + if (tempdir == NULL) { + tempdir = choose_tempdir(); + if (tempdir == NULL) { + fprintf(stderr, "Failed to choose tempdir: %s\n", + strerror(errno)); + return -1; + } + } - find_tempdir(); - if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN)) + tempname = malloc(strlen(tempdir) + strlen(template) + 1); + if (tempname == NULL) return -1; - if (template[0] != '/') - strcpy(tempname, tempdir); - else - tempname[0] = '\0'; - strncat(tempname, template, MAXPATHLEN-1-strlen(tempname)); + strcpy(tempname, tempdir); + strcat(tempname, template); fd = mkstemp(tempname); if (fd < 0) { fprintf(stderr, "open - cannot create %s: %s\n", tempname, strerror(errno)); goto out; } - if (do_unlink && (unlink(tempname) < 0)) { + if (unlink(tempname) < 0) { perror("unlink"); - goto out; + goto close; } - if (out_tempname) { - *out_tempname = tempname; - } else - free(tempname); + free(tempname); return fd; +close: + close(fd); out: free(tempname); return -1; } -#define TEMPNAME_TEMPLATE "vm_file-XXXXXX" +#define TEMPNAME_TEMPLATE "/vm_file-XXXXXX" static int __init create_tmp_file(unsigned long long len) { int fd, err; char zero; - fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); + fd = make_tempfile(TEMPNAME_TEMPLATE); if (fd < 0) exit(1); @@ -253,7 +182,6 @@ int __init create_mem_file(unsigned long long len) return fd; } - void __init check_tmpexec(void) { void *addr; @@ -261,14 +189,13 @@ void __init check_tmpexec(void) addr = mmap(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); - printf("Checking PROT_EXEC mmap in %s...",tempdir); - fflush(stdout); + printf("Checking PROT_EXEC mmap in %s...", tempdir); if (addr == MAP_FAILED) { err = errno; - perror("failed"); + printf("%s\n", strerror(err)); close(fd); if (err == EPERM) - printf("%s must be not mounted noexec\n",tempdir); + printf("%s must be not mounted noexec\n", tempdir); exit(1); } printf("OK\n"); diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index e0477c3ee89..33496fe2bb5 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -4,6 +4,7 @@ */ #include <stdio.h> +#include <stdlib.h> #include <unistd.h> #include <errno.h> #include <signal.h> @@ -12,13 +13,10 @@ #include <sys/ptrace.h> #include <sys/wait.h> #include <asm/unistd.h> -#include "init.h" -#include "kern_constants.h" -#include "longjmp.h" -#include "os.h" -#include "process.h" -#include "skas_ptrace.h" -#include "user.h" +#include <init.h> +#include <longjmp.h> +#include <os.h> +#include <skas_ptrace.h> #define ARBITRARY_ADDR -1 #define FAILURE_PID -1 @@ -235,35 +233,65 @@ out: return ok; } -void init_new_thread_signals(void) +static int os_page_mincore(void *addr) { - set_handler(SIGSEGV, (__sighandler_t) sig_handler, SA_ONSTACK, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_handler(SIGTRAP, (__sighandler_t) sig_handler, SA_ONSTACK, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_handler(SIGFPE, (__sighandler_t) sig_handler, SA_ONSTACK, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_handler(SIGILL, (__sighandler_t) sig_handler, SA_ONSTACK, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_handler(SIGBUS, (__sighandler_t) sig_handler, SA_ONSTACK, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - signal(SIGHUP, SIG_IGN); + char vec[2]; + int ret; - set_handler(SIGIO, (__sighandler_t) sig_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, - SIGVTALRM, -1); - signal(SIGWINCH, SIG_IGN); + ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); + if (ret < 0) { + if (errno == ENOMEM || errno == EINVAL) + return 0; + else + return -errno; + } + + return vec[0] & 1; } -int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr) +int os_mincore(void *addr, unsigned long len) { - jmp_buf buf; - int n; - - *jmp_ptr = &buf; - n = UML_SETJMP(&buf); - if (n != 0) - return n; - (*fn)(arg); - return 0; + char *vec; + int ret, i; + + if (len <= UM_KERN_PAGE_SIZE) + return os_page_mincore(addr); + + vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); + if (!vec) + return -ENOMEM; + + ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); + if (ret < 0) { + if (errno == ENOMEM || errno == EINVAL) + ret = 0; + else + ret = -errno; + + goto out; + } + + for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) { + if (!(vec[i] & 1)) { + ret = 0; + goto out; + } + } + + ret = 1; +out: + free(vec); + return ret; +} + +void init_new_thread_signals(void) +{ + set_handler(SIGSEGV); + set_handler(SIGTRAP); + set_handler(SIGFPE); + set_handler(SIGILL); + set_handler(SIGBUS); + signal(SIGHUP, SIG_IGN); + set_handler(SIGIO); + signal(SIGWINCH, SIG_IGN); } diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c index 830fe6a1518..2ff8d4fe83c 100644 --- a/arch/um/os-Linux/registers.c +++ b/arch/um/os-Linux/registers.c @@ -7,7 +7,9 @@ #include <errno.h> #include <string.h> #include <sys/ptrace.h> -#include "sysdep/ptrace.h" +#include <sysdep/ptrace.h> +#include <sysdep/ptrace_user.h> +#include <registers.h> int save_registers(int pid, struct uml_pt_regs *regs) { @@ -32,6 +34,7 @@ int restore_registers(int pid, struct uml_pt_regs *regs) /* This is set once at boot time and not changed thereafter */ static unsigned long exec_regs[MAX_REG_NR]; +static unsigned long exec_fp_regs[FP_SIZE]; int init_registers(int pid) { @@ -42,10 +45,14 @@ int init_registers(int pid) return -errno; arch_init_registers(pid); + get_fp_registers(pid, exec_fp_regs); return 0; } -void get_safe_registers(unsigned long *regs) +void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) { memcpy(regs, exec_regs, sizeof(exec_regs)); + + if (fp_regs) + memcpy(fp_regs, exec_fp_regs, sizeof(exec_fp_regs)); } diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index abf47a7c4ab..46e762f926e 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -11,13 +11,11 @@ #include <sched.h> #include <signal.h> #include <string.h> -#include "kern_constants.h" -#include "kern_util.h" -#include "init.h" -#include "os.h" -#include "sigio.h" -#include "um_malloc.h" -#include "user.h" +#include <kern_util.h> +#include <init.h> +#include <os.h> +#include <sigio.h> +#include <um_malloc.h> /* * Protected by sigio_lock(), also used by sigio_cleanup, which is an @@ -57,7 +55,7 @@ static int write_sigio_thread(void *unused) int i, n, respond_fd; char c; - signal(SIGWINCH, SIG_IGN); + os_fix_helper_signals(); fds = ¤t_poll; while (1) { n = poll(fds->poll, fds->used, -1); @@ -109,7 +107,7 @@ static int need_poll(struct pollfds *polls, int n) if (n <= polls->size) return 0; - new = kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); + new = uml_kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); if (new == NULL) { printk(UM_KERN_ERR "need_poll : failed to allocate new " "pollfds\n"); @@ -243,7 +241,7 @@ static struct pollfd *setup_initial_poll(int fd) { struct pollfd *p; - p = kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); + p = uml_kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); if (p == NULL) { printk(UM_KERN_ERR "setup_initial_poll : failed to allocate " "poll\n"); @@ -338,20 +336,10 @@ out_close1: close(l_write_sigio_fds[1]); } -/* Changed during early boot */ -static int pty_output_sigio = 0; -static int pty_close_sigio = 0; - -void maybe_sigio_broken(int fd, int read) +void sigio_broken(int fd, int read) { int err; - if (!isatty(fd)) - return; - - if ((read || pty_output_sigio) && (!read || pty_close_sigio)) - return; - write_sigio_workaround(); sigio_lock(); @@ -370,6 +358,21 @@ out: sigio_unlock(); } +/* Changed during early boot */ +static int pty_output_sigio; +static int pty_close_sigio; + +void maybe_sigio_broken(int fd, int read) +{ + if (!isatty(fd)) + return; + + if ((read || pty_output_sigio) && (!read || pty_close_sigio)) + return; + + sigio_broken(fd, read); +} + static void sigio_cleanup(void) { if (write_sigio_pid == -1) @@ -383,7 +386,7 @@ static void sigio_cleanup(void) __uml_exitcall(sigio_cleanup); /* Used as a flag during SIGIO testing early in boot */ -static volatile int got_sigio = 0; +static int got_sigio; static void __init handler(int sig) { @@ -498,7 +501,8 @@ static void tty_output(int master, int slave) if (errno != EAGAIN) printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n", errno); - while (((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) + while (((n = read(slave, buf, sizeof(buf))) > 0) && + !({ barrier(); got_sigio; })) ; if (got_sigio) { @@ -523,7 +527,7 @@ static void tty_close(int master, int slave) printk(UM_KERN_CONT "No, enabling workaround\n"); } -void __init check_sigio(void) +static void __init check_sigio(void) { if ((access("/dev/ptmx", R_OK) < 0) && (access("/dev/ptyp0", R_OK) < 0)) { diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 3f1694b134c..7b605e4dfff 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -9,17 +9,13 @@ #include <errno.h> #include <signal.h> #include <strings.h> -#include "as-layout.h" -#include "kern_util.h" -#include "os.h" -#include "sysdep/barrier.h" -#include "sysdep/sigcontext.h" -#include "user.h" +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> +#include <sysdep/mcontext.h> +#include "internal.h" -/* Copied from linux/compiler-gcc.h since we can't include it directly */ -#define barrier() __asm__ __volatile__("": : :"memory") - -void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { +void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { [SIGTRAP] = relay_signal, [SIGFPE] = relay_signal, [SIGILL] = relay_signal, @@ -29,7 +25,7 @@ void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { [SIGIO] = sigio_handler, [SIGVTALRM] = timer_handler }; -static void sig_handler_common(int sig, struct sigcontext *sc) +static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) { struct uml_pt_regs r; int save_errno = errno; @@ -37,15 +33,15 @@ static void sig_handler_common(int sig, struct sigcontext *sc) r.is_user = 0; if (sig == SIGSEGV) { /* For segfaults, we want the data from the sigcontext. */ - copy_sc(&r, sc); - GET_FAULTINFO_FROM_SC(r.faultinfo, sc); + get_regs_from_mc(&r, mc); + GET_FAULTINFO_FROM_MC(r.faultinfo, mc); } /* enable signals if sig isn't IRQ signal */ if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) unblock_signals(); - (*sig_info[sig])(sig, &r); + (*sig_info[sig])(sig, si, &r); errno = save_errno; } @@ -65,7 +61,7 @@ static void sig_handler_common(int sig, struct sigcontext *sc) static int signals_enabled; static unsigned int signals_pending; -void sig_handler(int sig, struct sigcontext *sc) +void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) { int enabled; @@ -77,23 +73,23 @@ void sig_handler(int sig, struct sigcontext *sc) block_signals(); - sig_handler_common(sig, sc); + sig_handler_common(sig, si, mc); set_signals(enabled); } -static void real_alarm_handler(struct sigcontext *sc) +static void real_alarm_handler(mcontext_t *mc) { struct uml_pt_regs regs; - if (sc != NULL) - copy_sc(®s, sc); + if (mc != NULL) + get_regs_from_mc(®s, mc); regs.is_user = 0; unblock_signals(); - timer_handler(SIGVTALRM, ®s); + timer_handler(SIGVTALRM, NULL, ®s); } -void alarm_handler(int sig, struct sigcontext *sc) +void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) { int enabled; @@ -105,14 +101,13 @@ void alarm_handler(int sig, struct sigcontext *sc) block_signals(); - real_alarm_handler(sc); + real_alarm_handler(mc); set_signals(enabled); } void timer_init(void) { - set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, -1); + set_handler(SIGVTALRM); } void set_sigstack(void *sig_stack, int size) @@ -125,10 +120,23 @@ void set_sigstack(void *sig_stack, int size) panic("enabling signal stack failed, errno = %d\n", errno); } -void (*handlers[_NSIG])(int sig, struct sigcontext *sc); +static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { + [SIGSEGV] = sig_handler, + [SIGBUS] = sig_handler, + [SIGILL] = sig_handler, + [SIGFPE] = sig_handler, + [SIGTRAP] = sig_handler, + + [SIGIO] = sig_handler, + [SIGWINCH] = sig_handler, + [SIGVTALRM] = alarm_handler +}; + -void handle_signal(int sig, struct sigcontext *sc) +static void hard_handler(int sig, siginfo_t *si, void *p) { + struct ucontext *uc = p; + mcontext_t *mc = &uc->uc_mcontext; unsigned long pending = 1UL << sig; do { @@ -154,7 +162,7 @@ void handle_signal(int sig, struct sigcontext *sc) while ((sig = ffs(pending)) != 0){ sig--; pending &= ~(1 << sig); - (*handlers[sig])(sig, sc); + (*handlers[sig])(sig, (struct siginfo *)si, mc); } /* @@ -168,28 +176,26 @@ void handle_signal(int sig, struct sigcontext *sc) } while (pending); } -extern void hard_handler(int sig); - -void set_handler(int sig, void (*handler)(int), int flags, ...) +void set_handler(int sig) { struct sigaction action; - va_list ap; + int flags = SA_SIGINFO | SA_ONSTACK; sigset_t sig_mask; - int mask; - handlers[sig] = (void (*)(int, struct sigcontext *)) handler; - action.sa_handler = hard_handler; + action.sa_sigaction = hard_handler; + /* block irq ones */ sigemptyset(&action.sa_mask); - - va_start(ap, flags); - while ((mask = va_arg(ap, int)) != -1) - sigaddset(&action.sa_mask, mask); - va_end(ap); + sigaddset(&action.sa_mask, SIGVTALRM); + sigaddset(&action.sa_mask, SIGIO); + sigaddset(&action.sa_mask, SIGWINCH); if (sig == SIGSEGV) flags |= SA_NODEFER; + if (sigismember(&action.sa_mask, sig)) + flags |= SA_RESTART; /* if it's an irq signal */ + action.sa_flags = flags; action.sa_restorer = NULL; if (sigaction(sig, &action, NULL) < 0) @@ -268,9 +274,12 @@ void unblock_signals(void) * Deal with SIGIO first because the alarm handler might * schedule, leaving the pending SIGIO stranded until we come * back here. + * + * SIGIO's handler doesn't use siginfo or mcontext, + * so they can be NULL. */ if (save_pending & SIGIO_MASK) - sig_handler_common(SIGIO, NULL); + sig_handler_common(SIGIO, NULL, NULL); if (save_pending & SIGVTALRM_MASK) real_alarm_handler(NULL); @@ -295,3 +304,11 @@ int set_signals(int enable) return ret; } + +int os_is_signal_stack(void) +{ + stack_t ss; + sigaltstack(NULL, &ss); + + return ss.ss_flags & SS_ONSTACK; +} diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c index 484e68f9f7a..689b18db798 100644 --- a/arch/um/os-Linux/skas/mem.c +++ b/arch/um/os-Linux/skas/mem.c @@ -8,19 +8,16 @@ #include <errno.h> #include <string.h> #include <sys/mman.h> -#include "init.h" -#include "kern_constants.h" -#include "as-layout.h" -#include "mm_id.h" -#include "os.h" -#include "proc_mm.h" -#include "ptrace_user.h" -#include "registers.h" -#include "skas.h" -#include "user.h" -#include "sysdep/ptrace.h" -#include "sysdep/stub.h" -#include "uml-config.h" +#include <init.h> +#include <as-layout.h> +#include <mm_id.h> +#include <os.h> +#include <proc_mm.h> +#include <ptrace_user.h> +#include <registers.h> +#include <skas.h> +#include <sysdep/ptrace.h> +#include <sysdep/stub.h> extern unsigned long batch_syscall_stub, __syscall_stub_start; @@ -40,7 +37,7 @@ static unsigned long syscall_regs[MAX_REG_NR]; static int __init init_syscall_regs(void) { - get_safe_registers(syscall_regs); + get_safe_registers(syscall_regs, NULL); syscall_regs[REGS_IP_INDEX] = STUB_CODE + ((unsigned long) &batch_syscall_stub - (unsigned long) &__syscall_stub_start); @@ -51,10 +48,6 @@ __initcall(init_syscall_regs); extern int proc_mm; -int single_count = 0; -int multi_count = 0; -int multi_op_count = 0; - static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) { int n, i; @@ -67,8 +60,6 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) /* FIXME: Need to look up userspace_pid by cpu */ pid = userspace_pid[0]; - multi_count++; - n = ptrace_setregs(pid, syscall_regs); if (n < 0) { printk(UM_KERN_ERR "Registers - \n"); @@ -129,9 +120,6 @@ long run_syscall_stub(struct mm_id * mm_idp, int syscall, { unsigned long *stack = check_init_stack(mm_idp, *addr); - if (done && *addr == NULL) - single_count++; - *stack += sizeof(long); stack += *stack / sizeof(long); @@ -144,7 +132,6 @@ long run_syscall_stub(struct mm_id * mm_idp, int syscall, *stack++ = args[5]; *stack++ = expected; *stack = 0; - multi_op_count++; if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) < UM_KERN_PAGE_SIZE - 10 * sizeof(long))) { diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 1e8cba6550a..908579f2b0a 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -9,31 +9,23 @@ #include <errno.h> #include <string.h> #include <sys/mman.h> -#include <sys/ptrace.h> #include <sys/wait.h> #include <asm/unistd.h> -#include "as-layout.h" -#include "chan_user.h" -#include "kern_constants.h" -#include "kern_util.h" -#include "mem.h" -#include "os.h" -#include "process.h" -#include "proc_mm.h" -#include "ptrace_user.h" -#include "registers.h" -#include "skas.h" -#include "skas_ptrace.h" -#include "user.h" -#include "sysdep/stub.h" +#include <as-layout.h> +#include <init.h> +#include <kern_util.h> +#include <mem.h> +#include <os.h> +#include <proc_mm.h> +#include <ptrace_user.h> +#include <registers.h> +#include <skas.h> +#include <skas_ptrace.h> +#include <sysdep/stub.h> int is_skas_winch(int pid, int fd, void *data) { - if (pid != getpgrp()) - return 0; - - register_winch_irq(-1, fd, -1, data, 0); - return 1; + return pid == getpgrp(); } static int ptrace_dump_regs(int pid) @@ -55,7 +47,7 @@ static int ptrace_dump_regs(int pid) * Signals that are OK to receive in the stub - we'll just continue it. * SIGWINCH will happen when UML is inside a detached screen. */ -#define STUB_SIG_MASK (1 << SIGVTALRM) +#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH)) /* Signals that the stub will finish with - anything else is an error */ #define STUB_DONE_MASK (1 << SIGTRAP) @@ -96,7 +88,7 @@ bad_wait: extern unsigned long current_stub_stack(void); -void get_skas_faultinfo(int pid, struct faultinfo * fi) +static void get_skas_faultinfo(int pid, struct faultinfo *fi) { int err; @@ -169,7 +161,7 @@ static void handle_trap(int pid, struct uml_pt_regs *regs, if (!local_using_sysemu) { - err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, + err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); if (err < 0) { printk(UM_KERN_ERR "handle_trap - nullifying syscall " @@ -257,8 +249,8 @@ static int userspace_tramp(void *stack) set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE); sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_ONSTACK | SA_NODEFER; - sa.sa_handler = (void *) v; + sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO; + sa.sa_sigaction = (void *) v; sa.sa_restorer = NULL; if (sigaction(SIGSEGV, &sa, NULL) < 0) { printk(UM_KERN_ERR "userspace_tramp - setting SIGSEGV " @@ -354,6 +346,10 @@ void userspace(struct uml_pt_regs *regs) int err, status, op, pid = userspace_pid[0]; /* To prevent races if using_sysemu changes under us.*/ int local_using_sysemu; + siginfo_t si; + + /* Handle any immediate reschedules or signals */ + interrupt_end(); if (getitimer(ITIMER_VIRTUAL, &timer)) printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno); @@ -373,6 +369,9 @@ void userspace(struct uml_pt_regs *regs) if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) fatal_sigsegv(); + if (put_fp_registers(pid, regs->fp)) + fatal_sigsegv(); + /* Now we set local_using_sysemu to be used for one loop */ local_using_sysemu = get_using_sysemu(); @@ -399,17 +398,27 @@ void userspace(struct uml_pt_regs *regs) fatal_sigsegv(); } + if (get_fp_registers(pid, regs->fp)) { + printk(UM_KERN_ERR "userspace - get_fp_registers failed, " + "errno = %d\n", errno); + fatal_sigsegv(); + } + UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ if (WIFSTOPPED(status)) { int sig = WSTOPSIG(status); + + ptrace(PTRACE_GETSIGINFO, pid, 0, (struct siginfo *)&si); + switch (sig) { case SIGSEGV: if (PTRACE_FULL_FAULTINFO || !ptrace_faultinfo) { get_skas_faultinfo(pid, ®s->faultinfo); - (*sig_info[SIGSEGV])(SIGSEGV, regs); + (*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si, + regs); } else handle_segv(pid, regs); break; @@ -417,14 +426,14 @@ void userspace(struct uml_pt_regs *regs) handle_trap(pid, regs, local_using_sysemu); break; case SIGTRAP: - relay_signal(SIGTRAP, regs); + relay_signal(SIGTRAP, (struct siginfo *)&si, regs); break; case SIGVTALRM: now = os_nsecs(); if (now < nsecs) break; block_signals(); - (*sig_info[sig])(sig, regs); + (*sig_info[sig])(sig, (struct siginfo *)&si, regs); unblock_signals(); nsecs = timer.it_value.tv_sec * UM_NSEC_PER_SEC + @@ -438,11 +447,11 @@ void userspace(struct uml_pt_regs *regs) case SIGFPE: case SIGWINCH: block_signals(); - (*sig_info[sig])(sig, regs); + (*sig_info[sig])(sig, (struct siginfo *)&si, regs); unblock_signals(); break; default: - printk(UM_KERN_ERR "userspace - child stopped " + printk(UM_KERN_ERR "userspace - child stopped " "with signal %d\n", sig); fatal_sigsegv(); } @@ -457,10 +466,11 @@ void userspace(struct uml_pt_regs *regs) } static unsigned long thread_regs[MAX_REG_NR]; +static unsigned long thread_fp_regs[FP_SIZE]; static int __init init_thread_regs(void) { - get_safe_registers(thread_regs); + get_safe_registers(thread_regs, thread_fp_regs); /* Set parent's instruction pointer to start of clone-stub */ thread_regs[REGS_IP_INDEX] = STUB_CODE + (unsigned long) stub_clone_handler - @@ -503,6 +513,13 @@ int copy_context_skas0(unsigned long new_stack, int pid) return err; } + err = put_fp_registers(pid, thread_fp_regs); + if (err < 0) { + printk(UM_KERN_ERR "copy_context_skas0 : put_fp_registers " + "failed, pid = %d, err = %d\n", pid, err); + return err; + } + /* set a well known return code for detection of child write failure */ child_data->err = 12345678; @@ -644,8 +661,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) { int n; - set_handler(SIGWINCH, (__sighandler_t) sig_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGVTALRM, -1); + set_handler(SIGWINCH); /* * Can't use UML_SETJMP or UML_LONGJMP here because they save diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index b616e15638f..337518c5042 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -13,27 +13,28 @@ #include <signal.h> #include <string.h> #include <sys/mman.h> -#include <sys/ptrace.h> #include <sys/stat.h> #include <sys/wait.h> +#include <sys/time.h> +#include <sys/resource.h> #include <asm/unistd.h> -#include "init.h" -#include "kern_constants.h" -#include "os.h" -#include "mem_user.h" -#include "ptrace_user.h" -#include "registers.h" -#include "skas_ptrace.h" - -static int ptrace_child(void) +#include <init.h> +#include <os.h> +#include <mem_user.h> +#include <ptrace_user.h> +#include <registers.h> +#include <skas.h> +#include <skas_ptrace.h> + +static void ptrace_child(void) { int ret; /* Calling os_getpid because some libcs cached getpid incorrectly */ int pid = os_getpid(), ppid = getppid(); int sc_result; - change_sig(SIGWINCH, 0); - if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { + if (change_sig(SIGWINCH, 0) < 0 || + ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { perror("ptrace"); kill(pid, SIGKILL); } @@ -75,9 +76,8 @@ static void fatal(char *fmt, ...) va_list list; va_start(list, fmt); - vprintf(fmt, list); + vfprintf(stderr, fmt, list); va_end(list); - fflush(stdout); exit(1); } @@ -87,9 +87,8 @@ static void non_fatal(char *fmt, ...) va_list list; va_start(list, fmt); - vprintf(fmt, list); + vfprintf(stderr, fmt, list); va_end(list); - fflush(stdout); } static int start_ptraced_child(void) @@ -122,8 +121,10 @@ static int stop_ptraced_child(int pid, int exitcode, int mustexit) { int status, n, ret = 0; - if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) - fatal_perror("stop_ptraced_child : ptrace failed"); + if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) { + perror("stop_ptraced_child : ptrace failed"); + return -1; + } CATCH_EINTR(n = waitpid(pid, &status, 0)); if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { int exit_with = WEXITSTATUS(status); @@ -142,14 +143,27 @@ static int stop_ptraced_child(int pid, int exitcode, int mustexit) } /* Changed only during early boot */ -int ptrace_faultinfo = 1; -int ptrace_ldt = 1; -int proc_mm = 1; -int skas_needs_stub = 0; +int ptrace_faultinfo; +static int disable_ptrace_faultinfo; + +int ptrace_ldt; +static int disable_ptrace_ldt; + +int proc_mm; +static int disable_proc_mm; + +int have_switch_mm; +static int disable_switch_mm; + +int skas_needs_stub; static int __init skas0_cmd_param(char *str, int* add) { - ptrace_faultinfo = proc_mm = 0; + disable_ptrace_faultinfo = 1; + disable_ptrace_ldt = 1; + disable_proc_mm = 1; + disable_switch_mm = 1; + return 0; } @@ -159,15 +173,12 @@ static int __init mode_skas0_cmd_param(char *str, int* add) __attribute__((alias("skas0_cmd_param"))); __uml_setup("skas0", skas0_cmd_param, - "skas0\n" - " Disables SKAS3 usage, so that SKAS0 is used, unless \n" - " you specify mode=tt.\n\n"); +"skas0\n" +" Disables SKAS3 and SKAS4 usage, so that SKAS0 is used\n\n"); __uml_setup("mode=skas0", mode_skas0_cmd_param, - "mode=skas0\n" - " Disables SKAS3 usage, so that SKAS0 is used, unless you \n" - " specify mode=tt. Note that this was recently added - on \n" - " older kernels you must use simply \"skas0\".\n\n"); +"mode=skas0\n" +" Disables SKAS3 and SKAS4 usage, so that SKAS0 is used.\n\n"); /* Changed only during early boot */ static int force_sysemu_disabled = 0; @@ -203,7 +214,7 @@ static void __init check_sysemu(void) if (n < 0) fatal_perror("check_sysemu : wait failed"); if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) - fatal("check_sysemu : expected SIGTRAP, got status = %d", + fatal("check_sysemu : expected SIGTRAP, got status = %d\n", status); if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) @@ -214,7 +225,7 @@ static void __init check_sysemu(void) goto fail; } - n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); + n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); if (n < 0) { non_fatal("check_sysemu : failed to modify system call " "return"); @@ -233,7 +244,7 @@ static void __init check_sysemu(void) if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *) PTRACE_O_TRACESYSGOOD) < 0)) - fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); + fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed"); while (1) { count++; @@ -241,14 +252,16 @@ static void __init check_sysemu(void) goto fail; CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if (n < 0) - fatal_perror("check_ptrace : wait failed"); + fatal_perror("check_sysemu: wait failed"); if (WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))) { - if (!count) - fatal("check_ptrace : SYSEMU_SINGLESTEP " - "doesn't singlestep"); - n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, + if (!count) { + non_fatal("check_sysemu: SYSEMU_SINGLESTEP " + "doesn't singlestep"); + goto fail; + } + n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); if (n < 0) fatal_perror("check_sysemu : failed to modify " @@ -257,9 +270,12 @@ static void __init check_sysemu(void) } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) count++; - else - fatal("check_ptrace : expected SIGTRAP or " - "(SIGTRAP | 0x80), got status = %d", status); + else { + non_fatal("check_sysemu: expected SIGTRAP or " + "(SIGTRAP | 0x80), got status = %d\n", + status); + goto fail; + } } if (stop_ptraced_child(pid, 0, 0) < 0) goto fail_stopped; @@ -301,10 +317,10 @@ static void __init check_ptrace(void) fatal("check_ptrace : expected (SIGTRAP|0x80), " "got status = %d", status); - syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, + syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0); if (syscall == __NR_getpid) { - n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, + n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getppid); if (n < 0) fatal_perror("check_ptrace : failed to modify " @@ -362,7 +378,7 @@ void __init os_early_checks(void) static int __init noprocmm_cmd_param(char *str, int* add) { - proc_mm = 0; + disable_proc_mm = 1; return 0; } @@ -374,7 +390,7 @@ __uml_setup("noprocmm", noprocmm_cmd_param, static int __init noptracefaultinfo_cmd_param(char *str, int* add) { - ptrace_faultinfo = 0; + disable_ptrace_faultinfo = 1; return 0; } @@ -386,7 +402,7 @@ __uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param, static int __init noptraceldt_cmd_param(char *str, int* add) { - ptrace_ldt = 0; + disable_ptrace_ldt = 1; return 0; } @@ -406,17 +422,15 @@ static inline void check_skas3_ptrace_faultinfo(void) n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); if (n < 0) { - ptrace_faultinfo = 0; if (errno == EIO) non_fatal("not found\n"); else perror("not found"); - } + } else if (disable_ptrace_faultinfo) + non_fatal("found but disabled on command line\n"); else { - if (!ptrace_faultinfo) - non_fatal("found but disabled on command line\n"); - else - non_fatal("found\n"); + ptrace_faultinfo = 1; + non_fatal("found\n"); } stop_ptraced_child(pid, 1, 1); @@ -439,38 +453,30 @@ static inline void check_skas3_ptrace_ldt(void) if (n < 0) { if (errno == EIO) non_fatal("not found\n"); - else { + else perror("not found"); - } - ptrace_ldt = 0; - } + } else if (disable_ptrace_ldt) + non_fatal("found, but use is disabled\n"); else { - if (ptrace_ldt) - non_fatal("found\n"); - else - non_fatal("found, but use is disabled\n"); + ptrace_ldt = 1; + non_fatal("found\n"); } stop_ptraced_child(pid, 1, 1); -#else - /* PTRACE_LDT might be disabled via cmdline option. - * We want to override this, else we might use the stub - * without real need - */ - ptrace_ldt = 1; #endif } static inline void check_skas3_proc_mm(void) { non_fatal(" - /proc/mm..."); - if (access("/proc/mm", W_OK) < 0) { - proc_mm = 0; + if (access("/proc/mm", W_OK) < 0) perror("not found"); - } - else if (!proc_mm) + else if (disable_proc_mm) non_fatal("found but disabled on command line\n"); - else non_fatal("found\n"); + else { + proc_mm = 1; + non_fatal("found\n"); + } } void can_do_skas(void) @@ -495,7 +501,7 @@ int __init parse_iomem(char *str, int *add) driver = str; file = strchr(str,','); if (file == NULL) { - printf("parse_iomem : failed to parse iomem\n"); + fprintf(stderr, "parse_iomem : failed to parse iomem\n"); goto out; } *file = '\0'; diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile deleted file mode 100644 index b4bc6ac4f30..00000000000 --- a/arch/um/os-Linux/sys-i386/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) -# Licensed under the GPL -# - -obj-y = registers.o signal.o task_size.o tls.o - -USER_OBJS := $(obj-y) - -include arch/um/scripts/Makefile.rules diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c deleted file mode 100644 index b613473b3ec..00000000000 --- a/arch/um/os-Linux/sys-i386/registers.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2004 PathScale, Inc - * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <errno.h> -#include "kern_constants.h" -#include "longjmp.h" -#include "user.h" -#include "sysdep/ptrace_user.h" - -int save_fp_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -int restore_fp_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -int save_fpx_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -int restore_fpx_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -unsigned long get_thread_reg(int reg, jmp_buf *buf) -{ - switch (reg) { - case EIP: - return buf[0]->__eip; - case UESP: - return buf[0]->__esp; - case EBP: - return buf[0]->__ebp; - default: - printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n", - reg); - return 0; - } -} - -int have_fpx_regs = 1; - -int get_fp_registers(int pid, unsigned long *regs) -{ - if (have_fpx_regs) - return save_fpx_registers(pid, regs); - else - return save_fp_registers(pid, regs); -} - -int put_fp_registers(int pid, unsigned long *regs) -{ - if (have_fpx_regs) - return restore_fpx_registers(pid, regs); - else - return restore_fp_registers(pid, regs); -} - -void arch_init_registers(int pid) -{ - unsigned long fpx_regs[HOST_XFP_SIZE]; - int err; - - err = ptrace(PTRACE_GETFPXREGS, pid, 0, fpx_regs); - if (!err) - return; - - if (errno != EIO) - panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", - errno); - - have_fpx_regs = 0; -} diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c deleted file mode 100644 index f311609f93d..00000000000 --- a/arch/um/os-Linux/sys-i386/signal.c +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <signal.h> - -extern void handle_signal(int sig, struct sigcontext *sc); - -void hard_handler(int sig) -{ - handle_signal(sig, (struct sigcontext *) (&sig + 1)); -} diff --git a/arch/um/os-Linux/sys-i386/task_size.c b/arch/um/os-Linux/sys-i386/task_size.c deleted file mode 100644 index 48d211b3d9a..00000000000 --- a/arch/um/os-Linux/sys-i386/task_size.c +++ /dev/null @@ -1,120 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <sys/mman.h> -#include "longjmp.h" -#include "kern_constants.h" - -static jmp_buf buf; - -static void segfault(int sig) -{ - longjmp(buf, 1); -} - -static int page_ok(unsigned long page) -{ - unsigned long *address = (unsigned long *) (page << UM_KERN_PAGE_SHIFT); - unsigned long n = ~0UL; - void *mapped = NULL; - int ok = 0; - - /* - * First see if the page is readable. If it is, it may still - * be a VDSO, so we go on to see if it's writable. If not - * then try mapping memory there. If that fails, then we're - * still in the kernel area. As a sanity check, we'll fail if - * the mmap succeeds, but gives us an address different from - * what we wanted. - */ - if (setjmp(buf) == 0) - n = *address; - else { - mapped = mmap(address, UM_KERN_PAGE_SIZE, - PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (mapped == MAP_FAILED) - return 0; - if (mapped != address) - goto out; - } - - /* - * Now, is it writeable? If so, then we're in user address - * space. If not, then try mprotecting it and try the write - * again. - */ - if (setjmp(buf) == 0) { - *address = n; - ok = 1; - goto out; - } else if (mprotect(address, UM_KERN_PAGE_SIZE, - PROT_READ | PROT_WRITE) != 0) - goto out; - - if (setjmp(buf) == 0) { - *address = n; - ok = 1; - } - - out: - if (mapped != NULL) - munmap(mapped, UM_KERN_PAGE_SIZE); - return ok; -} - -unsigned long os_get_task_size(void) -{ - struct sigaction sa, old; - unsigned long bottom = 0; - /* - * A 32-bit UML on a 64-bit host gets confused about the VDSO at - * 0xffffe000. It is mapped, is readable, can be reprotected writeable - * and written. However, exec discovers later that it can't be - * unmapped. So, just set the highest address to be checked to just - * below it. This might waste some address space on 4G/4G 32-bit - * hosts, but shouldn't hurt otherwise. - */ - unsigned long top = 0xffffd000 >> UM_KERN_PAGE_SHIFT; - unsigned long test; - - printf("Locating the top of the address space ... "); - fflush(stdout); - - /* - * We're going to be longjmping out of the signal handler, so - * SA_DEFER needs to be set. - */ - sa.sa_handler = segfault; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_NODEFER; - sigaction(SIGSEGV, &sa, &old); - - if (!page_ok(bottom)) { - fprintf(stderr, "Address 0x%x no good?\n", - bottom << UM_KERN_PAGE_SHIFT); - exit(1); - } - - /* This could happen with a 4G/4G split */ - if (page_ok(top)) - goto out; - - do { - test = bottom + (top - bottom) / 2; - if (page_ok(test)) - bottom = test; - else - top = test; - } while (top - bottom > 1); - -out: - /* Restore the old SIGSEGV handling */ - sigaction(SIGSEGV, &old, NULL); - - top <<= UM_KERN_PAGE_SHIFT; - printf("0x%x\n", top); - fflush(stdout); - - return top; -} diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c deleted file mode 100644 index 32ed41ec1a3..00000000000 --- a/arch/um/os-Linux/sys-i386/tls.c +++ /dev/null @@ -1,36 +0,0 @@ -#include <errno.h> -#include <linux/unistd.h> - -#include <sys/syscall.h> -#include <unistd.h> - -#include "sysdep/tls.h" -#include "user.h" - -/* Checks whether host supports TLS, and sets *tls_min according to the value - * valid on the host. - * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ -void check_host_supports_tls(int *supports_tls, int *tls_min) { - /* Values for x86 and x86_64.*/ - int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64}; - int i; - - for (i = 0; i < ARRAY_SIZE(val); i++) { - user_desc_t info; - info.entry_number = val[i]; - - if (syscall(__NR_get_thread_area, &info) == 0) { - *tls_min = val[i]; - *supports_tls = 1; - return; - } else { - if (errno == EINVAL) - continue; - else if (errno == ENOSYS) - *supports_tls = 0; - return; - } - } - - *supports_tls = 0; -} diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile deleted file mode 100644 index a44a47f8f57..00000000000 --- a/arch/um/os-Linux/sys-x86_64/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) -# Licensed under the GPL -# - -obj-y = registers.o prctl.o signal.o task_size.o - -USER_OBJS := $(obj-y) - -include arch/um/scripts/Makefile.rules diff --git a/arch/um/os-Linux/sys-x86_64/prctl.c b/arch/um/os-Linux/sys-x86_64/prctl.c deleted file mode 100644 index 9d34eddb517..00000000000 --- a/arch/um/os-Linux/sys-x86_64/prctl.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (C) 2007 Jeff Dike (jdike@{addtoit.com,linux.intel.com}) - * Licensed under the GPL - */ - -#include <sys/ptrace.h> -#include <linux/ptrace.h> - -int os_arch_prctl(int pid, int code, unsigned long *addr) -{ - return ptrace(PTRACE_ARCH_PRCTL, pid, (unsigned long) addr, code); -} diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c deleted file mode 100644 index 594d97ad02b..00000000000 --- a/arch/um/os-Linux/sys-x86_64/registers.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2006 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <errno.h> -#include <sys/ptrace.h> -#define __FRAME_OFFSETS -#include <asm/ptrace.h> -#include "kern_constants.h" -#include "longjmp.h" -#include "user.h" - -int save_fp_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -int restore_fp_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -unsigned long get_thread_reg(int reg, jmp_buf *buf) -{ - switch (reg) { - case RIP: - return buf[0]->__rip; - case RSP: - return buf[0]->__rsp; - case RBP: - return buf[0]->__rbp; - default: - printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n", - reg); - return 0; - } -} - -int get_fp_registers(int pid, unsigned long *regs) -{ - return save_fp_registers(pid, regs); -} - -int put_fp_registers(int pid, unsigned long *regs) -{ - return restore_fp_registers(pid, regs); -} diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c deleted file mode 100644 index 82a388822cd..00000000000 --- a/arch/um/os-Linux/sys-x86_64/signal.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <signal.h> - -extern void handle_signal(int sig, struct sigcontext *sc); - -void hard_handler(int sig) -{ - struct ucontext *uc; - asm("movq %%rdx, %0" : "=r" (uc)); - - handle_signal(sig, (struct sigcontext *) &uc->uc_mcontext); -} diff --git a/arch/um/os-Linux/sys-x86_64/task_size.c b/arch/um/os-Linux/sys-x86_64/task_size.c deleted file mode 100644 index fad6f57f8ee..00000000000 --- a/arch/um/os-Linux/sys-x86_64/task_size.c +++ /dev/null @@ -1,5 +0,0 @@ -unsigned long os_get_task_size(unsigned long shift) -{ - /* The old value of CONFIG_TOP_ADDR */ - return 0x7fc0000000; -} diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index e4928059946..e9824d5dd7d 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -8,9 +8,9 @@ #include <signal.h> #include <time.h> #include <sys/time.h> -#include "kern_constants.h" -#include "os.h" -#include "user.h" +#include <kern_util.h> +#include <os.h> +#include "internal.h" int set_interval(void) { @@ -58,12 +58,17 @@ static inline long long timeval_to_ns(const struct timeval *tv) long long disable_timer(void) { struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } }); + long long remain, max = UM_NSEC_PER_SEC / UM_HZ; if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0) printk(UM_KERN_ERR "disable_timer - setitimer failed, " "errno = %d\n", errno); - return timeval_to_ns(&time.it_value); + remain = timeval_to_ns(&time.it_value); + if (remain > max) + remain = max; + + return remain; } long long os_nsecs(void) @@ -74,12 +79,53 @@ long long os_nsecs(void) return timeval_to_ns(&tv); } -#ifdef UML_CONFIG_NO_HZ +#ifdef UML_CONFIG_NO_HZ_COMMON static int after_sleep_interval(struct timespec *ts) { return 0; } + +static void deliver_alarm(void) +{ + alarm_handler(SIGVTALRM, NULL, NULL); +} + +static unsigned long long sleep_time(unsigned long long nsecs) +{ + return nsecs; +} + #else +unsigned long long last_tick; +unsigned long long skew; + +static void deliver_alarm(void) +{ + unsigned long long this_tick = os_nsecs(); + int one_tick = UM_NSEC_PER_SEC / UM_HZ; + + /* Protection against the host's time going backwards */ + if ((last_tick != 0) && (this_tick < last_tick)) + this_tick = last_tick; + + if (last_tick == 0) + last_tick = this_tick - one_tick; + + skew += this_tick - last_tick; + + while (skew >= one_tick) { + alarm_handler(SIGVTALRM, NULL, NULL); + skew -= one_tick; + } + + last_tick = this_tick; +} + +static unsigned long long sleep_time(unsigned long long nsecs) +{ + return nsecs > skew ? nsecs - skew : 0; +} + static inline long long timespec_to_us(const struct timespec *ts) { return ((long long) ts->tv_sec * UM_USEC_PER_SEC) + @@ -102,6 +148,11 @@ static int after_sleep_interval(struct timespec *ts) */ if (start_usecs > usec) start_usecs = usec; + + start_usecs -= skew / UM_NSEC_PER_USEC; + if (start_usecs < 0) + start_usecs = 0; + tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC, .tv_usec = start_usecs % UM_USEC_PER_SEC }); interval = ((struct itimerval) { { 0, usec }, tv }); @@ -113,8 +164,6 @@ static int after_sleep_interval(struct timespec *ts) } #endif -extern void alarm_handler(int sig, struct sigcontext *sc); - void idle_sleep(unsigned long long nsecs) { struct timespec ts; @@ -126,10 +175,12 @@ void idle_sleep(unsigned long long nsecs) */ if (nsecs == 0) nsecs = UM_NSEC_PER_SEC / UM_HZ; + + nsecs = sleep_time(nsecs); ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC, .tv_nsec = nsecs % UM_NSEC_PER_SEC }); if (nanosleep(&ts, &ts) == 0) - alarm_handler(SIGVTALRM, NULL); + deliver_alarm(); after_sleep_interval(&ts); } diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c deleted file mode 100644 index 73277801ef1..00000000000 --- a/arch/um/os-Linux/tls.c +++ /dev/null @@ -1,35 +0,0 @@ -#include <errno.h> -#include <sys/ptrace.h> -#include "sysdep/tls.h" - -/* TLS support - we basically rely on the host's one.*/ - -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA 25 -#endif - -#ifndef PTRACE_SET_THREAD_AREA -#define PTRACE_SET_THREAD_AREA 26 -#endif - -int os_set_thread_area(user_desc_t *info, int pid) -{ - int ret; - - ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number, - (unsigned long) info); - if (ret < 0) - ret = -errno; - return ret; -} - -int os_get_thread_area(user_desc_t *info, int pid) -{ - int ret; - - ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number, - (unsigned long) info); - if (ret < 0) - ret = -errno; - return ret; -} diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c index b09ff66a77e..721d8afa329 100644 --- a/arch/um/os-Linux/tty.c +++ b/arch/um/os-Linux/tty.c @@ -7,10 +7,8 @@ #include <unistd.h> #include <errno.h> #include <fcntl.h> -#include "kern_constants.h" -#include "kern_util.h" -#include "os.h" -#include "user.h" +#include <kern_util.h> +#include <os.h> struct grantpt_info { int fd; diff --git a/arch/um/os-Linux/tty_log.c b/arch/um/os-Linux/tty_log.c deleted file mode 100644 index cc648e6fd3a..00000000000 --- a/arch/um/os-Linux/tty_log.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and - * geoffrey hing <ghing@net.ohio-state.edu> - * Licensed under the GPL - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/time.h> -#include "init.h" -#include "user.h" -#include "os.h" - -#define TTY_LOG_DIR "./" - -/* Set early in boot and then unchanged */ -static char *tty_log_dir = TTY_LOG_DIR; -static int tty_log_fd = -1; - -#define TTY_LOG_OPEN 1 -#define TTY_LOG_CLOSE 2 -#define TTY_LOG_WRITE 3 -#define TTY_LOG_EXEC 4 - -#define TTY_READ 1 -#define TTY_WRITE 2 - -struct tty_log_buf { - int what; - unsigned long tty; - int len; - int direction; - unsigned long sec; - unsigned long usec; -}; - -int open_tty_log(void *tty, void *current_tty) -{ - struct timeval tv; - struct tty_log_buf data; - char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; - int fd; - - gettimeofday(&tv, NULL); - if(tty_log_fd != -1){ - data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, - .tty = (unsigned long) tty, - .len = sizeof(current_tty), - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - write(tty_log_fd, &data, sizeof(data)); - write(tty_log_fd, ¤t_tty, data.len); - return tty_log_fd; - } - - sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, - (unsigned int) tv.tv_usec); - - fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))), - 0644); - if(fd < 0){ - printk("open_tty_log : couldn't open '%s', errno = %d\n", - buf, -fd); - } - return fd; -} - -void close_tty_log(int fd, void *tty) -{ - struct tty_log_buf data; - struct timeval tv; - - if(tty_log_fd != -1){ - gettimeofday(&tv, NULL); - data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE, - .tty = (unsigned long) tty, - .len = 0, - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - write(tty_log_fd, &data, sizeof(data)); - return; - } - os_close_file(fd); -} - -static int log_chunk(int fd, const char *buf, int len) -{ - int total = 0, try, missed, n; - char chunk[64]; - - while(len > 0){ - try = (len > sizeof(chunk)) ? sizeof(chunk) : len; - missed = copy_from_user_proc(chunk, (char *) buf, try); - try -= missed; - n = write(fd, chunk, try); - if(n != try) { - if(n < 0) - return -errno; - return -EIO; - } - if(missed != 0) - return -EFAULT; - - len -= try; - total += try; - buf += try; - } - - return total; -} - -int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) -{ - struct timeval tv; - struct tty_log_buf data; - int direction; - - if(fd == tty_log_fd){ - gettimeofday(&tv, NULL); - direction = is_read ? TTY_READ : TTY_WRITE; - data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE, - .tty = (unsigned long) tty, - .len = len, - .direction = direction, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - write(tty_log_fd, &data, sizeof(data)); - } - - return log_chunk(fd, buf, len); -} - -void log_exec(char **argv, void *tty) -{ - struct timeval tv; - struct tty_log_buf data; - char **ptr,*arg; - int len; - - if(tty_log_fd == -1) return; - - gettimeofday(&tv, NULL); - - len = 0; - for(ptr = argv; ; ptr++){ - if(copy_from_user_proc(&arg, ptr, sizeof(arg))) - return; - if(arg == NULL) break; - len += strlen_user_proc(arg); - } - - data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC, - .tty = (unsigned long) tty, - .len = len, - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - write(tty_log_fd, &data, sizeof(data)); - - for(ptr = argv; ; ptr++){ - if(copy_from_user_proc(&arg, ptr, sizeof(arg))) - return; - if(arg == NULL) break; - log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); - } -} - -extern void register_tty_logger(int (*opener)(void *, void *), - int (*writer)(int, const char *, int, - void *, int), - void (*closer)(int, void *)); - -static int register_logger(void) -{ - register_tty_logger(open_tty_log, write_tty_log, close_tty_log); - return 0; -} - -__uml_initcall(register_logger); - -static int __init set_tty_log_dir(char *name, int *add) -{ - tty_log_dir = name; - return 0; -} - -__uml_setup("tty_log_dir=", set_tty_log_dir, -"tty_log_dir=<directory>\n" -" This is used to specify the directory where the logs of all pty\n" -" data from this UML machine will be written.\n\n" -); - -static int __init set_tty_log_fd(char *name, int *add) -{ - char *end; - - tty_log_fd = strtoul(name, &end, 0); - if((*end != '\0') || (end == name)){ - printf("set_tty_log_fd - strtoul failed on '%s'\n", name); - tty_log_fd = -1; - } - - *add = 0; - return 0; -} - -__uml_setup("tty_log_fd=", set_tty_log_fd, -"tty_log_fd=<fd>\n" -" This is used to specify a preconfigured file descriptor to which all\n" -" tty data will be written. Preconfigure the descriptor with something\n" -" like '10>tty_log tty_log_fd=10'.\n\n" -); diff --git a/arch/um/os-Linux/uaccess.c b/arch/um/os-Linux/uaccess.c deleted file mode 100644 index 087ed74ffca..00000000000 --- a/arch/um/os-Linux/uaccess.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) - * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <stddef.h> -#include "longjmp.h" - -unsigned long __do_user_copy(void *to, const void *from, int n, - void **fault_addr, jmp_buf **fault_catcher, - void (*op)(void *to, const void *from, - int n), int *faulted_out) -{ - unsigned long *faddrp = (unsigned long *) fault_addr, ret; - - jmp_buf jbuf; - *fault_catcher = &jbuf; - if (UML_SETJMP(&jbuf) == 0) { - (*op)(to, from, n); - ret = 0; - *faulted_out = 0; - } - else { - ret = *faddrp; - *faulted_out = 1; - } - *fault_addr = NULL; - *fault_catcher = NULL; - return ret; -} - diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index 106fa864155..c1dc89261f6 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c @@ -12,10 +12,8 @@ #include <string.h> #include <unistd.h> #include <sys/stat.h> -#include "init.h" -#include "kern_constants.h" -#include "os.h" -#include "user.h" +#include <init.h> +#include <os.h> #define UML_DIR "~/.uml/" @@ -245,7 +243,7 @@ int __init set_umid(char *name) /* Changed in make_umid, which is called during early boot */ static int umid_setup = 0; -int __init make_umid(void) +static int __init make_umid(void) { int fd, err; char tmp[256]; diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index 74f49bb9b12..db4a034aeee 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c @@ -1,5 +1,5 @@ -#include "linux/types.h" -#include "linux/module.h" +#include <linux/types.h> +#include <linux/module.h> /* Some of this are builtin function (some are not but could in the future), * so I *must* declare good prototypes for them and then EXPORT them. @@ -14,7 +14,6 @@ #undef memset extern size_t strlen(const char *); -extern void *memcpy(void *, const void *, size_t); extern void *memmove(void *, const void *, size_t); extern void *memset(void *, int, size_t); extern int printf(const char *, ...); @@ -24,7 +23,11 @@ extern int printf(const char *, ...); EXPORT_SYMBOL(strstr); #endif +#ifndef __x86_64__ +extern void *memcpy(void *, const void *, size_t); EXPORT_SYMBOL(memcpy); +#endif + EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(printf); @@ -42,7 +45,7 @@ EXPORT_SYMBOL(readdir64); extern void truncate64(void) __attribute__((weak)); EXPORT_SYMBOL(truncate64); -#ifdef SUBARCH_i386 +#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA EXPORT_SYMBOL(vsyscall_ehdr); EXPORT_SYMBOL(vsyscall_end); #endif @@ -100,9 +103,18 @@ EXPORT_SYMBOL_PROTO(getuid); EXPORT_SYMBOL_PROTO(fsync); EXPORT_SYMBOL_PROTO(fdatasync); +EXPORT_SYMBOL_PROTO(lstat64); +EXPORT_SYMBOL_PROTO(fstat64); +EXPORT_SYMBOL_PROTO(mknod); + /* Export symbols used by GCC for the stack protector. */ extern void __stack_smash_handler(void *) __attribute__((weak)); EXPORT_SYMBOL(__stack_smash_handler); extern long __guard __attribute__((weak)); EXPORT_SYMBOL(__guard); + +#ifdef _FORTIFY_SOURCE +extern int __sprintf_chk(char *str, int flag, size_t strlen, const char *format); +EXPORT_SYMBOL(__sprintf_chk); +#endif diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index 6ea77979531..faee55ef6d2 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <errno.h> #include <signal.h> #include <string.h> @@ -12,9 +13,7 @@ #include <wait.h> #include <sys/mman.h> #include <sys/utsname.h> -#include "kern_constants.h" -#include "os.h" -#include "user.h" +#include <os.h> void stack_protections(unsigned long address) { @@ -75,6 +74,36 @@ void setup_hostinfo(char *buf, int len) host.release, host.version, host.machine); } +/* + * We cannot use glibc's abort(). It makes use of tgkill() which + * has no effect within UML's kernel threads. + * After that glibc would execute an invalid instruction to kill + * the calling process and UML crashes with SIGSEGV. + */ +static inline void __attribute__ ((noreturn)) uml_abort(void) +{ + sigset_t sig; + + fflush(NULL); + + if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT)) + sigprocmask(SIG_UNBLOCK, &sig, 0); + + for (;;) + if (kill(getpid(), SIGABRT) < 0) + exit(127); +} + +/* + * UML helper threads must not handle SIGWINCH/INT/TERM + */ +void os_fix_helper_signals(void) +{ + signal(SIGWINCH, SIG_IGN); + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); +} + void os_dump_core(void) { int pid; @@ -116,5 +145,10 @@ void os_dump_core(void) while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0) os_kill_ptraced_process(pid, 0); - abort(); + uml_abort(); +} + +void um_early_printk(const char *s, unsigned int n) +{ + printf("%.*s", n, s); } diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 61107b68e05..15889df9b46 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -8,9 +8,7 @@ USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS:.o=.%): \ - c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(basetarget).o) -$(USER_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ - -Dunix -D__unix__ -D__$(SUBARCH)__ $(CF) + c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include $(srctree)/include/linux/kern_levels.h -include user.h $(CFLAGS_$(basetarget).o) # These are like USER_OBJS but filter USER_CFLAGS through unprofile instead of # using it directly. @@ -18,15 +16,11 @@ UNPROFILE_OBJS := $(foreach file,$(UNPROFILE_OBJS),$(obj)/$(file)) $(UNPROFILE_OBJS:.o=.%): \ c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) $(CFLAGS_$(basetarget).o) -$(UNPROFILE_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ - -Dunix -D__unix__ -D__$(SUBARCH)__ $(CF) + +$(USER_OBJS) $(UNPROFILE_OBJS): \ + CHECKFLAGS := $(patsubst $(NOSTDINC_FLAGS),,$(CHECKFLAGS)) # The stubs can't try to call mcount or update basic block data define unprofile $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) endef - -ifdef subarch-obj-y -obj-y += subarch.o -subarch-y = $(addprefix ../../$(HEADER_ARCH)/,$(subarch-obj-y)) -endif diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile deleted file mode 100644 index 964dc1a04c3..00000000000 --- a/arch/um/sys-i386/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) -# - -obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ - ptrace_user.o setjmp.o signal.o stub.o stub_segv.o syscalls.o sysrq.o \ - sys_call_table.o tls.o - -subarch-obj-y = lib/bitops_32.o lib/semaphore_32.o lib/string_32.o -subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o -subarch-obj-$(CONFIG_MODULES) += kernel/module_32.o - -USER_OBJS := bugs.o ptrace_user.o fault.o - -USER_OBJS += user-offsets.s -extra-y += user-offsets.s - -UNPROFILE_OBJS := stub_segv.o -CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING) - -include arch/um/scripts/Makefile.rules diff --git a/arch/um/sys-i386/bug.c b/arch/um/sys-i386/bug.c deleted file mode 100644 index 8d4f273f121..00000000000 --- a/arch/um/sys-i386/bug.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL V2 - */ - -#include <linux/uaccess.h> -#include <asm/errno.h> - -/* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because - * that's not relevant in skas mode. - */ - -int is_valid_bugaddr(unsigned long eip) -{ - unsigned short ud2; - - if (probe_kernel_address((unsigned short __user *)eip, ud2)) - return 0; - - return ud2 == 0x0b0f; -} diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c deleted file mode 100644 index a74442d1376..00000000000 --- a/arch/um/sys-i386/bugs.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <signal.h> -#include "kern_constants.h" -#include "kern_util.h" -#include "longjmp.h" -#include "task.h" -#include "user.h" -#include "sysdep/ptrace.h" - -/* Set during early boot */ -int host_has_cmov = 1; -static jmp_buf cmov_test_return; - -static void cmov_sigill_test_handler(int sig) -{ - host_has_cmov = 0; - longjmp(cmov_test_return, 1); -} - -void arch_check_bugs(void) -{ - struct sigaction old, new; - - printk(UM_KERN_INFO "Checking for host processor cmov support..."); - new.sa_handler = cmov_sigill_test_handler; - - /* Make sure that SIGILL is enabled after the handler longjmps back */ - new.sa_flags = SA_NODEFER; - sigemptyset(&new.sa_mask); - sigaction(SIGILL, &new, &old); - - if (setjmp(cmov_test_return) == 0) { - unsigned long foo = 0; - __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo)); - printk(UM_KERN_CONT "Yes\n"); - } else - printk(UM_KERN_CONT "No\n"); - - sigaction(SIGILL, &old, &new); -} - -void arch_examine_signal(int sig, struct uml_pt_regs *regs) -{ - unsigned char tmp[2]; - - /* - * This is testing for a cmov (0x0f 0x4x) instruction causing a - * SIGILL in init. - */ - if ((sig != SIGILL) || (TASK_PID(get_current()) != 1)) - return; - - if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) { - printk(UM_KERN_ERR "SIGILL in init, could not read " - "instructions!\n"); - return; - } - - if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40)) - return; - - if (host_has_cmov == 0) - printk(UM_KERN_ERR "SIGILL caused by cmov, which this " - "processor doesn't implement. Boot a filesystem " - "compiled for older processors"); - else if (host_has_cmov == 1) - printk(UM_KERN_ERR "SIGILL caused by cmov, which this " - "processor claims to implement"); - else - printk(UM_KERN_ERR "Bad value for host_has_cmov (%d)", - host_has_cmov); -} diff --git a/arch/um/sys-i386/checksum.S b/arch/um/sys-i386/checksum.S deleted file mode 100644 index 62c7e564f22..00000000000 --- a/arch/um/sys-i386/checksum.S +++ /dev/null @@ -1,459 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * IP/TCP/UDP checksumming routines - * - * Authors: Jorge Cwik, <jorge@laser.satlink.net> - * Arnt Gulbrandsen, <agulbra@nvg.unit.no> - * Tom May, <ftom@netcom.com> - * Pentium Pro/II routines: - * Alexander Kjeldaas <astor@guardian.no> - * Finn Arne Gangstad <finnag@guardian.no> - * Lots of code moved from tcp.c and ip.c; see those files - * for more names. - * - * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception - * handling. - * Andi Kleen, add zeroing on error - * converted to pure assembler - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <asm/errno.h> - -/* - * computes a partial checksum, e.g. for TCP/UDP fragments - */ - -/* -unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) - */ - -.text -.align 4 -.globl csum_partial - -#ifndef CONFIG_X86_USE_PPRO_CHECKSUM - - /* - * Experiments with Ethernet and SLIP connections show that buff - * is aligned on either a 2-byte or 4-byte boundary. We get at - * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. - * Fortunately, it is easy to convert 2-byte alignment to 4-byte - * alignment for the unrolled loop. - */ -csum_partial: - pushl %esi - pushl %ebx - movl 20(%esp),%eax # Function arg: unsigned int sum - movl 16(%esp),%ecx # Function arg: int len - movl 12(%esp),%esi # Function arg: unsigned char *buff - testl $2, %esi # Check alignment. - jz 2f # Jump if alignment is ok. - subl $2, %ecx # Alignment uses up two bytes. - jae 1f # Jump if we had at least two bytes. - addl $2, %ecx # ecx was < 2. Deal with it. - jmp 4f -1: movw (%esi), %bx - addl $2, %esi - addw %bx, %ax - adcl $0, %eax -2: - movl %ecx, %edx - shrl $5, %ecx - jz 2f - testl %esi, %esi -1: movl (%esi), %ebx - adcl %ebx, %eax - movl 4(%esi), %ebx - adcl %ebx, %eax - movl 8(%esi), %ebx - adcl %ebx, %eax - movl 12(%esi), %ebx - adcl %ebx, %eax - movl 16(%esi), %ebx - adcl %ebx, %eax - movl 20(%esi), %ebx - adcl %ebx, %eax - movl 24(%esi), %ebx - adcl %ebx, %eax - movl 28(%esi), %ebx - adcl %ebx, %eax - lea 32(%esi), %esi - dec %ecx - jne 1b - adcl $0, %eax -2: movl %edx, %ecx - andl $0x1c, %edx - je 4f - shrl $2, %edx # This clears CF -3: adcl (%esi), %eax - lea 4(%esi), %esi - dec %edx - jne 3b - adcl $0, %eax -4: andl $3, %ecx - jz 7f - cmpl $2, %ecx - jb 5f - movw (%esi),%cx - leal 2(%esi),%esi - je 6f - shll $16,%ecx -5: movb (%esi),%cl -6: addl %ecx,%eax - adcl $0, %eax -7: - popl %ebx - popl %esi - ret - -#else - -/* Version for PentiumII/PPro */ - -csum_partial: - pushl %esi - pushl %ebx - movl 20(%esp),%eax # Function arg: unsigned int sum - movl 16(%esp),%ecx # Function arg: int len - movl 12(%esp),%esi # Function arg: const unsigned char *buf - - testl $2, %esi - jnz 30f -10: - movl %ecx, %edx - movl %ecx, %ebx - andl $0x7c, %ebx - shrl $7, %ecx - addl %ebx,%esi - shrl $2, %ebx - negl %ebx - lea 45f(%ebx,%ebx,2), %ebx - testl %esi, %esi - jmp *%ebx - - # Handle 2-byte-aligned regions -20: addw (%esi), %ax - lea 2(%esi), %esi - adcl $0, %eax - jmp 10b - -30: subl $2, %ecx - ja 20b - je 32f - movzbl (%esi),%ebx # csumming 1 byte, 2-aligned - addl %ebx, %eax - adcl $0, %eax - jmp 80f -32: - addw (%esi), %ax # csumming 2 bytes, 2-aligned - adcl $0, %eax - jmp 80f - -40: - addl -128(%esi), %eax - adcl -124(%esi), %eax - adcl -120(%esi), %eax - adcl -116(%esi), %eax - adcl -112(%esi), %eax - adcl -108(%esi), %eax - adcl -104(%esi), %eax - adcl -100(%esi), %eax - adcl -96(%esi), %eax - adcl -92(%esi), %eax - adcl -88(%esi), %eax - adcl -84(%esi), %eax - adcl -80(%esi), %eax - adcl -76(%esi), %eax - adcl -72(%esi), %eax - adcl -68(%esi), %eax - adcl -64(%esi), %eax - adcl -60(%esi), %eax - adcl -56(%esi), %eax - adcl -52(%esi), %eax - adcl -48(%esi), %eax - adcl -44(%esi), %eax - adcl -40(%esi), %eax - adcl -36(%esi), %eax - adcl -32(%esi), %eax - adcl -28(%esi), %eax - adcl -24(%esi), %eax - adcl -20(%esi), %eax - adcl -16(%esi), %eax - adcl -12(%esi), %eax - adcl -8(%esi), %eax - adcl -4(%esi), %eax -45: - lea 128(%esi), %esi - adcl $0, %eax - dec %ecx - jge 40b - movl %edx, %ecx -50: andl $3, %ecx - jz 80f - - # Handle the last 1-3 bytes without jumping - notl %ecx # 1->2, 2->1, 3->0, higher bits are masked - movl $0xffffff,%ebx # by the shll and shrl instructions - shll $3,%ecx - shrl %cl,%ebx - andl -128(%esi),%ebx # esi is 4-aligned so should be ok - addl %ebx,%eax - adcl $0,%eax -80: - popl %ebx - popl %esi - ret - -#endif - -/* -unsigned int csum_partial_copy_generic (const char *src, char *dst, - int len, int sum, int *src_err_ptr, int *dst_err_ptr) - */ - -/* - * Copy from ds while checksumming, otherwise like csum_partial - * - * The macros SRC and DST specify the type of access for the instruction. - * thus we can call a custom exception handler for all access types. - * - * FIXME: could someone double-check whether I haven't mixed up some SRC and - * DST definitions? It's damn hard to trigger all cases. I hope I got - * them all but there's no guarantee. - */ - -#define SRC(y...) \ - 9999: y; \ - .section __ex_table, "a"; \ - .long 9999b, 6001f ; \ - .previous - -#define DST(y...) \ - 9999: y; \ - .section __ex_table, "a"; \ - .long 9999b, 6002f ; \ - .previous - -.align 4 -.globl csum_partial_copy_generic_i386 - -#ifndef CONFIG_X86_USE_PPRO_CHECKSUM - -#define ARGBASE 16 -#define FP 12 - -csum_partial_copy_generic_i386: - subl $4,%esp - pushl %edi - pushl %esi - pushl %ebx - movl ARGBASE+16(%esp),%eax # sum - movl ARGBASE+12(%esp),%ecx # len - movl ARGBASE+4(%esp),%esi # src - movl ARGBASE+8(%esp),%edi # dst - - testl $2, %edi # Check alignment. - jz 2f # Jump if alignment is ok. - subl $2, %ecx # Alignment uses up two bytes. - jae 1f # Jump if we had at least two bytes. - addl $2, %ecx # ecx was < 2. Deal with it. - jmp 4f -SRC(1: movw (%esi), %bx ) - addl $2, %esi -DST( movw %bx, (%edi) ) - addl $2, %edi - addw %bx, %ax - adcl $0, %eax -2: - movl %ecx, FP(%esp) - shrl $5, %ecx - jz 2f - testl %esi, %esi -SRC(1: movl (%esi), %ebx ) -SRC( movl 4(%esi), %edx ) - adcl %ebx, %eax -DST( movl %ebx, (%edi) ) - adcl %edx, %eax -DST( movl %edx, 4(%edi) ) - -SRC( movl 8(%esi), %ebx ) -SRC( movl 12(%esi), %edx ) - adcl %ebx, %eax -DST( movl %ebx, 8(%edi) ) - adcl %edx, %eax -DST( movl %edx, 12(%edi) ) - -SRC( movl 16(%esi), %ebx ) -SRC( movl 20(%esi), %edx ) - adcl %ebx, %eax -DST( movl %ebx, 16(%edi) ) - adcl %edx, %eax -DST( movl %edx, 20(%edi) ) - -SRC( movl 24(%esi), %ebx ) -SRC( movl 28(%esi), %edx ) - adcl %ebx, %eax -DST( movl %ebx, 24(%edi) ) - adcl %edx, %eax -DST( movl %edx, 28(%edi) ) - - lea 32(%esi), %esi - lea 32(%edi), %edi - dec %ecx - jne 1b - adcl $0, %eax -2: movl FP(%esp), %edx - movl %edx, %ecx - andl $0x1c, %edx - je 4f - shrl $2, %edx # This clears CF -SRC(3: movl (%esi), %ebx ) - adcl %ebx, %eax -DST( movl %ebx, (%edi) ) - lea 4(%esi), %esi - lea 4(%edi), %edi - dec %edx - jne 3b - adcl $0, %eax -4: andl $3, %ecx - jz 7f - cmpl $2, %ecx - jb 5f -SRC( movw (%esi), %cx ) - leal 2(%esi), %esi -DST( movw %cx, (%edi) ) - leal 2(%edi), %edi - je 6f - shll $16,%ecx -SRC(5: movb (%esi), %cl ) -DST( movb %cl, (%edi) ) -6: addl %ecx, %eax - adcl $0, %eax -7: -5000: - -# Exception handler: -.section .fixup, "ax" - -6001: - movl ARGBASE+20(%esp), %ebx # src_err_ptr - movl $-EFAULT, (%ebx) - - # zero the complete destination - computing the rest - # is too much work - movl ARGBASE+8(%esp), %edi # dst - movl ARGBASE+12(%esp), %ecx # len - xorl %eax,%eax - rep ; stosb - - jmp 5000b - -6002: - movl ARGBASE+24(%esp), %ebx # dst_err_ptr - movl $-EFAULT,(%ebx) - jmp 5000b - -.previous - - popl %ebx - popl %esi - popl %edi - popl %ecx # equivalent to addl $4,%esp - ret - -#else - -/* Version for PentiumII/PPro */ - -#define ROUND1(x) \ - SRC(movl x(%esi), %ebx ) ; \ - addl %ebx, %eax ; \ - DST(movl %ebx, x(%edi) ) ; - -#define ROUND(x) \ - SRC(movl x(%esi), %ebx ) ; \ - adcl %ebx, %eax ; \ - DST(movl %ebx, x(%edi) ) ; - -#define ARGBASE 12 - -csum_partial_copy_generic_i386: - pushl %ebx - pushl %edi - pushl %esi - movl ARGBASE+4(%esp),%esi #src - movl ARGBASE+8(%esp),%edi #dst - movl ARGBASE+12(%esp),%ecx #len - movl ARGBASE+16(%esp),%eax #sum -# movl %ecx, %edx - movl %ecx, %ebx - movl %esi, %edx - shrl $6, %ecx - andl $0x3c, %ebx - negl %ebx - subl %ebx, %esi - subl %ebx, %edi - lea -1(%esi),%edx - andl $-32,%edx - lea 3f(%ebx,%ebx), %ebx - testl %esi, %esi - jmp *%ebx -1: addl $64,%esi - addl $64,%edi - SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl) - ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52) - ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36) - ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20) - ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4) -3: adcl $0,%eax - addl $64, %edx - dec %ecx - jge 1b -4: movl ARGBASE+12(%esp),%edx #len - andl $3, %edx - jz 7f - cmpl $2, %edx - jb 5f -SRC( movw (%esi), %dx ) - leal 2(%esi), %esi -DST( movw %dx, (%edi) ) - leal 2(%edi), %edi - je 6f - shll $16,%edx -5: -SRC( movb (%esi), %dl ) -DST( movb %dl, (%edi) ) -6: addl %edx, %eax - adcl $0, %eax -7: -.section .fixup, "ax" -6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr - movl $-EFAULT, (%ebx) - # zero the complete destination (computing the rest is too much work) - movl ARGBASE+8(%esp),%edi # dst - movl ARGBASE+12(%esp),%ecx # len - xorl %eax,%eax - rep; stosb - jmp 7b -6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr - movl $-EFAULT, (%ebx) - jmp 7b -.previous - - popl %esi - popl %edi - popl %ebx - ret - -#undef ROUND -#undef ROUND1 - -#endif diff --git a/arch/um/sys-i386/delay.c b/arch/um/sys-i386/delay.c deleted file mode 100644 index d623e074f41..00000000000 --- a/arch/um/sys-i386/delay.c +++ /dev/null @@ -1,29 +0,0 @@ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <asm/param.h> - -void __delay(unsigned long time) -{ - /* Stolen from the i386 __loop_delay */ - int d0; - __asm__ __volatile__( - "\tjmp 1f\n" - ".align 16\n" - "1:\tjmp 2f\n" - ".align 16\n" - "2:\tdecl %0\n\tjns 2b" - :"=&a" (d0) - :"0" (time)); -} - -void __udelay(unsigned long usecs) -{ - int i, n; - - n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) - cpu_relax(); -} - -EXPORT_SYMBOL(__udelay); diff --git a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c deleted file mode 100644 index d670f68532f..00000000000 --- a/arch/um/sys-i386/fault.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include "sysdep/ptrace.h" - -/* These two are from asm-um/uaccess.h and linux/module.h, check them. */ -struct exception_table_entry -{ - unsigned long insn; - unsigned long fixup; -}; - -const struct exception_table_entry *search_exception_tables(unsigned long add); - -/* Compare this to arch/i386/mm/extable.c:fixup_exception() */ -int arch_fixup(unsigned long address, struct uml_pt_regs *regs) -{ - const struct exception_table_entry *fixup; - - fixup = search_exception_tables(address); - if (fixup != 0) { - UPT_IP(regs) = fixup->fixup; - return 1; - } - return 0; -} diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c deleted file mode 100644 index 2a1eac1859c..00000000000 --- a/arch/um/sys-i386/ksyms.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "linux/module.h" -#include "linux/in6.h" -#include "linux/rwsem.h" -#include "asm/byteorder.h" -#include "asm/delay.h" -#include "asm/semaphore.h" -#include "asm/uaccess.h" -#include "asm/checksum.h" -#include "asm/errno.h" - -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__down_failed_trylock); -EXPORT_SYMBOL(__up_wakeup); - -/* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial); diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c deleted file mode 100644 index a34263e6b08..00000000000 --- a/arch/um/sys-i386/ldt.c +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <linux/mm.h> -#include <linux/sched.h> -#include <asm/unistd.h> -#include "os.h" -#include "proc_mm.h" -#include "skas.h" -#include "skas_ptrace.h" -#include "sysdep/tls.h" - -extern int modify_ldt(int func, void *ptr, unsigned long bytecount); - -long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, - void **addr, int done) -{ - long res; - - if (proc_mm) { - /* - * This is a special handling for the case, that the mm to - * modify isn't current->active_mm. - * If this is called directly by modify_ldt, - * (current->active_mm->context.skas.u == mm_idp) - * will be true. So no call to __switch_mm(mm_idp) is done. - * If this is called in case of init_new_ldt or PTRACE_LDT, - * mm_idp won't belong to current->active_mm, but child->mm. - * So we need to switch child's mm into our userspace, then - * later switch back. - * - * Note: I'm unsure: should interrupts be disabled here? - */ - if (!current->active_mm || current->active_mm == &init_mm || - mm_idp != ¤t->active_mm->context.id) - __switch_mm(mm_idp); - } - - if (ptrace_ldt) { - struct ptrace_ldt ldt_op = (struct ptrace_ldt) { - .func = func, - .ptr = desc, - .bytecount = sizeof(*desc)}; - u32 cpu; - int pid; - - if (!proc_mm) - pid = mm_idp->u.pid; - else { - cpu = get_cpu(); - pid = userspace_pid[cpu]; - } - - res = os_ptrace_ldt(pid, 0, (unsigned long) &ldt_op); - - if (proc_mm) - put_cpu(); - } - else { - void *stub_addr; - res = syscall_stub_data(mm_idp, (unsigned long *)desc, - (sizeof(*desc) + sizeof(long) - 1) & - ~(sizeof(long) - 1), - addr, &stub_addr); - if (!res) { - unsigned long args[] = { func, - (unsigned long)stub_addr, - sizeof(*desc), - 0, 0, 0 }; - res = run_syscall_stub(mm_idp, __NR_modify_ldt, args, - 0, addr, done); - } - } - - if (proc_mm) { - /* - * This is the second part of special handling, that makes - * PTRACE_LDT possible to implement. - */ - if (current->active_mm && current->active_mm != &init_mm && - mm_idp != ¤t->active_mm->context.id) - __switch_mm(¤t->active_mm->context.id); - } - - return res; -} - -static long read_ldt_from_host(void __user * ptr, unsigned long bytecount) -{ - int res, n; - struct ptrace_ldt ptrace_ldt = (struct ptrace_ldt) { - .func = 0, - .bytecount = bytecount, - .ptr = kmalloc(bytecount, GFP_KERNEL)}; - u32 cpu; - - if (ptrace_ldt.ptr == NULL) - return -ENOMEM; - - /* - * This is called from sys_modify_ldt only, so userspace_pid gives - * us the right number - */ - - cpu = get_cpu(); - res = os_ptrace_ldt(userspace_pid[cpu], 0, (unsigned long) &ptrace_ldt); - put_cpu(); - if (res < 0) - goto out; - - n = copy_to_user(ptr, ptrace_ldt.ptr, res); - if (n != 0) - res = -EFAULT; - - out: - kfree(ptrace_ldt.ptr); - - return res; -} - -/* - * In skas mode, we hold our own ldt data in UML. - * Thus, the code implementing sys_modify_ldt_skas - * is very similar to (and mostly stolen from) sys_modify_ldt - * for arch/i386/kernel/ldt.c - * The routines copied and modified in part are: - * - read_ldt - * - read_default_ldt - * - write_ldt - * - sys_modify_ldt_skas - */ - -static int read_ldt(void __user * ptr, unsigned long bytecount) -{ - int i, err = 0; - unsigned long size; - uml_ldt_t * ldt = ¤t->mm->context.ldt; - - if (!ldt->entry_count) - goto out; - if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) - bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; - err = bytecount; - - if (ptrace_ldt) - return read_ldt_from_host(ptr, bytecount); - - mutex_lock(&ldt->lock); - if (ldt->entry_count <= LDT_DIRECT_ENTRIES) { - size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES; - if (size > bytecount) - size = bytecount; - if (copy_to_user(ptr, ldt->u.entries, size)) - err = -EFAULT; - bytecount -= size; - ptr += size; - } - else { - for (i=0; i<ldt->entry_count/LDT_ENTRIES_PER_PAGE && bytecount; - i++) { - size = PAGE_SIZE; - if (size > bytecount) - size = bytecount; - if (copy_to_user(ptr, ldt->u.pages[i], size)) { - err = -EFAULT; - break; - } - bytecount -= size; - ptr += size; - } - } - mutex_unlock(&ldt->lock); - - if (bytecount == 0 || err == -EFAULT) - goto out; - - if (clear_user(ptr, bytecount)) - err = -EFAULT; - -out: - return err; -} - -static int read_default_ldt(void __user * ptr, unsigned long bytecount) -{ - int err; - - if (bytecount > 5*LDT_ENTRY_SIZE) - bytecount = 5*LDT_ENTRY_SIZE; - - err = bytecount; - /* - * UML doesn't support lcall7 and lcall27. - * So, we don't really have a default ldt, but emulate - * an empty ldt of common host default ldt size. - */ - if (clear_user(ptr, bytecount)) - err = -EFAULT; - - return err; -} - -static int write_ldt(void __user * ptr, unsigned long bytecount, int func) -{ - uml_ldt_t * ldt = ¤t->mm->context.ldt; - struct mm_id * mm_idp = ¤t->mm->context.id; - int i, err; - struct user_desc ldt_info; - struct ldt_entry entry0, *ldt_p; - void *addr = NULL; - - err = -EINVAL; - if (bytecount != sizeof(ldt_info)) - goto out; - err = -EFAULT; - if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) - goto out; - - err = -EINVAL; - if (ldt_info.entry_number >= LDT_ENTRIES) - goto out; - if (ldt_info.contents == 3) { - if (func == 1) - goto out; - if (ldt_info.seg_not_present == 0) - goto out; - } - - if (!ptrace_ldt) - mutex_lock(&ldt->lock); - - err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); - if (err) - goto out_unlock; - else if (ptrace_ldt) { - /* With PTRACE_LDT available, this is used as a flag only */ - ldt->entry_count = 1; - goto out; - } - - if (ldt_info.entry_number >= ldt->entry_count && - ldt_info.entry_number >= LDT_DIRECT_ENTRIES) { - for (i=ldt->entry_count/LDT_ENTRIES_PER_PAGE; - i*LDT_ENTRIES_PER_PAGE <= ldt_info.entry_number; - i++) { - if (i == 0) - memcpy(&entry0, ldt->u.entries, - sizeof(entry0)); - ldt->u.pages[i] = (struct ldt_entry *) - __get_free_page(GFP_KERNEL|__GFP_ZERO); - if (!ldt->u.pages[i]) { - err = -ENOMEM; - /* Undo the change in host */ - memset(&ldt_info, 0, sizeof(ldt_info)); - write_ldt_entry(mm_idp, 1, &ldt_info, &addr, 1); - goto out_unlock; - } - if (i == 0) { - memcpy(ldt->u.pages[0], &entry0, - sizeof(entry0)); - memcpy(ldt->u.pages[0]+1, ldt->u.entries+1, - sizeof(entry0)*(LDT_DIRECT_ENTRIES-1)); - } - ldt->entry_count = (i + 1) * LDT_ENTRIES_PER_PAGE; - } - } - if (ldt->entry_count <= ldt_info.entry_number) - ldt->entry_count = ldt_info.entry_number + 1; - - if (ldt->entry_count <= LDT_DIRECT_ENTRIES) - ldt_p = ldt->u.entries + ldt_info.entry_number; - else - ldt_p = ldt->u.pages[ldt_info.entry_number/LDT_ENTRIES_PER_PAGE] + - ldt_info.entry_number%LDT_ENTRIES_PER_PAGE; - - if (ldt_info.base_addr == 0 && ldt_info.limit == 0 && - (func == 1 || LDT_empty(&ldt_info))) { - ldt_p->a = 0; - ldt_p->b = 0; - } - else{ - if (func == 1) - ldt_info.useable = 0; - ldt_p->a = LDT_entry_a(&ldt_info); - ldt_p->b = LDT_entry_b(&ldt_info); - } - err = 0; - -out_unlock: - mutex_unlock(&ldt->lock); -out: - return err; -} - -static long do_modify_ldt_skas(int func, void __user *ptr, - unsigned long bytecount) -{ - int ret = -ENOSYS; - - switch (func) { - case 0: - ret = read_ldt(ptr, bytecount); - break; - case 1: - case 0x11: - ret = write_ldt(ptr, bytecount, func); - break; - case 2: - ret = read_default_ldt(ptr, bytecount); - break; - } - return ret; -} - -static DEFINE_SPINLOCK(host_ldt_lock); -static short dummy_list[9] = {0, -1}; -static short * host_ldt_entries = NULL; - -static void ldt_get_host_info(void) -{ - long ret; - struct ldt_entry * ldt; - short *tmp; - int i, size, k, order; - - spin_lock(&host_ldt_lock); - - if (host_ldt_entries != NULL) { - spin_unlock(&host_ldt_lock); - return; - } - host_ldt_entries = dummy_list+1; - - spin_unlock(&host_ldt_lock); - - for (i = LDT_PAGES_MAX-1, order=0; i; i>>=1, order++) - ; - - ldt = (struct ldt_entry *) - __get_free_pages(GFP_KERNEL|__GFP_ZERO, order); - if (ldt == NULL) { - printk(KERN_ERR "ldt_get_host_info: couldn't allocate buffer " - "for host ldt\n"); - return; - } - - ret = modify_ldt(0, ldt, (1<<order)*PAGE_SIZE); - if (ret < 0) { - printk(KERN_ERR "ldt_get_host_info: couldn't read host ldt\n"); - goto out_free; - } - if (ret == 0) { - /* default_ldt is active, simply write an empty entry 0 */ - host_ldt_entries = dummy_list; - goto out_free; - } - - for (i=0, size=0; i<ret/LDT_ENTRY_SIZE; i++) { - if (ldt[i].a != 0 || ldt[i].b != 0) - size++; - } - - if (size < ARRAY_SIZE(dummy_list)) - host_ldt_entries = dummy_list; - else { - size = (size + 1) * sizeof(dummy_list[0]); - tmp = kmalloc(size, GFP_KERNEL); - if (tmp == NULL) { - printk(KERN_ERR "ldt_get_host_info: couldn't allocate " - "host ldt list\n"); - goto out_free; - } - host_ldt_entries = tmp; - } - - for (i=0, k=0; i<ret/LDT_ENTRY_SIZE; i++) { - if (ldt[i].a != 0 || ldt[i].b != 0) - host_ldt_entries[k++] = i; - } - host_ldt_entries[k] = -1; - -out_free: - free_pages((unsigned long)ldt, order); -} - -long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm) -{ - struct user_desc desc; - short * num_p; - int i; - long page, err=0; - void *addr = NULL; - struct proc_mm_op copy; - - - if (!ptrace_ldt) - mutex_init(&new_mm->ldt.lock); - - if (!from_mm) { - memset(&desc, 0, sizeof(desc)); - /* - * We have to initialize a clean ldt. - */ - if (proc_mm) { - /* - * If the new mm was created using proc_mm, host's - * default-ldt currently is assigned, which normally - * contains the call-gates for lcall7 and lcall27. - * To remove these gates, we simply write an empty - * entry as number 0 to the host. - */ - err = write_ldt_entry(&new_mm->id, 1, &desc, &addr, 1); - } - else{ - /* - * Now we try to retrieve info about the ldt, we - * inherited from the host. All ldt-entries found - * will be reset in the following loop - */ - ldt_get_host_info(); - for (num_p=host_ldt_entries; *num_p != -1; num_p++) { - desc.entry_number = *num_p; - err = write_ldt_entry(&new_mm->id, 1, &desc, - &addr, *(num_p + 1) == -1); - if (err) - break; - } - } - new_mm->ldt.entry_count = 0; - - goto out; - } - - if (proc_mm) { - /* - * We have a valid from_mm, so we now have to copy the LDT of - * from_mm to new_mm, because using proc_mm an new mm with - * an empty/default LDT was created in new_mm() - */ - copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, - .u = - { .copy_segments = - from_mm->id.u.mm_fd } } ); - i = os_write_file(new_mm->id.u.mm_fd, ©, sizeof(copy)); - if (i != sizeof(copy)) - printk(KERN_ERR "new_mm : /proc/mm copy_segments " - "failed, err = %d\n", -i); - } - - if (!ptrace_ldt) { - /* - * Our local LDT is used to supply the data for - * modify_ldt(READLDT), if PTRACE_LDT isn't available, - * i.e., we have to use the stub for modify_ldt, which - * can't handle the big read buffer of up to 64kB. - */ - mutex_lock(&from_mm->ldt.lock); - if (from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES) - memcpy(new_mm->ldt.u.entries, from_mm->ldt.u.entries, - sizeof(new_mm->ldt.u.entries)); - else { - i = from_mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE; - while (i-->0) { - page = __get_free_page(GFP_KERNEL|__GFP_ZERO); - if (!page) { - err = -ENOMEM; - break; - } - new_mm->ldt.u.pages[i] = - (struct ldt_entry *) page; - memcpy(new_mm->ldt.u.pages[i], - from_mm->ldt.u.pages[i], PAGE_SIZE); - } - } - new_mm->ldt.entry_count = from_mm->ldt.entry_count; - mutex_unlock(&from_mm->ldt.lock); - } - - out: - return err; -} - - -void free_ldt(struct mm_context *mm) -{ - int i; - - if (!ptrace_ldt && mm->ldt.entry_count > LDT_DIRECT_ENTRIES) { - i = mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE; - while (i-- > 0) - free_page((long) mm->ldt.u.pages[i]); - } - mm->ldt.entry_count = 0; -} - -int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) -{ - return do_modify_ldt_skas(func, ptr, bytecount); -} diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c deleted file mode 100644 index 6b4499906a6..00000000000 --- a/arch/um/sys-i386/ptrace.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include "linux/mm.h" -#include "linux/sched.h" -#include "asm/uaccess.h" -#include "skas.h" - -extern int arch_switch_tls(struct task_struct *to); - -void arch_switch_to(struct task_struct *to) -{ - int err = arch_switch_tls(to); - if (!err) - return; - - if (err != -EINVAL) - printk(KERN_WARNING "arch_switch_tls failed, errno %d, " - "not EINVAL\n", -err); - else - printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n"); -} - -int is_syscall(unsigned long addr) -{ - unsigned short instr; - int n; - - n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); - if (n) { - /* access_process_vm() grants access to vsyscall and stub, - * while copy_from_user doesn't. Maybe access_process_vm is - * slow, but that doesn't matter, since it will be called only - * in case of singlestepping, if copy_from_user failed. - */ - n = access_process_vm(current, addr, &instr, sizeof(instr), 0); - if (n != sizeof(instr)) { - printk(KERN_ERR "is_syscall : failed to read " - "instruction from 0x%lx\n", addr); - return 1; - } - } - /* int 0x80 or sysenter */ - return (instr == 0x80cd) || (instr == 0x340f); -} - -/* determines which flags the user has access to. */ -/* 1 = access 0 = no access */ -#define FLAG_MASK 0x00044dd5 - -int putreg(struct task_struct *child, int regno, unsigned long value) -{ - regno >>= 2; - switch (regno) { - case FS: - if (value && (value & 3) != 3) - return -EIO; - PT_REGS_FS(&child->thread.regs) = value; - return 0; - case GS: - if (value && (value & 3) != 3) - return -EIO; - PT_REGS_GS(&child->thread.regs) = value; - return 0; - case DS: - case ES: - if (value && (value & 3) != 3) - return -EIO; - value &= 0xffff; - break; - case SS: - case CS: - if ((value & 3) != 3) - return -EIO; - value &= 0xffff; - break; - case EFL: - value &= FLAG_MASK; - value |= PT_REGS_EFLAGS(&child->thread.regs); - break; - } - PT_REGS_SET(&child->thread.regs, regno, value); - return 0; -} - -int poke_user(struct task_struct *child, long addr, long data) -{ - if ((addr & 3) || addr < 0) - return -EIO; - - if (addr < MAX_REG_OFFSET) - return putreg(child, addr, data); - else if ((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))) { - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - if ((addr == 4) || (addr == 5)) - return -EIO; - child->thread.arch.debugregs[addr] = data; - return 0; - } - return -EIO; -} - -unsigned long getreg(struct task_struct *child, int regno) -{ - unsigned long retval = ~0UL; - - regno >>= 2; - switch (regno) { - case FS: - case GS: - case DS: - case ES: - case SS: - case CS: - retval = 0xffff; - /* fall through */ - default: - retval &= PT_REG(&child->thread.regs, regno); - } - return retval; -} - -/* read the word at location addr in the USER area. */ -int peek_user(struct task_struct *child, long addr, long data) -{ - unsigned long tmp; - - if ((addr & 3) || addr < 0) - return -EIO; - - tmp = 0; /* Default return condition */ - if (addr < MAX_REG_OFFSET) { - tmp = getreg(child, addr); - } - else if ((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))) { - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - tmp = child->thread.arch.debugregs[addr]; - } - return put_user(tmp, (unsigned long __user *) data); -} - -int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) -{ - int err, n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_FP_SIZE]; - - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - err = save_fp_registers(userspace_pid[cpu], fpregs); - if (err) - return err; - - n = copy_to_user(buf, fpregs, sizeof(fpregs)); - if(n > 0) - return -EFAULT; - - return n; -} - -int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) -{ - int n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_FP_SIZE]; - - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - n = copy_from_user(fpregs, buf, sizeof(fpregs)); - if (n > 0) - return -EFAULT; - - return restore_fp_registers(userspace_pid[cpu], fpregs); -} - -int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) -{ - int err, n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_XFP_SIZE]; - - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - err = save_fpx_registers(userspace_pid[cpu], fpregs); - if (err) - return err; - - n = copy_to_user(buf, fpregs, sizeof(fpregs)); - if(n > 0) - return -EFAULT; - - return n; -} - -int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) -{ - int n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_XFP_SIZE]; - - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - n = copy_from_user(fpregs, buf, sizeof(fpregs)); - if (n > 0) - return -EFAULT; - - return restore_fpx_registers(userspace_pid[cpu], fpregs); -} - -long subarch_ptrace(struct task_struct *child, long request, long addr, - long data) -{ - return -EIO; -} diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c deleted file mode 100644 index 0b10c3e7402..00000000000 --- a/arch/um/sys-i386/ptrace_user.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <errno.h> -#include <sys/ptrace.h> - -int ptrace_getregs(long pid, unsigned long *regs_out) -{ - if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) - return -errno; - return 0; -} - -int ptrace_setregs(long pid, unsigned long *regs) -{ - if (ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) - return -errno; - return 0; -} diff --git a/arch/um/sys-i386/setjmp.S b/arch/um/sys-i386/setjmp.S deleted file mode 100644 index b766792c993..00000000000 --- a/arch/um/sys-i386/setjmp.S +++ /dev/null @@ -1,58 +0,0 @@ -# -# arch/i386/setjmp.S -# -# setjmp/longjmp for the i386 architecture -# - -# -# The jmp_buf is assumed to contain the following, in order: -# %ebx -# %esp -# %ebp -# %esi -# %edi -# <return address> -# - - .text - .align 4 - .globl setjmp - .type setjmp, @function -setjmp: -#ifdef _REGPARM - movl %eax,%edx -#else - movl 4(%esp),%edx -#endif - popl %ecx # Return address, and adjust the stack - xorl %eax,%eax # Return value - movl %ebx,(%edx) - movl %esp,4(%edx) # Post-return %esp! - pushl %ecx # Make the call/return stack happy - movl %ebp,8(%edx) - movl %esi,12(%edx) - movl %edi,16(%edx) - movl %ecx,20(%edx) # Return address - ret - - .size setjmp,.-setjmp - - .text - .align 4 - .globl longjmp - .type longjmp, @function -longjmp: -#ifdef _REGPARM - xchgl %eax,%edx -#else - movl 4(%esp),%edx # jmp_ptr address - movl 8(%esp),%eax # Return value -#endif - movl (%edx),%ebx - movl 4(%edx),%esp - movl 8(%edx),%ebp - movl 12(%edx),%esi - movl 16(%edx),%edi - jmp *20(%edx) - - .size longjmp,.-longjmp diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c deleted file mode 100644 index fd0c25ad6af..00000000000 --- a/arch/um/sys-i386/signal.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <linux/ptrace.h> -#include <asm/unistd.h> -#include <asm/uaccess.h> -#include <asm/ucontext.h> -#include "frame_kern.h" -#include "skas.h" - -void copy_sc(struct uml_pt_regs *regs, void *from) -{ - struct sigcontext *sc = from; - - REGS_GS(regs->gp) = sc->gs; - REGS_FS(regs->gp) = sc->fs; - REGS_ES(regs->gp) = sc->es; - REGS_DS(regs->gp) = sc->ds; - REGS_EDI(regs->gp) = sc->di; - REGS_ESI(regs->gp) = sc->si; - REGS_EBP(regs->gp) = sc->bp; - REGS_SP(regs->gp) = sc->sp; - REGS_EBX(regs->gp) = sc->bx; - REGS_EDX(regs->gp) = sc->dx; - REGS_ECX(regs->gp) = sc->cx; - REGS_EAX(regs->gp) = sc->ax; - REGS_IP(regs->gp) = sc->ip; - REGS_CS(regs->gp) = sc->cs; - REGS_EFLAGS(regs->gp) = sc->flags; - REGS_SS(regs->gp) = sc->ss; -} - -/* - * FPU tag word conversions. - */ - -static inline unsigned short twd_i387_to_fxsr(unsigned short twd) -{ - unsigned int tmp; /* to avoid 16 bit prefixes in the code */ - - /* Transform each pair of bits into 01 (valid) or 00 (empty) */ - tmp = ~twd; - tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ - /* and move the valid bits to the lower byte. */ - tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ - tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ - tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ - return tmp; -} - -static inline unsigned long twd_fxsr_to_i387(struct user_fxsr_struct *fxsave) -{ - struct _fpxreg *st = NULL; - unsigned long twd = (unsigned long) fxsave->twd; - unsigned long tag; - unsigned long ret = 0xffff0000; - int i; - -#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16); - - for (i = 0; i < 8; i++) { - if (twd & 0x1) { - st = (struct _fpxreg *) FPREG_ADDR(fxsave, i); - - switch (st->exponent & 0x7fff) { - case 0x7fff: - tag = 2; /* Special */ - break; - case 0x0000: - if ( !st->significand[0] && - !st->significand[1] && - !st->significand[2] && - !st->significand[3] ) { - tag = 1; /* Zero */ - } else { - tag = 2; /* Special */ - } - break; - default: - if (st->significand[3] & 0x8000) { - tag = 0; /* Valid */ - } else { - tag = 2; /* Special */ - } - break; - } - } else { - tag = 3; /* Empty */ - } - ret |= (tag << (2 * i)); - twd = twd >> 1; - } - return ret; -} - -static int convert_fxsr_to_user(struct _fpstate __user *buf, - struct user_fxsr_struct *fxsave) -{ - unsigned long env[7]; - struct _fpreg __user *to; - struct _fpxreg *from; - int i; - - env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul; - env[1] = (unsigned long)fxsave->swd | 0xffff0000ul; - env[2] = twd_fxsr_to_i387(fxsave); - env[3] = fxsave->fip; - env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); - env[5] = fxsave->foo; - env[6] = fxsave->fos; - - if (__copy_to_user(buf, env, 7 * sizeof(unsigned long))) - return 1; - - to = &buf->_st[0]; - from = (struct _fpxreg *) &fxsave->st_space[0]; - for (i = 0; i < 8; i++, to++, from++) { - unsigned long __user *t = (unsigned long __user *)to; - unsigned long *f = (unsigned long *)from; - - if (__put_user(*f, t) || - __put_user(*(f + 1), t + 1) || - __put_user(from->exponent, &to->exponent)) - return 1; - } - return 0; -} - -static int convert_fxsr_from_user(struct user_fxsr_struct *fxsave, - struct _fpstate __user *buf) -{ - unsigned long env[7]; - struct _fpxreg *to; - struct _fpreg __user *from; - int i; - - if (copy_from_user( env, buf, 7 * sizeof(long))) - return 1; - - fxsave->cwd = (unsigned short)(env[0] & 0xffff); - fxsave->swd = (unsigned short)(env[1] & 0xffff); - fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); - fxsave->fip = env[3]; - fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16); - fxsave->fcs = (env[4] & 0xffff); - fxsave->foo = env[5]; - fxsave->fos = env[6]; - - to = (struct _fpxreg *) &fxsave->st_space[0]; - from = &buf->_st[0]; - for (i = 0; i < 8; i++, to++, from++) { - unsigned long *t = (unsigned long *)to; - unsigned long __user *f = (unsigned long __user *)from; - - if (__get_user(*t, f) || - __get_user(*(t + 1), f + 1) || - __get_user(to->exponent, &from->exponent)) - return 1; - } - return 0; -} - -extern int have_fpx_regs; - -static int copy_sc_from_user(struct pt_regs *regs, - struct sigcontext __user *from) -{ - struct sigcontext sc; - int err, pid; - - err = copy_from_user(&sc, from, sizeof(sc)); - if (err) - return err; - - pid = userspace_pid[current_thread_info()->cpu]; - copy_sc(®s->regs, &sc); - if (have_fpx_regs) { - struct user_fxsr_struct fpx; - - err = copy_from_user(&fpx, &sc.fpstate->_fxsr_env[0], - sizeof(struct user_fxsr_struct)); - if (err) - return 1; - - err = convert_fxsr_from_user(&fpx, sc.fpstate); - if (err) - return 1; - - err = restore_fpx_registers(pid, (unsigned long *) &fpx); - if (err < 0) { - printk(KERN_ERR "copy_sc_from_user - " - "restore_fpx_registers failed, errno = %d\n", - -err); - return 1; - } - } - else { - struct user_i387_struct fp; - - err = copy_from_user(&fp, sc.fpstate, - sizeof(struct user_i387_struct)); - if (err) - return 1; - - err = restore_fp_registers(pid, (unsigned long *) &fp); - if (err < 0) { - printk(KERN_ERR "copy_sc_from_user - " - "restore_fp_registers failed, errno = %d\n", - -err); - return 1; - } - } - - return 0; -} - -static int copy_sc_to_user(struct sigcontext __user *to, - struct _fpstate __user *to_fp, struct pt_regs *regs, - unsigned long sp) -{ - struct sigcontext sc; - struct faultinfo * fi = ¤t->thread.arch.faultinfo; - int err, pid; - - sc.gs = REGS_GS(regs->regs.gp); - sc.fs = REGS_FS(regs->regs.gp); - sc.es = REGS_ES(regs->regs.gp); - sc.ds = REGS_DS(regs->regs.gp); - sc.di = REGS_EDI(regs->regs.gp); - sc.si = REGS_ESI(regs->regs.gp); - sc.bp = REGS_EBP(regs->regs.gp); - sc.sp = sp; - sc.bx = REGS_EBX(regs->regs.gp); - sc.dx = REGS_EDX(regs->regs.gp); - sc.cx = REGS_ECX(regs->regs.gp); - sc.ax = REGS_EAX(regs->regs.gp); - sc.ip = REGS_IP(regs->regs.gp); - sc.cs = REGS_CS(regs->regs.gp); - sc.flags = REGS_EFLAGS(regs->regs.gp); - sc.sp_at_signal = regs->regs.gp[UESP]; - sc.ss = regs->regs.gp[SS]; - sc.cr2 = fi->cr2; - sc.err = fi->error_code; - sc.trapno = fi->trap_no; - - to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1)); - sc.fpstate = to_fp; - - pid = userspace_pid[current_thread_info()->cpu]; - if (have_fpx_regs) { - struct user_fxsr_struct fpx; - - err = save_fpx_registers(pid, (unsigned long *) &fpx); - if (err < 0){ - printk(KERN_ERR "copy_sc_to_user - save_fpx_registers " - "failed, errno = %d\n", err); - return 1; - } - - err = convert_fxsr_to_user(to_fp, &fpx); - if (err) - return 1; - - err |= __put_user(fpx.swd, &to_fp->status); - err |= __put_user(X86_FXSR_MAGIC, &to_fp->magic); - if (err) - return 1; - - if (copy_to_user(&to_fp->_fxsr_env[0], &fpx, - sizeof(struct user_fxsr_struct))) - return 1; - } - else { - struct user_i387_struct fp; - - err = save_fp_registers(pid, (unsigned long *) &fp); - if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct))) - return 1; - } - - return copy_to_user(to, &sc, sizeof(sc)); -} - -static int copy_ucontext_to_user(struct ucontext __user *uc, - struct _fpstate __user *fp, sigset_t *set, - unsigned long sp) -{ - int err = 0; - - err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp); - err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags); - err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); - err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs, sp); - err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); - return err; -} - -struct sigframe -{ - char __user *pretcode; - int sig; - struct sigcontext sc; - struct _fpstate fpstate; - unsigned long extramask[_NSIG_WORDS-1]; - char retcode[8]; -}; - -struct rt_sigframe -{ - char __user *pretcode; - int sig; - struct siginfo __user *pinfo; - void __user *puc; - struct siginfo info; - struct ucontext uc; - struct _fpstate fpstate; - char retcode[8]; -}; - -int setup_signal_stack_sc(unsigned long stack_top, int sig, - struct k_sigaction *ka, struct pt_regs *regs, - sigset_t *mask) -{ - struct sigframe __user *frame; - void __user *restorer; - unsigned long save_sp = PT_REGS_SP(regs); - int err = 0; - - /* This is the same calculation as i386 - ((sp + 4) & 15) == 0 */ - stack_top = ((stack_top + 4) & -16UL) - 4; - frame = (struct sigframe __user *) stack_top - 1; - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - return 1; - - restorer = frame->retcode; - if (ka->sa.sa_flags & SA_RESTORER) - restorer = ka->sa.sa_restorer; - - /* Update SP now because the page fault handler refuses to extend - * the stack if the faulting address is too far below the current - * SP, which frame now certainly is. If there's an error, the original - * value is restored on the way out. - * When writing the sigcontext to the stack, we have to write the - * original value, so that's passed to copy_sc_to_user, which does - * the right thing with it. - */ - PT_REGS_SP(regs) = (unsigned long) frame; - - err |= __put_user(restorer, &frame->pretcode); - err |= __put_user(sig, &frame->sig); - err |= copy_sc_to_user(&frame->sc, NULL, regs, save_sp); - err |= __put_user(mask->sig[0], &frame->sc.oldmask); - if (_NSIG_WORDS > 1) - err |= __copy_to_user(&frame->extramask, &mask->sig[1], - sizeof(frame->extramask)); - - /* - * This is popl %eax ; movl $,%eax ; int $0x80 - * - * WE DO NOT USE IT ANY MORE! It's only left here for historical - * reasons and because gdb uses it as a signature to notice - * signal handler stack frames. - */ - err |= __put_user(0xb858, (short __user *)(frame->retcode+0)); - err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2)); - err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); - - if (err) - goto err; - - PT_REGS_SP(regs) = (unsigned long) frame; - PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; - PT_REGS_EAX(regs) = (unsigned long) sig; - PT_REGS_EDX(regs) = (unsigned long) 0; - PT_REGS_ECX(regs) = (unsigned long) 0; - - if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) - ptrace_notify(SIGTRAP); - return 0; - -err: - PT_REGS_SP(regs) = save_sp; - return err; -} - -int setup_signal_stack_si(unsigned long stack_top, int sig, - struct k_sigaction *ka, struct pt_regs *regs, - siginfo_t *info, sigset_t *mask) -{ - struct rt_sigframe __user *frame; - void __user *restorer; - unsigned long save_sp = PT_REGS_SP(regs); - int err = 0; - - stack_top &= -8UL; - frame = (struct rt_sigframe __user *) stack_top - 1; - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - return 1; - - restorer = frame->retcode; - if (ka->sa.sa_flags & SA_RESTORER) - restorer = ka->sa.sa_restorer; - - /* See comment above about why this is here */ - PT_REGS_SP(regs) = (unsigned long) frame; - - err |= __put_user(restorer, &frame->pretcode); - err |= __put_user(sig, &frame->sig); - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); - err |= copy_siginfo_to_user(&frame->info, info); - err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, - save_sp); - - /* - * This is movl $,%eax ; int $0x80 - * - * WE DO NOT USE IT ANY MORE! It's only left here for historical - * reasons and because gdb uses it as a signature to notice - * signal handler stack frames. - */ - err |= __put_user(0xb8, (char __user *)(frame->retcode+0)); - err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1)); - err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); - - if (err) - goto err; - - PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; - PT_REGS_EAX(regs) = (unsigned long) sig; - PT_REGS_EDX(regs) = (unsigned long) &frame->info; - PT_REGS_ECX(regs) = (unsigned long) &frame->uc; - - if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) - ptrace_notify(SIGTRAP); - return 0; - -err: - PT_REGS_SP(regs) = save_sp; - return err; -} - -long sys_sigreturn(struct pt_regs regs) -{ - unsigned long sp = PT_REGS_SP(¤t->thread.regs); - struct sigframe __user *frame = (struct sigframe __user *)(sp - 8); - sigset_t set; - struct sigcontext __user *sc = &frame->sc; - unsigned long __user *oldmask = &sc->oldmask; - unsigned long __user *extramask = frame->extramask; - int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); - - if (copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) || - copy_from_user(&set.sig[1], extramask, sig_size)) - goto segfault; - - sigdelsetmask(&set, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (copy_sc_from_user(¤t->thread.regs, sc)) - goto segfault; - - /* Avoid ERESTART handling */ - PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; - return PT_REGS_SYSCALL_RET(¤t->thread.regs); - - segfault: - force_sig(SIGSEGV, current); - return 0; -} - -long sys_rt_sigreturn(struct pt_regs regs) -{ - unsigned long sp = PT_REGS_SP(¤t->thread.regs); - struct rt_sigframe __user *frame = - (struct rt_sigframe __user *) (sp - 4); - sigset_t set; - struct ucontext __user *uc = &frame->uc; - int sig_size = _NSIG_WORDS * sizeof(unsigned long); - - if (copy_from_user(&set, &uc->uc_sigmask, sig_size)) - goto segfault; - - sigdelsetmask(&set, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) - goto segfault; - - /* Avoid ERESTART handling */ - PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; - return PT_REGS_SYSCALL_RET(¤t->thread.regs); - - segfault: - force_sig(SIGSEGV, current); - return 0; -} diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S deleted file mode 100644 index 7699e89f660..00000000000 --- a/arch/um/sys-i386/stub.S +++ /dev/null @@ -1,52 +0,0 @@ -#include "uml-config.h" -#include "as-layout.h" - - .globl syscall_stub -.section .__syscall_stub, "x" - - .globl batch_syscall_stub -batch_syscall_stub: - /* load pointer to first operation */ - mov $(STUB_DATA+8), %esp - -again: - /* load length of additional data */ - mov 0x0(%esp), %eax - - /* if(length == 0) : end of list */ - /* write possible 0 to header */ - mov %eax, STUB_DATA+4 - cmpl $0, %eax - jz done - - /* save current pointer */ - mov %esp, STUB_DATA+4 - - /* skip additional data */ - add %eax, %esp - - /* load syscall-# */ - pop %eax - - /* load syscall params */ - pop %ebx - pop %ecx - pop %edx - pop %esi - pop %edi - pop %ebp - - /* execute syscall */ - int $0x80 - - /* check return value */ - pop %ebx - cmp %ebx, %eax - je again - -done: - /* save return value */ - mov %eax, STUB_DATA - - /* stop */ - int3 diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c deleted file mode 100644 index 28ccf737a79..00000000000 --- a/arch/um/sys-i386/stub_segv.c +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include "sysdep/stub.h" -#include "sysdep/sigcontext.h" - -void __attribute__ ((__section__ (".__syscall_stub"))) -stub_segv_handler(int sig) -{ - struct sigcontext *sc = (struct sigcontext *) (&sig + 1); - - GET_FAULTINFO_FROM_SC(*((struct faultinfo *) STUB_DATA), sc); - - trap_myself(); -} diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S deleted file mode 100644 index 00e5f5203ee..00000000000 --- a/arch/um/sys-i386/sys_call_table.S +++ /dev/null @@ -1,17 +0,0 @@ -#include <linux/linkage.h> -/* Steal i386 syscall table for our purposes, but with some slight changes.*/ - -#define sys_iopl sys_ni_syscall -#define sys_ioperm sys_ni_syscall - -#define sys_vm86old sys_ni_syscall -#define sys_vm86 sys_ni_syscall - -#define old_mmap old_mmap_i386 - -.section .rodata,"a" - -#include "../../x86/kernel/syscall_table_32.S" - -ENTRY(syscall_table_size) -.long .-sys_call_table diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c deleted file mode 100644 index e2d14268441..00000000000 --- a/arch/um/sys-i386/syscalls.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "linux/shm.h" -#include "linux/ipc.h" -#include "asm/mman.h" -#include "asm/uaccess.h" -#include "asm/unistd.h" - -/* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux/i386 didn't use to be able to handle more than - * 4 system call parameters, so these system calls used a memory - * block for parameter passing.. - */ - -struct mmap_arg_struct { - unsigned long addr; - unsigned long len; - unsigned long prot; - unsigned long flags; - unsigned long fd; - unsigned long offset; -}; - -extern int old_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long offset); - -long old_mmap_i386(struct mmap_arg_struct __user *arg) -{ - struct mmap_arg_struct a; - int err = -EFAULT; - - if (copy_from_user(&a, arg, sizeof(a))) - goto out; - - err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); - out: - return err; -} - -struct sel_arg_struct { - unsigned long n; - fd_set __user *inp; - fd_set __user *outp; - fd_set __user *exp; - struct timeval __user *tvp; -}; - -long old_select(struct sel_arg_struct __user *arg) -{ - struct sel_arg_struct a; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - /* sys_select() does the appropriate kernel locking */ - return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); -} - -/* - * The prototype on i386 is: - * - * int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr) - * - * and the "newtls" arg. on i386 is read by copy_thread directly from the - * register saved on the stack. - */ -long sys_clone(unsigned long clone_flags, unsigned long newsp, - int __user *parent_tid, void *newtls, int __user *child_tid) -{ - long ret; - - if (!newsp) - newsp = UPT_SP(¤t->thread.regs.regs); - - current->thread.forking = 1; - ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, - child_tid); - current->thread.forking = 0; - return ret; -} - -/* - * sys_ipc() is the de-multiplexer for the SysV IPC calls.. - * - * This is really horribly ugly. - */ -long sys_ipc (uint call, int first, int second, - int third, void __user *ptr, long fifth) -{ - int version, ret; - - version = call >> 16; /* hack for backward compatibility */ - call &= 0xffff; - - switch (call) { - case SEMOP: - return sys_semtimedop(first, (struct sembuf __user *) ptr, - second, NULL); - case SEMTIMEDOP: - return sys_semtimedop(first, (struct sembuf __user *) ptr, - second, - (const struct timespec __user *) fifth); - case SEMGET: - return sys_semget (first, second, third); - case SEMCTL: { - union semun fourth; - if (!ptr) - return -EINVAL; - if (get_user(fourth.__pad, (void __user * __user *) ptr)) - return -EFAULT; - return sys_semctl (first, second, third, fourth); - } - - case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); - case MSGRCV: - switch (version) { - case 0: { - struct ipc_kludge tmp; - if (!ptr) - return -EINVAL; - - if (copy_from_user(&tmp, - (struct ipc_kludge *) ptr, - sizeof (tmp))) - return -EFAULT; - return sys_msgrcv (first, tmp.msgp, second, - tmp.msgtyp, third); - } - default: - panic("msgrcv with version != 0"); - return sys_msgrcv (first, - (struct msgbuf *) ptr, - second, fifth, third); - } - case MSGGET: - return sys_msgget ((key_t) first, second); - case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); - - case SHMAT: - switch (version) { - default: { - ulong raddr; - ret = do_shmat (first, (char *) ptr, second, &raddr); - if (ret) - return ret; - return put_user (raddr, (ulong *) third); - } - case 1: /* iBCS2 emulator entry point */ - if (!segment_eq(get_fs(), get_ds())) - return -EINVAL; - return do_shmat (first, (char *) ptr, second, (ulong *) third); - } - case SHMDT: - return sys_shmdt ((char *)ptr); - case SHMGET: - return sys_shmget (first, second, third); - case SHMCTL: - return sys_shmctl (first, second, - (struct shmid_ds *) ptr); - default: - return -ENOSYS; - } -} - -long sys_sigaction(int sig, const struct old_sigaction __user *act, - struct old_sigaction __user *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset_t mask; - if (!access_ok(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c deleted file mode 100644 index 171b3e9dc86..00000000000 --- a/arch/um/sys-i386/sysrq.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include "linux/kernel.h" -#include "linux/smp.h" -#include "linux/sched.h" -#include "linux/kallsyms.h" -#include "asm/ptrace.h" -#include "sysrq.h" - -/* This is declared by <linux/sched.h> */ -void show_regs(struct pt_regs *regs) -{ - printk("\n"); - printk("EIP: %04lx:[<%08lx>] CPU: %d %s", - 0xffff & PT_REGS_CS(regs), PT_REGS_IP(regs), - smp_processor_id(), print_tainted()); - if (PT_REGS_CS(regs) & 3) - printk(" ESP: %04lx:%08lx", 0xffff & PT_REGS_SS(regs), - PT_REGS_SP(regs)); - printk(" EFLAGS: %08lx\n %s\n", PT_REGS_EFLAGS(regs), - print_tainted()); - printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", - PT_REGS_EAX(regs), PT_REGS_EBX(regs), - PT_REGS_ECX(regs), - PT_REGS_EDX(regs)); - printk("ESI: %08lx EDI: %08lx EBP: %08lx", - PT_REGS_ESI(regs), PT_REGS_EDI(regs), - PT_REGS_EBP(regs)); - printk(" DS: %04lx ES: %04lx\n", - 0xffff & PT_REGS_DS(regs), - 0xffff & PT_REGS_ES(regs)); - - show_trace(NULL, (unsigned long *) ®s); -} - -/* Copied from i386. */ -static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) -{ - return p > (void *)tinfo && - p < (void *)tinfo + THREAD_SIZE - 3; -} - -/* Adapted from i386 (we also print the address we read from). */ -static inline unsigned long print_context_stack(struct thread_info *tinfo, - unsigned long *stack, unsigned long ebp) -{ - unsigned long addr; - -#ifdef CONFIG_FRAME_POINTER - while (valid_stack_ptr(tinfo, (void *)ebp)) { - addr = *(unsigned long *)(ebp + 4); - printk("%08lx: [<%08lx>]", ebp + 4, addr); - print_symbol(" %s", addr); - printk("\n"); - ebp = *(unsigned long *)ebp; - } -#else - while (valid_stack_ptr(tinfo, stack)) { - addr = *stack; - if (__kernel_text_address(addr)) { - printk("%08lx: [<%08lx>]", (unsigned long) stack, addr); - print_symbol(" %s", addr); - printk("\n"); - } - stack++; - } -#endif - return ebp; -} - -void show_trace(struct task_struct* task, unsigned long * stack) -{ - unsigned long ebp; - struct thread_info *context; - - /* Turn this into BUG_ON if possible. */ - if (!stack) { - stack = (unsigned long*) &stack; - printk("show_trace: got NULL stack, implicit assumption task == current"); - WARN_ON(1); - } - - if (!task) - task = current; - - if (task != current) { - ebp = (unsigned long) KSTK_EBP(task); - } else { - asm ("movl %%ebp, %0" : "=r" (ebp) : ); - } - - context = (struct thread_info *) - ((unsigned long)stack & (~(THREAD_SIZE - 1))); - print_context_stack(context, stack, ebp); - - printk("\n"); -} - diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c deleted file mode 100644 index c6c7131e563..00000000000 --- a/arch/um/sys-i386/tls.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> - * Licensed under the GPL - */ - -#include "linux/percpu.h" -#include "linux/sched.h" -#include "asm/uaccess.h" -#include "os.h" -#include "skas.h" -#include "sysdep/tls.h" - -/* - * If needed we can detect when it's uninitialized. - * - * These are initialized in an initcall and unchanged thereafter. - */ -static int host_supports_tls = -1; -int host_gdt_entry_tls_min; - -int do_set_thread_area(struct user_desc *info) -{ - int ret; - u32 cpu; - - cpu = get_cpu(); - ret = os_set_thread_area(info, userspace_pid[cpu]); - put_cpu(); - - if (ret) - printk(KERN_ERR "PTRACE_SET_THREAD_AREA failed, err = %d, " - "index = %d\n", ret, info->entry_number); - - return ret; -} - -int do_get_thread_area(struct user_desc *info) -{ - int ret; - u32 cpu; - - cpu = get_cpu(); - ret = os_get_thread_area(info, userspace_pid[cpu]); - put_cpu(); - - if (ret) - printk(KERN_ERR "PTRACE_GET_THREAD_AREA failed, err = %d, " - "index = %d\n", ret, info->entry_number); - - return ret; -} - -/* - * sys_get_thread_area: get a yet unused TLS descriptor index. - * XXX: Consider leaving one free slot for glibc usage at first place. This must - * be done here (and by changing GDT_ENTRY_TLS_* macros) and nowhere else. - * - * Also, this must be tested when compiling in SKAS mode with dynamic linking - * and running against NPTL. - */ -static int get_free_idx(struct task_struct* task) -{ - struct thread_struct *t = &task->thread; - int idx; - - if (!t->arch.tls_array) - return GDT_ENTRY_TLS_MIN; - - for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) - if (!t->arch.tls_array[idx].present) - return idx + GDT_ENTRY_TLS_MIN; - return -ESRCH; -} - -static inline void clear_user_desc(struct user_desc* info) -{ - /* Postcondition: LDT_empty(info) returns true. */ - memset(info, 0, sizeof(*info)); - - /* - * Check the LDT_empty or the i386 sys_get_thread_area code - we obtain - * indeed an empty user_desc. - */ - info->read_exec_only = 1; - info->seg_not_present = 1; -} - -#define O_FORCE 1 - -static int load_TLS(int flags, struct task_struct *to) -{ - int ret = 0; - int idx; - - for (idx = GDT_ENTRY_TLS_MIN; idx < GDT_ENTRY_TLS_MAX; idx++) { - struct uml_tls_struct* curr = - &to->thread.arch.tls_array[idx - GDT_ENTRY_TLS_MIN]; - - /* - * Actually, now if it wasn't flushed it gets cleared and - * flushed to the host, which will clear it. - */ - if (!curr->present) { - if (!curr->flushed) { - clear_user_desc(&curr->tls); - curr->tls.entry_number = idx; - } else { - WARN_ON(!LDT_empty(&curr->tls)); - continue; - } - } - - if (!(flags & O_FORCE) && curr->flushed) - continue; - - ret = do_set_thread_area(&curr->tls); - if (ret) - goto out; - - curr->flushed = 1; - } -out: - return ret; -} - -/* - * Verify if we need to do a flush for the new process, i.e. if there are any - * present desc's, only if they haven't been flushed. - */ -static inline int needs_TLS_update(struct task_struct *task) -{ - int i; - int ret = 0; - - for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { - struct uml_tls_struct* curr = - &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; - - /* - * Can't test curr->present, we may need to clear a descriptor - * which had a value. - */ - if (curr->flushed) - continue; - ret = 1; - break; - } - return ret; -} - -/* - * On a newly forked process, the TLS descriptors haven't yet been flushed. So - * we mark them as such and the first switch_to will do the job. - */ -void clear_flushed_tls(struct task_struct *task) -{ - int i; - - for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { - struct uml_tls_struct* curr = - &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; - - /* - * Still correct to do this, if it wasn't present on the host it - * will remain as flushed as it was. - */ - if (!curr->present) - continue; - - curr->flushed = 0; - } -} - -/* - * In SKAS0 mode, currently, multiple guest threads sharing the same ->mm have a - * common host process. So this is needed in SKAS0 too. - * - * However, if each thread had a different host process (and this was discussed - * for SMP support) this won't be needed. - * - * And this will not need be used when (and if) we'll add support to the host - * SKAS patch. - */ - -int arch_switch_tls(struct task_struct *to) -{ - if (!host_supports_tls) - return 0; - - /* - * We have no need whatsoever to switch TLS for kernel threads; beyond - * that, that would also result in us calling os_set_thread_area with - * userspace_pid[cpu] == 0, which gives an error. - */ - if (likely(to->mm)) - return load_TLS(O_FORCE, to); - - return 0; -} - -static int set_tls_entry(struct task_struct* task, struct user_desc *info, - int idx, int flushed) -{ - struct thread_struct *t = &task->thread; - - if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) - return -EINVAL; - - t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls = *info; - t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present = 1; - t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed = flushed; - - return 0; -} - -int arch_copy_tls(struct task_struct *new) -{ - struct user_desc info; - int idx, ret = -EFAULT; - - if (copy_from_user(&info, - (void __user *) UPT_ESI(&new->thread.regs.regs), - sizeof(info))) - goto out; - - ret = -EINVAL; - if (LDT_empty(&info)) - goto out; - - idx = info.entry_number; - - ret = set_tls_entry(new, &info, idx, 0); -out: - return ret; -} - -/* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */ -static int get_tls_entry(struct task_struct *task, struct user_desc *info, - int idx) -{ - struct thread_struct *t = &task->thread; - - if (!t->arch.tls_array) - goto clear; - - if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) - return -EINVAL; - - if (!t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present) - goto clear; - - *info = t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls; - -out: - /* - * Temporary debugging check, to make sure that things have been - * flushed. This could be triggered if load_TLS() failed. - */ - if (unlikely(task == current && - !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) { - printk(KERN_ERR "get_tls_entry: task with pid %d got here " - "without flushed TLS.", current->pid); - } - - return 0; -clear: - /* - * When the TLS entry has not been set, the values read to user in the - * tls_array are 0 (because it's cleared at boot, see - * arch/i386/kernel/head.S:cpu_gdt_table). Emulate that. - */ - clear_user_desc(info); - info->entry_number = idx; - goto out; -} - -int sys_set_thread_area(struct user_desc __user *user_desc) -{ - struct user_desc info; - int idx, ret; - - if (!host_supports_tls) - return -ENOSYS; - - if (copy_from_user(&info, user_desc, sizeof(info))) - return -EFAULT; - - idx = info.entry_number; - - if (idx == -1) { - idx = get_free_idx(current); - if (idx < 0) - return idx; - info.entry_number = idx; - /* Tell the user which slot we chose for him.*/ - if (put_user(idx, &user_desc->entry_number)) - return -EFAULT; - } - - ret = do_set_thread_area(&info); - if (ret) - return ret; - return set_tls_entry(current, &info, idx, 1); -} - -/* - * Perform set_thread_area on behalf of the traced child. - * Note: error handling is not done on the deferred load, and this differ from - * i386. However the only possible error are caused by bugs. - */ -int ptrace_set_thread_area(struct task_struct *child, int idx, - struct user_desc __user *user_desc) -{ - struct user_desc info; - - if (!host_supports_tls) - return -EIO; - - if (copy_from_user(&info, user_desc, sizeof(info))) - return -EFAULT; - - return set_tls_entry(child, &info, idx, 0); -} - -int sys_get_thread_area(struct user_desc __user *user_desc) -{ - struct user_desc info; - int idx, ret; - - if (!host_supports_tls) - return -ENOSYS; - - if (get_user(idx, &user_desc->entry_number)) - return -EFAULT; - - ret = get_tls_entry(current, &info, idx); - if (ret < 0) - goto out; - - if (copy_to_user(user_desc, &info, sizeof(info))) - ret = -EFAULT; - -out: - return ret; -} - -/* - * Perform get_thread_area on behalf of the traced child. - */ -int ptrace_get_thread_area(struct task_struct *child, int idx, - struct user_desc __user *user_desc) -{ - struct user_desc info; - int ret; - - if (!host_supports_tls) - return -EIO; - - ret = get_tls_entry(child, &info, idx); - if (ret < 0) - goto out; - - if (copy_to_user(user_desc, &info, sizeof(info))) - ret = -EFAULT; -out: - return ret; -} - -/* - * This code is really i386-only, but it detects and logs x86_64 GDT indexes - * if a 32-bit UML is running on a 64-bit host. - */ -static int __init __setup_host_supports_tls(void) -{ - check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min); - if (host_supports_tls) { - printk(KERN_INFO "Host TLS support detected\n"); - printk(KERN_INFO "Detected host type: "); - switch (host_gdt_entry_tls_min) { - case GDT_ENTRY_TLS_MIN_I386: - printk(KERN_CONT "i386"); - break; - case GDT_ENTRY_TLS_MIN_X86_64: - printk(KERN_CONT "x86_64"); - break; - } - printk(KERN_CONT " (GDT indexes %d to %d)\n", - host_gdt_entry_tls_min, - host_gdt_entry_tls_min + GDT_ENTRY_TLS_ENTRIES); - } else - printk(KERN_ERR " Host TLS support NOT detected! " - "TLS support inside UML will not work\n"); - return 0; -} - -__initcall(__setup_host_supports_tls); diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c deleted file mode 100644 index 39bd32bf84f..00000000000 --- a/arch/um/sys-i386/user-offsets.c +++ /dev/null @@ -1,53 +0,0 @@ -#include <stdio.h> -#include <stddef.h> -#include <signal.h> -#include <sys/poll.h> -#include <sys/user.h> -#include <sys/mman.h> -#include <asm/ptrace.h> - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define DEFINE_LONGS(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long))) - -#define OFFSET(sym, str, mem) \ - DEFINE(sym, offsetof(struct str, mem)); - -void foo(void) -{ - OFFSET(HOST_SC_TRAPNO, sigcontext, trapno); - OFFSET(HOST_SC_ERR, sigcontext, err); - OFFSET(HOST_SC_CR2, sigcontext, cr2); - - DEFINE_LONGS(HOST_FP_SIZE, sizeof(struct user_fpregs_struct)); - DEFINE_LONGS(HOST_XFP_SIZE, sizeof(struct user_fpxregs_struct)); - - DEFINE(HOST_IP, EIP); - DEFINE(HOST_SP, UESP); - DEFINE(HOST_EFLAGS, EFL); - DEFINE(HOST_EAX, EAX); - DEFINE(HOST_EBX, EBX); - DEFINE(HOST_ECX, ECX); - DEFINE(HOST_EDX, EDX); - DEFINE(HOST_ESI, ESI); - DEFINE(HOST_EDI, EDI); - DEFINE(HOST_EBP, EBP); - DEFINE(HOST_CS, CS); - DEFINE(HOST_SS, SS); - DEFINE(HOST_DS, DS); - DEFINE(HOST_FS, FS); - DEFINE(HOST_ES, ES); - DEFINE(HOST_GS, GS); - DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); - - /* XXX Duplicated between i386 and x86_64 */ - DEFINE(UM_POLLIN, POLLIN); - DEFINE(UM_POLLPRI, POLLPRI); - DEFINE(UM_POLLOUT, POLLOUT); - - DEFINE(UM_PROT_READ, PROT_READ); - DEFINE(UM_PROT_WRITE, PROT_WRITE); - DEFINE(UM_PROT_EXEC, PROT_EXEC); -} diff --git a/arch/um/sys-ia64/sysdep/ptrace.h b/arch/um/sys-ia64/sysdep/ptrace.h new file mode 100644 index 00000000000..0f0f4e6fd33 --- /dev/null +++ b/arch/um/sys-ia64/sysdep/ptrace.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_IA64_PTRACE_H +#define __SYSDEP_IA64_PTRACE_H + +struct sys_pt_regs { + int foo; +}; + +#define EMPTY_REGS { 0 } + +#endif + diff --git a/arch/um/sys-ia64/sysdep/sigcontext.h b/arch/um/sys-ia64/sysdep/sigcontext.h new file mode 100644 index 00000000000..76b43161e77 --- /dev/null +++ b/arch/um/sys-ia64/sysdep/sigcontext.h @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_IA64_SIGCONTEXT_H +#define __SYSDEP_IA64_SIGCONTEXT_H + +#endif + diff --git a/arch/um/include/sysdep-ia64/skas_ptrace.h b/arch/um/sys-ia64/sysdep/skas_ptrace.h index 25a38e71570..25a38e71570 100644 --- a/arch/um/include/sysdep-ia64/skas_ptrace.h +++ b/arch/um/sys-ia64/sysdep/skas_ptrace.h diff --git a/arch/um/sys-ia64/sysdep/syscalls.h b/arch/um/sys-ia64/sysdep/syscalls.h new file mode 100644 index 00000000000..5f6700c4155 --- /dev/null +++ b/arch/um/sys-ia64/sysdep/syscalls.h @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_IA64_SYSCALLS_H +#define __SYSDEP_IA64_SYSCALLS_H + +#endif + diff --git a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile index 08901526e89..20d363bd700 100644 --- a/arch/um/sys-ppc/Makefile +++ b/arch/um/sys-ppc/Makefile @@ -3,10 +3,10 @@ OBJ = built-in.o .S.o: $(CC) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o -OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \ +OBJS = ptrace.o sigcontext.o checksum.o miscthings.o misc.o \ ptrace_user.o sysrq.o -EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(srctree)/arch/ppc/kernel +asflags-y := -DCONFIG_PPC32 -I. -I$(srctree)/arch/ppc/kernel all: $(OBJ) @@ -15,14 +15,10 @@ $(OBJ): $(OBJS) $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ ptrace_user.o: ptrace_user.c - $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< + $(CC) -D__KERNEL__ $(USER_CFLAGS) $(ccflags-y) -c -o $@ $< sigcontext.o: sigcontext.c - $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< - -semaphore.c: - rm -f $@ - ln -s $(srctree)/arch/ppc/kernel/$@ $@ + $(CC) $(USER_CFLAGS) $(ccflags-y) -c -o $@ $< checksum.S: rm -f $@ @@ -57,13 +53,13 @@ ppc_defs.h: mk_defs.c ppc_defs.head \ checksum.o: checksum.S rm -f asm ln -s $(srctree)/include/asm-ppc asm - $(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o + $(CC) $(asflags-y) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o rm -f asm misc.o: misc.S ppc_defs.h rm -f asm ln -s $(srctree)/include/asm-ppc asm - $(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o + $(CC) $(asflags-y) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o rm -f asm -clean-files := $(OBJS) ppc_defs.h checksum.S semaphore.c mk_defs.c +clean-files := $(OBJS) ppc_defs.h checksum.S mk_defs.c diff --git a/arch/um/sys-ppc/asm/archparam.h b/arch/um/sys-ppc/asm/archparam.h new file mode 100644 index 00000000000..4269d8a37b4 --- /dev/null +++ b/arch/um/sys-ppc/asm/archparam.h @@ -0,0 +1,8 @@ +#ifndef __UM_ARCHPARAM_PPC_H +#define __UM_ARCHPARAM_PPC_H + +/********* Bits for asm-um/string.h **********/ + +#define __HAVE_ARCH_STRRCHR + +#endif diff --git a/arch/um/sys-ppc/asm/elf.h b/arch/um/sys-ppc/asm/elf.h new file mode 100644 index 00000000000..8aacaf56508 --- /dev/null +++ b/arch/um/sys-ppc/asm/elf.h @@ -0,0 +1,51 @@ +#ifndef __UM_ELF_PPC_H +#define __UM_ELF_PPC_H + + +extern long elf_aux_hwcap; +#define ELF_HWCAP (elf_aux_hwcap) + +#define SET_PERSONALITY(ex) do ; while(0) + +#define ELF_EXEC_PAGESIZE 4096 + +#define elf_check_arch(x) (1) + +#ifdef CONFIG_64BIT +#define ELF_CLASS ELFCLASS64 +#else +#define ELF_CLASS ELFCLASS32 +#endif + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + +#define ELF_PLATFORM (0) + +#define ELF_ET_DYN_BASE (0x08000000) + +/* the following stolen from asm-ppc/elf.h */ +#define ELF_NGREG 48 /* includes nip, msr, lr, etc. */ +#define ELF_NFPREG 33 /* includes fpscr */ +/* General registers */ +typedef unsigned long elf_greg_t; +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +/* Floating point registers */ +typedef double elf_fpreg_t; +typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_PPC + +#endif diff --git a/arch/um/sys-ppc/asm/processor.h b/arch/um/sys-ppc/asm/processor.h new file mode 100644 index 00000000000..95932315122 --- /dev/null +++ b/arch/um/sys-ppc/asm/processor.h @@ -0,0 +1,15 @@ +#ifndef __UM_PROCESSOR_PPC_H +#define __UM_PROCESSOR_PPC_H + +#if defined(__ASSEMBLY__) + +#define CONFIG_PPC_MULTIPLATFORM +#include "arch/processor.h" + +#else + +#include "asm/processor-generic.h" + +#endif + +#endif diff --git a/arch/um/sys-ppc/miscthings.c b/arch/um/sys-ppc/miscthings.c index 373061c5012..25908d26ce0 100644 --- a/arch/um/sys-ppc/miscthings.c +++ b/arch/um/sys-ppc/miscthings.c @@ -1,6 +1,6 @@ -#include "linux/threads.h" -#include "linux/stddef.h" // for NULL -#include "linux/elf.h" // for AT_NULL +#include <linux/threads.h> +#include <linux/stddef.h> // for NULL +#include <linux/elf.h> // for AT_NULL /* The following function nicked from arch/ppc/kernel/process.c and * adapted slightly */ @@ -40,14 +40,3 @@ void shove_aux_table(unsigned long sp) } /* END stuff taken from arch/ppc/kernel/process.c */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-ppc/ptrace.c b/arch/um/sys-ppc/ptrace.c index 8e71b47f2b8..8245df41b20 100644 --- a/arch/um/sys-ppc/ptrace.c +++ b/arch/um/sys-ppc/ptrace.c @@ -1,4 +1,4 @@ -#include "linux/sched.h" +#include <linux/sched.h> #include "asm/ptrace.h" int putreg(struct task_struct *child, unsigned long regno, @@ -56,13 +56,3 @@ int peek_user(struct task_struct *child, long addr, long data) return put_user(tmp, (unsigned long *) data); } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-ppc/ptrace_user.c b/arch/um/sys-ppc/ptrace_user.c index ff0b9c077a1..4601b9296aa 100644 --- a/arch/um/sys-ppc/ptrace_user.c +++ b/arch/um/sys-ppc/ptrace_user.c @@ -1,6 +1,6 @@ #include <errno.h> #include <asm/ptrace.h> -#include "sysdep/ptrace.h" +#include <sysdep/ptrace.h> int ptrace_getregs(long pid, unsigned long *regs_out) { @@ -27,13 +27,3 @@ int ptrace_setregs(long pid, unsigned long *regs_in) } return 0; } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-ppc/ptrace.h b/arch/um/sys-ppc/shared/sysdep/ptrace.h index df2397dba3e..efe0c1a3ea9 100644 --- a/arch/um/include/sysdep-ppc/ptrace.h +++ b/arch/um/sys-ppc/shared/sysdep/ptrace.h @@ -5,7 +5,7 @@ #ifndef __SYS_PTRACE_PPC_H #define __SYS_PTRACE_PPC_H -#include "linux/types.h" +#include <linux/types.h> /* the following taken from <asm-ppc/ptrace.h> */ @@ -91,13 +91,3 @@ extern void shove_aux_table(unsigned long sp); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-ppc/sigcontext.h b/arch/um/sys-ppc/shared/sysdep/sigcontext.h index f20d965de9c..b7286f0a1e0 100644 --- a/arch/um/include/sysdep-ppc/sigcontext.h +++ b/arch/um/sys-ppc/shared/sysdep/sigcontext.h @@ -50,13 +50,3 @@ #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/sysdep-ppc/skas_ptrace.h b/arch/um/sys-ppc/shared/sysdep/skas_ptrace.h index d9fbbac10de..d9fbbac10de 100644 --- a/arch/um/include/sysdep-ppc/skas_ptrace.h +++ b/arch/um/sys-ppc/shared/sysdep/skas_ptrace.h diff --git a/arch/um/include/sysdep-ppc/syscalls.h b/arch/um/sys-ppc/shared/sysdep/syscalls.h index 679df351e19..1ff81552251 100644 --- a/arch/um/include/sysdep-ppc/syscalls.h +++ b/arch/um/sys-ppc/shared/sysdep/syscalls.h @@ -41,13 +41,3 @@ int old_mmap(unsigned long addr, unsigned long len, #define LAST_ARCH_SYSCALL __NR_fadvise64 -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-ppc/sigcontext.c b/arch/um/sys-ppc/sigcontext.c index 4bdc15c89ed..aac6c83fe44 100644 --- a/arch/um/sys-ppc/sigcontext.c +++ b/arch/um/sys-ppc/sigcontext.c @@ -1,14 +1,4 @@ #include "asm/ptrace.h" #include "asm/sigcontext.h" -#include "sysdep/ptrace.h" +#include <sysdep/ptrace.h> -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-ppc/sysrq.c b/arch/um/sys-ppc/sysrq.c index 2f816f1a0ff..1ff1ad7f27d 100644 --- a/arch/um/sys-ppc/sysrq.c +++ b/arch/um/sys-ppc/sysrq.c @@ -3,14 +3,16 @@ * Licensed under the GPL */ -#include "linux/kernel.h" -#include "linux/smp.h" +#include <linux/kernel.h> +#include <linux/smp.h> #include "asm/ptrace.h" #include "sysrq.h" void show_regs(struct pt_regs_subarch *regs) { printk("\n"); + show_regs_print_info(KERN_DEFAULT); + printk("show_regs(): insert regs here.\n"); #if 0 printk("\n"); diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile deleted file mode 100644 index 3c22de53208..00000000000 --- a/arch/um/sys-x86_64/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright 2003 PathScale, Inc. -# -# Licensed under the GPL -# - -obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ - setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \ - sysrq.o ksyms.o tls.o - -obj-$(CONFIG_MODULES) += um_module.o - -subarch-obj-y = lib/bitops_64.o lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o -subarch-obj-$(CONFIG_MODULES) += kernel/module_64.o - -ldt-y = ../sys-i386/ldt.o - -USER_OBJS := ptrace_user.o - -USER_OBJS += user-offsets.s -extra-y += user-offsets.s - -UNPROFILE_OBJS := stub_segv.o -CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING) - -include arch/um/scripts/Makefile.rules diff --git a/arch/um/sys-x86_64/bug.c b/arch/um/sys-x86_64/bug.c deleted file mode 100644 index e8034e363d8..00000000000 --- a/arch/um/sys-x86_64/bug.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL V2 - */ - -#include <linux/uaccess.h> - -/* - * Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because - * that's not relevant in skas mode. - */ - -int is_valid_bugaddr(unsigned long eip) -{ - unsigned short ud2; - - if (probe_kernel_address((unsigned short __user *)eip, ud2)) - return 0; - - return ud2 == 0x0b0f; -} diff --git a/arch/um/sys-x86_64/bugs.c b/arch/um/sys-x86_64/bugs.c deleted file mode 100644 index 44e02ba2a26..00000000000 --- a/arch/um/sys-x86_64/bugs.c +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include "sysdep/ptrace.h" - -void arch_check_bugs(void) -{ -} - -void arch_examine_signal(int sig, struct uml_pt_regs *regs) -{ -} diff --git a/arch/um/sys-x86_64/delay.c b/arch/um/sys-x86_64/delay.c deleted file mode 100644 index dee5be66da8..00000000000 --- a/arch/um/sys-x86_64/delay.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * Copied from arch/x86_64 - * - * Licensed under the GPL - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <asm/processor.h> -#include <asm/param.h> - -void __delay(unsigned long loops) -{ - unsigned long i; - - for(i = 0; i < loops; i++) - cpu_relax(); -} - -void __udelay(unsigned long usecs) -{ - unsigned long i, n; - - n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) - cpu_relax(); -} - -EXPORT_SYMBOL(__udelay); diff --git a/arch/um/sys-x86_64/fault.c b/arch/um/sys-x86_64/fault.c deleted file mode 100644 index ce85117fc64..00000000000 --- a/arch/um/sys-x86_64/fault.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include "sysdep/ptrace.h" - -/* These two are from asm-um/uaccess.h and linux/module.h, check them. */ -struct exception_table_entry -{ - unsigned long insn; - unsigned long fixup; -}; - -const struct exception_table_entry *search_exception_tables(unsigned long add); - -int arch_fixup(unsigned long address, struct uml_pt_regs *regs) -{ - const struct exception_table_entry *fixup; - - fixup = search_exception_tables(address); - if (fixup != 0) { - UPT_IP(regs) = fixup->fixup; - return 1; - } - return 0; -} diff --git a/arch/um/sys-x86_64/ksyms.c b/arch/um/sys-x86_64/ksyms.c deleted file mode 100644 index 12c593607c5..00000000000 --- a/arch/um/sys-x86_64/ksyms.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "linux/module.h" -#include "linux/in6.h" -#include "linux/rwsem.h" -#include "asm/byteorder.h" -#include "asm/semaphore.h" -#include "asm/uaccess.h" -#include "asm/checksum.h" -#include "asm/errno.h" - -EXPORT_SYMBOL(__down_failed); -EXPORT_SYMBOL(__down_failed_interruptible); -EXPORT_SYMBOL(__down_failed_trylock); -EXPORT_SYMBOL(__up_wakeup); - -/*XXX: we need them because they would be exported by x86_64 */ -EXPORT_SYMBOL(__memcpy); diff --git a/arch/um/sys-x86_64/mem.c b/arch/um/sys-x86_64/mem.c deleted file mode 100644 index 3f59a0a4f15..00000000000 --- a/arch/um/sys-x86_64/mem.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include "linux/mm.h" -#include "asm/page.h" -#include "asm/mman.h" - -unsigned long vm_stack_flags = __VM_STACK_FLAGS; -unsigned long vm_stack_flags32 = __VM_STACK_FLAGS; -unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS; -unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS; -unsigned long vm_force_exec32 = PROT_EXEC; - -/* Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c deleted file mode 100644 index f3458d7d1c5..00000000000 --- a/arch/um/sys-x86_64/ptrace.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * - * Licensed under the GPL - */ - -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/errno.h> -#define __FRAME_OFFSETS -#include <asm/ptrace.h> -#include <asm/uaccess.h> - -/* - * determines which flags the user has access to. - * 1 = access 0 = no access - */ -#define FLAG_MASK 0x44dd5UL - -int putreg(struct task_struct *child, int regno, unsigned long value) -{ - unsigned long tmp; - -#ifdef TIF_IA32 - /* - * Some code in the 64bit emulation may not be 64bit clean. - * Don't take any chances. - */ - if (test_tsk_thread_flag(child, TIF_IA32)) - value &= 0xffffffff; -#endif - switch (regno) { - case FS: - case GS: - case DS: - case ES: - case SS: - case CS: - if (value && (value & 3) != 3) - return -EIO; - value &= 0xffff; - break; - - case FS_BASE: - case GS_BASE: - if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) - return -EIO; - break; - - case EFLAGS: - value &= FLAG_MASK; - tmp = PT_REGS_EFLAGS(&child->thread.regs) & ~FLAG_MASK; - value |= tmp; - break; - } - - PT_REGS_SET(&child->thread.regs, regno, value); - return 0; -} - -int poke_user(struct task_struct *child, long addr, long data) -{ - if ((addr & 3) || addr < 0) - return -EIO; - - if (addr < MAX_REG_OFFSET) - return putreg(child, addr, data); - else if ((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))) { - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - if ((addr == 4) || (addr == 5)) - return -EIO; - child->thread.arch.debugregs[addr] = data; - return 0; - } - return -EIO; -} - -unsigned long getreg(struct task_struct *child, int regno) -{ - unsigned long retval = ~0UL; - switch (regno) { - case FS: - case GS: - case DS: - case ES: - case SS: - case CS: - retval = 0xffff; - /* fall through */ - default: - retval &= PT_REG(&child->thread.regs, regno); -#ifdef TIF_IA32 - if (test_tsk_thread_flag(child, TIF_IA32)) - retval &= 0xffffffff; -#endif - } - return retval; -} - -int peek_user(struct task_struct *child, long addr, long data) -{ - /* read the word at location addr in the USER area. */ - unsigned long tmp; - - if ((addr & 3) || addr < 0) - return -EIO; - - tmp = 0; /* Default return condition */ - if (addr < MAX_REG_OFFSET) - tmp = getreg(child, addr); - else if ((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))) { - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - tmp = child->thread.arch.debugregs[addr]; - } - return put_user(tmp, (unsigned long *) data); -} - -/* XXX Mostly copied from sys-i386 */ -int is_syscall(unsigned long addr) -{ - unsigned short instr; - int n; - - n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); - if (n) { - /* - * access_process_vm() grants access to vsyscall and stub, - * while copy_from_user doesn't. Maybe access_process_vm is - * slow, but that doesn't matter, since it will be called only - * in case of singlestepping, if copy_from_user failed. - */ - n = access_process_vm(current, addr, &instr, sizeof(instr), 0); - if (n != sizeof(instr)) { - printk("is_syscall : failed to read instruction from " - "0x%lx\n", addr); - return 1; - } - } - /* sysenter */ - return instr == 0x050f; -} - -int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) -{ - int err, n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_FP_SIZE]; - - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - err = save_fp_registers(userspace_pid[cpu], fpregs); - if (err) - return err; - - n = copy_to_user(buf, fpregs, sizeof(fpregs)); - if (n > 0) - return -EFAULT; - - return n; -} - -int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) -{ - int n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_FP_SIZE]; - - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - n = copy_from_user(fpregs, buf, sizeof(fpregs)); - if (n > 0) - return -EFAULT; - - return restore_fp_registers(userspace_pid[cpu], fpregs); -} - -long subarch_ptrace(struct task_struct *child, long request, long addr, - long data) -{ - int ret = -EIO; - - switch (request) { - case PTRACE_GETFPXREGS: /* Get the child FPU state. */ - ret = get_fpregs((struct user_i387_struct __user *) data, - child); - break; - case PTRACE_SETFPXREGS: /* Set the child FPU state. */ - ret = set_fpregs((struct user_i387_struct __user *) data, - child); - break; - } - - return ret; -} diff --git a/arch/um/sys-x86_64/ptrace_user.c b/arch/um/sys-x86_64/ptrace_user.c deleted file mode 100644 index c57a496d3f5..00000000000 --- a/arch/um/sys-x86_64/ptrace_user.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include <errno.h> -#include "ptrace_user.h" - -int ptrace_getregs(long pid, unsigned long *regs_out) -{ - if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) - return -errno; - return(0); -} - -int ptrace_setregs(long pid, unsigned long *regs_out) -{ - if (ptrace(PTRACE_SETREGS, pid, 0, regs_out) < 0) - return -errno; - return(0); -} diff --git a/arch/um/sys-x86_64/setjmp.S b/arch/um/sys-x86_64/setjmp.S deleted file mode 100644 index 45f547b4043..00000000000 --- a/arch/um/sys-x86_64/setjmp.S +++ /dev/null @@ -1,54 +0,0 @@ -# -# arch/x86_64/setjmp.S -# -# setjmp/longjmp for the x86-64 architecture -# - -# -# The jmp_buf is assumed to contain the following, in order: -# %rbx -# %rsp (post-return) -# %rbp -# %r12 -# %r13 -# %r14 -# %r15 -# <return address> -# - - .text - .align 4 - .globl setjmp - .type setjmp, @function -setjmp: - pop %rsi # Return address, and adjust the stack - xorl %eax,%eax # Return value - movq %rbx,(%rdi) - movq %rsp,8(%rdi) # Post-return %rsp! - push %rsi # Make the call/return stack happy - movq %rbp,16(%rdi) - movq %r12,24(%rdi) - movq %r13,32(%rdi) - movq %r14,40(%rdi) - movq %r15,48(%rdi) - movq %rsi,56(%rdi) # Return address - ret - - .size setjmp,.-setjmp - - .text - .align 4 - .globl longjmp - .type longjmp, @function -longjmp: - movl %esi,%eax # Return value (int) - movq (%rdi),%rbx - movq 8(%rdi),%rsp - movq 16(%rdi),%rbp - movq 24(%rdi),%r12 - movq 32(%rdi),%r13 - movq 40(%rdi),%r14 - movq 48(%rdi),%r15 - jmp *56(%rdi) - - .size longjmp,.-longjmp diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c deleted file mode 100644 index 1a899a7ed7a..00000000000 --- a/arch/um/sys-x86_64/signal.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2003 PathScale, Inc. - * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <linux/personality.h> -#include <linux/ptrace.h> -#include <asm/unistd.h> -#include <asm/uaccess.h> -#include <asm/ucontext.h> -#include "frame_kern.h" -#include "skas.h" - -void copy_sc(struct uml_pt_regs *regs, void *from) -{ - struct sigcontext *sc = from; - -#define GETREG(regs, regno, sc, regname) \ - (regs)->gp[(regno) / sizeof(unsigned long)] = (sc)->regname - - GETREG(regs, R8, sc, r8); - GETREG(regs, R9, sc, r9); - GETREG(regs, R10, sc, r10); - GETREG(regs, R11, sc, r11); - GETREG(regs, R12, sc, r12); - GETREG(regs, R13, sc, r13); - GETREG(regs, R14, sc, r14); - GETREG(regs, R15, sc, r15); - GETREG(regs, RDI, sc, di); - GETREG(regs, RSI, sc, si); - GETREG(regs, RBP, sc, bp); - GETREG(regs, RBX, sc, bx); - GETREG(regs, RDX, sc, dx); - GETREG(regs, RAX, sc, ax); - GETREG(regs, RCX, sc, cx); - GETREG(regs, RSP, sc, sp); - GETREG(regs, RIP, sc, ip); - GETREG(regs, EFLAGS, sc, flags); - GETREG(regs, CS, sc, cs); - -#undef GETREG -} - -static int copy_sc_from_user(struct pt_regs *regs, - struct sigcontext __user *from, - struct _fpstate __user *fpp) -{ - struct user_i387_struct fp; - int err = 0; - -#define GETREG(regs, regno, sc, regname) \ - __get_user((regs)->regs.gp[(regno) / sizeof(unsigned long)], \ - &(sc)->regname) - - err |= GETREG(regs, R8, from, r8); - err |= GETREG(regs, R9, from, r9); - err |= GETREG(regs, R10, from, r10); - err |= GETREG(regs, R11, from, r11); - err |= GETREG(regs, R12, from, r12); - err |= GETREG(regs, R13, from, r13); - err |= GETREG(regs, R14, from, r14); - err |= GETREG(regs, R15, from, r15); - err |= GETREG(regs, RDI, from, di); - err |= GETREG(regs, RSI, from, si); - err |= GETREG(regs, RBP, from, bp); - err |= GETREG(regs, RBX, from, bx); - err |= GETREG(regs, RDX, from, dx); - err |= GETREG(regs, RAX, from, ax); - err |= GETREG(regs, RCX, from, cx); - err |= GETREG(regs, RSP, from, sp); - err |= GETREG(regs, RIP, from, ip); - err |= GETREG(regs, EFLAGS, from, flags); - err |= GETREG(regs, CS, from, cs); - if (err) - return 1; - -#undef GETREG - - err = copy_from_user(&fp, fpp, sizeof(struct user_i387_struct)); - if (err) - return 1; - - err = restore_fp_registers(userspace_pid[current_thread_info()->cpu], - (unsigned long *) &fp); - if (err < 0) { - printk(KERN_ERR "copy_sc_from_user - " - "restore_fp_registers failed, errno = %d\n", - -err); - return 1; - } - - return 0; -} - -static int copy_sc_to_user(struct sigcontext __user *to, - struct _fpstate __user *to_fp, struct pt_regs *regs, - unsigned long mask, unsigned long sp) -{ - struct faultinfo * fi = ¤t->thread.arch.faultinfo; - struct user_i387_struct fp; - int err = 0; - - err |= __put_user(0, &to->gs); - err |= __put_user(0, &to->fs); - -#define PUTREG(regs, regno, sc, regname) \ - __put_user((regs)->regs.gp[(regno) / sizeof(unsigned long)], \ - &(sc)->regname) - - err |= PUTREG(regs, RDI, to, di); - err |= PUTREG(regs, RSI, to, si); - err |= PUTREG(regs, RBP, to, bp); - /* - * Must use original RSP, which is passed in, rather than what's in - * the pt_regs, because that's already been updated to point at the - * signal frame. - */ - err |= __put_user(sp, &to->sp); - err |= PUTREG(regs, RBX, to, bx); - err |= PUTREG(regs, RDX, to, dx); - err |= PUTREG(regs, RCX, to, cx); - err |= PUTREG(regs, RAX, to, ax); - err |= PUTREG(regs, R8, to, r8); - err |= PUTREG(regs, R9, to, r9); - err |= PUTREG(regs, R10, to, r10); - err |= PUTREG(regs, R11, to, r11); - err |= PUTREG(regs, R12, to, r12); - err |= PUTREG(regs, R13, to, r13); - err |= PUTREG(regs, R14, to, r14); - err |= PUTREG(regs, R15, to, r15); - err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */ - - err |= __put_user(fi->cr2, &to->cr2); - err |= __put_user(fi->error_code, &to->err); - err |= __put_user(fi->trap_no, &to->trapno); - - err |= PUTREG(regs, RIP, to, ip); - err |= PUTREG(regs, EFLAGS, to, flags); -#undef PUTREG - - err |= __put_user(mask, &to->oldmask); - if (err) - return 1; - - err = save_fp_registers(userspace_pid[current_thread_info()->cpu], - (unsigned long *) &fp); - if (err < 0) { - printk(KERN_ERR "copy_sc_from_user - restore_fp_registers " - "failed, errno = %d\n", -err); - return 1; - } - - if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct))) - return 1; - - return err; -} - -struct rt_sigframe -{ - char __user *pretcode; - struct ucontext uc; - struct siginfo info; - struct _fpstate fpstate; -}; - -#define round_down(m, n) (((m) / (n)) * (n)) - -int setup_signal_stack_si(unsigned long stack_top, int sig, - struct k_sigaction *ka, struct pt_regs * regs, - siginfo_t *info, sigset_t *set) -{ - struct rt_sigframe __user *frame; - unsigned long save_sp = PT_REGS_RSP(regs); - int err = 0; - struct task_struct *me = current; - - frame = (struct rt_sigframe __user *) - round_down(stack_top - sizeof(struct rt_sigframe), 16); - /* Subtract 128 for a red zone and 8 for proper alignment */ - frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto out; - - if (ka->sa.sa_flags & SA_SIGINFO) { - err |= copy_siginfo_to_user(&frame->info, info); - if (err) - goto out; - } - - /* - * Update SP now because the page fault handler refuses to extend - * the stack if the faulting address is too far below the current - * SP, which frame now certainly is. If there's an error, the original - * value is restored on the way out. - * When writing the sigcontext to the stack, we have to write the - * original value, so that's passed to copy_sc_to_user, which does - * the right thing with it. - */ - PT_REGS_RSP(regs) = (unsigned long) frame; - - /* Create the ucontext. */ - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(save_sp), - &frame->uc.uc_stack.ss_flags); - err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs, - set->sig[0], save_sp); - err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate); - if (sizeof(*set) == 16) { - __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); - __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); - } - else - err |= __copy_to_user(&frame->uc.uc_sigmask, set, - sizeof(*set)); - - /* - * Set up to return from userspace. If provided, use a stub - * already in userspace. - */ - /* x86-64 should always use SA_RESTORER. */ - if (ka->sa.sa_flags & SA_RESTORER) - err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); - else - /* could use a vstub here */ - goto restore_sp; - - if (err) - goto restore_sp; - - /* Set up registers for signal handler */ - { - struct exec_domain *ed = current_thread_info()->exec_domain; - if (unlikely(ed && ed->signal_invmap && sig < 32)) - sig = ed->signal_invmap[sig]; - } - - PT_REGS_RDI(regs) = sig; - /* In case the signal handler was declared without prototypes */ - PT_REGS_RAX(regs) = 0; - - /* - * This also works for non SA_SIGINFO handlers because they expect the - * next argument after the signal number on the stack. - */ - PT_REGS_RSI(regs) = (unsigned long) &frame->info; - PT_REGS_RDX(regs) = (unsigned long) &frame->uc; - PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; - out: - return err; - -restore_sp: - PT_REGS_RSP(regs) = save_sp; - return err; -} - -long sys_rt_sigreturn(struct pt_regs *regs) -{ - unsigned long sp = PT_REGS_SP(¤t->thread.regs); - struct rt_sigframe __user *frame = - (struct rt_sigframe __user *)(sp - 8); - struct ucontext __user *uc = &frame->uc; - sigset_t set; - - if (copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) - goto segfault; - - sigdelsetmask(&set, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext, - &frame->fpstate)) - goto segfault; - - /* Avoid ERESTART handling */ - PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; - return PT_REGS_SYSCALL_RET(¤t->thread.regs); - - segfault: - force_sig(SIGSEGV, current); - return 0; -} diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S deleted file mode 100644 index 56876876315..00000000000 --- a/arch/um/sys-x86_64/stub.S +++ /dev/null @@ -1,67 +0,0 @@ -#include "uml-config.h" -#include "as-layout.h" - - .globl syscall_stub -.section .__syscall_stub, "x" -syscall_stub: - syscall - /* We don't have 64-bit constants, so this constructs the address - * we need. - */ - movq $(STUB_DATA >> 32), %rbx - salq $32, %rbx - movq $(STUB_DATA & 0xffffffff), %rcx - or %rcx, %rbx - movq %rax, (%rbx) - int3 - - .globl batch_syscall_stub -batch_syscall_stub: - mov $(STUB_DATA >> 32), %rbx - sal $32, %rbx - mov $(STUB_DATA & 0xffffffff), %rax - or %rax, %rbx - /* load pointer to first operation */ - mov %rbx, %rsp - add $0x10, %rsp -again: - /* load length of additional data */ - mov 0x0(%rsp), %rax - - /* if(length == 0) : end of list */ - /* write possible 0 to header */ - mov %rax, 8(%rbx) - cmp $0, %rax - jz done - - /* save current pointer */ - mov %rsp, 8(%rbx) - - /* skip additional data */ - add %rax, %rsp - - /* load syscall-# */ - pop %rax - - /* load syscall params */ - pop %rdi - pop %rsi - pop %rdx - pop %r10 - pop %r8 - pop %r9 - - /* execute syscall */ - syscall - - /* check return value */ - pop %rcx - cmp %rcx, %rax - je again - -done: - /* save return value */ - mov %rax, (%rbx) - - /* stop */ - int3 diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c deleted file mode 100644 index ced051afc70..00000000000 --- a/arch/um/sys-x86_64/stub_segv.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <signal.h> -#include "as-layout.h" -#include "sysdep/stub.h" -#include "sysdep/faultinfo.h" -#include "sysdep/sigcontext.h" - -void __attribute__ ((__section__ (".__syscall_stub"))) -stub_segv_handler(int sig) -{ - struct ucontext *uc; - - __asm__ __volatile__("movq %%rdx, %0" : "=g" (uc) :); - GET_FAULTINFO_FROM_SC(*((struct faultinfo *) STUB_DATA), - &uc->uc_mcontext); - trap_myself(); -} - diff --git a/arch/um/sys-x86_64/syscall_table.c b/arch/um/sys-x86_64/syscall_table.c deleted file mode 100644 index c128eb89700..00000000000 --- a/arch/um/sys-x86_64/syscall_table.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c - * with some changes for UML. - */ - -#include <linux/linkage.h> -#include <linux/sys.h> -#include <linux/cache.h> -#include <kern_constants.h> - -#define __NO_STUBS - -/* - * Below you can see, in terms of #define's, the differences between the x86-64 - * and the UML syscall table. - */ - -/* Not going to be implemented by UML, since we have no hardware. */ -#define stub_iopl sys_ni_syscall -#define sys_ioperm sys_ni_syscall - -/* - * The UML TLS problem. Note that x86_64 does not implement this, so the below - * is needed only for the ia32 compatibility. - */ - -/* On UML we call it this way ("old" means it's not mmap2) */ -#define sys_mmap old_mmap -/* - * On x86-64 sys_uname is actually sys_newuname plus a compatibility trick. - * See arch/x86_64/kernel/sys_x86_64.c - */ -#define sys_uname sys_uname64 - -#define stub_clone sys_clone -#define stub_fork sys_fork -#define stub_vfork sys_vfork -#define stub_execve sys_execve -#define stub_rt_sigsuspend sys_rt_sigsuspend -#define stub_sigaltstack sys_sigaltstack -#define stub_rt_sigreturn sys_rt_sigreturn - -#define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ; -#undef _ASM_X86_64_UNISTD_H_ -#include <asm-x86/unistd_64.h> - -#undef __SYSCALL -#define __SYSCALL(nr, sym) [ nr ] = sym, -#undef _ASM_X86_64_UNISTD_H_ - -typedef void (*sys_call_ptr_t)(void); - -extern void sys_ni_syscall(void); - -/* - * We used to have a trick here which made sure that holes in the - * x86_64 table were filled in with sys_ni_syscall, but a comment in - * unistd_64.h says that holes aren't allowed, so the trick was - * removed. - * The trick looked like this - * [0 ... UM_NR_syscall_max] = &sys_ni_syscall - * before including unistd_64.h - the later initializations overwrote - * the sys_ni_syscall filler. - */ - -sys_call_ptr_t sys_call_table[] __cacheline_aligned = { -#include <asm-x86/unistd_64.h> -}; - -int syscall_table_size = sizeof(sys_call_table); diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c deleted file mode 100644 index f1199fd34d3..00000000000 --- a/arch/um/sys-x86_64/syscalls.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include "linux/linkage.h" -#include "linux/personality.h" -#include "linux/utsname.h" -#include "asm/prctl.h" /* XXX This should get the constants from libc */ -#include "asm/uaccess.h" -#include "os.h" - -asmlinkage long sys_uname64(struct new_utsname __user * name) -{ - int err; - - down_read(&uts_sem); - err = copy_to_user(name, utsname(), sizeof (*name)); - up_read(&uts_sem); - - if (personality(current->personality) == PER_LINUX32) - err |= copy_to_user(&name->machine, "i686", 5); - - return err ? -EFAULT : 0; -} - -long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr) -{ - unsigned long *ptr = addr, tmp; - long ret; - int pid = task->mm->context.id.u.pid; - - /* - * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to - * be safe), we need to call arch_prctl on the host because - * setting %fs may result in something else happening (like a - * GDT or thread.fs being set instead). So, we let the host - * fiddle the registers and thread struct and restore the - * registers afterwards. - * - * So, the saved registers are stored to the process (this - * needed because a stub may have been the last thing to run), - * arch_prctl is run on the host, then the registers are read - * back. - */ - switch (code) { - case ARCH_SET_FS: - case ARCH_SET_GS: - ret = restore_registers(pid, ¤t->thread.regs.regs); - if (ret) - return ret; - break; - case ARCH_GET_FS: - case ARCH_GET_GS: - /* - * With these two, we read to a local pointer and - * put_user it to the userspace pointer that we were - * given. If addr isn't valid (because it hasn't been - * faulted in or is just bogus), we want put_user to - * fault it in (or return -EFAULT) instead of having - * the host return -EFAULT. - */ - ptr = &tmp; - } - - ret = os_arch_prctl(pid, code, ptr); - if (ret) - return ret; - - switch (code) { - case ARCH_SET_FS: - current->thread.arch.fs = (unsigned long) ptr; - ret = save_registers(pid, ¤t->thread.regs.regs); - break; - case ARCH_SET_GS: - ret = save_registers(pid, ¤t->thread.regs.regs); - break; - case ARCH_GET_FS: - ret = put_user(tmp, addr); - break; - case ARCH_GET_GS: - ret = put_user(tmp, addr); - break; - } - - return ret; -} - -long sys_arch_prctl(int code, unsigned long addr) -{ - return arch_prctl(current, code, (unsigned long __user *) addr); -} - -long sys_clone(unsigned long clone_flags, unsigned long newsp, - void __user *parent_tid, void __user *child_tid) -{ - long ret; - - if (!newsp) - newsp = UPT_SP(¤t->thread.regs.regs); - current->thread.forking = 1; - ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, - child_tid); - current->thread.forking = 0; - return ret; -} - -void arch_switch_to(struct task_struct *to) -{ - if ((to->thread.arch.fs == 0) || (to->mm == NULL)) - return; - - arch_prctl(to, ARCH_SET_FS, (void __user *) to->thread.arch.fs); -} diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c deleted file mode 100644 index f4f82beb350..00000000000 --- a/arch/um/sys-x86_64/sysrq.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2003 PathScale, Inc. - * - * Licensed under the GPL - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/utsname.h> -#include <asm/current.h> -#include <asm/ptrace.h> -#include "sysrq.h" - -void __show_regs(struct pt_regs *regs) -{ - printk("\n"); - print_modules(); - printk(KERN_INFO "Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current), - current->comm, print_tainted(), init_utsname()->release); - printk(KERN_INFO "RIP: %04lx:[<%016lx>]\n", PT_REGS_CS(regs) & 0xffff, - PT_REGS_RIP(regs)); - printk(KERN_INFO "RSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs), - PT_REGS_EFLAGS(regs)); - printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n", - PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs)); - printk(KERN_INFO "RDX: %016lx RSI: %016lx RDI: %016lx\n", - PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs)); - printk(KERN_INFO "RBP: %016lx R08: %016lx R09: %016lx\n", - PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs)); - printk(KERN_INFO "R10: %016lx R11: %016lx R12: %016lx\n", - PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs)); - printk(KERN_INFO "R13: %016lx R14: %016lx R15: %016lx\n", - PT_REGS_R13(regs), PT_REGS_R14(regs), PT_REGS_R15(regs)); -} - -void show_regs(struct pt_regs *regs) -{ - __show_regs(regs); - show_trace(current, (unsigned long *) ®s); -} diff --git a/arch/um/sys-x86_64/tls.c b/arch/um/sys-x86_64/tls.c deleted file mode 100644 index f7ba46200ec..00000000000 --- a/arch/um/sys-x86_64/tls.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "linux/sched.h" - -void clear_flushed_tls(struct task_struct *task) -{ -} - -int arch_copy_tls(struct task_struct *t) -{ - /* - * If CLONE_SETTLS is set, we need to save the thread id - * (which is argument 5, child_tid, of clone) so it can be set - * during context switches. - */ - t->thread.arch.fs = t->thread.regs.regs.gp[R8 / sizeof(long)]; - - return 0; -} diff --git a/arch/um/sys-x86_64/um_module.c b/arch/um/sys-x86_64/um_module.c deleted file mode 100644 index 3dead392a41..00000000000 --- a/arch/um/sys-x86_64/um_module.c +++ /dev/null @@ -1,21 +0,0 @@ -#include <linux/vmalloc.h> -#include <linux/moduleloader.h> - -/* Copied from i386 arch/i386/kernel/module.c */ -void *module_alloc(unsigned long size) -{ - if (size == 0) - return NULL; - return vmalloc_exec(size); -} - -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) -{ - vfree(module_region); - /* - * FIXME: If module_region == mod->init_region, trim exception - * table entries. - */ -} - diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c deleted file mode 100644 index 2f3443c6e85..00000000000 --- a/arch/um/sys-x86_64/user-offsets.c +++ /dev/null @@ -1,66 +0,0 @@ -#include <stdio.h> -#include <stddef.h> -#include <signal.h> -#include <sys/poll.h> -#include <sys/mman.h> -#include <sys/user.h> -#define __FRAME_OFFSETS -#include <asm/ptrace.h> -#include <asm/types.h> - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define DEFINE_LONGS(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long))) - -#define OFFSET(sym, str, mem) \ - DEFINE(sym, offsetof(struct str, mem)); - -void foo(void) -{ - OFFSET(HOST_SC_CR2, sigcontext, cr2); - OFFSET(HOST_SC_ERR, sigcontext, err); - OFFSET(HOST_SC_TRAPNO, sigcontext, trapno); - - DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long)); - DEFINE(HOST_XFP_SIZE, 0); - DEFINE_LONGS(HOST_RBX, RBX); - DEFINE_LONGS(HOST_RCX, RCX); - DEFINE_LONGS(HOST_RDI, RDI); - DEFINE_LONGS(HOST_RSI, RSI); - DEFINE_LONGS(HOST_RDX, RDX); - DEFINE_LONGS(HOST_RBP, RBP); - DEFINE_LONGS(HOST_RAX, RAX); - DEFINE_LONGS(HOST_R8, R8); - DEFINE_LONGS(HOST_R9, R9); - DEFINE_LONGS(HOST_R10, R10); - DEFINE_LONGS(HOST_R11, R11); - DEFINE_LONGS(HOST_R12, R12); - DEFINE_LONGS(HOST_R13, R13); - DEFINE_LONGS(HOST_R14, R14); - DEFINE_LONGS(HOST_R15, R15); - DEFINE_LONGS(HOST_ORIG_RAX, ORIG_RAX); - DEFINE_LONGS(HOST_CS, CS); - DEFINE_LONGS(HOST_SS, SS); - DEFINE_LONGS(HOST_EFLAGS, EFLAGS); -#if 0 - DEFINE_LONGS(HOST_FS, FS); - DEFINE_LONGS(HOST_GS, GS); - DEFINE_LONGS(HOST_DS, DS); - DEFINE_LONGS(HOST_ES, ES); -#endif - - DEFINE_LONGS(HOST_IP, RIP); - DEFINE_LONGS(HOST_SP, RSP); - DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); - - /* XXX Duplicated between i386 and x86_64 */ - DEFINE(UM_POLLIN, POLLIN); - DEFINE(UM_POLLPRI, POLLPRI); - DEFINE(UM_POLLOUT, POLLOUT); - - DEFINE(UM_PROT_READ, PROT_READ); - DEFINE(UM_PROT_WRITE, PROT_WRITE); - DEFINE(UM_PROT_EXEC, PROT_EXEC); -} |
