summaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/Kconfig43
-rw-r--r--arch/um/Kconfig.i3866
-rw-r--r--arch/um/Makefile28
-rw-r--r--arch/um/Makefile-x86_644
-rw-r--r--arch/um/drivers/chan_kern.c275
-rw-r--r--arch/um/drivers/daemon_kern.c4
-rw-r--r--arch/um/drivers/daemon_user.c6
-rw-r--r--arch/um/drivers/fd.c1
-rw-r--r--arch/um/drivers/line.c298
-rw-r--r--arch/um/drivers/mconsole_kern.c232
-rw-r--r--arch/um/drivers/mconsole_user.c12
-rw-r--r--arch/um/drivers/net_kern.c29
-rw-r--r--arch/um/drivers/ssl.c47
-rw-r--r--arch/um/drivers/stdio_console.c33
-rw-r--r--arch/um/drivers/ubd_kern.c96
-rw-r--r--arch/um/include/chan_kern.h25
-rw-r--r--arch/um/include/choose-mode.h3
-rw-r--r--arch/um/include/irq_user.h13
-rw-r--r--arch/um/include/kern.h13
-rw-r--r--arch/um/include/kern_util.h23
-rw-r--r--arch/um/include/line.h37
-rw-r--r--arch/um/include/longjmp.h19
-rw-r--r--arch/um/include/mconsole.h8
-rw-r--r--arch/um/include/mode_kern.h15
-rw-r--r--arch/um/include/os.h91
-rw-r--r--arch/um/include/signal_user.h28
-rw-r--r--arch/um/include/skas/mm_id.h (renamed from arch/um/kernel/skas/include/mm_id.h)0
-rw-r--r--arch/um/include/skas/mmu-skas.h24
-rw-r--r--arch/um/include/skas/mode-skas.h19
-rw-r--r--arch/um/include/skas/mode_kern_skas.h (renamed from arch/um/kernel/skas/include/mode_kern-skas.h)12
-rw-r--r--arch/um/include/skas/proc_mm.h (renamed from arch/um/kernel/skas/include/proc_mm.h)17
-rw-r--r--arch/um/include/skas/skas.h26
-rw-r--r--arch/um/include/skas/stub-data.h (renamed from arch/um/kernel/skas/include/stub-data.h)0
-rw-r--r--arch/um/include/skas/uaccess-skas.h (renamed from arch/um/kernel/skas/include/uaccess-skas.h)11
-rw-r--r--arch/um/include/sysdep-i386/checksum.h4
-rw-r--r--arch/um/include/sysdep-i386/kernel-offsets.h (renamed from arch/um/sys-i386/kernel-offsets.c)5
-rw-r--r--arch/um/include/sysdep-i386/stub.h29
-rw-r--r--arch/um/include/sysdep-x86_64/kernel-offsets.h (renamed from arch/um/sys-x86_64/kernel-offsets.c)2
-rw-r--r--arch/um/include/sysdep-x86_64/stub.h30
-rw-r--r--arch/um/include/time_user.h19
-rw-r--r--arch/um/include/tt/debug.h (renamed from arch/um/kernel/tt/include/debug.h)2
-rw-r--r--arch/um/include/tt/mmu-tt.h12
-rw-r--r--arch/um/include/tt/mode-tt.h23
-rw-r--r--arch/um/include/tt/mode_kern_tt.h41
-rw-r--r--arch/um/include/tt/tt.h (renamed from arch/um/kernel/tt/include/tt.h)12
-rw-r--r--arch/um/include/tt/uaccess-tt.h (renamed from arch/um/kernel/tt/include/uaccess-tt.h)11
-rw-r--r--arch/um/include/user.h1
-rw-r--r--arch/um/include/user_util.h29
-rw-r--r--arch/um/kernel/Makefile7
-rw-r--r--arch/um/kernel/asm-offsets.c2
-rw-r--r--arch/um/kernel/exec_kern.c1
-rw-r--r--arch/um/kernel/irq_user.c49
-rw-r--r--arch/um/kernel/process_kern.c29
-rw-r--r--arch/um/kernel/reboot.c2
-rw-r--r--arch/um/kernel/sigio_user.c85
-rw-r--r--arch/um/kernel/signal_kern.c92
-rw-r--r--arch/um/kernel/signal_user.c157
-rw-r--r--arch/um/kernel/skas/Makefile8
-rw-r--r--arch/um/kernel/skas/clone.c23
-rw-r--r--arch/um/kernel/skas/include/mmu-skas.h35
-rw-r--r--arch/um/kernel/skas/include/mode-skas.h33
-rw-r--r--arch/um/kernel/skas/include/skas.h50
-rw-r--r--arch/um/kernel/skas/mmu.c8
-rw-r--r--arch/um/kernel/skas/process.c16
-rw-r--r--arch/um/kernel/skas/process_kern.c40
-rw-r--r--arch/um/kernel/skas/uaccess.c2
-rw-r--r--arch/um/kernel/syscall.c4
-rw-r--r--arch/um/kernel/time.c9
-rw-r--r--arch/um/kernel/time_kern.c132
-rw-r--r--arch/um/kernel/trap_kern.c25
-rw-r--r--arch/um/kernel/trap_user.c98
-rw-r--r--arch/um/kernel/tt/exec_kern.c4
-rw-r--r--arch/um/kernel/tt/gdb.c1
-rw-r--r--arch/um/kernel/tt/include/mmu-tt.h23
-rw-r--r--arch/um/kernel/tt/process_kern.c10
-rw-r--r--arch/um/kernel/tt/ptproxy/ptrace.c1
-rw-r--r--arch/um/kernel/tt/ptproxy/sysdep.c1
-rw-r--r--arch/um/kernel/tt/tracer.c1
-rw-r--r--arch/um/kernel/tt/trap_user.c21
-rw-r--r--arch/um/kernel/um_arch.c15
-rw-r--r--arch/um/kernel/umid.c323
-rw-r--r--arch/um/os-Linux/Makefile8
-rw-r--r--arch/um/os-Linux/aio.c467
-rw-r--r--arch/um/os-Linux/helper.c4
-rw-r--r--arch/um/os-Linux/main.c14
-rw-r--r--arch/um/os-Linux/process.c31
-rw-r--r--arch/um/os-Linux/signal.c246
-rw-r--r--arch/um/os-Linux/skas/Makefile10
-rw-r--r--arch/um/os-Linux/skas/mem.c (renamed from arch/um/kernel/skas/mem_user.c)202
-rw-r--r--arch/um/os-Linux/skas/process.c566
-rw-r--r--arch/um/os-Linux/skas/trap.c (renamed from arch/um/kernel/skas/trap_user.c)49
-rw-r--r--arch/um/os-Linux/start_up.c24
-rw-r--r--arch/um/os-Linux/time.c131
-rw-r--r--arch/um/os-Linux/trap.c41
-rw-r--r--arch/um/os-Linux/tt.c64
-rw-r--r--arch/um/os-Linux/uaccess.c4
-rw-r--r--arch/um/os-Linux/umid.c335
-rw-r--r--arch/um/os-Linux/user_syms.c5
-rw-r--r--arch/um/os-Linux/util.c (renamed from arch/um/kernel/user_util.c)69
-rw-r--r--arch/um/scripts/Makefile.rules5
-rw-r--r--arch/um/sys-i386/Makefile8
-rw-r--r--arch/um/sys-i386/ldt.c26
-rw-r--r--arch/um/sys-i386/signal.c1
-rw-r--r--arch/um/sys-x86_64/Makefile5
104 files changed, 3101 insertions, 2239 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 563301fe5df..5982fe2753e 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -22,10 +22,6 @@ config SBUS
config PCI
bool
-config UID16
- bool
- default y
-
config GENERIC_CALIBRATE_DELAY
bool
default y
@@ -39,12 +35,12 @@ menu "UML-specific options"
config MODE_TT
bool "Tracing thread support"
- default y
+ default n
help
This option controls whether tracing thread support is compiled
- into UML. Normally, this should be set to Y. If you intend to
- use only skas mode (and the host has the skas patch applied to it),
- then it is OK to say N here.
+ into UML. This option is largely obsolete, given that skas0 provides
+ skas security and performance without needing to patch the host.
+ It is safe to say 'N' here.
config STATIC_LINK
bool "Force a static link"
@@ -83,7 +79,7 @@ config KERNEL_HALF_GIGS
of physical memory.
config MODE_SKAS
- bool "Separate Kernel Address Space support"
+ bool "Separate Kernel Address Space support" if MODE_TT
default y
help
This option controls whether skas (separate kernel address space)
@@ -147,6 +143,7 @@ config HOSTFS
config HPPFS
tristate "HoneyPot ProcFS (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
help
hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
entries to be overridden, removed, or fabricated from the host.
@@ -159,10 +156,6 @@ config HPPFS
You only need this if you are setting up a UML honeypot. Otherwise,
it is safe to say 'N' here.
- If you are actively using it, please report any problems, since it's
- getting fixed. In this moment, it is experimental on 2.6 (it works on
- 2.4).
-
config MCONSOLE
bool "Management console"
default y
@@ -247,8 +240,16 @@ config NEST_LEVEL
Only change this if you are running nested UMLs.
config HIGHMEM
- bool "Highmem support"
- depends on !64BIT
+ bool "Highmem support (EXPERIMENTAL)"
+ depends on !64BIT && EXPERIMENTAL
+ default n
+ help
+ This was used to allow UML to run with big amounts of memory.
+ Currently it is unstable, so if unsure say N.
+
+ To use big amounts of memory, it is recommended to disable TT mode (i.e.
+ CONFIG_MODE_TT) and enable static linking (i.e. CONFIG_STATIC_LINK) -
+ this should allow the guest to use up to 2.75G of memory.
config KERNEL_STACK_ORDER
int "Kernel stack size order"
@@ -273,22 +274,20 @@ endmenu
source "init/Kconfig"
-source "net/Kconfig"
-
-source "drivers/base/Kconfig"
+source "drivers/block/Kconfig"
source "arch/um/Kconfig.char"
-source "drivers/block/Kconfig"
+source "drivers/base/Kconfig"
-config NETDEVICES
- bool
- default NET
+source "net/Kconfig"
source "arch/um/Kconfig.net"
source "drivers/net/Kconfig"
+source "drivers/connector/Kconfig"
+
source "fs/Kconfig"
source "security/Kconfig"
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386
index c71b39a677a..ef79ed25aec 100644
--- a/arch/um/Kconfig.i386
+++ b/arch/um/Kconfig.i386
@@ -22,13 +22,17 @@ config TOP_ADDR
default 0x80000000 if HOST_2G_2G
config 3_LEVEL_PGTABLES
- bool "Three-level pagetables"
+ bool "Three-level pagetables (EXPERIMENTAL)"
default n
+ depends on EXPERIMENTAL
help
Three-level pagetables will let UML have more than 4G of physical
memory. All the memory that can't be mapped directly will be treated
as high memory.
+ However, this it experimental on 32-bit architectures, so if unsure say
+ N (on x86-64 it's automatically enabled, instead, as it's safe there).
+
config STUB_CODE
hex
default 0xbfffe000
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 1b12feeba36..6430a638385 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -32,7 +32,7 @@ um-modes-$(CONFIG_MODE_TT) += tt
um-modes-$(CONFIG_MODE_SKAS) += skas
MODE_INCLUDE += $(foreach mode,$(um-modes-y),\
- -I$(srctree)/$(ARCH_DIR)/kernel/$(mode)/include)
+ -I$(srctree)/$(ARCH_DIR)/include/$(mode))
MAKEFILES-INCL += $(foreach mode,$(um-modes-y),\
$(srctree)/$(ARCH_DIR)/Makefile-$(mode))
@@ -67,7 +67,8 @@ USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
# in CFLAGS. Otherwise, it would cause ld to complain about the two different
# errnos.
-CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask
+CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \
+ -Dmktime=kernel_mktime
CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
@@ -189,6 +190,12 @@ define filechk_umlconfig
sed 's/ CONFIG/ UML_CONFIG/'
endef
+$(ARCH_DIR)/include/uml-config.h : include/linux/autoconf.h
+ $(call filechk,umlconfig)
+
+$(ARCH_DIR)/user-offsets.s: $(ARCH_DIR)/sys-$(SUBARCH)/user-offsets.c
+ $(CC) $(USER_CFLAGS) -S -o $@ $<
+
define filechk_gen-asm-offsets
(set -e; \
echo "/*"; \
@@ -202,24 +209,13 @@ define filechk_gen-asm-offsets
echo ""; )
endef
-$(ARCH_DIR)/include/uml-config.h : include/linux/autoconf.h
- $(call filechk,umlconfig)
-
-$(ARCH_DIR)/user-offsets.s: $(ARCH_DIR)/sys-$(SUBARCH)/user-offsets.c
- $(CC) $(USER_CFLAGS) -S -o $@ $<
-
$(ARCH_DIR)/include/user_constants.h: $(ARCH_DIR)/user-offsets.s
$(call filechk,gen-asm-offsets)
CLEAN_FILES += $(ARCH_DIR)/user-offsets.s
-$(ARCH_DIR)/kernel-offsets.s: $(ARCH_DIR)/sys-$(SUBARCH)/kernel-offsets.c \
- archprepare
- $(CC) $(CFLAGS) $(NOSTDINC_FLAGS) $(CPPFLAGS) -S -o $@ $<
-
-$(ARCH_DIR)/include/kern_constants.h: $(ARCH_DIR)/kernel-offsets.s
- $(call filechk,gen-asm-offsets)
-
-CLEAN_FILES += $(ARCH_DIR)/kernel-offsets.s
+$(ARCH_DIR)/include/kern_constants.h:
+ @echo ' SYMLINK $@'
+ $(Q) ln -sf ../../../include/asm-um/asm-offsets.h $@
export SUBARCH USER_CFLAGS OS
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index 4f118d5cc2e..38df311e75d 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -12,3 +12,7 @@ CHECKFLAGS += -m64
ELF_ARCH := i386:x86-64
ELF_FORMAT := elf64-x86-64
+
+# Not on all 64-bit distros /lib is a symlink to /lib64. PLD is an example.
+
+LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib64
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 5b58fad4529..ab0d0b17081 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -58,7 +58,7 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts)
{
my_puts("Using a channel type which is configured out of "
"UML\n");
- return(NULL);
+ return NULL;
}
static int not_configged_open(int input, int output, int primary, void *data,
@@ -66,7 +66,7 @@ static int not_configged_open(int input, int output, int primary, void *data,
{
my_puts("Using a channel type which is configured out of "
"UML\n");
- return(-ENODEV);
+ return -ENODEV;
}
static void not_configged_close(int fd, void *data)
@@ -79,21 +79,21 @@ static int not_configged_read(int fd, char *c_out, void *data)
{
my_puts("Using a channel type which is configured out of "
"UML\n");
- return(-EIO);
+ return -EIO;
}
static int not_configged_write(int fd, const char *buf, int len, void *data)
{
my_puts("Using a channel type which is configured out of "
"UML\n");
- return(-EIO);
+ return -EIO;
}
static int not_configged_console_write(int fd, const char *buf, int len)
{
my_puts("Using a channel type which is configured out of "
"UML\n");
- return(-EIO);
+ return -EIO;
}
static int not_configged_window_size(int fd, void *data, unsigned short *rows,
@@ -101,7 +101,7 @@ static int not_configged_window_size(int fd, void *data, unsigned short *rows,
{
my_puts("Using a channel type which is configured out of "
"UML\n");
- return(-ENODEV);
+ return -ENODEV;
}
static void not_configged_free(void *data)
@@ -135,17 +135,17 @@ int generic_read(int fd, char *c_out, void *unused)
n = os_read_file(fd, c_out, sizeof(*c_out));
if(n == -EAGAIN)
- return(0);
+ return 0;
else if(n == 0)
- return(-EIO);
- return(n);
+ return -EIO;
+ return n;
}
/* XXX Trivial wrapper around os_write_file */
int generic_write(int fd, const char *buf, int n, void *unused)
{
- return(os_write_file(fd, buf, n));
+ return os_write_file(fd, buf, n);
}
int generic_window_size(int fd, void *unused, unsigned short *rows_out,
@@ -156,14 +156,14 @@ int generic_window_size(int fd, void *unused, unsigned short *rows_out,
ret = os_window_size(fd, &rows, &cols);
if(ret < 0)
- return(ret);
+ return ret;
ret = ((*rows_out != rows) || (*cols_out != cols));
*rows_out = rows;
*cols_out = cols;
- return(ret);
+ return ret;
}
void generic_free(void *data)
@@ -186,25 +186,26 @@ static void tty_receive_char(struct tty_struct *tty, char ch)
}
}
- if((tty->flip.flag_buf_ptr == NULL) ||
- (tty->flip.char_buf_ptr == NULL))
- return;
tty_insert_flip_char(tty, ch, TTY_NORMAL);
}
-static int open_one_chan(struct chan *chan, int input, int output, int primary)
+static int open_one_chan(struct chan *chan)
{
int fd;
- if(chan->opened) return(0);
- if(chan->ops->open == NULL) fd = 0;
- else fd = (*chan->ops->open)(input, output, primary, chan->data,
- &chan->dev);
- if(fd < 0) return(fd);
+ if(chan->opened)
+ return 0;
+
+ if(chan->ops->open == NULL)
+ fd = 0;
+ else fd = (*chan->ops->open)(chan->input, chan->output, chan->primary,
+ chan->data, &chan->dev);
+ if(fd < 0)
+ return fd;
chan->fd = fd;
chan->opened = 1;
- return(0);
+ return 0;
}
int open_chan(struct list_head *chans)
@@ -215,11 +216,11 @@ int open_chan(struct list_head *chans)
list_for_each(ele, chans){
chan = list_entry(ele, struct chan, list);
- ret = open_one_chan(chan, chan->input, chan->output,
- chan->primary);
- if(chan->primary) err = ret;
+ ret = open_one_chan(chan);
+ if(chan->primary)
+ err = ret;
}
- return(err);
+ return err;
}
void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
@@ -236,20 +237,65 @@ void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
}
}
-void enable_chan(struct list_head *chans, struct tty_struct *tty)
+void enable_chan(struct line *line)
{
struct list_head *ele;
struct chan *chan;
- list_for_each(ele, chans){
+ list_for_each(ele, &line->chan_list){
chan = list_entry(ele, struct chan, list);
- if(!chan->opened) continue;
+ if(open_one_chan(chan))
+ continue;
- line_setup_irq(chan->fd, chan->input, chan->output, tty);
+ if(chan->enabled)
+ continue;
+ line_setup_irq(chan->fd, chan->input, chan->output, line,
+ chan);
+ chan->enabled = 1;
}
}
-void close_chan(struct list_head *chans)
+static LIST_HEAD(irqs_to_free);
+
+void free_irqs(void)
+{
+ struct chan *chan;
+
+ while(!list_empty(&irqs_to_free)){
+ chan = list_entry(irqs_to_free.next, struct chan, free_list);
+ list_del(&chan->free_list);
+
+ if(chan->input)
+ free_irq(chan->line->driver->read_irq, chan);
+ if(chan->output)
+ free_irq(chan->line->driver->write_irq, chan);
+ chan->enabled = 0;
+ }
+}
+
+static void close_one_chan(struct chan *chan, int delay_free_irq)
+{
+ if(!chan->opened)
+ return;
+
+ if(delay_free_irq){
+ list_add(&chan->free_list, &irqs_to_free);
+ }
+ else {
+ if(chan->input)
+ free_irq(chan->line->driver->read_irq, chan);
+ if(chan->output)
+ free_irq(chan->line->driver->write_irq, chan);
+ chan->enabled = 0;
+ }
+ if(chan->ops->close != NULL)
+ (*chan->ops->close)(chan->fd, chan->data);
+
+ chan->opened = 0;
+ chan->fd = -1;
+}
+
+void close_chan(struct list_head *chans, int delay_free_irq)
{
struct chan *chan;
@@ -259,15 +305,37 @@ void close_chan(struct list_head *chans)
* so it must be the last closed.
*/
list_for_each_entry_reverse(chan, chans, list) {
- if(!chan->opened) continue;
- if(chan->ops->close != NULL)
- (*chan->ops->close)(chan->fd, chan->data);
- chan->opened = 0;
- chan->fd = -1;
+ close_one_chan(chan, delay_free_irq);
}
}
-int write_chan(struct list_head *chans, const char *buf, int len,
+void deactivate_chan(struct list_head *chans, int irq)
+{
+ struct list_head *ele;
+
+ struct chan *chan;
+ list_for_each(ele, chans) {
+ chan = list_entry(ele, struct chan, list);
+
+ if(chan->enabled && chan->input)
+ deactivate_fd(chan->fd, irq);
+ }
+}
+
+void reactivate_chan(struct list_head *chans, int irq)
+{
+ struct list_head *ele;
+ struct chan *chan;
+
+ list_for_each(ele, chans) {
+ chan = list_entry(ele, struct chan, list);
+
+ if(chan->enabled && chan->input)
+ reactivate_fd(chan->fd, irq);
+ }
+}
+
+int write_chan(struct list_head *chans, const char *buf, int len,
int write_irq)
{
struct list_head *ele;
@@ -285,7 +353,7 @@ int write_chan(struct list_head *chans, const char *buf, int len,
reactivate_fd(chan->fd, write_irq);
}
}
- return(ret);
+ return ret;
}
int console_write_chan(struct list_head *chans, const char *buf, int len)
@@ -301,19 +369,18 @@ int console_write_chan(struct list_head *chans, const char *buf, int len)
n = chan->ops->console_write(chan->fd, buf, len);
if(chan->primary) ret = n;
}
- return(ret);
+ return ret;
}
-int console_open_chan(struct line *line, struct console *co, struct chan_opts *opts)
+int console_open_chan(struct line *line, struct console *co,
+ struct chan_opts *opts)
{
- if (!list_empty(&line->chan_list))
- return 0;
+ int err;
+
+ err = open_chan(&line->chan_list);
+ if(err)
+ return err;
- if (0 != parse_chan_pair(line->init_str, &line->chan_list,
- line->init_pri, co->index, opts))
- return -1;
- if (0 != open_chan(&line->chan_list))
- return -1;
printk("Console initialized on /dev/%s%d\n",co->name,co->index);
return 0;
}
@@ -327,32 +394,36 @@ int chan_window_size(struct list_head *chans, unsigned short *rows_out,
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));
+ if(chan->ops->window_size == NULL)
+ return 0;
+ return chan->ops->window_size(chan->fd, chan->data,
+ rows_out, cols_out);
}
}
- return(0);
+ return 0;
}
-void free_one_chan(struct chan *chan)
+void free_one_chan(struct chan *chan, int delay_free_irq)
{
list_del(&chan->list);
+
+ close_one_chan(chan, delay_free_irq);
+
if(chan->ops->free != NULL)
(*chan->ops->free)(chan->data);
- free_irq_by_fd(chan->fd);
+
if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
kfree(chan);
}
-void free_chan(struct list_head *chans)
+void free_chan(struct list_head *chans, int delay_free_irq)
{
struct list_head *ele, *next;
struct chan *chan;
list_for_each_safe(ele, next, chans){
chan = list_entry(ele, struct chan, list);
- free_one_chan(chan);
+ free_one_chan(chan, delay_free_irq);
}
}
@@ -363,23 +434,23 @@ static int one_chan_config_string(struct chan *chan, char *str, int size,
if(chan == NULL){
CONFIG_CHUNK(str, size, n, "none", 1);
- return(n);
+ return n;
}
CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
if(chan->dev == NULL){
CONFIG_CHUNK(str, size, n, "", 1);
- return(n);
+ return n;
}
CONFIG_CHUNK(str, size, n, ":", 0);
CONFIG_CHUNK(str, size, n, chan->dev, 0);
- return(n);
+ return n;
}
-static int chan_pair_config_string(struct chan *in, struct chan *out,
+static int chan_pair_config_string(struct chan *in, struct chan *out,
char *str, int size, char **error_out)
{
int n;
@@ -390,7 +461,7 @@ static int chan_pair_config_string(struct chan *in, struct chan *out,
if(in == out){
CONFIG_CHUNK(str, size, n, "", 1);
- return(n);
+ return n;
}
CONFIG_CHUNK(str, size, n, ",", 1);
@@ -399,10 +470,10 @@ static int chan_pair_config_string(struct chan *in, struct chan *out,
size -= n;
CONFIG_CHUNK(str, size, n, "", 1);
- return(n);
+ return n;
}
-int chan_config_string(struct list_head *chans, char *str, int size,
+int chan_config_string(struct list_head *chans, char *str, int size,
char **error_out)
{
struct list_head *ele;
@@ -418,7 +489,7 @@ int chan_config_string(struct list_head *chans, char *str, int size,
out = chan;
}
- return(chan_pair_config_string(in, out, str, size, error_out));
+ return chan_pair_config_string(in, out, str, size, error_out);
}
struct chan_type {
@@ -462,7 +533,7 @@ struct chan_type chan_table[] = {
#endif
};
-static struct chan *parse_chan(char *str, int pri, int device,
+static struct chan *parse_chan(struct line *line, char *str, int device,
struct chan_opts *opts)
{
struct chan_type *entry;
@@ -484,36 +555,42 @@ static struct chan *parse_chan(char *str, int pri, int device,
if(ops == NULL){
my_printf("parse_chan couldn't parse \"%s\"\n",
str);
- return(NULL);
+ return NULL;
}
- if(ops->init == NULL) return(NULL);
+ if(ops->init == NULL)
+ return NULL;
data = (*ops->init)(str, device, opts);
- if(data == NULL) return(NULL);
+ if(data == NULL)
+ return NULL;
chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
- if(chan == NULL) return(NULL);
+ if(chan == NULL)
+ return NULL;
*chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
+ .free_list =
+ LIST_HEAD_INIT(chan->free_list),
+ .line = line,
.primary = 1,
.input = 0,
.output = 0,
.opened = 0,
+ .enabled = 0,
.fd = -1,
- .pri = pri,
.ops = ops,
.data = data });
- return(chan);
+ return chan;
}
-int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
+int parse_chan_pair(char *str, struct line *line, int device,
struct chan_opts *opts)
{
+ struct list_head *chans = &line->chan_list;
struct chan *new, *chan;
char *in, *out;
if(!list_empty(chans)){
chan = list_entry(chans->next, struct chan, list);
- if(chan->pri >= pri) return(0);
- free_chan(chans);
+ free_chan(chans, 0);
INIT_LIST_HEAD(chans);
}
@@ -522,24 +599,30 @@ int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
in = str;
*out = '\0';
out++;
- new = parse_chan(in, pri, device, opts);
- if(new == NULL) return(-1);
+ new = parse_chan(line, in, device, opts);
+ if(new == NULL)
+ return -1;
+
new->input = 1;
list_add(&new->list, chans);
- new = parse_chan(out, pri, device, opts);
- if(new == NULL) return(-1);
+ new = parse_chan(line, out, device, opts);
+ if(new == NULL)
+ return -1;
+
list_add(&new->list, chans);
new->output = 1;
}
else {
- new = parse_chan(str, pri, device, opts);
- if(new == NULL) return(-1);
+ new = parse_chan(line, str, device, opts);
+ if(new == NULL)
+ return -1;
+
list_add(&new->list, chans);
new->input = 1;
new->output = 1;
}
- return(0);
+ return 0;
}
int chan_out_fd(struct list_head *chans)
@@ -550,9 +633,9 @@ int chan_out_fd(struct list_head *chans)
list_for_each(ele, chans){
chan = list_entry(ele, struct chan, list);
if(chan->primary && chan->output)
- return(chan->fd);
+ return chan->fd;
}
- return(-1);
+ return -1;
}
void chan_interrupt(struct list_head *chans, struct work_struct *task,
@@ -567,9 +650,8 @@ void chan_interrupt(struct list_head *chans, struct work_struct *task,
chan = list_entry(ele, struct chan, list);
if(!chan->input || (chan->ops->read == NULL)) continue;
do {
- if((tty != NULL) &&
- (tty->flip.count >= TTY_FLIPBUF_SIZE)){
- schedule_work(task);
+ if (tty && !tty_buffer_request_room(tty, 1)) {
+ schedule_delayed_work(task, 1);
goto out;
}
err = chan->ops->read(chan->fd, &c, chan->data);
@@ -582,29 +664,12 @@ void chan_interrupt(struct list_head *chans, struct work_struct *task,
if(chan->primary){
if(tty != NULL)
tty_hangup(tty);
- line_disable(tty, irq);
- close_chan(chans);
- free_chan(chans);
+ close_chan(chans, 1);
return;
}
- else {
- if(chan->ops->close != NULL)
- chan->ops->close(chan->fd, chan->data);
- free_one_chan(chan);
- }
+ else close_one_chan(chan, 1);
}
}
out:
if(tty) tty_flip_buffer_push(tty);
}
-
-/*
- * 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/daemon_kern.c b/arch/um/drivers/daemon_kern.c
index 30d285b266a..507e3cbac9d 100644
--- a/arch/um/drivers/daemon_kern.c
+++ b/arch/um/drivers/daemon_kern.c
@@ -31,6 +31,10 @@ void daemon_init(struct net_device *dev, void *data)
dpri->fd = -1;
dpri->control = -1;
dpri->dev = dev;
+ /* We will free this pointer. If it contains crap we're burned. */
+ dpri->ctl_addr = NULL;
+ dpri->data_addr = NULL;
+ dpri->local_addr = NULL;
printk("daemon backend (uml_switch version %d) - %s:%s",
SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock);
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index 1bb085b2824..c944265955e 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -158,10 +158,16 @@ static void daemon_remove(void *data)
struct daemon_data *pri = data;
os_close_file(pri->fd);
+ pri->fd = -1;
os_close_file(pri->control);
+ pri->control = -1;
+
kfree(pri->data_addr);
+ pri->data_addr = NULL;
kfree(pri->ctl_addr);
+ pri->ctl_addr = NULL;
kfree(pri->local_addr);
+ pri->local_addr = NULL;
}
int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index 3296e86a03a..c41f75e4acb 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -11,6 +11,7 @@
#include "user.h"
#include "user_util.h"
#include "chan_user.h"
+#include "os.h"
struct fd_chan {
int fd;
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index e0fdffa2d54..46ceb25a995 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -23,8 +23,9 @@
static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused)
{
- struct tty_struct *tty = data;
- struct line *line = tty->driver_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);
@@ -33,10 +34,11 @@ static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused)
static void line_timer_cb(void *arg)
{
- struct tty_struct *tty = arg;
- struct line *line = tty->driver_data;
+ struct line *line = arg;
- line_interrupt(line->driver->read_irq, arg, NULL);
+ if(!line->throttled)
+ chan_interrupt(&line->chan_list, &line->task, line->tty,
+ line->driver->read_irq);
}
/* Returns the free space inside the ring buffer of this line.
@@ -124,7 +126,8 @@ static int buffer_data(struct line *line, const char *buf, int len)
if (len < end){
memcpy(line->tail, buf, len);
line->tail += len;
- } else {
+ }
+ else {
/* The circular buffer is wrapping */
memcpy(line->tail, buf, end);
buf += end;
@@ -170,7 +173,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_list, line->head, count,
line->driver->write_irq);
if(n < 0)
@@ -227,7 +230,7 @@ int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
if (err <= 0 && (err != -EAGAIN || !ret))
ret = err;
} else {
- n = write_chan(&line->chan_list, buf, len,
+ n = write_chan(&line->chan_list, buf, len,
line->driver->write_irq);
if (n < 0) {
ret = n;
@@ -338,11 +341,36 @@ int line_ioctl(struct tty_struct *tty, struct file * file,
return ret;
}
+void line_throttle(struct tty_struct *tty)
+{
+ struct line *line = tty->driver_data;
+
+ deactivate_chan(&line->chan_list, line->driver->read_irq);
+ line->throttled = 1;
+}
+
+void line_unthrottle(struct tty_struct *tty)
+{
+ struct line *line = tty->driver_data;
+
+ line->throttled = 0;
+ chan_interrupt(&line->chan_list, &line->task, tty,
+ line->driver->read_irq);
+
+ /* Maybe there is enough stuff pending that calling the interrupt
+ * throttles us again. In this case, line->throttled will be 1
+ * again and we shouldn't turn the interrupt back on.
+ */
+ if(!line->throttled)
+ reactivate_chan(&line->chan_list, line->driver->read_irq);
+}
+
static irqreturn_t line_write_interrupt(int irq, void *data,
struct pt_regs *unused)
{
- struct tty_struct *tty = data;
- struct line *line = tty->driver_data;
+ struct chan *chan = data;
+ struct line *line = chan->line;
+ struct tty_struct *tty = line->tty;
int err;
/* Interrupts are enabled here because we registered the interrupt with
@@ -364,7 +392,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data,
if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
(tty->ldisc.write_wakeup != NULL))
(tty->ldisc.write_wakeup)(tty);
-
+
/* BLOCKING mode
* In blocking mode, everything sleeps on tty->write_wait.
* Sleeping in the console driver would break non-blocking
@@ -376,53 +404,29 @@ static irqreturn_t line_write_interrupt(int irq, void *data,
return IRQ_HANDLED;
}
-int line_setup_irq(int fd, int input, int output, struct tty_struct *tty)
+int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
{
- struct line *line = tty->driver_data;
struct line_driver *driver = line->driver;
int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM;
if (input)
err = um_request_irq(driver->read_irq, fd, IRQ_READ,
- line_interrupt, flags,
- driver->read_irq_name, tty);
+ line_interrupt, flags,
+ driver->read_irq_name, data);
if (err)
return err;
if (output)
err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
- line_write_interrupt, flags,
- driver->write_irq_name, tty);
+ line_write_interrupt, flags,
+ driver->write_irq_name, data);
line->have_irq = 1;
return err;
}
-void line_disable(struct tty_struct *tty, int current_irq)
-{
- struct line *line = tty->driver_data;
-
- if(!line->have_irq)
- return;
-
- if(line->driver->read_irq == current_irq)
- free_irq_later(line->driver->read_irq, tty);
- else {
- free_irq(line->driver->read_irq, tty);
- }
-
- if(line->driver->write_irq == current_irq)
- free_irq_later(line->driver->write_irq, tty);
- else {
- free_irq(line->driver->write_irq, tty);
- }
-
- line->have_irq = 0;
-}
-
-int line_open(struct line *lines, struct tty_struct *tty,
- struct chan_opts *opts)
+int line_open(struct line *lines, struct tty_struct *tty)
{
struct line *line;
- int err = 0;
+ int err = -ENODEV;
line = &lines[tty->index];
tty->driver_data = line;
@@ -430,31 +434,29 @@ int line_open(struct line *lines, struct tty_struct *tty,
/* The IRQ which takes this lock is not yet enabled and won't be run
* before the end, so we don't need to use spin_lock_irq.*/
spin_lock(&line->lock);
- if (tty->count == 1) {
- if (!line->valid) {
- err = -ENODEV;
- goto out;
- }
- if (list_empty(&line->chan_list)) {
- err = parse_chan_pair(line->init_str, &line->chan_list,
- line->init_pri, tty->index, opts);
- if(err) goto out;
- err = open_chan(&line->chan_list);
- if(err) goto out;
+
+ tty->driver_data = line;
+ line->tty = tty;
+ if(!line->valid)
+ goto out;
+
+ if(tty->count == 1){
+ /* Here the device is opened, if necessary, and interrupt
+ * is registered.
+ */
+ enable_chan(line);
+ INIT_WORK(&line->task, line_timer_cb, line);
+
+ if(!line->sigio){
+ chan_enable_winch(&line->chan_list, tty);
+ line->sigio = 1;
}
- /* Here the interrupt is registered.*/
- enable_chan(&line->chan_list, tty);
- INIT_WORK(&line->task, line_timer_cb, tty);
- }
- if(!line->sigio){
- chan_enable_winch(&line->chan_list, tty);
- line->sigio = 1;
+ chan_window_size(&line->chan_list, &tty->winsize.ws_row,
+ &tty->winsize.ws_col);
}
- chan_window_size(&line->chan_list, &tty->winsize.ws_row,
- &tty->winsize.ws_col);
- line->count++;
+ err = 0;
out:
spin_unlock(&line->lock);
return err;
@@ -474,15 +476,14 @@ void line_close(struct tty_struct *tty, struct file * filp)
/* We ignore the error anyway! */
flush_buffer(line);
- line->count--;
- if (tty->count == 1) {
- line_disable(tty, -1);
+ if(tty->count == 1){
+ line->tty = NULL;
tty->driver_data = NULL;
- }
- if((line->count == 0) && line->sigio){
- unregister_winch(tty);
- line->sigio = 0;
+ if(line->sigio){
+ unregister_winch(tty);
+ line->sigio = 0;
+ }
}
spin_unlock_irq(&line->lock);
@@ -493,17 +494,15 @@ void close_lines(struct line *lines, int nlines)
int i;
for(i = 0; i < nlines; i++)
- close_chan(&lines[i].chan_list);
+ close_chan(&lines[i].chan_list, 0);
}
/* Common setup code for both startup command line and mconsole initialization.
* @lines contains the the array (of size @num) to modify;
* @init is the setup string;
- * @all_allowed is a boolean saying if we can setup the whole @lines
- * at once. For instance, it will be usually true for startup init. (where we
- * can use con=xterm) and false for mconsole.*/
+ */
-int line_setup(struct line *lines, unsigned int num, char *init, int all_allowed)
+int line_setup(struct line *lines, unsigned int num, char *init)
{
int i, n;
char *end;
@@ -512,10 +511,11 @@ int line_setup(struct line *lines, unsigned int num, char *init, int all_allowed
/* We said con=/ssl= instead of con#=, so we are configuring all
* consoles at once.*/
n = -1;
- } else {
+ }
+ else {
n = simple_strtoul(init, &end, 0);
if(*end != '='){
- printk(KERN_ERR "line_setup failed to parse \"%s\"\n",
+ printk(KERN_ERR "line_setup failed to parse \"%s\"\n",
init);
return 0;
}
@@ -527,8 +527,9 @@ int line_setup(struct line *lines, unsigned int num, char *init, int all_allowed
printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
n, num - 1);
return 0;
- } else if (n >= 0){
- if (lines[n].count > 0) {
+ }
+ else if (n >= 0){
+ if (lines[n].tty != NULL) {
printk("line_setup - device %d is open\n", n);
return 0;
}
@@ -539,13 +540,10 @@ int line_setup(struct line *lines, unsigned int num, char *init, int all_allowed
else {
lines[n].init_str = init;
lines[n].valid = 1;
- }
+ }
}
- } else if(!all_allowed){
- printk("line_setup - can't configure all devices from "
- "mconsole\n");
- return 0;
- } else {
+ }
+ else {
for(i = 0; i < num; i++){
if(lines[i].init_pri <= INIT_ALL){
lines[i].init_pri = INIT_ALL;
@@ -557,18 +555,33 @@ int line_setup(struct line *lines, unsigned int num, char *init, int all_allowed
}
}
}
- return 1;
+ return n == -1 ? num : n;
}
-int line_config(struct line *lines, unsigned int num, char *str)
+int line_config(struct line *lines, unsigned int num, char *str,
+ struct chan_opts *opts)
{
- char *new = uml_strdup(str);
+ struct line *line;
+ char *new;
+ int n;
+ if(*str == '='){
+ printk("line_config - can't configure all devices from "
+ "mconsole\n");
+ return 1;
+ }
+
+ new = kstrdup(str, GFP_KERNEL);
if(new == NULL){
- printk("line_config - uml_strdup failed\n");
- return -ENOMEM;
+ printk("line_config - kstrdup failed\n");
+ return 1;
}
- return !line_setup(lines, num, new, 0);
+ n = line_setup(lines, num, new);
+ if(n < 0)
+ return 1;
+
+ line = &lines[n];
+ return parse_chan_pair(line->init_str, line, n, opts);
}
int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
@@ -594,7 +607,7 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
spin_lock(&line->lock);
if(!line->valid)
CONFIG_CHUNK(str, size, n, "none", 1);
- else if(line->count == 0)
+ 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->lock);
@@ -619,14 +632,18 @@ int line_id(char **str, int *start_out, int *end_out)
int line_remove(struct line *lines, unsigned int num, int n)
{
+ int err;
char config[sizeof("conxxxx=none\0")];
sprintf(config, "%d=none", n);
- return !line_setup(lines, num, config, 0);
+ err = line_setup(lines, num, config);
+ if(err >= 0)
+ err = 0;
+ return err;
}
struct tty_driver *line_register_devfs(struct lines *set,
- struct line_driver *line_driver,
+ struct line_driver *line_driver,
struct tty_operations *ops, struct line *lines,
int nlines)
{
@@ -655,7 +672,7 @@ struct tty_driver *line_register_devfs(struct lines *set,
}
for(i = 0; i < nlines; i++){
- if(!lines[i].valid)
+ if(!lines[i].valid)
tty_unregister_device(driver, i);
}
@@ -663,24 +680,28 @@ struct tty_driver *line_register_devfs(struct lines *set,
return driver;
}
-static spinlock_t winch_handler_lock;
-LIST_HEAD(winch_handlers);
+static DEFINE_SPINLOCK(winch_handler_lock);
+static LIST_HEAD(winch_handlers);
-void lines_init(struct line *lines, int nlines)
+void lines_init(struct line *lines, int nlines, struct chan_opts *opts)
{
struct line *line;
int i;
- spin_lock_init(&winch_handler_lock);
for(i = 0; i < nlines; i++){
line = &lines[i];
INIT_LIST_HEAD(&line->chan_list);
- spin_lock_init(&line->lock);
- if(line->init_str != NULL){
- line->init_str = uml_strdup(line->init_str);
- if(line->init_str == NULL)
- printk("lines_init - uml_strdup returned "
- "NULL\n");
+
+ if(line->init_str == NULL)
+ continue;
+
+ line->init_str = kstrdup(line->init_str, GFP_KERNEL);
+ if(line->init_str == NULL)
+ printk("lines_init - kstrdup returned NULL\n");
+
+ if(parse_chan_pair(line->init_str, line, i, opts)){
+ printk("parse_chan_pair failed for device %d\n", i);
+ line->valid = 0;
}
}
}
@@ -717,8 +738,7 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
tty = winch->tty;
if (tty != NULL) {
line = tty->driver_data;
- chan_window_size(&line->chan_list,
- &tty->winsize.ws_row,
+ chan_window_size(&line->chan_list, &tty->winsize.ws_row,
&tty->winsize.ws_col);
kill_pg(tty->pgrp, SIGWINCH, 1);
}
@@ -749,60 +769,54 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
spin_unlock(&winch_handler_lock);
if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
- SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
+ SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
"winch", winch) < 0)
printk("register_winch_irq - failed to register IRQ\n");
}
+static void free_winch(struct winch *winch)
+{
+ list_del(&winch->list);
+
+ if(winch->pid != -1)
+ os_kill_process(winch->pid, 1);
+ if(winch->fd != -1)
+ os_close_file(winch->fd);
+
+ free_irq(WINCH_IRQ, winch);
+ kfree(winch);
+}
+
static void unregister_winch(struct tty_struct *tty)
{
struct list_head *ele;
- struct winch *winch, *found = NULL;
+ struct winch *winch;
spin_lock(&winch_handler_lock);
+
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->tty == tty){
- found = winch;
- break;
+ free_winch(winch);
+ break;
}
}
- if(found == NULL)
- goto err;
-
- list_del(&winch->list);
- spin_unlock(&winch_handler_lock);
-
- if(winch->pid != -1)
- os_kill_process(winch->pid, 1);
-
- free_irq(WINCH_IRQ, winch);
- kfree(winch);
-
- return;
-err:
spin_unlock(&winch_handler_lock);
}
-/* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup
- * order... are we sure that nothing else is done on the list? */
static void winch_cleanup(void)
{
- struct list_head *ele;
+ struct list_head *ele, *next;
struct winch *winch;
- list_for_each(ele, &winch_handlers){
+ spin_lock(&winch_handler_lock);
+
+ list_for_each_safe(ele, next, &winch_handlers){
winch = list_entry(ele, struct winch, list);
- if(winch->fd != -1){
- /* Why is this different from the above free_irq(),
- * which deactivates SIGIO? This searches the FD
- * somewhere else and removes it from the list... */
- deactivate_fd(winch->fd, WINCH_IRQ);
- os_close_file(winch->fd);
- }
- if(winch->pid != -1)
- os_kill_process(winch->pid, 1);
+ free_winch(winch);
}
+
+ spin_unlock(&winch_handler_lock);
}
__uml_exitcall(winch_cleanup);
@@ -811,10 +825,10 @@ char *add_xterm_umid(char *base)
char *umid, *title;
int len;
- umid = get_umid(1);
- if(umid == NULL)
+ umid = get_umid();
+ if(*umid == '\0')
return base;
-
+
len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
title = kmalloc(len, GFP_KERNEL);
if(title == NULL){
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 12c95368124..e3d57656717 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -20,6 +20,7 @@
#include "linux/namei.h"
#include "linux/proc_fs.h"
#include "linux/syscalls.h"
+#include "linux/console.h"
#include "asm/irq.h"
#include "asm/uaccess.h"
#include "user_util.h"
@@ -34,7 +35,7 @@
#include "irq_kern.h"
#include "choose-mode.h"
-static int do_unlink_socket(struct notifier_block *notifier,
+static int do_unlink_socket(struct notifier_block *notifier,
unsigned long what, void *data)
{
return(mconsole_unlink_socket());
@@ -46,12 +47,12 @@ static struct notifier_block reboot_notifier = {
.priority = 0,
};
-/* Safe without explicit locking for now. Tasklets provide their own
+/* Safe without explicit locking for now. Tasklets provide their own
* locking, and the interrupt handler is safe because it can't interrupt
* itself and it can only happen on CPU 0.
*/
-LIST_HEAD(mc_requests);
+static LIST_HEAD(mc_requests);
static void mc_work_proc(void *unused)
{
@@ -60,7 +61,7 @@ static void mc_work_proc(void *unused)
while(!list_empty(&mc_requests)){
local_save_flags(flags);
- req = list_entry(mc_requests.next, struct mconsole_entry,
+ req = list_entry(mc_requests.next, struct mconsole_entry,
list);
list_del(&req->list);
local_irq_restore(flags);
@@ -69,7 +70,7 @@ static void mc_work_proc(void *unused)
}
}
-DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
+static DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
static irqreturn_t mconsole_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
@@ -103,8 +104,8 @@ void mconsole_version(struct mc_request *req)
{
char version[256];
- sprintf(version, "%s %s %s %s %s", system_utsname.sysname,
- system_utsname.nodename, system_utsname.release,
+ sprintf(version, "%s %s %s %s %s", system_utsname.sysname,
+ system_utsname.nodename, system_utsname.release,
system_utsname.version, system_utsname.machine);
mconsole_reply(req, version, 0, 0);
}
@@ -348,7 +349,7 @@ static struct mc_device *mconsole_find_dev(char *name)
#define CONFIG_BUF_SIZE 64
-static void mconsole_get_config(int (*get_config)(char *, char *, int,
+static void mconsole_get_config(int (*get_config)(char *, char *, int,
char **),
struct mc_request *req, char *name)
{
@@ -389,7 +390,6 @@ static void mconsole_get_config(int (*get_config)(char *, char *, int,
out:
if(buf != default_buf)
kfree(buf);
-
}
void mconsole_config(struct mc_request *req)
@@ -420,9 +420,9 @@ void mconsole_config(struct mc_request *req)
void mconsole_remove(struct mc_request *req)
{
- struct mc_device *dev;
+ struct mc_device *dev;
char *ptr = req->request.data, *err_msg = "";
- char error[256];
+ char error[256];
int err, start, end, n;
ptr += strlen("remove");
@@ -433,37 +433,112 @@ void mconsole_remove(struct mc_request *req)
return;
}
- ptr = &ptr[strlen(dev->name)];
-
- err = 1;
- n = (*dev->id)(&ptr, &start, &end);
- if(n < 0){
- err_msg = "Couldn't parse device number";
- goto out;
- }
- else if((n < start) || (n > end)){
- sprintf(error, "Invalid device number - must be between "
- "%d and %d", start, end);
- err_msg = error;
- goto out;
- }
+ ptr = &ptr[strlen(dev->name)];
+
+ err = 1;
+ n = (*dev->id)(&ptr, &start, &end);
+ if(n < 0){
+ err_msg = "Couldn't parse device number";
+ goto out;
+ }
+ else if((n < start) || (n > end)){
+ sprintf(error, "Invalid device number - must be between "
+ "%d and %d", start, end);
+ err_msg = error;
+ goto out;
+ }
err = (*dev->remove)(n);
- switch(err){
- case -ENODEV:
- err_msg = "Device doesn't exist";
- break;
- case -EBUSY:
- err_msg = "Device is currently open";
- break;
- default:
- break;
- }
- out:
+ switch(err){
+ case -ENODEV:
+ err_msg = "Device doesn't exist";
+ break;
+ case -EBUSY:
+ err_msg = "Device is currently open";
+ break;
+ default:
+ break;
+ }
+out:
mconsole_reply(req, err_msg, err, 0);
}
+static DEFINE_SPINLOCK(console_lock);
+static LIST_HEAD(clients);
+static char console_buf[MCONSOLE_MAX_DATA];
+static int console_index = 0;
+
+static void console_write(struct console *console, const char *string,
+ unsigned len)
+{
+ struct list_head *ele;
+ int n;
+
+ if(list_empty(&clients))
+ return;
+
+ while(1){
+ n = min(len, ARRAY_SIZE(console_buf) - console_index);
+ strncpy(&console_buf[console_index], string, n);
+ console_index += n;
+ string += n;
+ len -= n;
+ if(len == 0)
+ return;
+
+ list_for_each(ele, &clients){
+ struct mconsole_entry *entry;
+
+ entry = list_entry(ele, struct mconsole_entry, list);
+ mconsole_reply_len(&entry->request, console_buf,
+ console_index, 0, 1);
+ }
+
+ console_index = 0;
+ }
+}
+
+static struct console mc_console = { .name = "mc",
+ .write = console_write,
+ .flags = CON_ENABLED,
+ .index = -1 };
+
+static int mc_add_console(void)
+{
+ register_console(&mc_console);
+ return 0;
+}
+
+late_initcall(mc_add_console);
+
+static void with_console(struct mc_request *req, void (*proc)(void *),
+ void *arg)
+{
+ struct mconsole_entry entry;
+ unsigned long flags;
+
+ INIT_LIST_HEAD(&entry.list);
+ entry.request = *req;
+ list_add(&entry.list, &clients);
+ spin_lock_irqsave(&console_lock, flags);
+
+ (*proc)(arg);
+
+ mconsole_reply_len(req, console_buf, console_index, 0, 0);
+ console_index = 0;
+
+ spin_unlock_irqrestore(&console_lock, flags);
+ list_del(&entry.list);
+}
+
#ifdef CONFIG_MAGIC_SYSRQ
+static void sysrq_proc(void *arg)
+{
+ char *op = arg;
+
+ handle_sysrq(*op, &current->thread.regs, NULL);
+}
+
void mconsole_sysrq(struct mc_request *req)
{
char *ptr = req->request.data;
@@ -471,8 +546,13 @@ void mconsole_sysrq(struct mc_request *req)
ptr += strlen("sysrq");
while(isspace(*ptr)) ptr++;
- mconsole_reply(req, "", 0, 0);
- handle_sysrq(*ptr, &current->thread.regs, NULL);
+ /* With 'b', the system will shut down without a chance to reply,
+ * so in this case, we reply first.
+ */
+ if(*ptr == 'b')
+ mconsole_reply(req, "", 0, 0);
+
+ with_console(req, sysrq_proc, ptr);
}
#else
void mconsole_sysrq(struct mc_request *req)
@@ -481,6 +561,14 @@ void mconsole_sysrq(struct mc_request *req)
}
#endif
+static void stack_proc(void *arg)
+{
+ struct task_struct *from = current, *to = arg;
+
+ to->thread.saved_task = from;
+ switch_to(from, to, from);
+}
+
/* Mconsole stack trace
* Added by Allan Graves, Jeff Dike
* Dumps a stacks registers to the linux console.
@@ -488,37 +576,34 @@ void mconsole_sysrq(struct mc_request *req)
*/
void do_stack(struct mc_request *req)
{
- char *ptr = req->request.data;
- int pid_requested= -1;
- struct task_struct *from = NULL;
+ char *ptr = req->request.data;
+ int pid_requested= -1;
+ struct task_struct *from = NULL;
struct task_struct *to = NULL;
- /* Would be nice:
- * 1) Send showregs output to mconsole.
+ /* Would be nice:
+ * 1) Send showregs output to mconsole.
* 2) Add a way to stack dump all pids.
*/
- ptr += strlen("stack");
- while(isspace(*ptr)) ptr++;
-
- /* Should really check for multiple pids or reject bad args here */
- /* What do the arguments in mconsole_reply mean? */
- if(sscanf(ptr, "%d", &pid_requested) == 0){
- mconsole_reply(req, "Please specify a pid", 1, 0);
- return;
- }
+ ptr += strlen("stack");
+ while(isspace(*ptr)) ptr++;
- from = current;
- to = find_task_by_pid(pid_requested);
+ /* Should really check for multiple pids or reject bad args here */
+ /* What do the arguments in mconsole_reply mean? */
+ if(sscanf(ptr, "%d", &pid_requested) == 0){
+ mconsole_reply(req, "Please specify a pid", 1, 0);
+ return;
+ }
- if((to == NULL) || (pid_requested == 0)) {
- mconsole_reply(req, "Couldn't find that pid", 1, 0);
- return;
- }
- to->thread.saved_task = current;
+ from = current;
- switch_to(from, to, from);
- mconsole_reply(req, "Stack Dumped to console and message log", 0, 0);
+ to = find_task_by_pid(pid_requested);
+ if((to == NULL) || (pid_requested == 0)) {
+ mconsole_reply(req, "Couldn't find that pid", 1, 0);
+ return;
+ }
+ with_console(req, stack_proc, to);
}
void mconsole_stack(struct mc_request *req)
@@ -534,9 +619,9 @@ void mconsole_stack(struct mc_request *req)
/* Changed by mconsole_setup, which is __setup, and called before SMP is
* active.
*/
-static char *notify_socket = NULL;
+static char *notify_socket = NULL;
-int mconsole_init(void)
+static int mconsole_init(void)
{
/* long to avoid size mismatch warnings from gcc */
long sock;
@@ -563,16 +648,16 @@ int mconsole_init(void)
}
if(notify_socket != NULL){
- notify_socket = uml_strdup(notify_socket);
+ notify_socket = kstrdup(notify_socket, GFP_KERNEL);
if(notify_socket != NULL)
mconsole_notify(notify_socket, MCONSOLE_SOCKET,
- mconsole_socket_name,
+ mconsole_socket_name,
strlen(mconsole_socket_name) + 1);
else printk(KERN_ERR "mconsole_setup failed to strdup "
"string\n");
}
- printk("mconsole (version %d) initialized on %s\n",
+ printk("mconsole (version %d) initialized on %s\n",
MCONSOLE_VERSION, mconsole_socket_name);
return(0);
}
@@ -585,7 +670,7 @@ static int write_proc_mconsole(struct file *file, const char __user *buffer,
char *buf;
buf = kmalloc(count + 1, GFP_KERNEL);
- if(buf == NULL)
+ if(buf == NULL)
return(-ENOMEM);
if(copy_from_user(buf, buffer, count)){
@@ -661,7 +746,7 @@ static int notify_panic(struct notifier_block *self, unsigned long unused1,
if(notify_socket == NULL) return(0);
- mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
+ mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
strlen(message) + 1);
return(0);
}
@@ -686,14 +771,3 @@ char *mconsole_notify_socket(void)
}
EXPORT_SYMBOL(mconsole_notify_socket);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
index 310c1f823f2..4b109fe7fff 100644
--- a/arch/um/drivers/mconsole_user.c
+++ b/arch/um/drivers/mconsole_user.c
@@ -122,12 +122,12 @@ int mconsole_get_request(int fd, struct mc_request *req)
return(1);
}
-int mconsole_reply(struct mc_request *req, char *str, int err, int more)
+int mconsole_reply_len(struct mc_request *req, const char *str, int total,
+ int err, int more)
{
struct mconsole_reply reply;
- int total, len, n;
+ int len, n;
- total = strlen(str);
do {
reply.err = err;
@@ -155,6 +155,12 @@ int mconsole_reply(struct mc_request *req, char *str, int err, int more)
return(0);
}
+int mconsole_reply(struct mc_request *req, const char *str, int err, int more)
+{
+ return mconsole_reply_len(req, str, strlen(str), err, more);
+}
+
+
int mconsole_unlink_socket(void)
{
unlink(mconsole_socket_name);
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 84c73a300ac..8ebb2241ad4 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -34,7 +34,7 @@
#define DRIVER_NAME "uml-netdev"
static DEFINE_SPINLOCK(opened_lock);
-LIST_HEAD(opened);
+static LIST_HEAD(opened);
static int uml_net_rx(struct net_device *dev)
{
@@ -68,6 +68,11 @@ static int uml_net_rx(struct net_device *dev)
return pkt_len;
}
+static void uml_dev_close(void* dev)
+{
+ dev_close( (struct net_device *) dev);
+}
+
irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
@@ -80,15 +85,21 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_lock(&lp->lock);
while((err = uml_net_rx(dev)) > 0) ;
if(err < 0) {
+ DECLARE_WORK(close_work, uml_dev_close, dev);
printk(KERN_ERR
"Device '%s' read returned %d, shutting it down\n",
dev->name, err);
- dev_close(dev);
+ /* dev_close can't be called in interrupt context, and takes
+ * again lp->lock.
+ * And dev_close() can be safely called multiple times on the
+ * same device, since it tests for (dev->flags & IFF_UP). So
+ * there's no harm in delaying the device shutdown. */
+ schedule_work(&close_work);
goto out;
}
reactivate_fd(lp->fd, UM_ETH_IRQ);
- out:
+out:
spin_unlock(&lp->lock);
return(IRQ_HANDLED);
}
@@ -150,6 +161,7 @@ static int uml_net_close(struct net_device *dev)
if(lp->close != NULL)
(*lp->close)(lp->fd, &lp->user);
lp->fd = -1;
+ list_del(&lp->list);
spin_unlock(&lp->lock);
return 0;
@@ -266,7 +278,7 @@ void uml_net_user_timer_expire(unsigned long _conn)
}
static DEFINE_SPINLOCK(devices_lock);
-static struct list_head devices = LIST_HEAD_INIT(devices);
+static LIST_HEAD(devices);
static struct platform_driver uml_net_driver = {
.driver = {
@@ -316,6 +328,11 @@ static int eth_configure(int n, void *init, char *mac,
return 1;
}
+ lp = dev->priv;
+ /* This points to the transport private data. It's still clear, but we
+ * must memset it to 0 *now*. Let's help the drivers. */
+ memset(lp, 0, size);
+
/* sysfs register */
if (!driver_registered) {
platform_driver_register(&uml_net_driver);
@@ -357,7 +374,6 @@ static int eth_configure(int n, void *init, char *mac,
free_netdev(dev);
return 1;
}
- lp = dev->priv;
/* lp.user is the first four bytes of the transport data, which
* has already been initialized. This structure assignment will
@@ -586,7 +602,7 @@ static int net_config(char *str)
err = eth_parse(str, &n, &str);
if(err) return(err);
- str = uml_strdup(str);
+ str = kstrdup(str, GFP_KERNEL);
if(str == NULL){
printk(KERN_ERR "net_config failed to strdup string\n");
return(-1);
@@ -715,6 +731,7 @@ static void close_devices(void)
list_for_each(ele, &opened){
lp = list_entry(ele, struct uml_net_private, list);
+ free_irq(lp->dev->irq, lp->dev);
if((lp->close != NULL) && (lp->fd >= 0))
(*lp->close)(lp->fd, &lp->user);
if(lp->remove != NULL) (*lp->remove)(&lp->user);
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index 62e04ecfada..a32ef55cb24 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -69,7 +69,7 @@ static struct line_driver driver = {
.name = "ssl",
.config = ssl_config,
.get_config = ssl_get_config,
- .id = line_id,
+ .id = line_id,
.remove = ssl_remove,
},
};
@@ -84,26 +84,23 @@ static struct lines lines = LINES_INIT(NR_PORTS);
static int ssl_config(char *str)
{
- return(line_config(serial_lines,
- sizeof(serial_lines)/sizeof(serial_lines[0]), str));
+ return line_config(serial_lines, ARRAY_SIZE(serial_lines), str, &opts);
}
static int ssl_get_config(char *dev, char *str, int size, char **error_out)
{
- return(line_get_config(dev, serial_lines,
- sizeof(serial_lines)/sizeof(serial_lines[0]),
- str, size, error_out));
+ return line_get_config(dev, serial_lines, ARRAY_SIZE(serial_lines), str,
+ size, error_out);
}
static int ssl_remove(int n)
{
- return line_remove(serial_lines,
- sizeof(serial_lines)/sizeof(serial_lines[0]), n);
+ return line_remove(serial_lines, ARRAY_SIZE(serial_lines), n);
}
int ssl_open(struct tty_struct *tty, struct file *filp)
{
- return line_open(serial_lines, tty, &opts);
+ return line_open(serial_lines, tty);
}
#if 0
@@ -112,16 +109,6 @@ static void ssl_flush_buffer(struct tty_struct *tty)
return;
}
-static void ssl_throttle(struct tty_struct * tty)
-{
- printk(KERN_ERR "Someone should implement ssl_throttle\n");
-}
-
-static void ssl_unthrottle(struct tty_struct * tty)
-{
- printk(KERN_ERR "Someone should implement ssl_unthrottle\n");
-}
-
static void ssl_stop(struct tty_struct *tty)
{
printk(KERN_ERR "Someone should implement ssl_stop\n");
@@ -148,9 +135,9 @@ static struct tty_operations ssl_ops = {
.flush_chars = line_flush_chars,
.set_termios = line_set_termios,
.ioctl = line_ioctl,
+ .throttle = line_throttle,
+ .unthrottle = line_unthrottle,
#if 0
- .throttle = ssl_throttle,
- .unthrottle = ssl_unthrottle,
.stop = ssl_stop,
.start = ssl_start,
.hangup = ssl_hangup,
@@ -183,7 +170,7 @@ static int ssl_console_setup(struct console *co, char *options)
{
struct line *line = &serial_lines[co->index];
- return console_open_chan(line,co,&opts);
+ return console_open_chan(line, co, &opts);
}
static struct console ssl_cons = {
@@ -199,12 +186,13 @@ int ssl_init(void)
{
char *new_title;
- printk(KERN_INFO "Initializing software serial port version %d\n",
+ printk(KERN_INFO "Initializing software serial port version %d\n",
ssl_version);
ssl_driver = line_register_devfs(&lines, &driver, &ssl_ops,
- serial_lines, ARRAY_SIZE(serial_lines));
+ serial_lines,
+ ARRAY_SIZE(serial_lines));
- lines_init(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]));
+ lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts);
new_title = add_xterm_umid(opts.xterm_title);
if (new_title != NULL)
@@ -212,7 +200,7 @@ int ssl_init(void)
ssl_init_done = 1;
register_console(&ssl_cons);
- return(0);
+ return 0;
}
late_initcall(ssl_init);
@@ -220,16 +208,13 @@ static void ssl_exit(void)
{
if (!ssl_init_done)
return;
- close_lines(serial_lines,
- sizeof(serial_lines)/sizeof(serial_lines[0]));
+ close_lines(serial_lines, ARRAY_SIZE(serial_lines));
}
__uml_exitcall(ssl_exit);
static int ssl_chan_setup(char *str)
{
- return(line_setup(serial_lines,
- sizeof(serial_lines)/sizeof(serial_lines[0]),
- str, 1));
+ return line_setup(serial_lines, ARRAY_SIZE(serial_lines), str);
}
__setup("ssl", ssl_chan_setup);
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index 005aa6333b6..61db8b2fc83 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -75,7 +75,7 @@ static struct line_driver driver = {
.name = "con",
.config = con_config,
.get_config = con_get_config,
- .id = line_id,
+ .id = line_id,
.remove = con_remove,
},
};
@@ -86,28 +86,27 @@ static struct lines console_lines = LINES_INIT(MAX_TTYS);
* individual elements are protected by individual semaphores.
*/
struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
- [ 1 ... MAX_TTYS - 1 ] =
+ [ 1 ... MAX_TTYS - 1 ] =
LINE_INIT(CONFIG_CON_CHAN, &driver) };
static int con_config(char *str)
{
- return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str));
+ return line_config(vts, ARRAY_SIZE(vts), str, &opts);
}
static int con_get_config(char *dev, char *str, int size, char **error_out)
{
- return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str,
- size, error_out));
+ return line_get_config(dev, vts, ARRAY_SIZE(vts), str, size, error_out);
}
static int con_remove(int n)
{
- return line_remove(vts, sizeof(vts)/sizeof(vts[0]), n);
+ return line_remove(vts, ARRAY_SIZE(vts), n);
}
static int con_open(struct tty_struct *tty, struct file *filp)
{
- return line_open(vts, tty, &opts);
+ return line_open(vts, tty);
}
static int con_init_done = 0;
@@ -117,16 +116,18 @@ static struct tty_operations console_ops = {
.close = line_close,
.write = line_write,
.put_char = line_put_char,
- .write_room = line_write_room,
+ .write_room = line_write_room,
.chars_in_buffer = line_chars_in_buffer,
.flush_buffer = line_flush_buffer,
.flush_chars = line_flush_chars,
.set_termios = line_set_termios,
.ioctl = line_ioctl,
+ .throttle = line_throttle,
+ .unthrottle = line_unthrottle,
};
static void uml_console_write(struct console *console, const char *string,
- unsigned len)
+ unsigned len)
{
struct line *line = &vts[console->index];
unsigned long flags;
@@ -146,7 +147,7 @@ static int uml_console_setup(struct console *co, char *options)
{
struct line *line = &vts[co->index];
- return console_open_chan(line,co,&opts);
+ return console_open_chan(line, co, &opts);
}
static struct console stdiocons = {
@@ -156,7 +157,7 @@ static struct console stdiocons = {
.setup = uml_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
- .data = &vts,
+ .data = &vts,
};
int stdio_init(void)
@@ -166,11 +167,11 @@ int stdio_init(void)
console_driver = line_register_devfs(&console_lines, &driver,
&console_ops, vts,
ARRAY_SIZE(vts));
- if (NULL == console_driver)
+ if (console_driver == NULL)
return -1;
printk(KERN_INFO "Initialized stdio console driver\n");
- lines_init(vts, sizeof(vts)/sizeof(vts[0]));
+ lines_init(vts, ARRAY_SIZE(vts), &opts);
new_title = add_xterm_umid(opts.xterm_title);
if(new_title != NULL)
@@ -178,7 +179,7 @@ int stdio_init(void)
con_init_done = 1;
register_console(&stdiocons);
- return(0);
+ return 0;
}
late_initcall(stdio_init);
@@ -186,13 +187,13 @@ static void console_exit(void)
{
if (!con_init_done)
return;
- close_lines(vts, sizeof(vts)/sizeof(vts[0]));
+ close_lines(vts, ARRAY_SIZE(vts));
}
__uml_exitcall(console_exit);
static int console_chan_setup(char *str)
{
- return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1));
+ return line_setup(vts, ARRAY_SIZE(vts), str);
}
__setup("con", console_chan_setup);
__channel_help(console_chan_setup, "con");
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 93898917cbe..101efd26d46 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -117,6 +117,7 @@ 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,
unsigned int cmd, unsigned long arg);
+static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
#define MAX_DEV (8)
@@ -125,6 +126,7 @@ static struct block_device_operations ubd_blops = {
.open = ubd_open,
.release = ubd_release,
.ioctl = ubd_ioctl,
+ .getgeo = ubd_getgeo,
};
/* Protected by the queue_lock */
@@ -706,7 +708,7 @@ static int ubd_config(char *str)
{
int n, err;
- str = uml_strdup(str);
+ str = kstrdup(str, GFP_KERNEL);
if(str == NULL){
printk(KERN_ERR "ubd_config failed to strdup string\n");
return(1);
@@ -1058,10 +1060,19 @@ static void do_ubd_request(request_queue_t *q)
}
}
+static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ struct ubd *dev = bdev->bd_disk->private_data;
+
+ geo->heads = 128;
+ geo->sectors = 32;
+ geo->cylinders = dev->size / (128 * 32 * 512);
+ return 0;
+}
+
static int ubd_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
- struct hd_geometry __user *loc = (struct hd_geometry __user *) arg;
struct ubd *dev = inode->i_bdev->bd_disk->private_data;
struct hd_driveid ubd_id = {
.cyls = 0,
@@ -1070,16 +1081,7 @@ static int ubd_ioctl(struct inode * inode, struct file * file,
};
switch (cmd) {
- struct hd_geometry g;
struct cdrom_volctrl volume;
- case HDIO_GETGEO:
- if(!loc) return(-EINVAL);
- g.heads = 128;
- g.sectors = 32;
- g.cylinders = dev->size / (128 * 32 * 512);
- g.start = get_start_sect(inode->i_bdev);
- return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);
-
case HDIO_GET_IDENTITY:
ubd_id.cyls = dev->size / (128 * 32 * 512);
if(copy_to_user((char __user *) arg, (char *) &ubd_id,
@@ -1101,31 +1103,33 @@ static int ubd_ioctl(struct inode * inode, struct file * file,
return(-EINVAL);
}
-static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
+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(1);
- if(!strcmp(from_cmdline, from_cow)) return(1);
+ 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(1);
+ 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);
+ return 1;
}
if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
- return(1);
+ return 0;
printk("Backing file mismatch - \"%s\" requested,\n"
"\"%s\" specified in COW header of \"%s\"\n",
from_cmdline, from_cow, cow);
- return(0);
+ return 1;
}
static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
@@ -1187,18 +1191,19 @@ int open_ubd_file(char *file, struct openflags *openflags,
unsigned long long size;
__u32 version, align;
char *backing_file;
- int fd, err, sectorsize, same, mode = 0644;
+ 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))
+ if (fd < 0) {
+ if ((fd == -ENOENT) && (create_cow_out != NULL))
*create_cow_out = 1;
- if(!openflags->w ||
- ((fd != -EROFS) && (fd != -EACCES))) return(fd);
+ 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 (fd < 0)
+ return fd;
}
err = os_lock_file(fd, openflags->w);
@@ -1207,7 +1212,9 @@ int open_ubd_file(char *file, struct openflags *openflags,
goto out_close;
}
- if(backing_file_out == NULL) return(fd);
+ /* Succesful return case! */
+ if(backing_file_out == NULL)
+ return(fd);
err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
&size, &sectorsize, &align, bitmap_offset_out);
@@ -1216,34 +1223,34 @@ int open_ubd_file(char *file, struct openflags *openflags,
"errno = %d\n", file, -err);
goto out_close;
}
- if(err) return(fd);
-
- if(backing_file_out == NULL) return(fd);
+ if(err)
+ return(fd);
- same = same_backing_files(*backing_file_out, backing_file, file);
+ asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
- if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
+ /* 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){
+ if (err) {
printk("Switch failed, errno = %d\n", -err);
- return(err);
+ goto out_close;
}
- }
- else {
+ } else {
*backing_file_out = backing_file;
err = backing_file_mismatch(*backing_file_out, size, mtime);
- if(err) goto out_close;
+ if (err)
+ goto out_close;
}
cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
bitmap_len_out, data_offset_out);
- return(fd);
+ return fd;
out_close:
os_close_file(fd);
- return(err);
+ return err;
}
int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
@@ -1387,15 +1394,6 @@ int io_thread(void *arg)
printk("io_thread - write failed, fd = %d, err = %d\n",
kernel_fd, -n);
}
-}
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+ return 0;
+}
diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h
index da9a6717e7a..1bb5e9d9427 100644
--- a/arch/um/include/chan_kern.h
+++ b/arch/um/include/chan_kern.h
@@ -14,21 +14,23 @@
struct chan {
struct list_head list;
+ struct list_head free_list;
+ struct line *line;
char *dev;
unsigned int primary:1;
unsigned int input:1;
unsigned int output:1;
unsigned int opened:1;
+ unsigned int enabled:1;
int fd;
- enum chan_init_pri pri;
struct chan_ops *ops;
void *data;
};
extern void chan_interrupt(struct list_head *chans, struct work_struct *task,
struct tty_struct *tty, int irq);
-extern int parse_chan_pair(char *str, struct list_head *chans, int pri,
- int device, struct chan_opts *opts);
+extern int parse_chan_pair(char *str, struct line *line, int device,
+ struct chan_opts *opts);
extern int open_chan(struct list_head *chans);
extern int write_chan(struct list_head *chans, const char *buf, int len,
int write_irq);
@@ -36,9 +38,11 @@ extern int console_write_chan(struct list_head *chans, const char *buf,
int len);
extern int console_open_chan(struct line *line, struct console *co,
struct chan_opts *opts);
-extern void close_chan(struct list_head *chans);
+extern void deactivate_chan(struct list_head *chans, int irq);
+extern void reactivate_chan(struct list_head *chans, int irq);
extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty);
-extern void enable_chan(struct list_head *chans, struct tty_struct *tty);
+extern void enable_chan(struct line *line);
+extern void close_chan(struct list_head *chans, int delay_free_irq);
extern int chan_window_size(struct list_head *chans,
unsigned short *rows_out,
unsigned short *cols_out);
@@ -47,14 +51,3 @@ extern int chan_config_string(struct list_head *chans, char *str, int size,
char **error_out);
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/choose-mode.h b/arch/um/include/choose-mode.h
index f25fa83a5da..b87b36a87d9 100644
--- a/arch/um/include/choose-mode.h
+++ b/arch/um/include/choose-mode.h
@@ -23,6 +23,9 @@ static inline void *__choose_mode(void *tt, void *skas) {
#elif defined(UML_CONFIG_MODE_TT)
#define CHOOSE_MODE(tt, skas) (tt)
+
+#else
+#error CONFIG_MODE_SKAS and CONFIG_MODE_TT are both disabled
#endif
#define CHOOSE_MODE_PROC(tt, skas, args...) \
diff --git a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h
index f724b717213..b61deb8b362 100644
--- a/arch/um/include/irq_user.h
+++ b/arch/um/include/irq_user.h
@@ -18,19 +18,8 @@ extern int deactivate_all_fds(void);
extern void forward_interrupts(int pid);
extern void init_irq_signals(int on_sigstack);
extern void forward_ipi(int fd, int pid);
-extern void free_irq_later(int irq, void *dev_id);
extern int activate_ipi(int fd, int pid);
extern unsigned long irq_lock(void);
extern void irq_unlock(unsigned long flags);
-#endif
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+#endif
diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h
index 1e3170768b5..7d223beccbc 100644
--- a/arch/um/include/kern.h
+++ b/arch/um/include/kern.h
@@ -17,7 +17,7 @@ extern int errno;
extern int clone(int (*proc)(void *), void *sp, int flags, void *data);
extern int sleep(int);
-extern int printf(char *fmt, ...);
+extern int printf(const char *fmt, ...);
extern char *strerror(int errnum);
extern char *ptsname(int __fd);
extern int munmap(void *, int);
@@ -35,15 +35,6 @@ extern int read(unsigned int, char *, int);
extern int pipe(int *);
extern int sched_yield(void);
extern int ptrace(int op, int pid, long addr, long data);
+
#endif
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index e5fec557019..c649108a9e9 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -10,6 +10,19 @@
#include "sysdep/ptrace.h"
#include "sysdep/faultinfo.h"
+typedef void (*kern_hndl)(int, union uml_pt_regs *);
+
+struct kern_handlers {
+ kern_hndl relay_signal;
+ kern_hndl winch;
+ kern_hndl bus_handler;
+ kern_hndl page_fault;
+ kern_hndl sigio_handler;
+ kern_hndl timer_handler;
+};
+
+extern struct kern_handlers handlinfo_kern;
+
extern int ncpus;
extern char *linux_prog;
extern char *gdb_init;
@@ -51,8 +64,6 @@ extern void timer_handler(int sig, union uml_pt_regs *regs);
extern int set_signals(int enable);
extern void force_sigbus(void);
extern int pid_to_processor_id(int pid);
-extern void block_signals(void);
-extern void unblock_signals(void);
extern void deliver_signals(void *t);
extern int next_syscall_index(int max);
extern int next_trap_index(int max);
@@ -109,9 +120,13 @@ extern void machine_halt(void);
extern int is_syscall(unsigned long addr);
extern void arch_switch(void);
extern void free_irq(unsigned int, void *);
-extern int um_in_interrupt(void);
extern int cpu(void);
+/* Are we disallowed to sleep? Used to choose between GFP_KERNEL and GFP_ATOMIC. */
+extern int __cant_sleep(void);
+extern void segv_handler(int sig, union uml_pt_regs *regs);
+extern void sigio_handler(int sig, union uml_pt_regs *regs);
+
#endif
/*
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
index 5323d22a6ca..6f4d680dc1d 100644
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -32,11 +32,13 @@ struct line_driver {
};
struct line {
+ struct tty_struct *tty;
char *init_str;
int init_pri;
struct list_head chan_list;
int valid;
int count;
+ int throttled;
/*This lock is actually, mostly, local to*/
spinlock_t lock;
@@ -58,14 +60,15 @@ struct line {
#define LINE_INIT(str, d) \
{ init_str : str, \
init_pri : INIT_STATIC, \
- chan_list : { }, \
valid : 1, \
+ throttled : 0, \
+ lock : SPIN_LOCK_UNLOCKED, \
buffer : NULL, \
head : NULL, \
tail : NULL, \
sigio : 0, \
- driver : d, \
- have_irq : 0 }
+ driver : d, \
+ have_irq : 0 }
struct lines {
int num;
@@ -74,11 +77,11 @@ struct lines {
#define LINES_INIT(n) { num : n }
extern void line_close(struct tty_struct *tty, struct file * filp);
-extern int line_open(struct line *lines, struct tty_struct *tty,
- struct chan_opts *opts);
-extern int line_setup(struct line *lines, unsigned int sizeof_lines, char *init,
- int all_allowed);
-extern int line_write(struct tty_struct *tty, const unsigned char *buf, int len);
+extern int line_open(struct line *lines, struct tty_struct *tty);
+extern int line_setup(struct line *lines, unsigned int sizeof_lines,
+ char *init);
+extern int line_write(struct tty_struct *tty, const unsigned char *buf,
+ int len);
extern void line_put_char(struct tty_struct *tty, unsigned char ch);
extern void line_set_termios(struct tty_struct *tty, struct termios * old);
extern int line_chars_in_buffer(struct tty_struct *tty);
@@ -87,23 +90,27 @@ extern void line_flush_chars(struct tty_struct *tty);
extern int line_write_room(struct tty_struct *tty);
extern int line_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
+extern void line_throttle(struct tty_struct *tty);
+extern void line_unthrottle(struct tty_struct *tty);
extern char *add_xterm_umid(char *base);
-extern int line_setup_irq(int fd, int input, int output, struct tty_struct *tty);
+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 void line_disable(struct tty_struct *tty, int current_irq);
-extern struct tty_driver * line_register_devfs(struct lines *set,
- struct line_driver *line_driver,
+extern struct tty_driver * line_register_devfs(struct lines *set,
+ struct line_driver *line_driver,
struct tty_operations *driver,
struct line *lines,
int nlines);
-extern void lines_init(struct line *lines, int nlines);
+extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts);
extern void close_lines(struct line *lines, int nlines);
-extern int line_config(struct line *lines, unsigned int sizeof_lines, char *str);
+extern int line_config(struct line *lines, unsigned int sizeof_lines,
+ char *str, struct chan_opts *opts);
extern int line_id(char **str, int *start_out, int *end_out);
extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n);
-extern int line_get_config(char *dev, struct line *lines, unsigned int sizeof_lines, char *str,
+extern int line_get_config(char *dev, struct line *lines,
+ unsigned int sizeof_lines, char *str,
int size, char **error_out);
#endif
diff --git a/arch/um/include/longjmp.h b/arch/um/include/longjmp.h
new file mode 100644
index 00000000000..018b3819ab0
--- /dev/null
+++ b/arch/um/include/longjmp.h
@@ -0,0 +1,19 @@
+#ifndef __UML_LONGJMP_H
+#define __UML_LONGJMP_H
+
+#include <setjmp.h>
+#include "os.h"
+
+#define UML_SIGLONGJMP(buf, val) do { \
+ longjmp(*buf, val); \
+} while(0)
+
+#define UML_SIGSETJMP(buf, enable) ({ \
+ int n; \
+ enable = get_signals(); \
+ n = setjmp(*buf); \
+ if(n != 0) \
+ set_signals(enable); \
+ n; })
+
+#endif
diff --git a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h
index b1b512f4703..58f67d39110 100644
--- a/arch/um/include/mconsole.h
+++ b/arch/um/include/mconsole.h
@@ -32,7 +32,7 @@ struct mconsole_reply {
struct mconsole_notify {
u32 magic;
- u32 version;
+ u32 version;
enum { MCONSOLE_SOCKET, MCONSOLE_PANIC, MCONSOLE_HANG,
MCONSOLE_USER_NOTIFY } type;
u32 len;
@@ -66,7 +66,9 @@ struct mc_request
extern char mconsole_socket_name[];
extern int mconsole_unlink_socket(void);
-extern int mconsole_reply(struct mc_request *req, char *reply, int err,
+extern int mconsole_reply_len(struct mc_request *req, const char *reply,
+ int len, int err, int more);
+extern int mconsole_reply(struct mc_request *req, const char *str, int err,
int more);
extern void mconsole_version(struct mc_request *req);
@@ -84,7 +86,7 @@ extern void mconsole_proc(struct mc_request *req);
extern void mconsole_stack(struct mc_request *req);
extern int mconsole_get_request(int fd, struct mc_request *req);
-extern int mconsole_notify(char *sock_name, int type, const void *data,
+extern int mconsole_notify(char *sock_name, int type, const void *data,
int len);
extern char *mconsole_notify_socket(void);
extern void lock_notify(void);
diff --git a/arch/um/include/mode_kern.h b/arch/um/include/mode_kern.h
index 2d88afd0cf1..e7539a8451e 100644
--- a/arch/um/include/mode_kern.h
+++ b/arch/um/include/mode_kern.h
@@ -9,22 +9,11 @@
#include "linux/config.h"
#ifdef CONFIG_MODE_TT
-#include "mode_kern-tt.h"
+#include "mode_kern_tt.h"
#endif
#ifdef CONFIG_MODE_SKAS
-#include "mode_kern-skas.h"
+#include "mode_kern_skas.h"
#endif
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 2cccfa5b8ab..eb1710b8125 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -9,6 +9,9 @@
#include "uml-config.h"
#include "asm/types.h"
#include "../os/include/file.h"
+#include "sysdep/ptrace.h"
+#include "kern_util.h"
+#include "skas/mm_id.h"
#define OS_TYPE_FILE 1
#define OS_TYPE_DIR 2
@@ -188,11 +191,12 @@ extern int os_protect_memory(void *addr, unsigned long len,
int r, int w, int x);
extern int os_unmap_memory(void *addr, int len);
extern void os_flush_stdout(void);
-extern unsigned long long os_usecs(void);
/* tt.c
* for tt mode only (will be deleted in future...)
*/
+extern void stop(void);
+extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
extern int protect_memory(unsigned long addr, unsigned long len,
int r, int w, int x, int must_succeed);
extern void forward_pending_sigio(int target);
@@ -213,15 +217,78 @@ extern int run_helper_thread(int (*proc)(void *), void *arg,
int stack_order);
extern int helper_wait(int pid);
-#endif
+/* umid.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:
- */
+extern int umid_file_name(char *name, char *buf, int len);
+extern int set_umid(char *name);
+extern char *get_umid(void);
+
+/* signal.c */
+extern void set_sigstack(void *sig_stack, int size);
+extern void remove_sigstack(void);
+extern void set_handler(int sig, void (*handler)(int), int flags, ...);
+extern int change_sig(int signal, int on);
+extern void block_signals(void);
+extern void unblock_signals(void);
+extern int get_signals(void);
+extern int set_signals(int enable);
+extern void os_usr1_signal(int on);
+
+/* trap.c */
+extern void os_fill_handlinfo(struct kern_handlers h);
+extern void do_longjmp(void *p, int val);
+
+/* util.c */
+extern void stack_protections(unsigned long address);
+extern void task_protections(unsigned long address);
+extern int raw(int fd);
+extern void setup_machinename(char *machine_out);
+extern void setup_hostinfo(void);
+extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
+
+/* time.c */
+#define BILLION (1000 * 1000 * 1000)
+
+extern void switch_timers(int to_real);
+extern void idle_sleep(int secs);
+extern void enable_timer(void);
+extern void disable_timer(void);
+extern void user_time_init(void);
+extern void uml_idle_timer(void);
+extern unsigned long long os_nsecs(void);
+
+/* skas/mem.c */
+extern long run_syscall_stub(struct mm_id * mm_idp,
+ int syscall, unsigned long *args, long expected,
+ void **addr, int done);
+extern long syscall_stub_data(struct mm_id * mm_idp,
+ unsigned long *data, int data_count,
+ void **addr, void **stub_addr);
+extern int map(struct mm_id * mm_idp, unsigned long virt,
+ unsigned long len, int r, int w, int x, int phys_fd,
+ unsigned long long offset, int done, void **data);
+extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len,
+ int done, void **data);
+extern int protect(struct mm_id * mm_idp, unsigned long addr,
+ unsigned long len, int r, int w, int x, int done,
+ void **data);
+
+/* skas/process.c */
+extern int is_skas_winch(int pid, int fd, void *data);
+extern int start_userspace(unsigned long stub_stack);
+extern int copy_context_skas0(unsigned long stack, int pid);
+extern void userspace(union uml_pt_regs *regs);
+extern void map_stub_pages(int fd, unsigned long code,
+ unsigned long data, unsigned long stack);
+extern void new_thread(void *stack, void **switch_buf_ptr,
+ void **fork_buf_ptr, void (*handler)(int));
+extern void thread_wait(void *sw, void *fb);
+extern void switch_threads(void *me, void *next);
+extern int start_idle_thread(void *stack, void *switch_buf_ptr,
+ void **fork_buf_ptr);
+extern void initial_thread_cb_skas(void (*proc)(void *),
+ void *arg);
+extern void halt_skas(void);
+extern void reboot_skas(void);
+
+#endif
diff --git a/arch/um/include/signal_user.h b/arch/um/include/signal_user.h
deleted file mode 100644
index b075e543d86..00000000000
--- a/arch/um/include/signal_user.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SIGNAL_USER_H__
-#define __SIGNAL_USER_H__
-
-extern int signal_stack_size;
-
-extern int change_sig(int signal, int on);
-extern void set_sigstack(void *stack, int size);
-extern void set_handler(int sig, void (*handler)(int), int flags, ...);
-extern int set_signals(int enable);
-extern int get_signals(void);
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/include/mm_id.h b/arch/um/include/skas/mm_id.h
index 48dd0989dda..48dd0989dda 100644
--- a/arch/um/kernel/skas/include/mm_id.h
+++ b/arch/um/include/skas/mm_id.h
diff --git a/arch/um/include/skas/mmu-skas.h b/arch/um/include/skas/mmu-skas.h
new file mode 100644
index 00000000000..d8869a6ef1b
--- /dev/null
+++ b/arch/um/include/skas/mmu-skas.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_MMU_H
+#define __SKAS_MMU_H
+
+#include "linux/config.h"
+#include "mm_id.h"
+#include "asm/ldt.h"
+
+struct mmu_context_skas {
+ struct mm_id id;
+ unsigned long last_page_table;
+#ifdef CONFIG_3_LEVEL_PGTABLES
+ unsigned long last_pmd;
+#endif
+ uml_ldt_t ldt;
+};
+
+extern void switch_mm_skas(struct mm_id * mm_idp);
+
+#endif
diff --git a/arch/um/include/skas/mode-skas.h b/arch/um/include/skas/mode-skas.h
new file mode 100644
index 00000000000..260065cfeef
--- /dev/null
+++ b/arch/um/include/skas/mode-skas.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_SKAS_H__
+#define __MODE_SKAS_H__
+
+#include <sysdep/ptrace.h>
+
+extern unsigned long exec_regs[];
+extern unsigned long exec_fp_regs[];
+extern unsigned long exec_fpx_regs[];
+extern int have_fpx_regs;
+
+extern void sig_handler_common_skas(int sig, void *sc_ptr);
+extern void kill_off_processes_skas(void);
+
+#endif
diff --git a/arch/um/kernel/skas/include/mode_kern-skas.h b/arch/um/include/skas/mode_kern_skas.h
index c97a80dfe37..63c58739bde 100644
--- a/arch/um/kernel/skas/include/mode_kern-skas.h
+++ b/arch/um/include/skas/mode_kern_skas.h
@@ -18,7 +18,6 @@ extern int copy_thread_skas(int nr, unsigned long clone_flags,
unsigned long sp, unsigned long stack_top,
struct task_struct *p, struct pt_regs *regs);
extern void release_thread_skas(struct task_struct *task);
-extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
extern void init_idle_skas(void);
extern void flush_tlb_kernel_range_skas(unsigned long start,
unsigned long end);
@@ -39,14 +38,3 @@ extern int thread_pid_skas(struct task_struct *task);
#define kmem_end_skas (host_task_size - 1024 * 1024)
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/include/proc_mm.h b/arch/um/include/skas/proc_mm.h
index cce61a67905..90280920960 100644
--- a/arch/um/kernel/skas/include/proc_mm.h
+++ b/arch/um/include/skas/proc_mm.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -22,13 +22,13 @@ struct mm_mmap {
struct mm_munmap {
unsigned long addr;
- unsigned long len;
+ unsigned long len;
};
struct mm_mprotect {
unsigned long addr;
unsigned long len;
- unsigned int prot;
+ unsigned int prot;
};
struct proc_mm_op {
@@ -42,14 +42,3 @@ struct proc_mm_op {
};
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h
new file mode 100644
index 00000000000..86357282d68
--- /dev/null
+++ b/arch/um/include/skas/skas.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_H
+#define __SKAS_H
+
+#include "mm_id.h"
+#include "sysdep/ptrace.h"
+
+extern int userspace_pid[];
+extern int proc_mm, ptrace_faultinfo, ptrace_ldt;
+extern int skas_needs_stub;
+
+extern int user_thread(unsigned long stack, int flags);
+extern void new_thread_proc(void *stack, void (*handler)(int sig));
+extern void new_thread_handler(int sig);
+extern void handle_syscall(union uml_pt_regs *regs);
+extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
+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);
+
+#endif
diff --git a/arch/um/kernel/skas/include/stub-data.h b/arch/um/include/skas/stub-data.h
index f6ed92c3727..f6ed92c3727 100644
--- a/arch/um/kernel/skas/include/stub-data.h
+++ b/arch/um/include/skas/stub-data.h
diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/include/skas/uaccess-skas.h
index 64516c556cd..224a75f4c02 100644
--- a/arch/um/kernel/skas/include/uaccess-skas.h
+++ b/arch/um/include/skas/uaccess-skas.h
@@ -19,14 +19,3 @@ extern int clear_user_skas(void __user *mem, int len);
extern int strnlen_user_skas(const void __user *str, int len);
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h
index 764ba4db478..7d3d202d7ff 100644
--- a/arch/um/include/sysdep-i386/checksum.h
+++ b/arch/um/include/sysdep-i386/checksum.h
@@ -36,7 +36,7 @@ unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *
int len, int sum)
{
memcpy(dst, src, len);
- return(csum_partial(dst, len, sum));
+ return csum_partial(dst, len, sum);
}
/*
@@ -104,7 +104,7 @@ static inline unsigned short ip_fast_csum(unsigned char * iph,
: "=r" (sum), "=r" (iph), "=r" (ihl)
: "1" (iph), "2" (ihl)
: "memory");
- return(sum);
+ return sum;
}
/*
diff --git a/arch/um/sys-i386/kernel-offsets.c b/arch/um/include/sysdep-i386/kernel-offsets.h
index 35db8505750..82f96c57414 100644
--- a/arch/um/sys-i386/kernel-offsets.c
+++ b/arch/um/include/sysdep-i386/kernel-offsets.h
@@ -1,12 +1,9 @@
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/sched.h>
-#include <linux/time.h>
#include <linux/elf.h>
-#include <asm/page.h>
#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
#define STR(x) #x
#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " STR(val) " " #val: : )
diff --git a/arch/um/include/sysdep-i386/stub.h b/arch/um/include/sysdep-i386/stub.h
index 6ba8cbbe0d3..b492b12b4a1 100644
--- a/arch/um/include/sysdep-i386/stub.h
+++ b/arch/um/include/sysdep-i386/stub.h
@@ -6,8 +6,12 @@
#ifndef __SYSDEP_STUB_H
#define __SYSDEP_STUB_H
+#include <sys/mman.h>
#include <asm/ptrace.h>
#include <asm/unistd.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);
@@ -76,23 +80,22 @@ static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3,
return ret;
}
-static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6)
+static inline void trap_myself(void)
{
- long ret;
-
- __asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; "
- "int $0x80 ; pop %%ebp"
- : "=a" (ret)
- : "g" (syscall), "b" (arg1), "c" (arg2), "d" (arg3),
- "S" (arg4), "D" (arg5), "0" (arg6));
-
- return ret;
+ __asm("int3");
}
-static inline void trap_myself(void)
+static inline void remap_stack(int fd, unsigned long offset)
{
- __asm("int3");
+ __asm__ volatile ("movl %%eax,%%ebp ; movl %0,%%eax ; int $0x80 ;"
+ "movl %7, %%ebx ; movl %%eax, (%%ebx)"
+ : : "g" (STUB_MMAP_NR), "b" (UML_CONFIG_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 *) UML_CONFIG_STUB_DATA)->err)
+ : "memory");
}
#endif
diff --git a/arch/um/sys-x86_64/kernel-offsets.c b/arch/um/include/sysdep-x86_64/kernel-offsets.h
index bfcb104b846..5ce93abd0b5 100644
--- a/arch/um/sys-x86_64/kernel-offsets.c
+++ b/arch/um/include/sysdep-x86_64/kernel-offsets.h
@@ -6,7 +6,7 @@
#include <asm/page.h>
#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (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: : )
diff --git a/arch/um/include/sysdep-x86_64/stub.h b/arch/um/include/sysdep-x86_64/stub.h
index c41689c13dc..92e989f8176 100644
--- a/arch/um/include/sysdep-x86_64/stub.h
+++ b/arch/um/include/sysdep-x86_64/stub.h
@@ -6,8 +6,12 @@
#ifndef __SYSDEP_STUB_H
#define __SYSDEP_STUB_H
+#include <sys/mman.h>
#include <asm/unistd.h>
#include <sysdep/ptrace_user.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);
@@ -81,23 +85,23 @@ static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3,
return ret;
}
-static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6)
+static inline void trap_myself(void)
{
- long ret;
-
- __asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; "
- "movq %7, %%r9; " __syscall : "=a" (ret)
- : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3),
- "g" (arg4), "g" (arg5), "g" (arg6)
- : __syscall_clobber, "r10", "r8", "r9" );
-
- return ret;
+ __asm("int3");
}
-static inline void trap_myself(void)
+static inline void remap_stack(long fd, unsigned long offset)
{
- __asm("int3");
+ __asm__ volatile ("movq %4,%%r10 ; movq %5,%%r8 ; "
+ "movq %6, %%r9; " __syscall "; movq %7, %%rbx ; "
+ "movq %%rax, (%%rbx)":
+ : "a" (STUB_MMAP_NR), "D" (UML_CONFIG_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 *) UML_CONFIG_STUB_DATA)->err)
+ : __syscall_clobber, "r10", "r8", "r9" );
}
#endif
diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h
deleted file mode 100644
index 17d7ef2141f..00000000000
--- a/arch/um/include/time_user.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __TIME_USER_H__
-#define __TIME_USER_H__
-
-extern void timer(void);
-extern void switch_timers(int to_real);
-extern void idle_sleep(int secs);
-extern void enable_timer(void);
-extern void prepare_timer(void * ptr);
-extern void disable_timer(void);
-extern unsigned long time_lock(void);
-extern void time_unlock(unsigned long);
-extern void user_time_init(void);
-
-#endif
diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/include/tt/debug.h
index 738435461e1..9778fa83829 100644
--- a/arch/um/kernel/tt/include/debug.h
+++ b/arch/um/include/tt/debug.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and
* Lars Brinkhoff.
* Licensed under the GPL
diff --git a/arch/um/include/tt/mmu-tt.h b/arch/um/include/tt/mmu-tt.h
new file mode 100644
index 00000000000..572a78b2258
--- /dev/null
+++ b/arch/um/include/tt/mmu-tt.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_MMU_H
+#define __TT_MMU_H
+
+struct mmu_context_tt {
+};
+
+#endif
diff --git a/arch/um/include/tt/mode-tt.h b/arch/um/include/tt/mode-tt.h
new file mode 100644
index 00000000000..2823cd56eea
--- /dev/null
+++ b/arch/um/include/tt/mode-tt.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_TT_H__
+#define __MODE_TT_H__
+
+#include "sysdep/ptrace.h"
+
+enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
+
+extern int tracing_pid;
+
+extern int tracer(int (*init_proc)(void *), void *sp);
+extern void sig_handler_common_tt(int sig, void *sc);
+extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
+extern void reboot_tt(void);
+extern void halt_tt(void);
+extern int is_tracer_winch(int pid, int fd, void *data);
+extern void kill_off_processes_tt(void);
+
+#endif
diff --git a/arch/um/include/tt/mode_kern_tt.h b/arch/um/include/tt/mode_kern_tt.h
new file mode 100644
index 00000000000..efa0012550d
--- /dev/null
+++ b/arch/um/include/tt/mode_kern_tt.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_MODE_KERN_H__
+#define __TT_MODE_KERN_H__
+
+#include "linux/sched.h"
+#include "asm/page.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+
+extern void switch_to_tt(void *prev, void *next);
+extern void flush_thread_tt(void);
+extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
+ unsigned long esp);
+extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
+ unsigned long stack_top, struct task_struct *p,
+ struct pt_regs *regs);
+extern void release_thread_tt(struct task_struct *task);
+extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
+extern void init_idle_tt(void);
+extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
+extern void flush_tlb_kernel_vm_tt(void);
+extern void __flush_tlb_one_tt(unsigned long addr);
+extern void flush_tlb_range_tt(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end);
+extern void flush_tlb_mm_tt(struct mm_struct *mm);
+extern void force_flush_all_tt(void);
+extern long execute_syscall_tt(void *r);
+extern void before_mem_tt(unsigned long brk_start);
+extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
+ unsigned long *task_size_out);
+extern int start_uml_tt(void);
+extern int external_pid_tt(struct task_struct *task);
+extern int thread_pid_tt(struct task_struct *task);
+
+#define kmem_end_tt (host_task_size - ABOVE_KMEM)
+
+#endif
diff --git a/arch/um/kernel/tt/include/tt.h b/arch/um/include/tt/tt.h
index c667b67af40..80852198018 100644
--- a/arch/um/kernel/tt/include/tt.h
+++ b/arch/um/include/tt/tt.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -34,13 +34,3 @@ extern long execute_syscall_tt(void *r);
#endif
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/include/tt/uaccess-tt.h
index b9bfe9c481c..b19645f32f2 100644
--- a/arch/um/kernel/tt/include/uaccess-tt.h
+++ b/arch/um/include/tt/uaccess-tt.h
@@ -46,14 +46,3 @@ extern int clear_user_tt(void __user *mem, int len);
extern int strnlen_user_tt(const void __user *str, int len);
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/user.h b/arch/um/include/user.h
index 0f865ef4691..91b0ac4ad88 100644
--- a/arch/um/include/user.h
+++ b/arch/um/include/user.h
@@ -18,6 +18,7 @@ extern int open_gdb_chan(void);
extern unsigned long strlcpy(char *, const char *, unsigned long);
extern unsigned long strlcat(char *, const char *, unsigned long);
extern void *um_vmalloc(int size);
+extern void *um_vmalloc_atomic(int size);
extern void vfree(void *ptr);
#endif
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
index bb505e01d99..a6f1f176cf8 100644
--- a/arch/um/include/user_util.h
+++ b/arch/um/include/user_util.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -23,12 +23,7 @@ struct cpu_task {
extern struct cpu_task cpu_tasks[];
-struct signal_info {
- void (*handler)(int, union uml_pt_regs *);
- int is_irq;
-};
-
-extern struct signal_info sig_info[];
+extern void (*sig_info[])(int, union uml_pt_regs *);
extern unsigned long low_physmem;
extern unsigned long high_physmem;
@@ -49,10 +44,6 @@ extern unsigned long brk_start;
extern int pty_output_sigio;
extern int pty_close_sigio;
-extern void stop(void);
-extern void stack_protections(unsigned long address);
-extern void task_protections(unsigned long address);
-extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
extern void *add_signal_handler(int sig, void (*handler)(int));
extern int linux_main(int argc, char **argv);
extern void set_cmdline(char *cmd);
@@ -60,12 +51,8 @@ extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
extern int get_pty(void);
extern void *um_kmalloc(int size);
extern int switcheroo(int fd, int prot, void *from, void *to, int size);
-extern void setup_machinename(char *machine_out);
-extern void setup_hostinfo(void);
extern void do_exec(int old_pid, int new_pid);
extern void tracer_panic(char *msg, ...);
-extern char *get_umid(int only_if_set);
-extern void do_longjmp(void *p, int val);
extern int detach(int pid, int sig);
extern int attach(int pid);
extern void kill_child_dead(int pid);
@@ -77,18 +64,6 @@ extern int cpu_feature(char *what, char *buf, int len);
extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
extern int arch_fixup(unsigned long address, void *sc_ptr);
extern void arch_init_thread(void);
-extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
extern int raw(int fd);
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index 3de9d21e36b..693018ba80f 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -9,9 +9,8 @@ clean-files :=
obj-y = config.o exec_kern.o exitcode.o \
init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \
process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \
- signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o time.o \
- time_kern.o tlb.o trap_kern.o trap_user.o uaccess.o um_arch.o \
- umid.o user_util.o
+ signal_kern.o smp.o syscall_kern.o sysrq.o \
+ time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
obj-$(CONFIG_GPROF) += gprof_syms.o
@@ -24,7 +23,7 @@ obj-$(CONFIG_MODE_SKAS) += skas/
user-objs-$(CONFIG_TTY_LOG) += tty_log.o
-USER_OBJS := $(user-objs-y) config.o time.o tty_log.o umid.o user_util.o
+USER_OBJS := $(user-objs-y) config.o tty_log.o
include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/asm-offsets.c b/arch/um/kernel/asm-offsets.c
index c13a64a288f..91ea538e161 100644
--- a/arch/um/kernel/asm-offsets.c
+++ b/arch/um/kernel/asm-offsets.c
@@ -1 +1 @@
-/* Dummy file to make kbuild happy - unused! */
+#include "sysdep/kernel-offsets.h"
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
index efd222ffe20..569fe8b9b05 100644
--- a/arch/um/kernel/exec_kern.c
+++ b/arch/um/kernel/exec_kern.c
@@ -17,7 +17,6 @@
#include "irq_user.h"
#include "tlb.h"
#include "os.h"
-#include "time_user.h"
#include "choose-mode.h"
#include "mode_kern.h"
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
index c3ccaf24f3e..0e32f5f4a88 100644
--- a/arch/um/kernel/irq_user.c
+++ b/arch/um/kernel/irq_user.c
@@ -15,7 +15,6 @@
#include "kern_util.h"
#include "user.h"
#include "process.h"
-#include "signal_user.h"
#include "sigio.h"
#include "irq_user.h"
#include "os.h"
@@ -29,7 +28,6 @@ struct irq_fd {
int pid;
int events;
int current_events;
- int freed;
};
static struct irq_fd *active_fds = NULL;
@@ -41,9 +39,11 @@ static int pollfds_size = 0;
extern int io_count, intr_count;
+extern void free_irqs(void);
+
void sigio_handler(int sig, union uml_pt_regs *regs)
{
- struct irq_fd *irq_fd, *next;
+ struct irq_fd *irq_fd;
int i, n;
if(smp_sigio_handler()) return;
@@ -66,29 +66,15 @@ void sigio_handler(int sig, union uml_pt_regs *regs)
irq_fd = irq_fd->next;
}
- for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){
- next = irq_fd->next;
+ for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
if(irq_fd->current_events != 0){
irq_fd->current_events = 0;
do_IRQ(irq_fd->irq, regs);
-
- /* This is here because the next irq may be
- * freed in the handler. If a console goes
- * away, both the read and write irqs will be
- * freed. After do_IRQ, ->next will point to
- * a good IRQ.
- * Irqs can't be freed inside their handlers,
- * so the next best thing is to have them
- * marked as needing freeing, so that they
- * can be freed here.
- */
- next = irq_fd->next;
- if(irq_fd->freed){
- free_irq(irq_fd->irq, irq_fd->id);
- }
}
}
}
+
+ free_irqs();
}
int activate_ipi(int fd, int pid)
@@ -136,8 +122,7 @@ int activate_fd(int irq, int fd, int type, void *dev_id)
.irq = irq,
.pid = pid,
.events = events,
- .current_events = 0,
- .freed = 0 } );
+ .current_events = 0 } );
/* Critical section - locked by a spinlock because this stuff can
* be changed from interrupt handlers. The stuff above is done
@@ -313,26 +298,6 @@ static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
return(irq);
}
-void free_irq_later(int irq, void *dev_id)
-{
- struct irq_fd *irq_fd;
- unsigned long flags;
-
- flags = irq_lock();
- for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
- if((irq_fd->irq == irq) && (irq_fd->id == dev_id))
- break;
- }
- if(irq_fd == NULL){
- printk("free_irq_later found no irq, irq = %d, "
- "dev_id = 0x%p\n", irq, dev_id);
- goto out;
- }
- irq_fd->freed = 1;
- out:
- irq_unlock(flags);
-}
-
void reactivate_fd(int fd, int irqnum)
{
struct irq_fd *irq;
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index 34b54a3e213..3113cab8675 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -36,11 +36,9 @@
#include "kern_util.h"
#include "kern.h"
#include "signal_kern.h"
-#include "signal_user.h"
#include "init.h"
#include "irq_user.h"
#include "mem_user.h"
-#include "time_user.h"
#include "tlb.h"
#include "frame_kern.h"
#include "sigcontext.h"
@@ -108,7 +106,7 @@ void set_current(void *t)
{
struct task_struct *task = t;
- cpu_tasks[task->thread_info->cpu] = ((struct cpu_task)
+ cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
{ external_pid(task), task });
}
@@ -289,17 +287,27 @@ EXPORT_SYMBOL(disable_hlt);
void *um_kmalloc(int size)
{
- return(kmalloc(size, GFP_KERNEL));
+ return kmalloc(size, GFP_KERNEL);
}
void *um_kmalloc_atomic(int size)
{
- return(kmalloc(size, GFP_ATOMIC));
+ return kmalloc(size, GFP_ATOMIC);
}
void *um_vmalloc(int size)
{
- return(vmalloc(size));
+ return vmalloc(size);
+}
+
+void *um_vmalloc_atomic(int size)
+{
+ return __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, PAGE_KERNEL);
+}
+
+int __cant_sleep(void) {
+ return in_atomic() || irqs_disabled() || in_interrupt();
+ /* Is in_interrupt() really needed? */
}
unsigned long get_fault_addr(void)
@@ -324,10 +332,6 @@ int user_context(unsigned long sp)
return(stack != (unsigned long) current_thread);
}
-extern void remove_umid_dir(void);
-
-__uml_exitcall(remove_umid_dir);
-
extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
void do_uml_exitcalls(void)
@@ -375,11 +379,6 @@ int smp_sigio_handler(void)
return(0);
}
-int um_in_interrupt(void)
-{
- return(in_interrupt());
-}
-
int cpu(void)
{
return(current_thread->cpu);
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index a637e885c58..6f1a3a28811 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -12,6 +12,8 @@
#include "mode.h"
#include "choose-mode.h"
+void (*pm_power_off)(void);
+
#ifdef CONFIG_SMP
static void kill_idlers(int me)
{
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
index 48b1f644b9a..f7b18e157d3 100644
--- a/arch/um/kernel/sigio_user.c
+++ b/arch/um/kernel/sigio_user.c
@@ -216,6 +216,8 @@ static int write_sigio_thread(void *unused)
"err = %d\n", -n);
}
}
+
+ return 0;
}
static int need_poll(int n)
@@ -335,70 +337,103 @@ int ignore_sigio_fd(int fd)
return(err);
}
-static int setup_initial_poll(int fd)
+static struct pollfd* setup_initial_poll(int fd)
{
struct pollfd *p;
- p = um_kmalloc_atomic(sizeof(struct pollfd));
- if(p == NULL){
+ p = um_kmalloc(sizeof(struct pollfd));
+ if (p == NULL) {
printk("setup_initial_poll : failed to allocate poll\n");
- return(-1);
+ return NULL;
}
*p = ((struct pollfd) { .fd = fd,
.events = POLLIN,
.revents = 0 });
- current_poll = ((struct pollfds) { .poll = p,
- .used = 1,
- .size = 1 });
- return(0);
+ return p;
}
void write_sigio_workaround(void)
{
unsigned long stack;
+ struct pollfd *p;
int err;
+ int l_write_sigio_fds[2];
+ int l_sigio_private[2];
+ int l_write_sigio_pid;
+ /* We call this *tons* of times - and most ones we must just fail. */
sigio_lock();
- if(write_sigio_pid != -1)
- goto out;
+ l_write_sigio_pid = write_sigio_pid;
+ sigio_unlock();
+
+ if (l_write_sigio_pid != -1)
+ return;
- err = os_pipe(write_sigio_fds, 1, 1);
+ err = os_pipe(l_write_sigio_fds, 1, 1);
if(err < 0){
printk("write_sigio_workaround - os_pipe 1 failed, "
"err = %d\n", -err);
- goto out;
+ return;
}
- err = os_pipe(sigio_private, 1, 1);
+ err = os_pipe(l_sigio_private, 1, 1);
if(err < 0){
- printk("write_sigio_workaround - os_pipe 2 failed, "
+ printk("write_sigio_workaround - os_pipe 1 failed, "
"err = %d\n", -err);
goto out_close1;
}
- if(setup_initial_poll(sigio_private[1]))
+
+ p = setup_initial_poll(l_sigio_private[1]);
+ if(!p)
goto out_close2;
- write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
+ sigio_lock();
+
+ /* Did we race? Don't try to optimize this, please, it's not so likely
+ * to happen, and no more than once at the boot. */
+ if(write_sigio_pid != -1)
+ goto out_unlock;
+
+ write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
CLONE_FILES | CLONE_VM, &stack, 0);
- if(write_sigio_pid < 0) goto out_close2;
+ if (write_sigio_pid < 0)
+ goto out_clear;
- if(write_sigio_irq(write_sigio_fds[0]))
+ if (write_sigio_irq(l_write_sigio_fds[0]))
goto out_kill;
- out:
+ /* Success, finally. */
+ memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds));
+ memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private));
+
+ current_poll = ((struct pollfds) { .poll = p,
+ .used = 1,
+ .size = 1 });
+
sigio_unlock();
return;
out_kill:
- os_kill_process(write_sigio_pid, 1);
+ l_write_sigio_pid = write_sigio_pid;
+ write_sigio_pid = -1;
+ sigio_unlock();
+ /* Going to call waitpid, avoid holding the lock. */
+ os_kill_process(l_write_sigio_pid, 1);
+ goto out_free;
+
+ out_clear:
write_sigio_pid = -1;
+ out_unlock:
+ sigio_unlock();
+ out_free:
+ kfree(p);
out_close2:
- os_close_file(sigio_private[0]);
- os_close_file(sigio_private[1]);
+ os_close_file(l_sigio_private[0]);
+ os_close_file(l_sigio_private[1]);
out_close1:
- os_close_file(write_sigio_fds[0]);
- os_close_file(write_sigio_fds[1]);
- sigio_unlock();
+ os_close_file(l_write_sigio_fds[0]);
+ os_close_file(l_write_sigio_fds[1]);
+ return;
}
int read_sigio_fd(int fd)
diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c
index 03618bd13d5..da17b7541e0 100644
--- a/arch/um/kernel/signal_kern.c
+++ b/arch/um/kernel/signal_kern.c
@@ -22,7 +22,6 @@
#include "asm/ucontext.h"
#include "kern_util.h"
#include "signal_kern.h"
-#include "signal_user.h"
#include "kern.h"
#include "frame_kern.h"
#include "sigcontext.h"
@@ -100,31 +99,46 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
return err;
}
-static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset)
+static int kern_do_signal(struct pt_regs *regs)
{
struct k_sigaction ka_copy;
siginfo_t info;
+ sigset_t *oldset;
int sig, handled_sig = 0;
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else
+ oldset = &current->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))
+ 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;
+ }
}
/* Did we come from a system call? */
if(!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)){
/* Restart the system call - no handlers present */
- if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND ||
- PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS ||
- PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){
+ switch(PT_REGS_SYSCALL_RET(regs)){
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
PT_REGS_RESTART_SYSCALL(regs);
- }
- else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){
+ break;
+ case -ERESTART_RESTARTBLOCK:
PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall;
PT_REGS_RESTART_SYSCALL(regs);
+ break;
}
}
@@ -138,12 +152,19 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset)
if(current->ptrace & PT_DTRACE)
current->thread.singlestep_syscall =
is_syscall(PT_REGS_IP(&current->thread.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, &current->saved_sigmask, NULL);
+ }
return(handled_sig);
}
int do_signal(void)
{
- return(kern_do_signal(&current->thread.regs, &current->blocked));
+ return(kern_do_signal(&current->thread.regs));
}
/*
@@ -151,63 +172,20 @@ int do_signal(void)
*/
long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
- sigset_t saveset;
-
mask &= _BLOCKABLE;
spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
+ current->saved_sigmask = current->blocked;
siginitset(&current->blocked, mask);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if(kern_do_signal(&current->thread.regs, &saveset))
- return(-EINTR);
- }
-}
-
-long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
-{
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
- current->blocked = newset;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (kern_do_signal(&current->thread.regs, &saveset))
- return(-EINTR);
- }
+ 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(&current->thread.regs)));
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c
deleted file mode 100644
index 62f457835fb..00000000000
--- a/arch/um/kernel/signal_user.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/mman.h>
-#include "user_util.h"
-#include "kern_util.h"
-#include "user.h"
-#include "signal_user.h"
-#include "signal_kern.h"
-#include "sysdep/sigcontext.h"
-#include "sigcontext.h"
-
-void set_sigstack(void *sig_stack, int size)
-{
- stack_t stack = ((stack_t) { .ss_flags = 0,
- .ss_sp = (__ptr_t) sig_stack,
- .ss_size = size - sizeof(void *) });
-
- if(sigaltstack(&stack, NULL) != 0)
- panic("enabling signal stack failed, errno = %d\n", errno);
-}
-
-void set_handler(int sig, void (*handler)(int), int flags, ...)
-{
- struct sigaction action;
- va_list ap;
- int mask;
-
- va_start(ap, flags);
- action.sa_handler = handler;
- sigemptyset(&action.sa_mask);
- while((mask = va_arg(ap, int)) != -1){
- sigaddset(&action.sa_mask, mask);
- }
- va_end(ap);
- action.sa_flags = flags;
- action.sa_restorer = NULL;
- if(sigaction(sig, &action, NULL) < 0)
- panic("sigaction failed");
-}
-
-int change_sig(int signal, int on)
-{
- sigset_t sigset, old;
-
- sigemptyset(&sigset);
- sigaddset(&sigset, signal);
- sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
- return(!sigismember(&old, signal));
-}
-
-/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
- * disable profiling; it's safe because the profiling code does not interact
- * with the kernel code at all.*/
-
-static void change_signals(int type)
-{
- sigset_t mask;
-
- sigemptyset(&mask);
- sigaddset(&mask, SIGVTALRM);
- sigaddset(&mask, SIGALRM);
- sigaddset(&mask, SIGIO);
- if(sigprocmask(type, &mask, NULL) < 0)
- panic("Failed to change signal mask - errno = %d", errno);
-}
-
-void block_signals(void)
-{
- change_signals(SIG_BLOCK);
-}
-
-void unblock_signals(void)
-{
- change_signals(SIG_UNBLOCK);
-}
-
-/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled
- * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to
- * be able to profile all of UML, not just the non-critical sections. If
- * profiling is not thread-safe, then that is not my problem. We can disable
- * profiling when SMP is enabled in that case.
- */
-#define SIGIO_BIT 0
-#define SIGVTALRM_BIT 1
-
-static int enable_mask(sigset_t *mask)
-{
- int sigs;
-
- sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
- sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
- sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
- return(sigs);
-}
-
-int get_signals(void)
-{
- sigset_t mask;
-
- if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
- panic("Failed to get signal mask");
- return(enable_mask(&mask));
-}
-
-int set_signals(int enable)
-{
- sigset_t mask;
- int ret;
-
- sigemptyset(&mask);
- if(enable & (1 << SIGIO_BIT))
- sigaddset(&mask, SIGIO);
- if(enable & (1 << SIGVTALRM_BIT)){
- sigaddset(&mask, SIGVTALRM);
- sigaddset(&mask, SIGALRM);
- }
-
- /* This is safe - sigprocmask is guaranteed to copy locally the
- * value of new_set, do his work and then, at the end, write to
- * old_set.
- */
- if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
- panic("Failed to enable signals");
- ret = enable_mask(&mask);
- sigemptyset(&mask);
- if((enable & (1 << SIGIO_BIT)) == 0)
- sigaddset(&mask, SIGIO);
- if((enable & (1 << SIGVTALRM_BIT)) == 0){
- sigaddset(&mask, SIGVTALRM);
- sigaddset(&mask, SIGALRM);
- }
- if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
- panic("Failed to block signals");
-
- return(ret);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index 8de471b59c1..57181a920d4 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -1,12 +1,12 @@
-#
+#
# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
# Licensed under the GPL
#
-obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
- syscall.o tlb.o trap_user.o uaccess.o
+obj-y := clone.o exec_kern.o mem.o mmu.o process_kern.o \
+ syscall.o tlb.o uaccess.o
-USER_OBJS := process.o clone.o
+USER_OBJS := clone.o
include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
index cb37ce9124a..47b812b3bca 100644
--- a/arch/um/kernel/skas/clone.c
+++ b/arch/um/kernel/skas/clone.c
@@ -18,11 +18,10 @@
* on some systems.
*/
-#define STUB_DATA(field) (((struct stub_data *) UML_CONFIG_STUB_DATA)->field)
-
void __attribute__ ((__section__ (".__syscall_stub")))
stub_clone_handler(void)
{
+ struct stub_data *data = (struct stub_data *) UML_CONFIG_STUB_DATA;
long err;
err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
@@ -35,17 +34,21 @@ stub_clone_handler(void)
if(err)
goto out;
- err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
- (long) &STUB_DATA(timer), 0);
+ err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
+ (long) &data->timer, 0);
if(err)
goto out;
- err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA,
- UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
- MAP_FIXED | MAP_SHARED, STUB_DATA(fd),
- STUB_DATA(offset));
+ remap_stack(data->fd, data->offset);
+ goto done;
+
out:
- /* save current result. Parent: pid; child: retcode of mmap */
- STUB_DATA(err) = err;
+ /* save current result.
+ * Parent: pid;
+ * child: retcode of mmap already saved and it jumps around this
+ * assignment
+ */
+ data->err = err;
+ done:
trap_myself();
}
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
deleted file mode 100644
index 44110c521e4..00000000000
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SKAS_MMU_H
-#define __SKAS_MMU_H
-
-#include "linux/config.h"
-#include "mm_id.h"
-#include "asm/ldt.h"
-
-struct mmu_context_skas {
- struct mm_id id;
- unsigned long last_page_table;
-#ifdef CONFIG_3_LEVEL_PGTABLES
- unsigned long last_pmd;
-#endif
- uml_ldt_t ldt;
-};
-
-extern void switch_mm_skas(struct mm_id * mm_idp);
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h
deleted file mode 100644
index bcd26a6a388..00000000000
--- a/arch/um/kernel/skas/include/mode-skas.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __MODE_SKAS_H__
-#define __MODE_SKAS_H__
-
-#include <sysdep/ptrace.h>
-
-extern unsigned long exec_regs[];
-extern unsigned long exec_fp_regs[];
-extern unsigned long exec_fpx_regs[];
-extern int have_fpx_regs;
-
-extern void sig_handler_common_skas(int sig, void *sc_ptr);
-extern void halt_skas(void);
-extern void reboot_skas(void);
-extern void kill_off_processes_skas(void);
-extern int is_skas_winch(int pid, int fd, void *data);
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
deleted file mode 100644
index daa2f85b684..00000000000
--- a/arch/um/kernel/skas/include/skas.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SKAS_H
-#define __SKAS_H
-
-#include "mm_id.h"
-#include "sysdep/ptrace.h"
-
-extern int userspace_pid[];
-extern int proc_mm, ptrace_faultinfo, ptrace_ldt;
-extern int skas_needs_stub;
-
-extern void switch_threads(void *me, void *next);
-extern void thread_wait(void *sw, void *fb);
-extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
- void (*handler)(int));
-extern int start_idle_thread(void *stack, void *switch_buf_ptr,
- void **fork_buf_ptr);
-extern int user_thread(unsigned long stack, int flags);
-extern void userspace(union uml_pt_regs *regs);
-extern void new_thread_proc(void *stack, void (*handler)(int sig));
-extern void remove_sigstack(void);
-extern void new_thread_handler(int sig);
-extern void handle_syscall(union uml_pt_regs *regs);
-extern int map(struct mm_id * mm_idp, unsigned long virt,
- unsigned long len, int r, int w, int x, int phys_fd,
- unsigned long long offset, int done, void **data);
-extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len,
- int done, void **data);
-extern int protect(struct mm_id * mm_idp, unsigned long addr,
- unsigned long len, int r, int w, int x, int done,
- void **data);
-extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
-extern int new_mm(int from, unsigned long stack);
-extern int start_userspace(unsigned long stub_stack);
-extern int copy_context_skas0(unsigned long stack, int pid);
-extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
-extern long execute_syscall_skas(void *r);
-extern unsigned long current_stub_stack(void);
-extern long run_syscall_stub(struct mm_id * mm_idp,
- int syscall, unsigned long *args, long expected,
- void **addr, int done);
-extern long syscall_stub_data(struct mm_id * mm_idp,
- unsigned long *data, int data_count,
- void **addr, void **stub_addr);
-
-#endif
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 677871f1b37..c5c9885a829 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -78,7 +78,7 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
struct mmu_context_skas *from_mm = NULL;
struct mmu_context_skas *to_mm = &mm->context.skas;
unsigned long stack = 0;
- int from_fd, ret = -ENOMEM;
+ int ret = -ENOMEM;
if(skas_needs_stub){
stack = get_zeroed_page(GFP_KERNEL);
@@ -108,11 +108,7 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
from_mm = &current->mm->context.skas;
if(proc_mm){
- if(from_mm)
- from_fd = from_mm->id.u.mm_fd;
- else from_fd = -1;
-
- ret = new_mm(from_fd, stack);
+ ret = new_mm(stack);
if(ret < 0){
printk("init_new_context_skas - new_mm failed, "
"errno = %d\n", ret);
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 599d679bd4f..eea1c9c4bb0 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -18,7 +18,6 @@
#include <asm/types.h>
#include "user.h"
#include "ptrace_user.h"
-#include "time_user.h"
#include "sysdep/ptrace.h"
#include "user_util.h"
#include "kern_util.h"
@@ -31,7 +30,6 @@
#include "proc_mm.h"
#include "skas_ptrace.h"
#include "chan_user.h"
-#include "signal_user.h"
#include "registers.h"
#include "mem.h"
#include "uml-config.h"
@@ -69,7 +67,7 @@ void wait_stub_done(int pid, int sig, char * fname)
if((n < 0) || !WIFSTOPPED(status) ||
(WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){
- unsigned long regs[FRAME_SIZE];
+ unsigned long regs[HOST_FRAME_SIZE];
if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
printk("Failed to get registers from stub, "
"errno = %d\n", errno);
@@ -77,7 +75,7 @@ void wait_stub_done(int pid, int sig, char * fname)
int i;
printk("Stub registers -\n");
- for(i = 0; i < FRAME_SIZE; i++)
+ for(i = 0; i < HOST_FRAME_SIZE; i++)
printk("\t%d - %lx\n", i, regs[i]);
}
panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
@@ -514,16 +512,6 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
siglongjmp(**switch_buf, 1);
}
-void remove_sigstack(void)
-{
- stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
- .ss_sp = NULL,
- .ss_size = 0 });
-
- if(sigaltstack(&stack, NULL) != 0)
- panic("disabling signal stack failed, errno = %d\n", errno);
-}
-
void initial_thread_cb_skas(void (*proc)(void *), void *arg)
{
sigjmp_buf here;
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index 9c990253966..3f70a2e12f0 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -13,15 +13,12 @@
#include "asm/uaccess.h"
#include "asm/atomic.h"
#include "kern_util.h"
-#include "time_user.h"
-#include "signal_user.h"
#include "skas.h"
#include "os.h"
#include "user_util.h"
#include "tlb.h"
#include "kern.h"
#include "mode.h"
-#include "proc_mm.h"
#include "registers.h"
void switch_to_skas(void *prev, void *next)
@@ -35,7 +32,7 @@ void switch_to_skas(void *prev, void *next)
if(current->pid == 0)
switch_timers(0);
- switch_threads(&from->thread.mode.skas.switch_buf,
+ switch_threads(&from->thread.mode.skas.switch_buf,
to->thread.mode.skas.switch_buf);
if(current->pid == 0)
@@ -51,8 +48,8 @@ void new_thread_handler(int sig)
fn = current->thread.request.u.thread.proc;
arg = current->thread.request.u.thread.arg;
- change_sig(SIGUSR1, 1);
- thread_wait(&current->thread.mode.skas.switch_buf,
+ os_usr1_signal(1);
+ thread_wait(&current->thread.mode.skas.switch_buf,
current->thread.mode.skas.fork_buf);
if(current->thread.prev_sched != NULL)
@@ -83,8 +80,8 @@ void release_thread_skas(struct task_struct *task)
void fork_handler(int sig)
{
- change_sig(SIGUSR1, 1);
- thread_wait(&current->thread.mode.skas.switch_buf,
+ os_usr1_signal(1);
+ thread_wait(&current->thread.mode.skas.switch_buf,
current->thread.mode.skas.fork_buf);
force_flush_all();
@@ -94,13 +91,13 @@ void fork_handler(int sig)
schedule_tail(current->thread.prev_sched);
current->thread.prev_sched = NULL;
- /* Handle any immediate reschedules or signals */
+/* Handle any immediate reschedules or signals */
interrupt_end();
userspace(&current->thread.regs.regs);
}
int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
- unsigned long stack_top, struct task_struct * p,
+ unsigned long stack_top, struct task_struct * p,
struct pt_regs *regs)
{
void (*handler)(int);
@@ -119,32 +116,19 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
handler = new_thread_handler;
}
- new_thread(p->thread_info, &p->thread.mode.skas.switch_buf,
+ new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf,
&p->thread.mode.skas.fork_buf, handler);
return(0);
}
-extern void map_stub_pages(int fd, unsigned long code,
- unsigned long data, unsigned long stack);
-int new_mm(int from, unsigned long stack)
+int new_mm(unsigned long stack)
{
- struct proc_mm_op copy;
- int n, fd;
+ int fd;
fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
if(fd < 0)
return(fd);
- if(from != -1){
- copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS,
- .u =
- { .copy_segments = from } } );
- n = os_write_file(fd, &copy, sizeof(copy));
- if(n != sizeof(copy))
- printk("new_mm : /proc/mm copy_segments failed, "
- "err = %d\n", -n);
- }
-
if(skas_needs_stub)
map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack);
@@ -186,7 +170,7 @@ int start_uml_skas(void)
init_task.thread.request.u.thread.proc = start_kernel_proc;
init_task.thread.request.u.thread.arg = NULL;
- return(start_idle_thread(init_task.thread_info,
+ return(start_idle_thread(task_stack_page(&init_task),
&init_task.thread.mode.skas.switch_buf,
&init_task.thread.mode.skas.fork_buf));
}
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
index a5a47528dec..5992c325716 100644
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -13,7 +13,7 @@
#include "asm/pgtable.h"
#include "asm/uaccess.h"
#include "kern_util.h"
-#include "user_util.h"
+#include "os.h"
extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
pte_t *pte_out);
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
index 1429c131879..1731d90e685 100644
--- a/arch/um/kernel/syscall.c
+++ b/arch/um/kernel/syscall.c
@@ -25,12 +25,12 @@ int record_syscall_start(int syscall)
syscall_record[index].syscall = syscall;
syscall_record[index].pid = current_pid();
syscall_record[index].result = 0xdeadbeef;
- syscall_record[index].start = os_usecs();
+ syscall_record[index].start = os_nsecs();
return(index);
}
void record_syscall_end(int index, long result)
{
syscall_record[index].result = result;
- syscall_record[index].end = os_usecs();
+ syscall_record[index].end = os_nsecs();
}
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index c40b611e3d9..8fa2ae7f302 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -14,9 +14,9 @@
#include "kern_util.h"
#include "user.h"
#include "process.h"
-#include "signal_user.h"
#include "time_user.h"
#include "kern_constants.h"
+#include "os.h"
/* XXX This really needs to be declared and initialized in a kernel file since
* it's in <linux/time.h>
@@ -99,7 +99,8 @@ void uml_idle_timer(void)
set_interval(ITIMER_REAL);
}
-extern int do_posix_clock_monotonic_gettime(struct timespec *tp);
+extern void ktime_get_ts(struct timespec *ts);
+#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
void time_init(void)
{
@@ -114,8 +115,8 @@ void time_init(void)
wall_to_monotonic.tv_nsec = -now.tv_nsec;
}
-/* Declared in linux/time.h, which can't be included here */
-extern void clock_was_set(void);
+/* Defined in linux/ktimer.h, which can't be included here */
+#define clock_was_set() do { } while (0)
void do_gettimeofday(struct timeval *tv)
{
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
index 020ca79b8d3..3c7626cdba4 100644
--- a/arch/um/kernel/time_kern.c
+++ b/arch/um/kernel/time_kern.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -13,12 +13,12 @@
#include "linux/interrupt.h"
#include "linux/init.h"
#include "linux/delay.h"
+#include "linux/hrtimer.h"
#include "asm/irq.h"
#include "asm/param.h"
#include "asm/current.h"
#include "kern_util.h"
#include "user_util.h"
-#include "time_user.h"
#include "mode.h"
#include "os.h"
@@ -39,7 +39,7 @@ unsigned long long sched_clock(void)
int timer_irq_inited = 0;
static int first_tick;
-static unsigned long long prev_usecs;
+static unsigned long long prev_nsecs;
#ifdef CONFIG_UML_REAL_TIME_CLOCK
static long long delta; /* Deviation per interval */
#endif
@@ -58,23 +58,23 @@ void timer_irq(union uml_pt_regs *regs)
if(first_tick){
#ifdef CONFIG_UML_REAL_TIME_CLOCK
/* We've had 1 tick */
- unsigned long long usecs = os_usecs();
+ unsigned long long nsecs = os_nsecs();
- delta += usecs - prev_usecs;
- prev_usecs = usecs;
+ delta += nsecs - prev_nsecs;
+ prev_nsecs = nsecs;
/* Protect against the host clock being set backwards */
if(delta < 0)
delta = 0;
- ticks += (delta * HZ) / MILLION;
- delta -= (ticks * MILLION) / HZ;
+ ticks += (delta * HZ) / BILLION;
+ delta -= (ticks * BILLION) / HZ;
#else
ticks = 1;
#endif
}
else {
- prev_usecs = os_usecs();
+ prev_nsecs = os_nsecs();
first_tick = 1;
}
@@ -84,49 +84,102 @@ void timer_irq(union uml_pt_regs *regs)
}
}
-void boot_timer_handler(int sig)
+void do_boot_timer_handler(struct sigcontext * sc)
{
struct pt_regs regs;
- CHOOSE_MODE((void)
- (UPT_SC(&regs.regs) = (struct sigcontext *) (&sig + 1)),
+ CHOOSE_MODE((void) (UPT_SC(&regs.regs) = sc),
(void) (regs.regs.skas.is_user = 0));
do_timer(&regs);
}
+static DEFINE_SPINLOCK(timer_spinlock);
+
+static unsigned long long local_offset = 0;
+
+static inline unsigned long long get_time(void)
+{
+ unsigned long long nsecs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&timer_spinlock, flags);
+ nsecs = os_nsecs();
+ nsecs += local_offset;
+ spin_unlock_irqrestore(&timer_spinlock, flags);
+
+ return nsecs;
+}
+
irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
{
+ unsigned long long nsecs;
unsigned long flags;
do_timer(regs);
+
write_seqlock_irqsave(&xtime_lock, flags);
- timer();
+ nsecs = get_time() + local_offset;
+ xtime.tv_sec = nsecs / NSEC_PER_SEC;
+ xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC;
write_sequnlock_irqrestore(&xtime_lock, flags);
+
return(IRQ_HANDLED);
}
long um_time(int __user *tloc)
{
- struct timeval now;
+ long ret = get_time() / NSEC_PER_SEC;
- do_gettimeofday(&now);
- if (tloc) {
- if (put_user(now.tv_sec, tloc))
- now.tv_sec = -EFAULT;
- }
- return now.tv_sec;
+ if((tloc != NULL) && put_user(ret, tloc))
+ return -EFAULT;
+
+ return ret;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long long nsecs = get_time();
+
+ tv->tv_sec = nsecs / NSEC_PER_SEC;
+ /* Careful about calculations here - this was originally done as
+ * (nsecs - tv->tv_sec * NSEC_PER_SEC) / NSEC_PER_USEC
+ * which gave bogus (> 1000000) values. Dunno why, suspect gcc
+ * (4.0.0) miscompiled it, or there's a subtle 64/32-bit conversion
+ * problem that I missed.
+ */
+ nsecs -= tv->tv_sec * NSEC_PER_SEC;
+ tv->tv_usec = (unsigned long) nsecs / NSEC_PER_USEC;
+}
+
+static inline void set_time(unsigned long long nsecs)
+{
+ unsigned long long now;
+ unsigned long flags;
+
+ spin_lock_irqsave(&timer_spinlock, flags);
+ now = os_nsecs();
+ local_offset = nsecs - now;
+ spin_unlock_irqrestore(&timer_spinlock, flags);
+
+ clock_was_set();
}
long um_stime(int __user *tptr)
{
int value;
- struct timespec new;
if (get_user(value, tptr))
return -EFAULT;
- new.tv_sec = value;
- new.tv_nsec = 0;
- do_settimeofday(&new);
+
+ set_time((unsigned long long) value * NSEC_PER_SEC);
+
+ return 0;
+}
+
+int do_settimeofday(struct timespec *tv)
+{
+ set_time((unsigned long long) tv->tv_sec * NSEC_PER_SEC + tv->tv_nsec);
+
return 0;
}
@@ -134,29 +187,15 @@ void timer_handler(int sig, union uml_pt_regs *regs)
{
local_irq_disable();
irq_enter();
- update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)),
- (regs)->skas.is_user));
+ update_process_times(CHOOSE_MODE(
+ (UPT_SC(regs) && user_context(UPT_SP(regs))),
+ (regs)->skas.is_user));
irq_exit();
local_irq_enable();
if(current_thread->cpu == 0)
timer_irq(regs);
}
-static DEFINE_SPINLOCK(timer_spinlock);
-
-unsigned long time_lock(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&timer_spinlock, flags);
- return(flags);
-}
-
-void time_unlock(unsigned long flags)
-{
- spin_unlock_irqrestore(&timer_spinlock, flags);
-}
-
int __init timer_init(void)
{
int err;
@@ -171,14 +210,3 @@ int __init timer_init(void)
}
__initcall(timer_init);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
index 0d4c10a7360..d56046c2aba 100644
--- a/arch/um/kernel/trap_kern.c
+++ b/arch/um/kernel/trap_kern.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -26,9 +26,13 @@
#include "mconsole_kern.h"
#include "mem.h"
#include "mem_kern.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/ptrace.h"
+#include "os.h"
#ifdef CONFIG_MODE_SKAS
#include "skas.h"
#endif
+#include "os.h"
/* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */
int handle_page_fault(unsigned long address, unsigned long ip,
@@ -125,6 +129,25 @@ out_of_memory:
goto out;
}
+void segv_handler(int sig, union uml_pt_regs *regs)
+{
+ struct faultinfo * fi = UPT_FAULTINFO(regs);
+
+ if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){
+ bad_segv(*fi, UPT_IP(regs));
+ return;
+ }
+ segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
+}
+
+struct kern_handlers handlinfo_kern = {
+ .relay_signal = relay_signal,
+ .winch = winch,
+ .bus_handler = relay_signal,
+ .page_fault = segv_handler,
+ .sigio_handler = sigio_handler,
+ .timer_handler = timer_handler
+};
/*
* We give a *copy* of the faultinfo in the regs to segv.
* This must be done, since nesting SEGVs could overwrite
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
deleted file mode 100644
index e9ccd6b8d3c..00000000000
--- a/arch/um/kernel/trap_user.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <stdlib.h>
-#include <errno.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <asm/page.h>
-#include <asm/unistd.h>
-#include <asm/ptrace.h>
-#include "init.h"
-#include "sysdep/ptrace.h"
-#include "sigcontext.h"
-#include "sysdep/sigcontext.h"
-#include "irq_user.h"
-#include "signal_user.h"
-#include "time_user.h"
-#include "task.h"
-#include "mode.h"
-#include "choose-mode.h"
-#include "kern_util.h"
-#include "user_util.h"
-#include "os.h"
-
-void kill_child_dead(int pid)
-{
- kill(pid, SIGKILL);
- kill(pid, SIGCONT);
- do {
- int n;
- CATCH_EINTR(n = waitpid(pid, NULL, 0));
- if (n > 0)
- kill(pid, SIGCONT);
- else
- break;
- } while(1);
-}
-
-void segv_handler(int sig, union uml_pt_regs *regs)
-{
- struct faultinfo * fi = UPT_FAULTINFO(regs);
-
- if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){
- bad_segv(*fi, UPT_IP(regs));
- return;
- }
- segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
-}
-
-void usr2_handler(int sig, union uml_pt_regs *regs)
-{
- CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0);
-}
-
-struct signal_info sig_info[] = {
- [ SIGTRAP ] { .handler = relay_signal,
- .is_irq = 0 },
- [ SIGFPE ] { .handler = relay_signal,
- .is_irq = 0 },
- [ SIGILL ] { .handler = relay_signal,
- .is_irq = 0 },
- [ SIGWINCH ] { .handler = winch,
- .is_irq = 1 },
- [ SIGBUS ] { .handler = bus_handler,
- .is_irq = 0 },
- [ SIGSEGV] { .handler = segv_handler,
- .is_irq = 0 },
- [ SIGIO ] { .handler = sigio_handler,
- .is_irq = 1 },
- [ SIGVTALRM ] { .handler = timer_handler,
- .is_irq = 1 },
- [ SIGALRM ] { .handler = timer_handler,
- .is_irq = 1 },
- [ SIGUSR2 ] { .handler = usr2_handler,
- .is_irq = 0 },
-};
-
-void do_longjmp(void *b, int val)
-{
- sigjmp_buf *buf = b;
-
- siglongjmp(*buf, val);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
index 065b504a653..5c1e4cc1c04 100644
--- a/arch/um/kernel/tt/exec_kern.c
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -13,8 +13,6 @@
#include "user_util.h"
#include "kern_util.h"
#include "irq_user.h"
-#include "time_user.h"
-#include "signal_user.h"
#include "mem_user.h"
#include "os.h"
#include "tlb.h"
@@ -40,7 +38,7 @@ void flush_thread_tt(void)
do_exit(SIGKILL);
}
- new_pid = start_fork_tramp(current->thread_info, stack, 0, exec_tramp);
+ new_pid = start_fork_tramp(task_stack_page(current), stack, 0, exec_tramp);
if(new_pid < 0){
printk(KERN_ERR
"flush_thread : new thread failed, errno = %d\n",
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
index 37e22d71a0d..786e4edd86c 100644
--- a/arch/um/kernel/tt/gdb.c
+++ b/arch/um/kernel/tt/gdb.c
@@ -20,6 +20,7 @@
#include "user_util.h"
#include "tt.h"
#include "sysdep/thread.h"
+#include "os.h"
extern int debugger_pid;
extern int debugger_fd;
diff --git a/arch/um/kernel/tt/include/mmu-tt.h b/arch/um/kernel/tt/include/mmu-tt.h
deleted file mode 100644
index 0440510ab3f..00000000000
--- a/arch/um/kernel/tt/include/mmu-tt.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __TT_MMU_H
-#define __TT_MMU_H
-
-struct mmu_context_tt {
-};
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
index cfaa373a6e7..295c1ac817b 100644
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -13,13 +13,11 @@
#include "asm/ptrace.h"
#include "asm/tlbflush.h"
#include "irq_user.h"
-#include "signal_user.h"
#include "kern_util.h"
#include "user_util.h"
#include "os.h"
#include "kern.h"
#include "sigcontext.h"
-#include "time_user.h"
#include "mem_user.h"
#include "tlb.h"
#include "mode.h"
@@ -37,7 +35,7 @@ void switch_to_tt(void *prev, void *next)
from = prev;
to = next;
- cpu = from->thread_info->cpu;
+ cpu = task_thread_info(from)->cpu;
if(cpu == 0)
forward_interrupts(to->thread.mode.tt.extern_pid);
#ifdef CONFIG_SMP
@@ -254,7 +252,7 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
clone_flags &= CLONE_VM;
p->thread.temp_stack = stack;
- new_pid = start_fork_tramp(p->thread_info, stack, clone_flags, tramp);
+ new_pid = start_fork_tramp(task_stack_page(p), stack, clone_flags, tramp);
if(new_pid < 0){
printk(KERN_ERR "copy_thread : clone failed - errno = %d\n",
-new_pid);
@@ -344,7 +342,7 @@ int do_proc_op(void *t, int proc_id)
pid = thread->request.u.exec.pid;
do_exec(thread->mode.tt.extern_pid, pid);
thread->mode.tt.extern_pid = pid;
- cpu_tasks[task->thread_info->cpu].pid = pid;
+ cpu_tasks[task_thread_info(task)->cpu].pid = pid;
break;
case OP_FORK:
attach_process(thread->request.u.fork.pid);
@@ -426,7 +424,7 @@ int start_uml_tt(void)
int pages;
pages = (1 << CONFIG_KERNEL_STACK_ORDER);
- sp = (void *) ((unsigned long) init_task.thread_info) +
+ sp = task_stack_page(&init_task) +
pages * PAGE_SIZE - sizeof(unsigned long);
return(tracer(start_kernel_proc, sp));
}
diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
index 528a5fc8d88..03774427d46 100644
--- a/arch/um/kernel/tt/ptproxy/ptrace.c
+++ b/arch/um/kernel/tt/ptproxy/ptrace.c
@@ -20,6 +20,7 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml
#include "kern_util.h"
#include "ptrace_user.h"
#include "tt.h"
+#include "os.h"
long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
long arg3, long arg4, pid_t child, int *ret)
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
index a5f0e01e214..99f178319d0 100644
--- a/arch/um/kernel/tt/ptproxy/sysdep.c
+++ b/arch/um/kernel/tt/ptproxy/sysdep.c
@@ -15,6 +15,7 @@ terms and conditions.
#include "ptrace_user.h"
#include "user_util.h"
#include "user.h"
+#include "os.h"
int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4,
long *arg5)
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
index d11e7399d7a..71daae24e48 100644
--- a/arch/um/kernel/tt/tracer.c
+++ b/arch/um/kernel/tt/tracer.c
@@ -19,7 +19,6 @@
#include "sigcontext.h"
#include "sysdep/sigcontext.h"
#include "os.h"
-#include "signal_user.h"
#include "user_util.h"
#include "mem_user.h"
#include "process.h"
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c
index fc108615bea..b5d9d64d91e 100644
--- a/arch/um/kernel/tt/trap_user.c
+++ b/arch/um/kernel/tt/trap_user.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -8,18 +8,18 @@
#include <signal.h>
#include "sysdep/ptrace.h"
#include "sysdep/sigcontext.h"
-#include "signal_user.h"
#include "user_util.h"
#include "kern_util.h"
#include "task.h"
#include "tt.h"
+#include "os.h"
void sig_handler_common_tt(int sig, void *sc_ptr)
{
struct sigcontext *sc = sc_ptr;
struct tt_regs save_regs, *r;
- struct signal_info *info;
- int save_errno = errno, is_user;
+ int save_errno = errno, is_user = 0;
+ void (*handler)(int, union uml_pt_regs *);
/* This is done because to allow SIGSEGV to be delivered inside a SEGV
* handler. This can happen in copy_user, and if SEGV is disabled,
@@ -35,15 +35,20 @@ void sig_handler_common_tt(int sig, void *sc_ptr)
GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
}
save_regs = *r;
- is_user = user_context(SC_SP(sc));
+ if (sc)
+ is_user = user_context(SC_SP(sc));
r->sc = sc;
if(sig != SIGUSR2)
r->syscall = -1;
- info = &sig_info[sig];
- if(!info->is_irq) unblock_signals();
+ handler = sig_info[sig];
+
+ /* unblock SIGALRM, SIGVTALRM, SIGIO if sig isn't IRQ signal */
+ if (sig != SIGIO && sig != SIGWINCH &&
+ sig != SIGVTALRM && sig != SIGALRM)
+ unblock_signals();
- (*info->handler)(sig, (union uml_pt_regs *) r);
+ handler(sig, (union uml_pt_regs *) r);
if(is_user){
interrupt_end();
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 142a9493912..e2d3ca445ef 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -146,8 +146,8 @@ void set_cmdline(char *cmd)
if(CHOOSE_MODE(honeypot, 0)) return;
- umid = get_umid(1);
- if(umid != NULL){
+ umid = get_umid();
+ if(*umid != '\0'){
snprintf(argv1_begin,
(argv1_end - argv1_begin) * sizeof(*ptr),
"(%s) ", umid);
@@ -243,10 +243,6 @@ static int __init mode_tt_setup(char *line, int *add)
return(0);
}
-#else
-
-#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled
-
#endif
#endif
#endif
@@ -363,6 +359,11 @@ int linux_main(int argc, char **argv)
uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
&host_task_size, &task_size);
+ /*
+ * Setting up handlers to 'sig_info' struct
+ */
+ os_fill_handlinfo(handlinfo_kern);
+
brk_start = (unsigned long) sbrk(0);
CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
/* Increase physical memory size for exec-shield users
diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
index 0b21d59ba0c..4eaee823bfd 100644
--- a/arch/um/kernel/umid.c
+++ b/arch/um/kernel/umid.c
@@ -3,61 +3,30 @@
* Licensed under the GPL
*/
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <dirent.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include "user.h"
-#include "umid.h"
+#include "asm/errno.h"
#include "init.h"
#include "os.h"
-#include "user_util.h"
-#include "choose-mode.h"
+#include "kern.h"
+#include "linux/kernel.h"
-#define UMID_LEN 64
-#define UML_DIR "~/.uml/"
-
-/* Changed by set_umid and make_umid, which are run early in boot */
-static char umid[UMID_LEN] = { 0 };
-
-/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */
-static char *uml_dir = UML_DIR;
-
-/* Changed by set_umid */
-static int umid_is_random = 1;
+/* Changed by set_umid_arg */
static int umid_inited = 0;
-/* Have we created the files? Should we remove them? */
-static int umid_owned = 0;
-static int make_umid(int (*printer)(const char *fmt, ...));
-
-static int __init set_umid(char *name, int is_random,
- int (*printer)(const char *fmt, ...))
+static int __init set_umid_arg(char *name, int *add)
{
- if(umid_inited){
- (*printer)("Unique machine name can't be set twice\n");
- return(-1);
- }
+ int err;
- if(strlen(name) > UMID_LEN - 1)
- (*printer)("Unique machine name is being truncated to %d "
- "characters\n", UMID_LEN);
- strlcpy(umid, name, sizeof(umid));
+ if(umid_inited)
+ return 0;
- umid_is_random = is_random;
- umid_inited = 1;
- return 0;
-}
-
-static int __init set_umid_arg(char *name, int *add)
-{
*add = 0;
- return(set_umid(name, 0, printf));
+ err = set_umid(name);
+ if(err == -EEXIST)
+ printf("umid '%s' already in use\n", name);
+ else if(!err)
+ umid_inited = 1;
+
+ return 0;
}
__uml_setup("umid=", set_umid_arg,
@@ -66,265 +35,3 @@ __uml_setup("umid=", set_umid_arg,
" is used for naming the pid file and management console socket.\n\n"
);
-int __init umid_file_name(char *name, char *buf, int len)
-{
- int n;
-
- if(!umid_inited && make_umid(printk)) return(-1);
-
- n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
- if(n > len){
- printk("umid_file_name : buffer too short\n");
- return(-1);
- }
-
- sprintf(buf, "%s%s/%s", uml_dir, umid, name);
- return(0);
-}
-
-extern int tracing_pid;
-
-static void __init create_pid_file(void)
-{
- char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
- char pid[sizeof("nnnnn\0")];
- int fd, n;
-
- if(umid_file_name("pid", file, sizeof(file)))
- return;
-
- fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))),
- 0644);
- if(fd < 0){
- printf("Open of machine pid file \"%s\" failed: %s\n",
- file, strerror(-fd));
- return;
- }
-
- sprintf(pid, "%d\n", os_getpid());
- n = os_write_file(fd, pid, strlen(pid));
- if(n != strlen(pid))
- printf("Write of pid file failed - err = %d\n", -n);
- os_close_file(fd);
-}
-
-static int actually_do_remove(char *dir)
-{
- DIR *directory;
- struct dirent *ent;
- int len;
- char file[256];
-
- directory = opendir(dir);
- if(directory == NULL){
- printk("actually_do_remove : couldn't open directory '%s', "
- "errno = %d\n", dir, errno);
- return(1);
- }
- while((ent = readdir(directory)) != NULL){
- if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
- continue;
- len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1;
- if(len > sizeof(file)){
- printk("Not deleting '%s' from '%s' - name too long\n",
- ent->d_name, dir);
- continue;
- }
- sprintf(file, "%s/%s", dir, ent->d_name);
- if(unlink(file) < 0){
- printk("actually_do_remove : couldn't remove '%s' "
- "from '%s', errno = %d\n", ent->d_name, dir,
- errno);
- return(1);
- }
- }
- if(rmdir(dir) < 0){
- printk("actually_do_remove : couldn't rmdir '%s', "
- "errno = %d\n", dir, errno);
- return(1);
- }
- return(0);
-}
-
-void remove_umid_dir(void)
-{
- char dir[strlen(uml_dir) + UMID_LEN + 1];
- if (!umid_owned)
- return;
-
- sprintf(dir, "%s%s", uml_dir, umid);
- actually_do_remove(dir);
-}
-
-char *get_umid(int only_if_set)
-{
- if(only_if_set && umid_is_random)
- return NULL;
- return umid;
-}
-
-static int not_dead_yet(char *dir)
-{
- char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
- char pid[sizeof("nnnnn\0")], *end;
- int dead, fd, p, n;
-
- sprintf(file, "%s/pid", dir);
- dead = 0;
- fd = os_open_file(file, of_read(OPENFLAGS()), 0);
- if(fd < 0){
- if(fd != -ENOENT){
- printk("not_dead_yet : couldn't open pid file '%s', "
- "err = %d\n", file, -fd);
- return(1);
- }
- dead = 1;
- }
- if(fd > 0){
- n = os_read_file(fd, pid, sizeof(pid));
- if(n < 0){
- printk("not_dead_yet : couldn't read pid file '%s', "
- "err = %d\n", file, -n);
- return(1);
- }
- p = strtoul(pid, &end, 0);
- if(end == pid){
- printk("not_dead_yet : couldn't parse pid file '%s', "
- "errno = %d\n", file, errno);
- dead = 1;
- }
- if(((kill(p, 0) < 0) && (errno == ESRCH)) ||
- (p == CHOOSE_MODE(tracing_pid, os_getpid())))
- dead = 1;
- }
- if(!dead)
- return(1);
- return(actually_do_remove(dir));
-}
-
-static int __init set_uml_dir(char *name, int *add)
-{
- if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
- uml_dir = malloc(strlen(name) + 2);
- if(uml_dir == NULL){
- printf("Failed to malloc uml_dir - error = %d\n",
- errno);
- uml_dir = name;
- /* Return 0 here because do_initcalls doesn't look at
- * the return value.
- */
- return(0);
- }
- sprintf(uml_dir, "%s/", name);
- }
- else uml_dir = name;
- return(0);
-}
-
-static int __init make_uml_dir(void)
-{
- char dir[MAXPATHLEN + 1] = { '\0' };
- int len;
-
- if(*uml_dir == '~'){
- char *home = getenv("HOME");
-
- if(home == NULL){
- printf("make_uml_dir : no value in environment for "
- "$HOME\n");
- exit(1);
- }
- strlcpy(dir, home, sizeof(dir));
- uml_dir++;
- }
- strlcat(dir, uml_dir, sizeof(dir));
- len = strlen(dir);
- if (len > 0 && dir[len - 1] != '/')
- strlcat(dir, "/", sizeof(dir));
-
- uml_dir = malloc(strlen(dir) + 1);
- if (uml_dir == NULL) {
- printf("make_uml_dir : malloc failed, errno = %d\n", errno);
- exit(1);
- }
- strcpy(uml_dir, dir);
-
- if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
- printf("Failed to mkdir %s: %s\n", uml_dir, strerror(errno));
- return(-1);
- }
- return 0;
-}
-
-static int __init make_umid(int (*printer)(const char *fmt, ...))
-{
- int fd, err;
- char tmp[strlen(uml_dir) + UMID_LEN + 1];
-
- strlcpy(tmp, uml_dir, sizeof(tmp));
-
- if(!umid_inited){
- strcat(tmp, "XXXXXX");
- fd = mkstemp(tmp);
- if(fd < 0){
- (*printer)("make_umid - mkstemp(%s) failed: %s\n",
- tmp,strerror(errno));
- return(1);
- }
-
- os_close_file(fd);
- /* There's a nice tiny little race between this unlink and
- * the mkdir below. It'd be nice if there were a mkstemp
- * for directories.
- */
- unlink(tmp);
- set_umid(&tmp[strlen(uml_dir)], 1, printer);
- }
-
- sprintf(tmp, "%s%s", uml_dir, umid);
-
- err = mkdir(tmp, 0777);
- if(err < 0){
- if(errno == EEXIST){
- if(not_dead_yet(tmp)){
- (*printer)("umid '%s' is in use\n", umid);
- umid_owned = 0;
- return(-1);
- }
- err = mkdir(tmp, 0777);
- }
- }
- if(err < 0){
- (*printer)("Failed to create %s - errno = %d\n", umid, errno);
- return(-1);
- }
-
- umid_owned = 1;
- return 0;
-}
-
-__uml_setup("uml_dir=", set_uml_dir,
-"uml_dir=<directory>\n"
-" The location to place the pid and umid files.\n\n"
-);
-
-static int __init make_umid_setup(void)
-{
- /* one function with the ordering we need ... */
- make_uml_dir();
- make_umid(printf);
- create_pid_file();
- return 0;
-}
-__uml_postsetup(make_umid_setup);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index b83ac8e21c3..08a4e628b24 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -4,11 +4,13 @@
#
obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \
- start_up.o time.o tt.o tty.o uaccess.o user_syms.o drivers/ \
- sys-$(SUBARCH)/
+ start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \
+ util.o drivers/ sys-$(SUBARCH)/
+
+obj-$(CONFIG_MODE_SKAS) += skas/
USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \
- start_up.o time.o tt.o tty.o uaccess.o
+ start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o util.o
elf_aux.o: $(ARCH_DIR)/kernel-offsets.h
CFLAGS_elf_aux.o += -I$(objtree)/arch/um
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
index ffa759addd3..f897140cc4a 100644
--- a/arch/um/os-Linux/aio.c
+++ b/arch/um/os-Linux/aio.c
@@ -16,12 +16,12 @@
#include "mode.h"
struct aio_thread_req {
- enum aio_type type;
- int io_fd;
- unsigned long long offset;
- char *buf;
- int len;
- struct aio_context *aio;
+ enum aio_type type;
+ int io_fd;
+ unsigned long long offset;
+ char *buf;
+ int len;
+ struct aio_context *aio;
};
static int aio_req_fd_r = -1;
@@ -38,18 +38,18 @@ static int aio_req_fd_w = -1;
static long io_setup(int n, aio_context_t *ctxp)
{
- return syscall(__NR_io_setup, n, ctxp);
+ return syscall(__NR_io_setup, n, ctxp);
}
static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
{
- return syscall(__NR_io_submit, ctx, nr, iocbpp);
+ return syscall(__NR_io_submit, ctx, nr, iocbpp);
}
static long io_getevents(aio_context_t ctx_id, long min_nr, long nr,
- struct io_event *events, struct timespec *timeout)
+ struct io_event *events, struct timespec *timeout)
{
- return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout);
+ return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout);
}
#endif
@@ -66,243 +66,245 @@ static long io_getevents(aio_context_t ctx_id, long min_nr, long nr,
*/
static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf,
- int len, unsigned long long offset, struct aio_context *aio)
+ int len, unsigned long long offset, struct aio_context *aio)
{
- struct iocb iocb, *iocbp = &iocb;
- char c;
- int err;
-
- iocb = ((struct iocb) { .aio_data = (unsigned long) aio,
- .aio_reqprio = 0,
- .aio_fildes = fd,
- .aio_buf = (unsigned long) buf,
- .aio_nbytes = len,
- .aio_offset = offset,
- .aio_reserved1 = 0,
- .aio_reserved2 = 0,
- .aio_reserved3 = 0 });
-
- switch(type){
- case AIO_READ:
- iocb.aio_lio_opcode = IOCB_CMD_PREAD;
- err = io_submit(ctx, 1, &iocbp);
- break;
- case AIO_WRITE:
- iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
- err = io_submit(ctx, 1, &iocbp);
- break;
- case AIO_MMAP:
- iocb.aio_lio_opcode = IOCB_CMD_PREAD;
- iocb.aio_buf = (unsigned long) &c;
- iocb.aio_nbytes = sizeof(c);
- err = io_submit(ctx, 1, &iocbp);
- break;
- default:
- printk("Bogus op in do_aio - %d\n", type);
- err = -EINVAL;
- break;
- }
-
- if(err > 0)
- err = 0;
+ struct iocb iocb, *iocbp = &iocb;
+ char c;
+ int err;
+
+ iocb = ((struct iocb) { .aio_data = (unsigned long) aio,
+ .aio_reqprio = 0,
+ .aio_fildes = fd,
+ .aio_buf = (unsigned long) buf,
+ .aio_nbytes = len,
+ .aio_offset = offset,
+ .aio_reserved1 = 0,
+ .aio_reserved2 = 0,
+ .aio_reserved3 = 0 });
+
+ switch(type){
+ case AIO_READ:
+ iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+ err = io_submit(ctx, 1, &iocbp);
+ break;
+ case AIO_WRITE:
+ iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
+ err = io_submit(ctx, 1, &iocbp);
+ break;
+ case AIO_MMAP:
+ iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+ iocb.aio_buf = (unsigned long) &c;
+ iocb.aio_nbytes = sizeof(c);
+ err = io_submit(ctx, 1, &iocbp);
+ break;
+ default:
+ printk("Bogus op in do_aio - %d\n", type);
+ err = -EINVAL;
+ break;
+ }
+
+ if(err > 0)
+ err = 0;
else
err = -errno;
- return err;
+ return err;
}
static aio_context_t ctx = 0;
static int aio_thread(void *arg)
{
- struct aio_thread_reply reply;
- struct io_event event;
- int err, n, reply_fd;
-
- signal(SIGWINCH, SIG_IGN);
-
- while(1){
- n = io_getevents(ctx, 1, 1, &event, NULL);
- if(n < 0){
- if(errno == EINTR)
- continue;
- printk("aio_thread - io_getevents failed, "
- "errno = %d\n", errno);
- }
- else {
- reply = ((struct aio_thread_reply)
- { .data = (void *) (long) event.data,
- .err = event.res });
+ struct aio_thread_reply reply;
+ struct io_event event;
+ int err, n, reply_fd;
+
+ signal(SIGWINCH, SIG_IGN);
+
+ while(1){
+ n = io_getevents(ctx, 1, 1, &event, NULL);
+ if(n < 0){
+ if(errno == EINTR)
+ continue;
+ printk("aio_thread - io_getevents failed, "
+ "errno = %d\n", errno);
+ }
+ else {
+ reply = ((struct aio_thread_reply)
+ { .data = (void *) (long) event.data,
+ .err = event.res });
reply_fd = ((struct aio_context *) reply.data)->reply_fd;
err = os_write_file(reply_fd, &reply, sizeof(reply));
- if(err != sizeof(reply))
+ if(err != sizeof(reply))
printk("aio_thread - write failed, fd = %d, "
- "err = %d\n", aio_req_fd_r, -err);
- }
- }
- return 0;
+ "err = %d\n", aio_req_fd_r, -err);
+ }
+ }
+ return 0;
}
#endif
static int do_not_aio(struct aio_thread_req *req)
{
- char c;
- int err;
-
- switch(req->type){
- case AIO_READ:
- err = os_seek_file(req->io_fd, req->offset);
- if(err)
- goto out;
-
- err = os_read_file(req->io_fd, req->buf, req->len);
- break;
- case AIO_WRITE:
- err = os_seek_file(req->io_fd, req->offset);
- if(err)
- goto out;
-
- err = os_write_file(req->io_fd, req->buf, req->len);
- break;
- case AIO_MMAP:
- err = os_seek_file(req->io_fd, req->offset);
- if(err)
- goto out;
-
- err = os_read_file(req->io_fd, &c, sizeof(c));
- break;
- default:
- printk("do_not_aio - bad request type : %d\n", req->type);
- err = -EINVAL;
- break;
- }
-
- out:
- return err;
+ char c;
+ int err;
+
+ switch(req->type){
+ case AIO_READ:
+ err = os_seek_file(req->io_fd, req->offset);
+ if(err)
+ goto out;
+
+ err = os_read_file(req->io_fd, req->buf, req->len);
+ break;
+ case AIO_WRITE:
+ err = os_seek_file(req->io_fd, req->offset);
+ if(err)
+ goto out;
+
+ err = os_write_file(req->io_fd, req->buf, req->len);
+ break;
+ case AIO_MMAP:
+ err = os_seek_file(req->io_fd, req->offset);
+ if(err)
+ goto out;
+
+ err = os_read_file(req->io_fd, &c, sizeof(c));
+ break;
+ default:
+ printk("do_not_aio - bad request type : %d\n", req->type);
+ err = -EINVAL;
+ break;
+ }
+
+out:
+ return err;
}
static int not_aio_thread(void *arg)
{
- struct aio_thread_req req;
- struct aio_thread_reply reply;
- int err;
-
- signal(SIGWINCH, SIG_IGN);
- while(1){
- err = os_read_file(aio_req_fd_r, &req, sizeof(req));
- if(err != sizeof(req)){
- if(err < 0)
- printk("not_aio_thread - read failed, "
- "fd = %d, err = %d\n", aio_req_fd_r,
- -err);
- else {
- printk("not_aio_thread - short read, fd = %d, "
- "length = %d\n", aio_req_fd_r, err);
- }
- continue;
- }
- err = do_not_aio(&req);
- reply = ((struct aio_thread_reply) { .data = req.aio,
- .err = err });
- err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply));
- if(err != sizeof(reply))
- printk("not_aio_thread - write failed, fd = %d, "
- "err = %d\n", aio_req_fd_r, -err);
- }
+ struct aio_thread_req req;
+ struct aio_thread_reply reply;
+ int err;
+
+ signal(SIGWINCH, SIG_IGN);
+ while(1){
+ err = os_read_file(aio_req_fd_r, &req, sizeof(req));
+ if(err != sizeof(req)){
+ if(err < 0)
+ printk("not_aio_thread - read failed, "
+ "fd = %d, err = %d\n", aio_req_fd_r,
+ -err);
+ else {
+ printk("not_aio_thread - short read, fd = %d, "
+ "length = %d\n", aio_req_fd_r, err);
+ }
+ continue;
+ }
+ err = do_not_aio(&req);
+ reply = ((struct aio_thread_reply) { .data = req.aio,
+ .err = err });
+ err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply));
+ if(err != sizeof(reply))
+ printk("not_aio_thread - write failed, fd = %d, "
+ "err = %d\n", aio_req_fd_r, -err);
+ }
+
+ return 0;
}
static int aio_pid = -1;
static int init_aio_24(void)
{
- unsigned long stack;
- int fds[2], err;
-
- err = os_pipe(fds, 1, 1);
- if(err)
- goto out;
-
- aio_req_fd_w = fds[0];
- aio_req_fd_r = fds[1];
- err = run_helper_thread(not_aio_thread, NULL,
- CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
- if(err < 0)
- goto out_close_pipe;
-
- aio_pid = err;
- goto out;
-
- out_close_pipe:
- os_close_file(fds[0]);
- os_close_file(fds[1]);
- aio_req_fd_w = -1;
- aio_req_fd_r = -1;
- out:
+ unsigned long stack;
+ int fds[2], err;
+
+ err = os_pipe(fds, 1, 1);
+ if(err)
+ goto out;
+
+ aio_req_fd_w = fds[0];
+ aio_req_fd_r = fds[1];
+ err = run_helper_thread(not_aio_thread, NULL,
+ CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+ if(err < 0)
+ goto out_close_pipe;
+
+ aio_pid = err;
+ goto out;
+
+out_close_pipe:
+ os_close_file(fds[0]);
+ os_close_file(fds[1]);
+ aio_req_fd_w = -1;
+ aio_req_fd_r = -1;
+out:
#ifndef HAVE_AIO_ABI
printk("/usr/include/linux/aio_abi.h not present during build\n");
#endif
printk("2.6 host AIO support not used - falling back to I/O "
"thread\n");
- return 0;
+ return 0;
}
#ifdef HAVE_AIO_ABI
#define DEFAULT_24_AIO 0
static int init_aio_26(void)
{
- unsigned long stack;
- int err;
+ unsigned long stack;
+ int err;
- if(io_setup(256, &ctx)){
+ if(io_setup(256, &ctx)){
err = -errno;
- printk("aio_thread failed to initialize context, err = %d\n",
- errno);
- return err;
- }
+ printk("aio_thread failed to initialize context, err = %d\n",
+ errno);
+ return err;
+ }
- err = run_helper_thread(aio_thread, NULL,
- CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
- if(err < 0)
- return err;
+ err = run_helper_thread(aio_thread, NULL,
+ CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+ if(err < 0)
+ return err;
- aio_pid = err;
+ aio_pid = err;
printk("Using 2.6 host AIO\n");
- return 0;
+ return 0;
}
static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len,
unsigned long long offset, struct aio_context *aio)
{
- struct aio_thread_reply reply;
- int err;
-
- err = do_aio(ctx, type, io_fd, buf, len, offset, aio);
- if(err){
- reply = ((struct aio_thread_reply) { .data = aio,
- .err = err });
- err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
- if(err != sizeof(reply))
- printk("submit_aio_26 - write failed, "
- "fd = %d, err = %d\n", aio->reply_fd, -err);
- else err = 0;
- }
-
- return err;
+ struct aio_thread_reply reply;
+ int err;
+
+ err = do_aio(ctx, type, io_fd, buf, len, offset, aio);
+ if(err){
+ reply = ((struct aio_thread_reply) { .data = aio,
+ .err = err });
+ err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
+ if(err != sizeof(reply))
+ printk("submit_aio_26 - write failed, "
+ "fd = %d, err = %d\n", aio->reply_fd, -err);
+ else err = 0;
+ }
+
+ return err;
}
#else
#define DEFAULT_24_AIO 1
static int init_aio_26(void)
{
- return -ENOSYS;
+ return -ENOSYS;
}
static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len,
unsigned long long offset, struct aio_context *aio)
{
- return -ENOSYS;
+ return -ENOSYS;
}
#endif
@@ -310,8 +312,8 @@ static int aio_24 = DEFAULT_24_AIO;
static int __init set_aio_24(char *name, int *add)
{
- aio_24 = 1;
- return 0;
+ aio_24 = 1;
+ return 0;
}
__uml_setup("aio=2.4", set_aio_24,
@@ -328,28 +330,27 @@ __uml_setup("aio=2.4", set_aio_24,
static int init_aio(void)
{
- int err;
-
- CHOOSE_MODE(({
- if(!aio_24){
- printk("Disabling 2.6 AIO in tt mode\n");
- aio_24 = 1;
- } }), (void) 0);
-
- if(!aio_24){
- err = init_aio_26();
- if(err && (errno == ENOSYS)){
- printk("2.6 AIO not supported on the host - "
- "reverting to 2.4 AIO\n");
- aio_24 = 1;
- }
- else return err;
- }
-
- if(aio_24)
- return init_aio_24();
-
- return 0;
+ int err;
+
+ CHOOSE_MODE(({ if(!aio_24){
+ printk("Disabling 2.6 AIO in tt mode\n");
+ aio_24 = 1;
+ } }), (void) 0);
+
+ if(!aio_24){
+ err = init_aio_26();
+ if(err && (errno == ENOSYS)){
+ printk("2.6 AIO not supported on the host - "
+ "reverting to 2.4 AIO\n");
+ aio_24 = 1;
+ }
+ else return err;
+ }
+
+ if(aio_24)
+ return init_aio_24();
+
+ return 0;
}
/* The reason for the __initcall/__uml_exitcall asymmetry is that init_aio
@@ -362,8 +363,8 @@ __initcall(init_aio);
static void exit_aio(void)
{
- if(aio_pid != -1)
- os_kill_process(aio_pid, 1);
+ if(aio_pid != -1)
+ os_kill_process(aio_pid, 1);
}
__uml_exitcall(exit_aio);
@@ -371,30 +372,30 @@ __uml_exitcall(exit_aio);
static int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len,
unsigned long long offset, struct aio_context *aio)
{
- struct aio_thread_req req = { .type = type,
- .io_fd = io_fd,
- .offset = offset,
- .buf = buf,
- .len = len,
- .aio = aio,
- };
- int err;
-
- err = os_write_file(aio_req_fd_w, &req, sizeof(req));
- if(err == sizeof(req))
- err = 0;
-
- return err;
+ struct aio_thread_req req = { .type = type,
+ .io_fd = io_fd,
+ .offset = offset,
+ .buf = buf,
+ .len = len,
+ .aio = aio,
+ };
+ int err;
+
+ err = os_write_file(aio_req_fd_w, &req, sizeof(req));
+ if(err == sizeof(req))
+ err = 0;
+
+ return err;
}
int submit_aio(enum aio_type type, int io_fd, char *buf, int len,
- unsigned long long offset, int reply_fd,
- struct aio_context *aio)
+ unsigned long long offset, int reply_fd,
+ struct aio_context *aio)
{
- aio->reply_fd = reply_fd;
- if(aio_24)
- return submit_aio_24(type, io_fd, buf, len, offset, aio);
- else {
- return submit_aio_26(type, io_fd, buf, len, offset, aio);
- }
+ aio->reply_fd = reply_fd;
+ if(aio_24)
+ return submit_aio_24(type, io_fd, buf, len, offset, aio);
+ else {
+ return submit_aio_26(type, io_fd, buf, len, offset, aio);
+ }
}
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index 36cc8475bcd..6490a4ff40a 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -60,7 +60,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
if((stack_out != NULL) && (*stack_out != 0))
stack = *stack_out;
- else stack = alloc_stack(0, um_in_interrupt());
+ else stack = alloc_stack(0, __cant_sleep());
if(stack == 0)
return(-ENOMEM);
@@ -124,7 +124,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
unsigned long stack, sp;
int pid, status, err;
- stack = alloc_stack(stack_order, um_in_interrupt());
+ stack = alloc_stack(stack_order, __cant_sleep());
if(stack == 0) return(-ENOMEM);
sp = stack + (page_size() << stack_order) - sizeof(void *);
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index 23da27d2256..2878e89a674 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -16,8 +16,6 @@
#include "user_util.h"
#include "kern_util.h"
#include "mem_user.h"
-#include "signal_user.h"
-#include "time_user.h"
#include "irq_user.h"
#include "user.h"
#include "init.h"
@@ -83,20 +81,8 @@ extern void scan_elf_aux( char **envp);
int main(int argc, char **argv, char **envp)
{
char **new_argv;
- sigset_t mask;
int ret, i, err;
- /* Enable all signals except SIGIO - in some environments, we can
- * enter with some signals blocked
- */
-
- sigemptyset(&mask);
- sigaddset(&mask, SIGIO);
- if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
- perror("sigprocmask");
- exit(1);
- }
-
#ifdef UML_CONFIG_CMDLINE_ON_HOST
/* Allocate memory for thread command lines */
if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index d9c52387c4a..7f5e2dac2a3 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -15,10 +15,10 @@
#include "os.h"
#include "user.h"
#include "user_util.h"
-#include "signal_user.h"
#include "process.h"
#include "irq_user.h"
#include "kern_util.h"
+#include "longjmp.h"
#define ARBITRARY_ADDR -1
#define FAILURE_PID -1
@@ -206,24 +206,13 @@ void init_new_thread_signals(int altstack)
int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
{
- sigjmp_buf buf;
- int n;
-
- *jmp_ptr = &buf;
- n = sigsetjmp(buf, 1);
- if(n != 0)
- return(n);
- (*fn)(arg);
- return(0);
+ sigjmp_buf buf;
+ int n, enable;
+
+ *jmp_ptr = &buf;
+ n = UML_SIGSETJMP(&buf, enable);
+ if(n != 0)
+ return(n);
+ (*fn)(arg);
+ 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/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index c7bfd5ee392..f11b3124a0c 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -4,27 +4,74 @@
*/
#include <signal.h>
-#include "time_user.h"
-#include "mode.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/mman.h>
+#include "user_util.h"
+#include "user.h"
+#include "signal_kern.h"
+#include "sysdep/sigcontext.h"
#include "sysdep/signal.h"
+#include "sigcontext.h"
+#include "mode.h"
+#include "os.h"
+
+/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled
+ * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to
+ * be able to profile all of UML, not just the non-critical sections. If
+ * profiling is not thread-safe, then that is not my problem. We can disable
+ * profiling when SMP is enabled in that case.
+ */
+#define SIGIO_BIT 0
+#define SIGIO_MASK (1 << SIGIO_BIT)
+
+#define SIGVTALRM_BIT 1
+#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)
+
+#define SIGALRM_BIT 2
+#define SIGALRM_MASK (1 << SIGALRM_BIT)
+
+static int signals_enabled = 1;
+static int pending = 0;
void sig_handler(ARCH_SIGHDLR_PARAM)
{
struct sigcontext *sc;
+ int enabled;
+
+ /* Must be the first thing that this handler does - x86_64 stores
+ * the sigcontext in %rdx, and we need to save it before it has a
+ * chance to get trashed.
+ */
ARCH_GET_SIGCONTEXT(sc, sig);
+
+ enabled = signals_enabled;
+ if(!enabled && (sig == SIGIO)){
+ pending |= SIGIO_MASK;
+ return;
+ }
+
+ block_signals();
+
CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
sig, sc);
+
+ set_signals(enabled);
}
extern int timer_irq_inited;
-void alarm_handler(ARCH_SIGHDLR_PARAM)
+static void real_alarm_handler(int sig, struct sigcontext *sc)
{
- struct sigcontext *sc;
-
- ARCH_GET_SIGCONTEXT(sc, sig);
- if(!timer_irq_inited) return;
+ if(!timer_irq_inited){
+ signals_enabled = 1;
+ return;
+ }
if(sig == SIGALRM)
switch_timers(0);
@@ -34,15 +81,180 @@ void alarm_handler(ARCH_SIGHDLR_PARAM)
if(sig == SIGALRM)
switch_timers(1);
+
}
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+void alarm_handler(ARCH_SIGHDLR_PARAM)
+{
+ struct sigcontext *sc;
+ int enabled;
+
+ ARCH_GET_SIGCONTEXT(sc, sig);
+
+ enabled = signals_enabled;
+ if(!signals_enabled){
+ if(sig == SIGVTALRM)
+ pending |= SIGVTALRM_MASK;
+ else pending |= SIGALRM_MASK;
+
+ return;
+ }
+
+ block_signals();
+
+ real_alarm_handler(sig, sc);
+ set_signals(enabled);
+}
+
+extern void do_boot_timer_handler(struct sigcontext * sc);
+
+void boot_timer_handler(ARCH_SIGHDLR_PARAM)
+{
+ struct sigcontext *sc;
+ int enabled;
+
+ ARCH_GET_SIGCONTEXT(sc, sig);
+
+ enabled = signals_enabled;
+ if(!enabled){
+ if(sig == SIGVTALRM)
+ pending |= SIGVTALRM_MASK;
+ else pending |= SIGALRM_MASK;
+ return;
+ }
+
+ block_signals();
+
+ do_boot_timer_handler(sc);
+ set_signals(enabled);
+}
+
+void set_sigstack(void *sig_stack, int size)
+{
+ stack_t stack = ((stack_t) { .ss_flags = 0,
+ .ss_sp = (__ptr_t) sig_stack,
+ .ss_size = size - sizeof(void *) });
+
+ if(sigaltstack(&stack, NULL) != 0)
+ panic("enabling signal stack failed, errno = %d\n", errno);
+}
+
+void remove_sigstack(void)
+{
+ stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
+ .ss_sp = NULL,
+ .ss_size = 0 });
+
+ if(sigaltstack(&stack, NULL) != 0)
+ panic("disabling signal stack failed, errno = %d\n", errno);
+}
+
+void set_handler(int sig, void (*handler)(int), int flags, ...)
+{
+ struct sigaction action;
+ va_list ap;
+ sigset_t sig_mask;
+ int mask;
+
+ va_start(ap, flags);
+ action.sa_handler = handler;
+ sigemptyset(&action.sa_mask);
+ while((mask = va_arg(ap, int)) != -1){
+ sigaddset(&action.sa_mask, mask);
+ }
+ va_end(ap);
+ action.sa_flags = flags;
+ action.sa_restorer = NULL;
+ if(sigaction(sig, &action, NULL) < 0)
+ panic("sigaction failed - errno = %d\n", errno);
+
+ sigemptyset(&sig_mask);
+ sigaddset(&sig_mask, sig);
+ if(sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0)
+ panic("sigprocmask failed - errno = %d\n", errno);
+}
+
+int change_sig(int signal, int on)
+{
+ sigset_t sigset, old;
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, signal);
+ sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
+ return(!sigismember(&old, signal));
+}
+
+void block_signals(void)
+{
+ signals_enabled = 0;
+}
+
+void unblock_signals(void)
+{
+ int save_pending;
+
+ if(signals_enabled == 1)
+ return;
+
+ /* We loop because the IRQ handler returns with interrupts off. So,
+ * interrupts may have arrived and we need to re-enable them and
+ * recheck pending.
+ */
+ while(1){
+ /* Save and reset save_pending after enabling signals. This
+ * way, pending won't be changed while we're reading it.
+ */
+ signals_enabled = 1;
+
+ save_pending = pending;
+ if(save_pending == 0)
+ return;
+
+ pending = 0;
+
+ /* We have pending interrupts, so disable signals, as the
+ * handlers expect them off when they are called. They will
+ * be enabled again above.
+ */
+
+ signals_enabled = 0;
+
+ /* Deal with SIGIO first because the alarm handler might
+ * schedule, leaving the pending SIGIO stranded until we come
+ * back here.
+ */
+ if(save_pending & SIGIO_MASK)
+ CHOOSE_MODE_PROC(sig_handler_common_tt,
+ sig_handler_common_skas, SIGIO, NULL);
+
+ if(save_pending & SIGALRM_MASK)
+ real_alarm_handler(SIGALRM, NULL);
+
+ if(save_pending & SIGVTALRM_MASK)
+ real_alarm_handler(SIGVTALRM, NULL);
+ }
+}
+
+int get_signals(void)
+{
+ return signals_enabled;
+}
+
+int set_signals(int enable)
+{
+ int ret;
+ if(signals_enabled == enable)
+ return enable;
+
+ ret = signals_enabled;
+ if(enable)
+ unblock_signals();
+ else block_signals();
+
+ return ret;
+}
+
+void os_usr1_signal(int on)
+{
+ change_sig(SIGUSR1, on);
+}
diff --git a/arch/um/os-Linux/skas/Makefile b/arch/um/os-Linux/skas/Makefile
new file mode 100644
index 00000000000..5fd8d4dad66
--- /dev/null
+++ b/arch/um/os-Linux/skas/Makefile
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
+# Licensed under the GPL
+#
+
+obj-y := mem.o process.o trap.o
+
+USER_OBJS := mem.o process.o trap.o
+
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/os-Linux/skas/mem.c
index 1d89640bd50..9890e9090f5 100644
--- a/arch/um/kernel/skas/mem_user.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -32,7 +32,7 @@ extern void wait_stub_done(int pid, int sig, char * fname);
static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
unsigned long *stack)
{
- if(stack == NULL){
+ if(stack == NULL) {
stack = (unsigned long *) mm_idp->stack + 2;
*stack = 0;
}
@@ -45,13 +45,14 @@ int single_count = 0;
int multi_count = 0;
int multi_op_count = 0;
-static long do_syscall_stub(struct mm_id *mm_idp, void **addr)
+static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
{
unsigned long regs[MAX_REG_NR];
- unsigned long *data;
- unsigned long *syscall;
+ int n;
long ret, offset;
- int n, pid = mm_idp->u.pid;
+ unsigned long * data;
+ unsigned long * syscall;
+ int pid = mm_idp->u.pid;
if(proc_mm)
#warning Need to look up userspace_pid by cpu
@@ -59,10 +60,11 @@ static long do_syscall_stub(struct mm_id *mm_idp, void **addr)
multi_count++;
- get_safe_registers(regs);
- regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ get_safe_registers(regs);
+ regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
((unsigned long) &batch_syscall_stub -
- (unsigned long) &__syscall_stub_start);
+ (unsigned long) &__syscall_stub_start);
+
n = ptrace_setregs(pid, regs);
if(n < 0)
panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n",
@@ -80,6 +82,8 @@ static long do_syscall_stub(struct mm_id *mm_idp, void **addr)
if (offset) {
data = (unsigned long *)(mm_idp->stack +
offset - UML_CONFIG_STUB_DATA);
+ printk("do_syscall_stub : ret = %d, offset = %d, "
+ "data = 0x%x\n", ret, offset, data);
syscall = (unsigned long *)((unsigned long)data + data[0]);
printk("do_syscall_stub: syscall %ld failed, return value = "
"0x%lx, expected return value = 0x%lx\n",
@@ -107,32 +111,32 @@ static long do_syscall_stub(struct mm_id *mm_idp, void **addr)
long run_syscall_stub(struct mm_id * mm_idp, int syscall,
unsigned long *args, long expected, void **addr,
- int done)
+ int done)
{
- unsigned long *stack = check_init_stack(mm_idp, *addr);
+ unsigned long *stack = check_init_stack(mm_idp, *addr);
if(done && *addr == NULL)
single_count++;
- *stack += sizeof(long);
+ *stack += sizeof(long);
stack += *stack / sizeof(long);
- *stack++ = syscall;
- *stack++ = args[0];
- *stack++ = args[1];
- *stack++ = args[2];
- *stack++ = args[3];
- *stack++ = args[4];
- *stack++ = args[5];
+ *stack++ = syscall;
+ *stack++ = args[0];
+ *stack++ = args[1];
+ *stack++ = args[2];
+ *stack++ = args[3];
+ *stack++ = args[4];
+ *stack++ = args[5];
*stack++ = expected;
- *stack = 0;
- multi_op_count++;
+ *stack = 0;
+ multi_op_count++;
- if(!done && ((((unsigned long) stack) & ~PAGE_MASK) <
+ if(!done && ((((unsigned long) stack) & ~PAGE_MASK) <
PAGE_SIZE - 10 * sizeof(long))){
*addr = stack;
- return 0;
- }
+ return 0;
+ }
return do_syscall_stub(mm_idp, addr);
}
@@ -150,7 +154,7 @@ long syscall_stub_data(struct mm_id * mm_idp,
if((((unsigned long) *addr) & ~PAGE_MASK) >=
PAGE_SIZE - (10 + data_count) * sizeof(long)) {
ret = do_syscall_stub(mm_idp, addr);
- /* in case of error, don't overwrite data on stack */
+ /* in case of error, don't overwrite data on stack */
if(ret)
return ret;
}
@@ -172,39 +176,39 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
int r, int w, int x, int phys_fd, unsigned long long offset,
int done, void **data)
{
- int prot, ret;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
-
- if(proc_mm){
- struct proc_mm_op map;
- int fd = mm_idp->u.mm_fd;
-
- map = ((struct proc_mm_op) { .op = MM_MMAP,
- .u =
- { .mmap =
- { .addr = virt,
- .len = len,
- .prot = prot,
- .flags = MAP_SHARED |
- MAP_FIXED,
- .fd = phys_fd,
- .offset= offset
- } } } );
+ int prot, ret;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+
+ if(proc_mm){
+ struct proc_mm_op map;
+ int fd = mm_idp->u.mm_fd;
+
+ map = ((struct proc_mm_op) { .op = MM_MMAP,
+ .u =
+ { .mmap =
+ { .addr = virt,
+ .len = len,
+ .prot = prot,
+ .flags = MAP_SHARED |
+ MAP_FIXED,
+ .fd = phys_fd,
+ .offset= offset
+ } } } );
ret = os_write_file(fd, &map, sizeof(map));
if(ret != sizeof(map))
printk("map : /proc/mm map failed, err = %d\n", -ret);
else ret = 0;
- }
- else {
- unsigned long args[] = { virt, len, prot,
- MAP_SHARED | MAP_FIXED, phys_fd,
- MMAP_OFFSET(offset) };
+ }
+ else {
+ unsigned long args[] = { virt, len, prot,
+ MAP_SHARED | MAP_FIXED, phys_fd,
+ MMAP_OFFSET(offset) };
ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt,
data, done);
- }
+ }
return ret;
}
@@ -212,68 +216,66 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
void **data)
{
- int ret;
-
- if(proc_mm){
- struct proc_mm_op unmap;
- int fd = mm_idp->u.mm_fd;
-
- unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
- .u =
- { .munmap =
- { .addr =
- (unsigned long) addr,
- .len = len } } } );
+ int ret;
+
+ if(proc_mm){
+ struct proc_mm_op unmap;
+ int fd = mm_idp->u.mm_fd;
+
+ unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
+ .u =
+ { .munmap =
+ { .addr =
+ (unsigned long) addr,
+ .len = len } } } );
ret = os_write_file(fd, &unmap, sizeof(unmap));
if(ret != sizeof(unmap))
printk("unmap - proc_mm write returned %d\n", ret);
else ret = 0;
- }
- else {
- unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
- 0 };
+ }
+ else {
+ unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
+ 0 };
ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0,
data, done);
- if(ret < 0)
- printk("munmap stub failed, errno = %d\n", ret);
- }
+ }
- return ret;
+ return ret;
}
int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
int r, int w, int x, int done, void **data)
{
- struct proc_mm_op protect;
- int prot, ret;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
-
- if(proc_mm){
- int fd = mm_idp->u.mm_fd;
- protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
- .u =
- { .mprotect =
- { .addr =
- (unsigned long) addr,
- .len = len,
- .prot = prot } } } );
-
- ret = os_write_file(fd, &protect, sizeof(protect));
- if(ret != sizeof(protect))
- printk("protect failed, err = %d", -ret);
- else ret = 0;
- }
- else {
- unsigned long args[] = { addr, len, prot, 0, 0, 0 };
-
- ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0,
- data, done);
- }
-
- return ret;
+ struct proc_mm_op protect;
+ int prot, ret;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+ if(proc_mm){
+ int fd = mm_idp->u.mm_fd;
+
+ protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
+ .u =
+ { .mprotect =
+ { .addr =
+ (unsigned long) addr,
+ .len = len,
+ .prot = prot } } } );
+
+ ret = os_write_file(fd, &protect, sizeof(protect));
+ if(ret != sizeof(protect))
+ printk("protect failed, err = %d", -ret);
+ else ret = 0;
+ }
+ else {
+ unsigned long args[] = { addr, len, prot, 0, 0, 0 };
+
+ ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0,
+ data, done);
+ }
+
+ return ret;
}
void before_mem_skas(unsigned long unused)
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
new file mode 100644
index 00000000000..120a21c5883
--- /dev/null
+++ b/arch/um/os-Linux/skas/process.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sched.h>
+#include "ptrace_user.h"
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <sys/time.h>
+#include <asm/unistd.h>
+#include <asm/types.h>
+#include "user.h"
+#include "sysdep/ptrace.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "skas.h"
+#include "stub-data.h"
+#include "mm_id.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/stub.h"
+#include "os.h"
+#include "proc_mm.h"
+#include "skas_ptrace.h"
+#include "chan_user.h"
+#include "registers.h"
+#include "mem.h"
+#include "uml-config.h"
+#include "process.h"
+#include "longjmp.h"
+
+int is_skas_winch(int pid, int fd, void *data)
+{
+ if(pid != os_getpgrp())
+ return(0);
+
+ register_winch_irq(-1, fd, -1, data);
+ return(1);
+}
+
+void wait_stub_done(int pid, int sig, char * fname)
+{
+ int n, status, err;
+
+ do {
+ if ( sig != -1 ) {
+ err = ptrace(PTRACE_CONT, pid, 0, sig);
+ if(err)
+ panic("%s : continue failed, errno = %d\n",
+ fname, errno);
+ }
+ sig = 0;
+
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+ } while((n >= 0) && WIFSTOPPED(status) &&
+ ((WSTOPSIG(status) == SIGVTALRM) ||
+ /* running UML inside a detached screen can cause
+ * SIGWINCHes
+ */
+ (WSTOPSIG(status) == SIGWINCH)));
+
+ if((n < 0) || !WIFSTOPPED(status) ||
+ (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){
+ unsigned long regs[HOST_FRAME_SIZE];
+
+ if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
+ printk("Failed to get registers from stub, "
+ "errno = %d\n", errno);
+ else {
+ int i;
+
+ printk("Stub registers -\n");
+ for(i = 0; i < HOST_FRAME_SIZE; i++)
+ printk("\t%d - %lx\n", i, regs[i]);
+ }
+ panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
+ "pid = %d, n = %d, errno = %d, status = 0x%x\n",
+ fname, pid, n, errno, status);
+ }
+}
+
+extern unsigned long current_stub_stack(void);
+
+void get_skas_faultinfo(int pid, struct faultinfo * fi)
+{
+ int err;
+
+ if(ptrace_faultinfo){
+ err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
+ if(err)
+ panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
+ "errno = %d\n", errno);
+
+ /* Special handling for i386, which has different structs */
+ if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
+ memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
+ sizeof(struct faultinfo) -
+ sizeof(struct ptrace_faultinfo));
+ }
+ else {
+ wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
+
+ /* faultinfo is prepared by the stub-segv-handler at start of
+ * the stub stack page. We just have to copy it.
+ */
+ memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
+ }
+}
+
+static void handle_segv(int pid, union uml_pt_regs * regs)
+{
+ get_skas_faultinfo(pid, &regs->skas.faultinfo);
+ segv(regs->skas.faultinfo, 0, 1, NULL);
+}
+
+/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
+static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu)
+{
+ int err, status;
+
+ /* Mark this as a syscall */
+ UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs);
+
+ if (!local_using_sysemu)
+ {
+ err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
+ __NR_getpid);
+ if(err < 0)
+ panic("handle_trap - nullifying syscall failed errno = %d\n",
+ errno);
+
+ err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
+ if(err < 0)
+ panic("handle_trap - continuing to end of syscall failed, "
+ "errno = %d\n", errno);
+
+ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
+ if((err < 0) || !WIFSTOPPED(status) ||
+ (WSTOPSIG(status) != SIGTRAP + 0x80))
+ panic("handle_trap - failed to wait at end of syscall, "
+ "errno = %d, status = %d\n", errno, status);
+ }
+
+ handle_syscall(regs);
+}
+
+extern int __syscall_stub_start;
+
+static int userspace_tramp(void *stack)
+{
+ void *addr;
+
+ ptrace(PTRACE_TRACEME, 0, 0, 0);
+
+ init_new_thread_signals(1);
+ enable_timer();
+
+ if(!proc_mm){
+ /* This has a pte, but it can't be mapped in with the usual
+ * tlb_flush mechanism because this is part of that mechanism
+ */
+ int fd;
+ __u64 offset;
+ fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
+ addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
+ PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
+ if(addr == MAP_FAILED){
+ printk("mapping mmap stub failed, errno = %d\n",
+ errno);
+ exit(1);
+ }
+
+ if(stack != NULL){
+ fd = phys_mapping(to_phys(stack), &offset);
+ addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
+ PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED, fd, offset);
+ if(addr == MAP_FAILED){
+ printk("mapping segfault stack failed, "
+ "errno = %d\n", errno);
+ exit(1);
+ }
+ }
+ }
+ if(!ptrace_faultinfo && (stack != NULL)){
+ unsigned long v = UML_CONFIG_STUB_CODE +
+ (unsigned long) stub_segv_handler -
+ (unsigned long) &__syscall_stub_start;
+
+ set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
+ set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
+ SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
+ SIGUSR1, -1);
+ }
+
+ os_stop_process(os_getpid());
+ return(0);
+}
+
+/* Each element set once, and only accessed by a single processor anyway */
+#undef NR_CPUS
+#define NR_CPUS 1
+int userspace_pid[NR_CPUS];
+
+int start_userspace(unsigned long stub_stack)
+{
+ void *stack;
+ unsigned long sp;
+ int pid, status, n, flags;
+
+ stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if(stack == MAP_FAILED)
+ panic("start_userspace : mmap failed, errno = %d", errno);
+ sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
+
+ flags = CLONE_FILES | SIGCHLD;
+ if(proc_mm) flags |= CLONE_VM;
+ pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
+ if(pid < 0)
+ panic("start_userspace : clone failed, errno = %d", errno);
+
+ do {
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+ if(n < 0)
+ panic("start_userspace : wait failed, errno = %d",
+ errno);
+ } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
+
+ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
+ panic("start_userspace : expected SIGSTOP, got status = %d",
+ status);
+
+ if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, (void *)PTRACE_O_TRACESYSGOOD) < 0)
+ panic("start_userspace : PTRACE_OLDSETOPTIONS failed, errno=%d\n",
+ errno);
+
+ if(munmap(stack, PAGE_SIZE) < 0)
+ panic("start_userspace : munmap failed, errno = %d\n", errno);
+
+ return(pid);
+}
+
+void userspace(union uml_pt_regs *regs)
+{
+ int err, status, op, pid = userspace_pid[0];
+ int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
+
+ while(1){
+ restore_registers(pid, regs);
+
+ /* Now we set local_using_sysemu to be used for one loop */
+ local_using_sysemu = get_using_sysemu();
+
+ op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
+
+ err = ptrace(op, pid, 0, 0);
+ if(err)
+ panic("userspace - could not resume userspace process, "
+ "pid=%d, ptrace operation = %d, errno = %d\n",
+ op, errno);
+
+ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
+ if(err < 0)
+ panic("userspace - waitpid failed, errno = %d\n",
+ errno);
+
+ regs->skas.is_user = 1;
+ save_registers(pid, regs);
+ UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
+
+ if(WIFSTOPPED(status)){
+ switch(WSTOPSIG(status)){
+ case SIGSEGV:
+ if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
+ user_signal(SIGSEGV, regs, pid);
+ else handle_segv(pid, regs);
+ break;
+ case SIGTRAP + 0x80:
+ handle_trap(pid, regs, local_using_sysemu);
+ break;
+ case SIGTRAP:
+ relay_signal(SIGTRAP, regs);
+ break;
+ case SIGIO:
+ case SIGVTALRM:
+ case SIGILL:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGWINCH:
+ user_signal(WSTOPSIG(status), regs, pid);
+ break;
+ default:
+ printk("userspace - child stopped with signal "
+ "%d\n", WSTOPSIG(status));
+ }
+ pid = userspace_pid[0];
+ interrupt_end();
+
+ /* Avoid -ERESTARTSYS handling in host */
+ if(PT_SYSCALL_NR_OFFSET != PT_SYSCALL_RET_OFFSET)
+ PT_SYSCALL_NR(regs->skas.regs) = -1;
+ }
+ }
+}
+#define INIT_JMP_NEW_THREAD 0
+#define INIT_JMP_REMOVE_SIGSTACK 1
+#define INIT_JMP_CALLBACK 2
+#define INIT_JMP_HALT 3
+#define INIT_JMP_REBOOT 4
+
+int copy_context_skas0(unsigned long new_stack, int pid)
+{
+ int err;
+ unsigned long regs[MAX_REG_NR];
+ unsigned long current_stack = current_stub_stack();
+ struct stub_data *data = (struct stub_data *) current_stack;
+ struct stub_data *child_data = (struct stub_data *) new_stack;
+ __u64 new_offset;
+ int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
+
+ /* prepare offset and fd of child's stack as argument for parent's
+ * and child's mmap2 calls
+ */
+ *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset),
+ .fd = new_fd,
+ .timer = ((struct itimerval)
+ { { 0, 1000000 / hz() },
+ { 0, 1000000 / hz() }})});
+ get_safe_registers(regs);
+
+ /* Set parent's instruction pointer to start of clone-stub */
+ regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ (unsigned long) stub_clone_handler -
+ (unsigned long) &__syscall_stub_start;
+ regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
+ sizeof(void *);
+#ifdef __SIGNAL_FRAMESIZE
+ regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
+#endif
+ err = ptrace_setregs(pid, regs);
+ if(err < 0)
+ panic("copy_context_skas0 : PTRACE_SETREGS failed, "
+ "pid = %d, errno = %d\n", pid, errno);
+
+ /* set a well known return code for detection of child write failure */
+ child_data->err = 12345678;
+
+ /* Wait, until parent has finished its work: read child's pid from
+ * parent's stack, and check, if bad result.
+ */
+ wait_stub_done(pid, 0, "copy_context_skas0");
+
+ pid = data->err;
+ if(pid < 0)
+ panic("copy_context_skas0 - stub-parent reports error %d\n",
+ pid);
+
+ /* Wait, until child has finished too: read child's result from
+ * child's stack and check it.
+ */
+ wait_stub_done(pid, -1, "copy_context_skas0");
+ if (child_data->err != UML_CONFIG_STUB_DATA)
+ panic("copy_context_skas0 - stub-child reports error %d\n",
+ child_data->err);
+
+ if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
+ (void *)PTRACE_O_TRACESYSGOOD) < 0)
+ panic("copy_context_skas0 : PTRACE_OLDSETOPTIONS failed, "
+ "errno = %d\n", errno);
+
+ return pid;
+}
+
+/*
+ * This is used only, if stub pages are needed, while proc_mm is
+ * availabl. Opening /proc/mm creates a new mm_context, which lacks
+ * the stub-pages. Thus, we map them using /proc/mm-fd
+ */
+void map_stub_pages(int fd, unsigned long code,
+ unsigned long data, unsigned long stack)
+{
+ struct proc_mm_op mmop;
+ int n;
+ __u64 code_offset;
+ int code_fd = phys_mapping(to_phys((void *) &__syscall_stub_start),
+ &code_offset);
+
+ mmop = ((struct proc_mm_op) { .op = MM_MMAP,
+ .u =
+ { .mmap =
+ { .addr = code,
+ .len = PAGE_SIZE,
+ .prot = PROT_EXEC,
+ .flags = MAP_FIXED | MAP_PRIVATE,
+ .fd = code_fd,
+ .offset = code_offset
+ } } });
+ n = os_write_file(fd, &mmop, sizeof(mmop));
+ if(n != sizeof(mmop))
+ panic("map_stub_pages : /proc/mm map for code failed, "
+ "err = %d\n", -n);
+
+ if ( stack ) {
+ __u64 map_offset;
+ int map_fd = phys_mapping(to_phys((void *)stack), &map_offset);
+ mmop = ((struct proc_mm_op)
+ { .op = MM_MMAP,
+ .u =
+ { .mmap =
+ { .addr = data,
+ .len = PAGE_SIZE,
+ .prot = PROT_READ | PROT_WRITE,
+ .flags = MAP_FIXED | MAP_SHARED,
+ .fd = map_fd,
+ .offset = map_offset
+ } } });
+ n = os_write_file(fd, &mmop, sizeof(mmop));
+ if(n != sizeof(mmop))
+ panic("map_stub_pages : /proc/mm map for data failed, "
+ "err = %d\n", -n);
+ }
+}
+
+void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
+ void (*handler)(int))
+{
+ unsigned long flags;
+ sigjmp_buf switch_buf, fork_buf;
+ int enable;
+
+ *switch_buf_ptr = &switch_buf;
+ *fork_buf_ptr = &fork_buf;
+
+ /* Somewhat subtle - siglongjmp restores the signal mask before doing
+ * the longjmp. This means that when jumping from one stack to another
+ * when the target stack has interrupts enabled, an interrupt may occur
+ * on the source stack. This is bad when starting up a process because
+ * it's not supposed to get timer ticks until it has been scheduled.
+ * So, we disable interrupts around the sigsetjmp to ensure that
+ * they can't happen until we get back here where they are safe.
+ */
+ flags = get_signals();
+ block_signals();
+ if(UML_SIGSETJMP(&fork_buf, enable) == 0)
+ new_thread_proc(stack, handler);
+
+ remove_sigstack();
+
+ set_signals(flags);
+}
+
+void thread_wait(void *sw, void *fb)
+{
+ sigjmp_buf buf, **switch_buf = sw, *fork_buf;
+ int enable;
+
+ *switch_buf = &buf;
+ fork_buf = fb;
+ if(UML_SIGSETJMP(&buf, enable) == 0)
+ siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK);
+}
+
+void switch_threads(void *me, void *next)
+{
+ sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
+ int enable;
+
+ *me_ptr = &my_buf;
+ if(UML_SIGSETJMP(&my_buf, enable) == 0)
+ UML_SIGLONGJMP(next_buf, 1);
+}
+
+static sigjmp_buf initial_jmpbuf;
+
+/* XXX Make these percpu */
+static void (*cb_proc)(void *arg);
+static void *cb_arg;
+static sigjmp_buf *cb_back;
+
+int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
+{
+ sigjmp_buf **switch_buf = switch_buf_ptr;
+ int n, enable;
+
+ set_handler(SIGWINCH, (__sighandler_t) sig_handler,
+ SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
+ SIGVTALRM, -1);
+
+ *fork_buf_ptr = &initial_jmpbuf;
+ n = UML_SIGSETJMP(&initial_jmpbuf, enable);
+ switch(n){
+ case INIT_JMP_NEW_THREAD:
+ new_thread_proc((void *) stack, new_thread_handler);
+ break;
+ case INIT_JMP_REMOVE_SIGSTACK:
+ remove_sigstack();
+ break;
+ case INIT_JMP_CALLBACK:
+ (*cb_proc)(cb_arg);
+ UML_SIGLONGJMP(cb_back, 1);
+ break;
+ case INIT_JMP_HALT:
+ kmalloc_ok = 0;
+ return(0);
+ case INIT_JMP_REBOOT:
+ kmalloc_ok = 0;
+ return(1);
+ default:
+ panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
+ }
+ UML_SIGLONGJMP(*switch_buf, 1);
+}
+
+void initial_thread_cb_skas(void (*proc)(void *), void *arg)
+{
+ sigjmp_buf here;
+ int enable;
+
+ cb_proc = proc;
+ cb_arg = arg;
+ cb_back = &here;
+
+ block_signals();
+ if(UML_SIGSETJMP(&here, enable) == 0)
+ UML_SIGLONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK);
+ unblock_signals();
+
+ cb_proc = NULL;
+ cb_arg = NULL;
+ cb_back = NULL;
+}
+
+void halt_skas(void)
+{
+ block_signals();
+ UML_SIGLONGJMP(&initial_jmpbuf, INIT_JMP_HALT);
+}
+
+void reboot_skas(void)
+{
+ block_signals();
+ UML_SIGLONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT);
+}
+
+void switch_mm_skas(struct mm_id *mm_idp)
+{
+ int err;
+
+#warning need cpu pid in switch_mm_skas
+ if(proc_mm){
+ err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
+ mm_idp->u.mm_fd);
+ if(err)
+ panic("switch_mm_skas - PTRACE_SWITCH_MM failed, "
+ "errno = %d\n", errno);
+ }
+ else userspace_pid[0] = mm_idp->u.pid;
+}
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/os-Linux/skas/trap.c
index 9950a6716fe..9ad5fbec459 100644
--- a/arch/um/kernel/skas/trap_user.c
+++ b/arch/um/os-Linux/skas/trap.c
@@ -1,11 +1,10 @@
-/*
+/*
* Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
#include <signal.h>
#include <errno.h>
-#include "signal_user.h"
#include "user_util.h"
#include "kern_util.h"
#include "task.h"
@@ -14,12 +13,13 @@
#include "ptrace_user.h"
#include "sysdep/ptrace.h"
#include "sysdep/ptrace_user.h"
+#include "os.h"
void sig_handler_common_skas(int sig, void *sc_ptr)
{
struct sigcontext *sc = sc_ptr;
struct skas_regs *r;
- struct signal_info *info;
+ void (*handler)(int, union uml_pt_regs *);
int save_errno = errno;
int save_user;
@@ -34,17 +34,22 @@ void sig_handler_common_skas(int sig, void *sc_ptr)
r = &TASK_REGS(get_current())->skas;
save_user = r->is_user;
r->is_user = 0;
- if ( sig == SIGFPE || sig == SIGSEGV ||
- sig == SIGBUS || sig == SIGILL ||
- sig == SIGTRAP ) {
- GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
- }
+ if ( sig == SIGFPE || sig == SIGSEGV ||
+ sig == SIGBUS || sig == SIGILL ||
+ sig == SIGTRAP ) {
+ GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
+ }
change_sig(SIGUSR1, 1);
- info = &sig_info[sig];
- if(!info->is_irq) unblock_signals();
- (*info->handler)(sig, (union uml_pt_regs *) r);
+ handler = sig_info[sig];
+
+ /* unblock SIGALRM, SIGVTALRM, SIGIO if sig isn't IRQ signal */
+ if (sig != SIGIO && sig != SIGWINCH &&
+ sig != SIGVTALRM && sig != SIGALRM)
+ unblock_signals();
+
+ handler(sig, (union uml_pt_regs *) r);
errno = save_errno;
r->is_user = save_user;
@@ -54,25 +59,15 @@ extern int ptrace_faultinfo;
void user_signal(int sig, union uml_pt_regs *regs, int pid)
{
- struct signal_info *info;
- int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
- (sig == SIGILL) || (sig == SIGTRAP));
+ void (*handler)(int, union uml_pt_regs *);
+ int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
+ (sig == SIGILL) || (sig == SIGTRAP));
if (segv)
get_skas_faultinfo(pid, &regs->skas.faultinfo);
- info = &sig_info[sig];
- (*info->handler)(sig, regs);
+
+ handler = sig_info[sig];
+ handler(sig, (union uml_pt_regs *) regs);
unblock_signals();
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index 37517d49c4a..6c5b17ed59e 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -24,13 +24,11 @@
#include "kern_util.h"
#include "user.h"
#include "signal_kern.h"
-#include "signal_user.h"
#include "sysdep/ptrace.h"
#include "sysdep/sigcontext.h"
#include "irq_user.h"
#include "ptrace_user.h"
#include "mem_user.h"
-#include "time_user.h"
#include "init.h"
#include "os.h"
#include "uml-config.h"
@@ -116,16 +114,16 @@ static int stop_ptraced_child(int pid, void *stack, int exitcode,
if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
int exit_with = WEXITSTATUS(status);
if (exit_with == 2)
- printk("check_ptrace : child exited with status 2. "
+ printf("check_ptrace : child exited with status 2. "
"Serious trouble happening! Try updating your "
"host skas patch!\nDisabling SYSEMU support.");
- printk("check_ptrace : child exited with exitcode %d, while "
+ printf("check_ptrace : child exited with exitcode %d, while "
"expecting %d; status 0x%x", exit_with,
exitcode, status);
if (mustpanic)
panic("\n");
else
- printk("\n");
+ printf("\n");
ret = -1;
}
@@ -183,7 +181,7 @@ static void __init check_sysemu(void)
void *stack;
int pid, n, status, count=0;
- printk("Checking syscall emulation patch for ptrace...");
+ printf("Checking syscall emulation patch for ptrace...");
sysemu_supported = 0;
pid = start_ptraced_child(&stack);
@@ -207,10 +205,10 @@ static void __init check_sysemu(void)
goto fail_stopped;
sysemu_supported = 1;
- printk("OK\n");
+ printf("OK\n");
set_using_sysemu(!force_sysemu_disabled);
- printk("Checking advanced syscall emulation patch for ptrace...");
+ printf("Checking advanced syscall emulation patch for ptrace...");
pid = start_ptraced_child(&stack);
if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
@@ -246,7 +244,7 @@ static void __init check_sysemu(void)
goto fail_stopped;
sysemu_supported = 2;
- printk("OK\n");
+ printf("OK\n");
if ( !force_sysemu_disabled )
set_using_sysemu(sysemu_supported);
@@ -255,7 +253,7 @@ static void __init check_sysemu(void)
fail:
stop_ptraced_child(pid, stack, 1, 0);
fail_stopped:
- printk("missing\n");
+ printf("missing\n");
}
static void __init check_ptrace(void)
@@ -263,7 +261,7 @@ static void __init check_ptrace(void)
void *stack;
int pid, syscall, n, status;
- printk("Checking that ptrace can change system call numbers...");
+ printf("Checking that ptrace can change system call numbers...");
pid = start_ptraced_child(&stack);
if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
@@ -292,7 +290,7 @@ static void __init check_ptrace(void)
}
}
stop_ptraced_child(pid, stack, 0, 1);
- printk("OK\n");
+ printf("OK\n");
check_sysemu();
}
@@ -472,6 +470,8 @@ int can_do_skas(void)
int have_devanon = 0;
+/* Runs on boot kernel stack - already safe to use printk. */
+
void check_devanon(void)
{
int fd;
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index cf30a39bc48..6f7626775ac 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -1,21 +1,128 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "process.h"
+#include "kern_constants.h"
+#include "os.h"
+
+/* XXX This really needs to be declared and initialized in a kernel file since
+ * it's in <linux/time.h>
+ */
+extern struct timespec wall_to_monotonic;
+
+static void set_interval(int timer_type)
+{
+ int usec = 1000000/hz();
+ struct itimerval interval = ((struct itimerval) { { 0, usec },
+ { 0, usec } });
+
+ if(setitimer(timer_type, &interval, NULL) == -1)
+ panic("setitimer failed - errno = %d\n", errno);
+}
+
+void enable_timer(void)
+{
+ set_interval(ITIMER_VIRTUAL);
+}
+
+void disable_timer(void)
+{
+ struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
+ if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) ||
+ (setitimer(ITIMER_REAL, &disable, NULL) < 0))
+ printk("disnable_timer - setitimer failed, errno = %d\n",
+ errno);
+ /* If there are signals already queued, after unblocking ignore them */
+ set_handler(SIGALRM, SIG_IGN, 0, -1);
+ set_handler(SIGVTALRM, SIG_IGN, 0, -1);
+}
+
+void switch_timers(int to_real)
+{
+ struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
+ struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() },
+ { 0, 1000000/hz() }});
+ int old, new;
+
+ if(to_real){
+ old = ITIMER_VIRTUAL;
+ new = ITIMER_REAL;
+ }
+ else {
+ old = ITIMER_REAL;
+ new = ITIMER_VIRTUAL;
+ }
+
+ if((setitimer(old, &disable, NULL) < 0) ||
+ (setitimer(new, &enable, NULL)))
+ printk("switch_timers - setitimer failed, errno = %d\n",
+ errno);
+}
-unsigned long long os_usecs(void)
+void uml_idle_timer(void)
+{
+ if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
+ panic("Couldn't unset SIGVTALRM handler");
+
+ set_handler(SIGALRM, (__sighandler_t) alarm_handler,
+ SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
+ set_interval(ITIMER_REAL);
+}
+
+extern void ktime_get_ts(struct timespec *ts);
+#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
+
+void time_init(void)
+{
+ struct timespec now;
+
+ if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
+ panic("Couldn't set SIGVTALRM handler");
+ set_interval(ITIMER_VIRTUAL);
+
+ do_posix_clock_monotonic_gettime(&now);
+ wall_to_monotonic.tv_sec = -now.tv_sec;
+ wall_to_monotonic.tv_nsec = -now.tv_nsec;
+}
+
+unsigned long long os_nsecs(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
- return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec);
+ return((unsigned long long) tv.tv_sec * BILLION + tv.tv_usec * 1000);
}
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+void idle_sleep(int secs)
+{
+ struct timespec ts;
+
+ ts.tv_sec = secs;
+ ts.tv_nsec = 0;
+ nanosleep(&ts, NULL);
+}
+
+/* XXX This partly duplicates init_irq_signals */
+
+void user_time_init(void)
+{
+ set_handler(SIGVTALRM, (__sighandler_t) alarm_handler,
+ SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH,
+ SIGALRM, SIGUSR2, -1);
+ set_handler(SIGALRM, (__sighandler_t) alarm_handler,
+ SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH,
+ SIGVTALRM, SIGUSR2, -1);
+ set_interval(ITIMER_VIRTUAL);
+}
diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c
new file mode 100644
index 00000000000..a9f6b26f982
--- /dev/null
+++ b/arch/um/os-Linux/trap.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+#include "mode.h"
+#include "longjmp.h"
+
+void usr2_handler(int sig, union uml_pt_regs *regs)
+{
+ CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0);
+}
+
+void (*sig_info[NSIG])(int, union uml_pt_regs *);
+
+void os_fill_handlinfo(struct kern_handlers h)
+{
+ sig_info[SIGTRAP] = h.relay_signal;
+ sig_info[SIGFPE] = h.relay_signal;
+ sig_info[SIGILL] = h.relay_signal;
+ sig_info[SIGWINCH] = h.winch;
+ sig_info[SIGBUS] = h.bus_handler;
+ sig_info[SIGSEGV] = h.page_fault;
+ sig_info[SIGIO] = h.sigio_handler;
+ sig_info[SIGVTALRM] = h.timer_handler;
+ sig_info[SIGALRM] = h.timer_handler;
+ sig_info[SIGUSR2] = usr2_handler;
+}
+
+void do_longjmp(void *b, int val)
+{
+ sigjmp_buf *buf = b;
+
+ UML_SIGLONGJMP(buf, val);
+}
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c
index a6db8877931..919d19f1153 100644
--- a/arch/um/os-Linux/tt.c
+++ b/arch/um/os-Linux/tt.c
@@ -23,12 +23,10 @@
#include "kern_util.h"
#include "user.h"
#include "signal_kern.h"
-#include "signal_user.h"
#include "sysdep/ptrace.h"
#include "sysdep/sigcontext.h"
#include "irq_user.h"
#include "ptrace_user.h"
-#include "time_user.h"
#include "init.h"
#include "os.h"
#include "uml-config.h"
@@ -50,6 +48,68 @@ int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
return(0);
}
+void kill_child_dead(int pid)
+{
+ kill(pid, SIGKILL);
+ kill(pid, SIGCONT);
+ do {
+ int n;
+ CATCH_EINTR(n = waitpid(pid, NULL, 0));
+ if (n > 0)
+ kill(pid, SIGCONT);
+ else
+ break;
+ } while(1);
+}
+
+void stop(void)
+{
+ while(1) sleep(1000000);
+}
+
+int wait_for_stop(int pid, int sig, int cont_type, void *relay)
+{
+ sigset_t *relay_signals = relay;
+ int status, ret;
+
+ while(1){
+ CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED));
+ if((ret < 0) ||
+ !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
+ if(ret < 0){
+ printk("wait failed, errno = %d\n",
+ errno);
+ }
+ else if(WIFEXITED(status))
+ printk("process %d exited with status %d\n",
+ pid, WEXITSTATUS(status));
+ else if(WIFSIGNALED(status))
+ printk("process %d exited with signal %d\n",
+ pid, WTERMSIG(status));
+ else if((WSTOPSIG(status) == SIGVTALRM) ||
+ (WSTOPSIG(status) == SIGALRM) ||
+ (WSTOPSIG(status) == SIGIO) ||
+ (WSTOPSIG(status) == SIGPROF) ||
+ (WSTOPSIG(status) == SIGCHLD) ||
+ (WSTOPSIG(status) == SIGWINCH) ||
+ (WSTOPSIG(status) == SIGINT)){
+ ptrace(cont_type, pid, 0, WSTOPSIG(status));
+ continue;
+ }
+ else if((relay_signals != NULL) &&
+ sigismember(relay_signals, WSTOPSIG(status))){
+ ptrace(cont_type, pid, 0, WSTOPSIG(status));
+ continue;
+ }
+ else printk("process %d stopped with signal %d\n",
+ pid, WSTOPSIG(status));
+ panic("wait_for_stop failed to wait for %d to stop "
+ "with %d\n", pid, sig);
+ }
+ return(status);
+ }
+}
+
/*
*-------------------------
* only for tt mode (will be deleted in future...)
diff --git a/arch/um/os-Linux/uaccess.c b/arch/um/os-Linux/uaccess.c
index 38d710158c3..166fb66995d 100644
--- a/arch/um/os-Linux/uaccess.c
+++ b/arch/um/os-Linux/uaccess.c
@@ -6,6 +6,7 @@
#include <setjmp.h>
#include <string.h>
+#include "longjmp.h"
unsigned long __do_user_copy(void *to, const void *from, int n,
void **fault_addr, void **fault_catcher,
@@ -13,10 +14,11 @@ unsigned long __do_user_copy(void *to, const void *from, int n,
int n), int *faulted_out)
{
unsigned long *faddrp = (unsigned long *) fault_addr, ret;
+ int enable;
sigjmp_buf jbuf;
*fault_catcher = &jbuf;
- if(sigsetjmp(jbuf, 1) == 0){
+ if(UML_SIGSETJMP(&jbuf, enable) == 0){
(*op)(to, from, n);
ret = 0;
*faulted_out = 0;
diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c
new file mode 100644
index 00000000000..ecf107ae5ac
--- /dev/null
+++ b/arch/um/os-Linux/umid.c
@@ -0,0 +1,335 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include "init.h"
+#include "os.h"
+#include "user.h"
+#include "mode.h"
+
+#define UML_DIR "~/.uml/"
+
+#define UMID_LEN 64
+
+/* Changed by set_umid, which is run early in boot */
+char umid[UMID_LEN] = { 0 };
+
+/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */
+static char *uml_dir = UML_DIR;
+
+static int __init make_uml_dir(void)
+{
+ char dir[512] = { '\0' };
+ int len, err;
+
+ if(*uml_dir == '~'){
+ char *home = getenv("HOME");
+
+ err = -ENOENT;
+ if(home == NULL){
+ printk("make_uml_dir : no value in environment for "
+ "$HOME\n");
+ goto err;
+ }
+ strlcpy(dir, home, sizeof(dir));
+ uml_dir++;
+ }
+ strlcat(dir, uml_dir, sizeof(dir));
+ len = strlen(dir);
+ if (len > 0 && dir[len - 1] != '/')
+ strlcat(dir, "/", sizeof(dir));
+
+ err = -ENOMEM;
+ uml_dir = malloc(strlen(dir) + 1);
+ if (uml_dir == NULL) {
+ printf("make_uml_dir : malloc failed, errno = %d\n", errno);
+ goto err;
+ }
+ strcpy(uml_dir, dir);
+
+ if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
+ printf("Failed to mkdir '%s': %s\n", uml_dir, strerror(errno));
+ err = -errno;
+ goto err_free;
+ }
+ return 0;
+
+err_free:
+ free(uml_dir);
+err:
+ uml_dir = NULL;
+ return err;
+}
+
+static int actually_do_remove(char *dir)
+{
+ DIR *directory;
+ struct dirent *ent;
+ int len;
+ char file[256];
+
+ directory = opendir(dir);
+ if(directory == NULL)
+ return -errno;
+
+ while((ent = readdir(directory)) != NULL){
+ if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
+ continue;
+ len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1;
+ if(len > sizeof(file))
+ return -E2BIG;
+
+ sprintf(file, "%s/%s", dir, ent->d_name);
+ if(unlink(file) < 0)
+ return -errno;
+ }
+ if(rmdir(dir) < 0)
+ return -errno;
+
+ return 0;
+}
+
+/* This says that there isn't already a user of the specified directory even if
+ * there are errors during the checking. This is because if these errors
+ * happen, the directory is unusable by the pre-existing UML, so we might as
+ * well take it over. This could happen either by
+ * the existing UML somehow corrupting its umid directory
+ * something other than UML sticking stuff in the directory
+ * this boot racing with a shutdown of the other UML
+ * In any of these cases, the directory isn't useful for anything else.
+ */
+
+static int not_dead_yet(char *dir)
+{
+ char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
+ char pid[sizeof("nnnnn\0")], *end;
+ int dead, fd, p, n, err;
+
+ n = snprintf(file, sizeof(file), "%s/pid", dir);
+ if(n >= sizeof(file)){
+ printk("not_dead_yet - pid filename too long\n");
+ err = -E2BIG;
+ goto out;
+ }
+
+ dead = 0;
+ fd = open(file, O_RDONLY);
+ if(fd < 0){
+ if(fd != -ENOENT){
+ printk("not_dead_yet : couldn't open pid file '%s', "
+ "err = %d\n", file, -fd);
+ }
+ goto out;
+ }
+
+ err = 0;
+ n = read(fd, pid, sizeof(pid));
+ if(n <= 0){
+ printk("not_dead_yet : couldn't read pid file '%s', "
+ "err = %d\n", file, -n);
+ goto out_close;
+ }
+
+ p = strtoul(pid, &end, 0);
+ if(end == pid){
+ printk("not_dead_yet : couldn't parse pid file '%s', "
+ "errno = %d\n", file, errno);
+ goto out_close;
+ }
+
+ if((kill(p, 0) == 0) || (errno != ESRCH))
+ return 1;
+
+ err = actually_do_remove(dir);
+ if(err)
+ printk("not_dead_yet - actually_do_remove failed with "
+ "err = %d\n", err);
+
+ return err;
+
+ out_close:
+ close(fd);
+ out:
+ return 0;
+}
+
+static void __init create_pid_file(void)
+{
+ char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
+ char pid[sizeof("nnnnn\0")];
+ int fd, n;
+
+ if(umid_file_name("pid", file, sizeof(file)))
+ return;
+
+ fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0644);
+ if(fd < 0){
+ printk("Open of machine pid file \"%s\" failed: %s\n",
+ file, strerror(-fd));
+ return;
+ }
+
+ snprintf(pid, sizeof(pid), "%d\n", getpid());
+ n = write(fd, pid, strlen(pid));
+ if(n != strlen(pid))
+ printk("Write of pid file failed - err = %d\n", -n);
+
+ close(fd);
+}
+
+int __init set_umid(char *name)
+{
+ if(strlen(name) > UMID_LEN - 1)
+ return -E2BIG;
+
+ strlcpy(umid, name, sizeof(umid));
+
+ return 0;
+}
+
+static int umid_setup = 0;
+
+int __init make_umid(void)
+{
+ int fd, err;
+ char tmp[256];
+
+ if(umid_setup)
+ return 0;
+
+ make_uml_dir();
+
+ if(*umid == '\0'){
+ strlcpy(tmp, uml_dir, sizeof(tmp));
+ strlcat(tmp, "XXXXXX", sizeof(tmp));
+ fd = mkstemp(tmp);
+ if(fd < 0){
+ printk("make_umid - mkstemp(%s) failed: %s\n",
+ tmp, strerror(errno));
+ err = -errno;
+ goto err;
+ }
+
+ close(fd);
+
+ set_umid(&tmp[strlen(uml_dir)]);
+
+ /* There's a nice tiny little race between this unlink and
+ * the mkdir below. It'd be nice if there were a mkstemp
+ * for directories.
+ */
+ if(unlink(tmp)){
+ err = -errno;
+ goto err;
+ }
+ }
+
+ snprintf(tmp, sizeof(tmp), "%s%s", uml_dir, umid);
+ err = mkdir(tmp, 0777);
+ if(err < 0){
+ err = -errno;
+ if(errno != EEXIST)
+ goto err;
+
+ if(not_dead_yet(tmp) < 0)
+ goto err;
+
+ err = mkdir(tmp, 0777);
+ }
+ if(err < 0){
+ printk("Failed to create '%s' - err = %d\n", umid, err);
+ goto err_rmdir;
+ }
+
+ umid_setup = 1;
+
+ create_pid_file();
+
+ return 0;
+
+ err_rmdir:
+ rmdir(tmp);
+ err:
+ return err;
+}
+
+static int __init make_umid_init(void)
+{
+ make_umid();
+
+ return 0;
+}
+
+__initcall(make_umid_init);
+
+int __init umid_file_name(char *name, char *buf, int len)
+{
+ int n, err;
+
+ err = make_umid();
+ if(err)
+ return err;
+
+ n = snprintf(buf, len, "%s%s/%s", uml_dir, umid, name);
+ if(n >= len){
+ printk("umid_file_name : buffer too short\n");
+ return -E2BIG;
+ }
+
+ return 0;
+}
+
+char *get_umid(void)
+{
+ return umid;
+}
+
+static int __init set_uml_dir(char *name, int *add)
+{
+ if(*name == '\0'){
+ printf("uml_dir can't be an empty string\n");
+ return 0;
+ }
+
+ if(name[strlen(name) - 1] == '/'){
+ uml_dir = name;
+ return 0;
+ }
+
+ uml_dir = malloc(strlen(name) + 2);
+ if(uml_dir == NULL){
+ printf("Failed to malloc uml_dir - error = %d\n", errno);
+
+ /* Return 0 here because do_initcalls doesn't look at
+ * the return value.
+ */
+ return 0;
+ }
+ sprintf(uml_dir, "%s/", name);
+
+ return 0;
+}
+
+__uml_setup("uml_dir=", set_uml_dir,
+"uml_dir=<directory>\n"
+" The location to place the pid and umid files.\n\n"
+);
+
+static void remove_umid_dir(void)
+{
+ char dir[strlen(uml_dir) + UMID_LEN + 1], err;
+
+ sprintf(dir, "%s%s", uml_dir, umid);
+ err = actually_do_remove(dir);
+ if(err)
+ printf("remove_umid_dir - actually_do_remove failed with "
+ "err = %d\n", err);
+}
+
+__uml_exitcall(remove_umid_dir);
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c
index 56d3f870926..8da6ab31152 100644
--- a/arch/um/os-Linux/user_syms.c
+++ b/arch/um/os-Linux/user_syms.c
@@ -34,6 +34,11 @@ EXPORT_SYMBOL(strstr);
int sym(void); \
EXPORT_SYMBOL(sym);
+extern void readdir64(void) __attribute__((weak));
+EXPORT_SYMBOL(readdir64);
+extern void truncate64(void) __attribute__((weak));
+EXPORT_SYMBOL(truncate64);
+
#ifdef SUBARCH_i386
EXPORT_SYMBOL(vsyscall_ehdr);
EXPORT_SYMBOL(vsyscall_end);
diff --git a/arch/um/kernel/user_util.c b/arch/um/os-Linux/util.c
index 4c231161f25..e32065e2fdc 100644
--- a/arch/um/kernel/user_util.c
+++ b/arch/um/os-Linux/util.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -29,17 +29,14 @@
#include "init.h"
#include "ptrace_user.h"
#include "uml-config.h"
-
-void stop(void)
-{
- while(1) sleep(1000000);
-}
+#include "os.h"
+#include "longjmp.h"
void stack_protections(unsigned long address)
{
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
- if(mprotect((void *) address, page_size(), prot) < 0)
+ if(mprotect((void *) address, page_size(), prot) < 0)
panic("protecting stack failed, errno = %d", errno);
}
@@ -59,49 +56,6 @@ void task_protections(unsigned long address)
panic("protecting stack failed, errno = %d", errno);
}
-int wait_for_stop(int pid, int sig, int cont_type, void *relay)
-{
- sigset_t *relay_signals = relay;
- int status, ret;
-
- while(1){
- CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED));
- if((ret < 0) ||
- !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
- if(ret < 0){
- printk("wait failed, errno = %d\n",
- errno);
- }
- else if(WIFEXITED(status))
- printk("process %d exited with status %d\n",
- pid, WEXITSTATUS(status));
- else if(WIFSIGNALED(status))
- printk("process %d exited with signal %d\n",
- pid, WTERMSIG(status));
- else if((WSTOPSIG(status) == SIGVTALRM) ||
- (WSTOPSIG(status) == SIGALRM) ||
- (WSTOPSIG(status) == SIGIO) ||
- (WSTOPSIG(status) == SIGPROF) ||
- (WSTOPSIG(status) == SIGCHLD) ||
- (WSTOPSIG(status) == SIGWINCH) ||
- (WSTOPSIG(status) == SIGINT)){
- ptrace(cont_type, pid, 0, WSTOPSIG(status));
- continue;
- }
- else if((relay_signals != NULL) &&
- sigismember(relay_signals, WSTOPSIG(status))){
- ptrace(cont_type, pid, 0, WSTOPSIG(status));
- continue;
- }
- else printk("process %d stopped with signal %d\n",
- pid, WSTOPSIG(status));
- panic("wait_for_stop failed to wait for %d to stop "
- "with %d\n", pid, sig);
- }
- return(status);
- }
-}
-
int raw(int fd)
{
struct termios tt;
@@ -113,7 +67,7 @@ int raw(int fd)
cfmakeraw(&tt);
- CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt));
+ CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt));
if(err < 0)
return -errno;
@@ -149,7 +103,7 @@ void setup_hostinfo(void)
int setjmp_wrapper(void (*proc)(void *, void *), ...)
{
- va_list args;
+ va_list args;
sigjmp_buf buf;
int n;
@@ -161,14 +115,3 @@ int setjmp_wrapper(void (*proc)(void *, void *), ...)
va_end(args);
return(n);
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
index b3fbf125709..2e41cabd3d9 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -21,11 +21,6 @@ define unprofile
endef
-# The stubs and unmap.o can't try to call mcount or update basic block data
-define unprofile
- $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
-endef
-
# cmd_make_link checks to see if the $(foo-dir) variable starts with a /. If
# so, it's considered to be a path relative to $(srcdir) rather than
# $(srcdir)/arch/$(SUBARCH). This is because x86_64 wants to get ldt.c from
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 150059dbee1..f5fd5b0156d 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,6 +1,8 @@
-obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
- ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \
- syscalls.o sysrq.o sys_call_table.o
+obj-y := bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
+ ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \
+ sys_call_table.o
+
+obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_MODULES) += module.o
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index 17746b4c08f..0cdfd4481d5 100644
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -16,6 +16,8 @@
#include "choose-mode.h"
#include "kern.h"
#include "mode_kern.h"
+#include "proc_mm.h"
+#include "os.h"
extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
@@ -456,13 +458,14 @@ long init_new_ldt(struct mmu_context_skas * new_mm,
int i;
long page, err=0;
void *addr = NULL;
+ struct proc_mm_op copy;
- memset(&desc, 0, sizeof(desc));
if(!ptrace_ldt)
init_MUTEX(&new_mm->ldt.semaphore);
if(!from_mm){
+ memset(&desc, 0, sizeof(desc));
/*
* We have to initialize a clean ldt.
*/
@@ -494,8 +497,26 @@ long init_new_ldt(struct mmu_context_skas * new_mm,
}
}
new_mm->ldt.entry_count = 0;
+
+ goto out;
}
- else if (!ptrace_ldt) {
+
+ 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, &copy, sizeof(copy));
+ if(i != sizeof(copy))
+ printk("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
@@ -524,6 +545,7 @@ long init_new_ldt(struct mmu_context_skas * new_mm,
up(&from_mm->ldt.semaphore);
}
+ out:
return err;
}
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 16bc19928b3..7cd1a82dc8c 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -10,7 +10,6 @@
#include "asm/uaccess.h"
#include "asm/unistd.h"
#include "frame_kern.h"
-#include "signal_user.h"
#include "sigcontext.h"
#include "registers.h"
#include "mode.h"
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 00b2025427d..a351091fbd9 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -6,8 +6,9 @@
#XXX: why into lib-y?
lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o ldt.o mem.o memcpy.o \
- ptrace.o ptrace_user.o sigcontext.o signal.o stub.o \
- stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
+ ptrace.o ptrace_user.o sigcontext.o signal.o syscalls.o \
+ syscall_table.o sysrq.o thunk.o
+lib-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
obj-y := ksyms.o
obj-$(CONFIG_MODULES) += module.o um_module.o