summaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2006-01-27 17:18:29 -0500
committerLen Brown <len.brown@intel.com>2006-01-27 17:18:29 -0500
commit292dd876ee765c478b27c93cc51e93a558ed58bf (patch)
tree5b740e93253295baee2a9c414a6c66d03d44a9ef /arch/um
parentd4ec6c7cc9a15a7a529719bc3b84f46812f9842e (diff)
parent9fdb62af92c741addbea15545f214a6e89460865 (diff)
downloadop-kernel-dev-292dd876ee765c478b27c93cc51e93a558ed58bf.zip
op-kernel-dev-292dd876ee765c478b27c93cc51e93a558ed58bf.tar.gz
Pull release into acpica branch
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/Kconfig41
-rw-r--r--arch/um/Kconfig.i3866
-rw-r--r--arch/um/Makefile28
-rw-r--r--arch/um/drivers/chan_kern.c6
-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/mconsole_kern.c2
-rw-r--r--arch/um/drivers/net_kern.c21
-rw-r--r--arch/um/drivers/ubd_kern.c81
-rw-r--r--arch/um/include/kern_util.h23
-rw-r--r--arch/um/include/longjmp.h19
-rw-r--r--arch/um/include/mode_kern.h15
-rw-r--r--arch/um/include/os.h74
-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-x86_64/kernel-offsets.h (renamed from arch/um/sys-x86_64/kernel-offsets.c)2
-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.h28
-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.c1
-rw-r--r--arch/um/kernel/process_kern.c25
-rw-r--r--arch/um/kernel/reboot.c2
-rw-r--r--arch/um/kernel/sigio_user.c83
-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/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.c11
-rw-r--r--arch/um/os-Linux/Makefile8
-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.c2
-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/util.c (renamed from arch/um/kernel/user_util.c)69
-rw-r--r--arch/um/sys-i386/ldt.c26
-rw-r--r--arch/um/sys-i386/signal.c1
83 files changed, 1854 insertions, 1141 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 1eb21de..5982fe2 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,17 +274,13 @@ 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"
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386
index c71b39a..ef79ed2 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 1b12fee..6430a63 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/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index cd13b91..ab0d0b1 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -186,9 +186,6 @@ 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);
}
@@ -653,8 +650,7 @@ 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)){
+ if (tty && !tty_buffer_request_room(tty, 1)) {
schedule_delayed_work(task, 1);
goto out;
}
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
index 30d285b..507e3cb 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 1bb085b2..c944265 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 3296e86..c41f75e 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/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index be61012..e3d5765 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -500,7 +500,7 @@ static void console_write(struct console *console, const char *string,
static struct console mc_console = { .name = "mc",
.write = console_write,
- .flags = CON_PRINTBUFFER | CON_ENABLED,
+ .flags = CON_ENABLED,
.index = -1 };
static int mc_add_console(void)
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index fb1f9fb..8ebb224 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -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);
}
@@ -317,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);
@@ -358,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
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 73f9652..101efd2 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 */
@@ -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,
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index e5fec55..c649108 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/longjmp.h b/arch/um/include/longjmp.h
new file mode 100644
index 0000000..018b381
--- /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/mode_kern.h b/arch/um/include/mode_kern.h
index 2d88afd..e7539a8 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 c279ee6..eb1710b 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);
@@ -219,4 +223,72 @@ 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 b075e54..0000000
--- 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 48dd098..48dd098 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 0000000..d8869a6
--- /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 0000000..260065c
--- /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 c97a80d..63c5873 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 cce61a6..9028092 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 0000000..8635728
--- /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 f6ed92c..f6ed92c 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 64516c5..224a75f 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 764ba4d..7d3d202 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 35db850..82f96c5 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/sys-x86_64/kernel-offsets.c b/arch/um/include/sysdep-x86_64/kernel-offsets.h
index bfcb104..5ce93abd 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/time_user.h b/arch/um/include/time_user.h
deleted file mode 100644
index 17d7ef2..0000000
--- 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 7384354..9778fa8 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 0000000..572a78b2
--- /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 0000000..2823cd5
--- /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 0000000..efa0012
--- /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 c667b67..8085219 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 b9bfe9c..b19645f 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 0f865ef..91b0ac4 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 b998400..a6f1f17 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,11 +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 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);
@@ -76,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 6f77005..693018b 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 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 c13a64a..91ea538 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 efd222f..569fe8b 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 50a2aa3..0e32f5f 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"
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index 651abf2..3113cab 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)
@@ -371,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 a637e88..6f1a3a2 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 62e5cfd..f7b18e1 100644
--- a/arch/um/kernel/sigio_user.c
+++ b/arch/um/kernel/sigio_user.c
@@ -337,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();
- err = os_pipe(write_sigio_fds, 1, 1);
+ if (l_write_sigio_pid != -1)
+ return;
+
+ 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 03618bd..da17b75 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 62f4578..0000000
--- 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 8de471b..57181a9 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/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
deleted file mode 100644
index 44110c5..0000000
--- 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 bcd26a6..0000000
--- 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 daa2f85..0000000
--- 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 677871f..c5c9885 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 599d679..eea1c9c4 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 9c99025..3f70a2e 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 a5a4752..5992c32 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 1429c13..1731d90 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 c40b611..8fa2ae7 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 020ca79..3c7626c 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 0d4c10a..d56046c 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 e9ccd6b..0000000
--- 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 065b504..5c1e4cc 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 37e22d7..786e4ed 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 0440510..0000000
--- 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 cfaa373a..295c1ac 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 528a5fc..0377442 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 a5f0e01..99f1783 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 d11e739..71daae2 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 fc10861..b5d9d64 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 26626b2b..e2d3ca4 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
*/
@@ -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/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index 11e30b13..08a4e62 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 umid.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 umid.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/helper.c b/arch/um/os-Linux/helper.c
index 36cc847..6490a4f 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 23da27d..2878e89 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 d9c5238..7f5e2da 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 c7bfd5e..f11b312 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 0000000..5fd8d4d
--- /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 1d89640..9890e90 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 0000000..120a21c
--- /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 9950a67..9ad5fbec 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 29a9e3f..6c5b17e 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"
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index cf30a39..6f76267 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 0000000..a9f6b26
--- /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 a6db887..919d19f 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 38d7101..166fb66 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/kernel/user_util.c b/arch/um/os-Linux/util.c
index 4c23116..e32065e 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/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index 17746b4..0cdfd44 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 16bc1992..7cd1a82 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"
OpenPOWER on IntegriCloud