diff options
author | Len Brown <len.brown@intel.com> | 2005-09-08 01:45:47 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2005-09-08 01:45:47 -0400 |
commit | 64e47488c913ac704d465a6af86a26786d1412a5 (patch) | |
tree | d3b0148592963dcde26e4bb35ddfec8b1eaf8e23 /arch/um | |
parent | 4a35a46bf1cda4737c428380d1db5d15e2590d18 (diff) | |
parent | caf39e87cc1182f7dae84eefc43ca14d54c78ef9 (diff) |
Merge linux-2.6 with linux-acpi-2.6
Diffstat (limited to 'arch/um')
68 files changed, 1823 insertions, 1147 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig index f945444df49c..684e1f8b2755 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig | |||
@@ -73,7 +73,7 @@ config MODE_SKAS | |||
73 | to CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this | 73 | to CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this |
74 | option will shrink the UML binary slightly. | 74 | option will shrink the UML binary slightly. |
75 | 75 | ||
76 | source "arch/um/Kconfig_arch" | 76 | source "arch/um/Kconfig.arch" |
77 | source "mm/Kconfig" | 77 | source "mm/Kconfig" |
78 | 78 | ||
79 | config LD_SCRIPT_STATIC | 79 | config LD_SCRIPT_STATIC |
@@ -196,7 +196,7 @@ config HOST_2G_2G | |||
196 | config SMP | 196 | config SMP |
197 | bool "Symmetric multi-processing support (EXPERIMENTAL)" | 197 | bool "Symmetric multi-processing support (EXPERIMENTAL)" |
198 | default n | 198 | default n |
199 | depends on MODE_TT && EXPERIMENTAL | 199 | depends on (MODE_TT && EXPERIMENTAL && !SMP_BROKEN) || (BROKEN && SMP_BROKEN) |
200 | help | 200 | help |
201 | This option enables UML SMP support. | 201 | This option enables UML SMP support. |
202 | It is NOT related to having a real SMP box. Not directly, at least. | 202 | It is NOT related to having a real SMP box. Not directly, at least. |
@@ -279,7 +279,7 @@ source "net/Kconfig" | |||
279 | 279 | ||
280 | source "drivers/base/Kconfig" | 280 | source "drivers/base/Kconfig" |
281 | 281 | ||
282 | source "arch/um/Kconfig_char" | 282 | source "arch/um/Kconfig.char" |
283 | 283 | ||
284 | source "drivers/block/Kconfig" | 284 | source "drivers/block/Kconfig" |
285 | 285 | ||
@@ -287,7 +287,7 @@ config NETDEVICES | |||
287 | bool | 287 | bool |
288 | default NET | 288 | default NET |
289 | 289 | ||
290 | source "arch/um/Kconfig_net" | 290 | source "arch/um/Kconfig.net" |
291 | 291 | ||
292 | source "drivers/net/Kconfig" | 292 | source "drivers/net/Kconfig" |
293 | 293 | ||
@@ -311,7 +311,7 @@ config GENERIC_ISA_DMA | |||
311 | depends on SCSI | 311 | depends on SCSI |
312 | default y | 312 | default y |
313 | 313 | ||
314 | source "arch/um/Kconfig_scsi" | 314 | source "arch/um/Kconfig.scsi" |
315 | 315 | ||
316 | endmenu | 316 | endmenu |
317 | 317 | ||
diff --git a/arch/um/Kconfig_char b/arch/um/Kconfig.char index 62d87b71179b..62d87b71179b 100644 --- a/arch/um/Kconfig_char +++ b/arch/um/Kconfig.char | |||
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug index bd41e4286d0d..5681a8bd370b 100644 --- a/arch/um/Kconfig.debug +++ b/arch/um/Kconfig.debug | |||
@@ -2,6 +2,17 @@ menu "Kernel hacking" | |||
2 | 2 | ||
3 | source "lib/Kconfig.debug" | 3 | source "lib/Kconfig.debug" |
4 | 4 | ||
5 | config CMDLINE_ON_HOST | ||
6 | bool "Show command line arguments on the host in TT mode" | ||
7 | depends on MODE_TT | ||
8 | default !DEBUG_INFO | ||
9 | help | ||
10 | This controls whether arguments in guest processes should be shown on | ||
11 | the host's ps output. | ||
12 | Enabling this option hinders debugging on some recent GDB versions | ||
13 | (because GDB gets "confused" when we do an execvp()). So probably you | ||
14 | should disable it. | ||
15 | |||
5 | config PT_PROXY | 16 | config PT_PROXY |
6 | bool "Enable ptrace proxy" | 17 | bool "Enable ptrace proxy" |
7 | depends on XTERM_CHAN && DEBUG_INFO && MODE_TT | 18 | depends on XTERM_CHAN && DEBUG_INFO && MODE_TT |
diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig.i386 index 27c18a8d9d17..8ad156a00499 100644 --- a/arch/um/Kconfig_i386 +++ b/arch/um/Kconfig.i386 | |||
@@ -6,6 +6,10 @@ config 64BIT | |||
6 | bool | 6 | bool |
7 | default n | 7 | default n |
8 | 8 | ||
9 | config SEMAPHORE_SLEEPERS | ||
10 | bool | ||
11 | default y | ||
12 | |||
9 | config TOP_ADDR | 13 | config TOP_ADDR |
10 | hex | 14 | hex |
11 | default 0xc0000000 if !HOST_2G_2G | 15 | default 0xc0000000 if !HOST_2G_2G |
diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig.net index fa2ab2dd78b7..14a04ebdeae9 100644 --- a/arch/um/Kconfig_net +++ b/arch/um/Kconfig.net | |||
@@ -34,7 +34,7 @@ config UML_NET_ETHERTAP | |||
34 | link with the host. | 34 | link with the host. |
35 | 35 | ||
36 | To use this, your host kernel must have support for Ethertap | 36 | To use this, your host kernel must have support for Ethertap |
37 | devices. Also, if your host kernel is 2.4.x, it must have | 37 | devices. Also, if your host kernel is 2.4.x, it must have |
38 | CONFIG_NETLINK_DEV configured as Y or M. | 38 | CONFIG_NETLINK_DEV configured as Y or M. |
39 | 39 | ||
40 | For more information, see | 40 | For more information, see |
@@ -43,7 +43,7 @@ config UML_NET_ETHERTAP | |||
43 | networking. | 43 | networking. |
44 | 44 | ||
45 | If you'd like to set up an IP network with the host and/or the | 45 | If you'd like to set up an IP network with the host and/or the |
46 | outside world, say Y to this, the Daemon Transport and/or the | 46 | outside world, say Y to this, the Daemon Transport and/or the |
47 | Slip Transport. You'll need at least one of them, but may choose | 47 | Slip Transport. You'll need at least one of them, but may choose |
48 | more than one without conflict. If you don't need UML networking, | 48 | more than one without conflict. If you don't need UML networking, |
49 | say N. | 49 | say N. |
@@ -78,7 +78,7 @@ config UML_NET_SLIP | |||
78 | 78 | ||
79 | The Ethertap Transport is preferred over slip because of its | 79 | The Ethertap Transport is preferred over slip because of its |
80 | limitations. If you prefer slip, however, say Y here. Otherwise | 80 | limitations. If you prefer slip, however, say Y here. Otherwise |
81 | choose the Multicast transport (to network multiple UMLs on | 81 | choose the Multicast transport (to network multiple UMLs on |
82 | multiple hosts), Ethertap (to network with the host and the | 82 | multiple hosts), Ethertap (to network with the host and the |
83 | outside world), and/or the Daemon transport (to network multiple | 83 | outside world), and/or the Daemon transport (to network multiple |
84 | UMLs on a single host). You may choose more than one without | 84 | UMLs on a single host). You may choose more than one without |
@@ -138,7 +138,7 @@ config UML_NET_PCAP | |||
138 | depends on UML_NET && EXPERIMENTAL | 138 | depends on UML_NET && EXPERIMENTAL |
139 | help | 139 | help |
140 | The pcap transport makes a pcap packet stream on the host look | 140 | The pcap transport makes a pcap packet stream on the host look |
141 | like an ethernet device inside UML. This is useful for making | 141 | like an ethernet device inside UML. This is useful for making |
142 | UML act as a network monitor for the host. You must have libcap | 142 | UML act as a network monitor for the host. You must have libcap |
143 | installed in order to build the pcap transport into UML. | 143 | installed in order to build the pcap transport into UML. |
144 | 144 | ||
@@ -169,11 +169,11 @@ config UML_NET_SLIRP | |||
169 | setup string. The effect of this transport on the UML is similar | 169 | setup string. The effect of this transport on the UML is similar |
170 | that of a host behind a firewall that masquerades all network | 170 | that of a host behind a firewall that masquerades all network |
171 | connections passing through it (but is less secure). | 171 | connections passing through it (but is less secure). |
172 | 172 | ||
173 | To use this you should first have slirp compiled somewhere | 173 | To use this you should first have slirp compiled somewhere |
174 | accessible on the host, and have read its documentation. If you | 174 | accessible on the host, and have read its documentation. If you |
175 | don't need UML networking, say N. | 175 | don't need UML networking, say N. |
176 | 176 | ||
177 | Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp" | 177 | Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp" |
178 | 178 | ||
179 | endmenu | 179 | endmenu |
diff --git a/arch/um/Kconfig_scsi b/arch/um/Kconfig.scsi index c291c942b1a8..c291c942b1a8 100644 --- a/arch/um/Kconfig_scsi +++ b/arch/um/Kconfig.scsi | |||
diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig.x86_64 index 735a047c890c..bd35e59419c8 100644 --- a/arch/um/Kconfig_x86_64 +++ b/arch/um/Kconfig.x86_64 | |||
@@ -6,6 +6,10 @@ config 64BIT | |||
6 | bool | 6 | bool |
7 | default y | 7 | default y |
8 | 8 | ||
9 | config SEMAPHORE_SLEEPERS | ||
10 | bool | ||
11 | default y | ||
12 | |||
9 | config TOP_ADDR | 13 | config TOP_ADDR |
10 | hex | 14 | hex |
11 | default 0x80000000 | 15 | default 0x80000000 |
@@ -33,3 +37,7 @@ config ARCH_HAS_SC_SIGNALS | |||
33 | config ARCH_REUSE_HOST_VSYSCALL_AREA | 37 | config ARCH_REUSE_HOST_VSYSCALL_AREA |
34 | bool | 38 | bool |
35 | default n | 39 | default n |
40 | |||
41 | config SMP_BROKEN | ||
42 | bool | ||
43 | default y | ||
diff --git a/arch/um/Makefile b/arch/um/Makefile index f5a83a72aa75..b15f6048caae 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile | |||
@@ -56,6 +56,7 @@ SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH) | |||
56 | 56 | ||
57 | CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ | 57 | CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ |
58 | $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap | 58 | $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap |
59 | AFLAGS += $(ARCH_INCLUDE) | ||
59 | 60 | ||
60 | USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) | 61 | USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) |
61 | USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ | 62 | USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ |
@@ -101,10 +102,10 @@ define archhelp | |||
101 | endef | 102 | endef |
102 | 103 | ||
103 | ifneq ($(KBUILD_SRC),) | 104 | ifneq ($(KBUILD_SRC),) |
104 | $(shell mkdir -p $(ARCH_DIR) && ln -fsn $(srctree)/$(ARCH_DIR)/Kconfig_$(SUBARCH) $(ARCH_DIR)/Kconfig_arch) | 105 | $(shell mkdir -p $(ARCH_DIR) && ln -fsn $(srctree)/$(ARCH_DIR)/Kconfig.$(SUBARCH) $(ARCH_DIR)/Kconfig.arch) |
105 | CLEAN_FILES += $(ARCH_DIR)/Kconfig_arch | 106 | CLEAN_FILES += $(ARCH_DIR)/Kconfig.arch |
106 | else | 107 | else |
107 | $(shell cd $(ARCH_DIR) && ln -sf Kconfig_$(SUBARCH) Kconfig_arch) | 108 | $(shell cd $(ARCH_DIR) && ln -sf Kconfig.$(SUBARCH) Kconfig.arch) |
108 | endif | 109 | endif |
109 | 110 | ||
110 | prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) | 111 | prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) |
@@ -147,7 +148,7 @@ CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \ | |||
147 | 148 | ||
148 | MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ | 149 | MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ |
149 | $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os \ | 150 | $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os \ |
150 | $(ARCH_DIR)/Kconfig_arch | 151 | $(ARCH_DIR)/Kconfig.arch |
151 | 152 | ||
152 | archclean: | 153 | archclean: |
153 | $(Q)$(MAKE) $(clean)=$(ARCH_DIR)/util | 154 | $(Q)$(MAKE) $(clean)=$(ARCH_DIR)/util |
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index a777e57dbf89..1ab431a53ac3 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 | |||
@@ -27,7 +27,7 @@ export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UML_OBJCOPYFLAGS | |||
27 | endif | 27 | endif |
28 | endif | 28 | endif |
29 | 29 | ||
30 | CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS) | 30 | CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) |
31 | 31 | ||
32 | ifneq ($(CONFIG_GPROF),y) | 32 | ifneq ($(CONFIG_GPROF),y) |
33 | ARCH_CFLAGS += -DUM_FASTCALL | 33 | ARCH_CFLAGS += -DUM_FASTCALL |
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index aa2f7174ebca..baddb5d64ca5 100644 --- a/arch/um/Makefile-x86_64 +++ b/arch/um/Makefile-x86_64 | |||
@@ -6,7 +6,7 @@ START := 0x60000000 | |||
6 | 6 | ||
7 | #We #undef __x86_64__ for kernelspace, not for userspace where | 7 | #We #undef __x86_64__ for kernelspace, not for userspace where |
8 | #it's needed for headers to work! | 8 | #it's needed for headers to work! |
9 | CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS) | 9 | CFLAGS += -U__$(SUBARCH)__ -fno-builtin |
10 | USER_CFLAGS += -fno-builtin | 10 | USER_CFLAGS += -fno-builtin |
11 | 11 | ||
12 | ELF_ARCH := i386:x86-64 | 12 | ELF_ARCH := i386:x86-64 |
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index de17d4c6e02d..783e18cae090 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile | |||
@@ -13,7 +13,7 @@ mcast-objs := mcast_kern.o mcast_user.o | |||
13 | net-objs := net_kern.o net_user.o | 13 | net-objs := net_kern.o net_user.o |
14 | mconsole-objs := mconsole_kern.o mconsole_user.o | 14 | mconsole-objs := mconsole_kern.o mconsole_user.o |
15 | hostaudio-objs := hostaudio_kern.o | 15 | hostaudio-objs := hostaudio_kern.o |
16 | ubd-objs := ubd_kern.o ubd_user.o | 16 | ubd-objs := ubd_kern.o |
17 | port-objs := port_kern.o port_user.o | 17 | port-objs := port_kern.o port_user.o |
18 | harddog-objs := harddog_kern.o harddog_user.o | 18 | harddog-objs := harddog_kern.o harddog_user.o |
19 | 19 | ||
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 5d3768156c92..de3bce71aeb3 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c | |||
@@ -63,7 +63,7 @@ error: | |||
63 | * | 63 | * |
64 | * SIGWINCH can't be received synchronously, so you have to set up to receive it | 64 | * SIGWINCH can't be received synchronously, so you have to set up to receive it |
65 | * as a signal. That being the case, if you are going to wait for it, it is | 65 | * as a signal. That being the case, if you are going to wait for it, it is |
66 | * convenient to sit in a pause() and wait for the signal to bounce you out of | 66 | * convenient to sit in sigsuspend() and wait for the signal to bounce you out of |
67 | * it (see below for how we make sure to exit only on SIGWINCH). | 67 | * it (see below for how we make sure to exit only on SIGWINCH). |
68 | */ | 68 | */ |
69 | 69 | ||
@@ -94,18 +94,19 @@ static int winch_thread(void *arg) | |||
94 | "byte, err = %d\n", -count); | 94 | "byte, err = %d\n", -count); |
95 | 95 | ||
96 | /* We are not using SIG_IGN on purpose, so don't fix it as I thought to | 96 | /* We are not using SIG_IGN on purpose, so don't fix it as I thought to |
97 | * do! If using SIG_IGN, the pause() call below would not stop on | 97 | * do! If using SIG_IGN, the sigsuspend() call below would not stop on |
98 | * SIGWINCH. */ | 98 | * SIGWINCH. */ |
99 | 99 | ||
100 | signal(SIGWINCH, winch_handler); | 100 | signal(SIGWINCH, winch_handler); |
101 | sigfillset(&sigs); | 101 | sigfillset(&sigs); |
102 | sigdelset(&sigs, SIGWINCH); | 102 | /* Block all signals possible. */ |
103 | /* Block anything else than SIGWINCH. */ | ||
104 | if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){ | 103 | if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){ |
105 | printk("winch_thread : sigprocmask failed, errno = %d\n", | 104 | printk("winch_thread : sigprocmask failed, errno = %d\n", |
106 | errno); | 105 | errno); |
107 | exit(1); | 106 | exit(1); |
108 | } | 107 | } |
108 | /* In sigsuspend(), block anything else than SIGWINCH. */ | ||
109 | sigdelset(&sigs, SIGWINCH); | ||
109 | 110 | ||
110 | if(setsid() < 0){ | 111 | if(setsid() < 0){ |
111 | printk("winch_thread : setsid failed, errno = %d\n", errno); | 112 | printk("winch_thread : setsid failed, errno = %d\n", errno); |
@@ -130,7 +131,7 @@ static int winch_thread(void *arg) | |||
130 | while(1){ | 131 | while(1){ |
131 | /* This will be interrupted by SIGWINCH only, since other signals | 132 | /* This will be interrupted by SIGWINCH only, since other signals |
132 | * are blocked.*/ | 133 | * are blocked.*/ |
133 | pause(); | 134 | sigsuspend(&sigs); |
134 | 135 | ||
135 | count = os_write_file(pipe_fd, &c, sizeof(c)); | 136 | count = os_write_file(pipe_fd, &c, sizeof(c)); |
136 | if(count != sizeof(c)) | 137 | if(count != sizeof(c)) |
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 344b24d09a7c..e77a38da4350 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "linux/blkpg.h" | 35 | #include "linux/blkpg.h" |
36 | #include "linux/genhd.h" | 36 | #include "linux/genhd.h" |
37 | #include "linux/spinlock.h" | 37 | #include "linux/spinlock.h" |
38 | #include "asm/atomic.h" | ||
38 | #include "asm/segment.h" | 39 | #include "asm/segment.h" |
39 | #include "asm/uaccess.h" | 40 | #include "asm/uaccess.h" |
40 | #include "asm/irq.h" | 41 | #include "asm/irq.h" |
@@ -53,20 +54,21 @@ | |||
53 | #include "mem.h" | 54 | #include "mem.h" |
54 | #include "mem_kern.h" | 55 | #include "mem_kern.h" |
55 | #include "cow.h" | 56 | #include "cow.h" |
57 | #include "aio.h" | ||
56 | 58 | ||
57 | enum ubd_req { UBD_READ, UBD_WRITE }; | 59 | enum ubd_req { UBD_READ, UBD_WRITE }; |
58 | 60 | ||
59 | struct io_thread_req { | 61 | struct io_thread_req { |
60 | enum ubd_req op; | 62 | enum aio_type op; |
61 | int fds[2]; | 63 | int fds[2]; |
62 | unsigned long offsets[2]; | 64 | unsigned long offsets[2]; |
63 | unsigned long long offset; | 65 | unsigned long long offset; |
64 | unsigned long length; | 66 | unsigned long length; |
65 | char *buffer; | 67 | char *buffer; |
66 | int sectorsize; | 68 | int sectorsize; |
67 | unsigned long sector_mask; | 69 | int bitmap_offset; |
68 | unsigned long long cow_offset; | 70 | long bitmap_start; |
69 | unsigned long bitmap_words[2]; | 71 | long bitmap_end; |
70 | int error; | 72 | int error; |
71 | }; | 73 | }; |
72 | 74 | ||
@@ -80,28 +82,31 @@ extern int create_cow_file(char *cow_file, char *backing_file, | |||
80 | unsigned long *bitmap_len_out, | 82 | unsigned long *bitmap_len_out, |
81 | int *data_offset_out); | 83 | int *data_offset_out); |
82 | extern int read_cow_bitmap(int fd, void *buf, int offset, int len); | 84 | extern int read_cow_bitmap(int fd, void *buf, int offset, int len); |
83 | extern void do_io(struct io_thread_req *req); | 85 | extern void do_io(struct io_thread_req *req, struct request *r, |
86 | unsigned long *bitmap); | ||
84 | 87 | ||
85 | static inline int ubd_test_bit(__u64 bit, unsigned char *data) | 88 | static inline int ubd_test_bit(__u64 bit, void *data) |
86 | { | 89 | { |
90 | unsigned char *buffer = data; | ||
87 | __u64 n; | 91 | __u64 n; |
88 | int bits, off; | 92 | int bits, off; |
89 | 93 | ||
90 | bits = sizeof(data[0]) * 8; | 94 | bits = sizeof(buffer[0]) * 8; |
91 | n = bit / bits; | 95 | n = bit / bits; |
92 | off = bit % bits; | 96 | off = bit % bits; |
93 | return((data[n] & (1 << off)) != 0); | 97 | return((buffer[n] & (1 << off)) != 0); |
94 | } | 98 | } |
95 | 99 | ||
96 | static inline void ubd_set_bit(__u64 bit, unsigned char *data) | 100 | static inline void ubd_set_bit(__u64 bit, void *data) |
97 | { | 101 | { |
102 | unsigned char *buffer = data; | ||
98 | __u64 n; | 103 | __u64 n; |
99 | int bits, off; | 104 | int bits, off; |
100 | 105 | ||
101 | bits = sizeof(data[0]) * 8; | 106 | bits = sizeof(buffer[0]) * 8; |
102 | n = bit / bits; | 107 | n = bit / bits; |
103 | off = bit % bits; | 108 | off = bit % bits; |
104 | data[n] |= (1 << off); | 109 | buffer[n] |= (1 << off); |
105 | } | 110 | } |
106 | /*End stuff from ubd_user.h*/ | 111 | /*End stuff from ubd_user.h*/ |
107 | 112 | ||
@@ -110,8 +115,6 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data) | |||
110 | static DEFINE_SPINLOCK(ubd_io_lock); | 115 | static DEFINE_SPINLOCK(ubd_io_lock); |
111 | static DEFINE_SPINLOCK(ubd_lock); | 116 | static DEFINE_SPINLOCK(ubd_lock); |
112 | 117 | ||
113 | static void (*do_ubd)(void); | ||
114 | |||
115 | static int ubd_open(struct inode * inode, struct file * filp); | 118 | static int ubd_open(struct inode * inode, struct file * filp); |
116 | static int ubd_release(struct inode * inode, struct file * file); | 119 | static int ubd_release(struct inode * inode, struct file * file); |
117 | static int ubd_ioctl(struct inode * inode, struct file * file, | 120 | static int ubd_ioctl(struct inode * inode, struct file * file, |
@@ -158,6 +161,8 @@ struct cow { | |||
158 | int data_offset; | 161 | int data_offset; |
159 | }; | 162 | }; |
160 | 163 | ||
164 | #define MAX_SG 64 | ||
165 | |||
161 | struct ubd { | 166 | struct ubd { |
162 | char *file; | 167 | char *file; |
163 | int count; | 168 | int count; |
@@ -168,6 +173,7 @@ struct ubd { | |||
168 | int no_cow; | 173 | int no_cow; |
169 | struct cow cow; | 174 | struct cow cow; |
170 | struct platform_device pdev; | 175 | struct platform_device pdev; |
176 | struct scatterlist sg[MAX_SG]; | ||
171 | }; | 177 | }; |
172 | 178 | ||
173 | #define DEFAULT_COW { \ | 179 | #define DEFAULT_COW { \ |
@@ -460,80 +466,113 @@ __uml_help(fakehd, | |||
460 | ); | 466 | ); |
461 | 467 | ||
462 | static void do_ubd_request(request_queue_t * q); | 468 | static void do_ubd_request(request_queue_t * q); |
463 | 469 | static int in_ubd; | |
464 | /* Only changed by ubd_init, which is an initcall. */ | ||
465 | int thread_fd = -1; | ||
466 | 470 | ||
467 | /* Changed by ubd_handler, which is serialized because interrupts only | 471 | /* Changed by ubd_handler, which is serialized because interrupts only |
468 | * happen on CPU 0. | 472 | * happen on CPU 0. |
469 | */ | 473 | */ |
470 | int intr_count = 0; | 474 | int intr_count = 0; |
471 | 475 | ||
472 | /* call ubd_finish if you need to serialize */ | 476 | static void ubd_end_request(struct request *req, int bytes, int uptodate) |
473 | static void __ubd_finish(struct request *req, int error) | ||
474 | { | 477 | { |
475 | int nsect; | 478 | if (!end_that_request_first(req, uptodate, bytes >> 9)) { |
476 | 479 | add_disk_randomness(req->rq_disk); | |
477 | if(error){ | 480 | end_that_request_last(req); |
478 | end_request(req, 0); | ||
479 | return; | ||
480 | } | 481 | } |
481 | nsect = req->current_nr_sectors; | ||
482 | req->sector += nsect; | ||
483 | req->buffer += nsect << 9; | ||
484 | req->errors = 0; | ||
485 | req->nr_sectors -= nsect; | ||
486 | req->current_nr_sectors = 0; | ||
487 | end_request(req, 1); | ||
488 | } | 482 | } |
489 | 483 | ||
490 | static inline void ubd_finish(struct request *req, int error) | 484 | /* call ubd_finish if you need to serialize */ |
485 | static void __ubd_finish(struct request *req, int bytes) | ||
491 | { | 486 | { |
492 | spin_lock(&ubd_io_lock); | 487 | if(bytes < 0){ |
493 | __ubd_finish(req, error); | 488 | ubd_end_request(req, 0, 0); |
494 | spin_unlock(&ubd_io_lock); | 489 | return; |
490 | } | ||
491 | |||
492 | ubd_end_request(req, bytes, 1); | ||
495 | } | 493 | } |
496 | 494 | ||
497 | /* Called without ubd_io_lock held */ | 495 | static inline void ubd_finish(struct request *req, int bytes) |
498 | static void ubd_handler(void) | ||
499 | { | 496 | { |
500 | struct io_thread_req req; | 497 | spin_lock(&ubd_io_lock); |
501 | struct request *rq = elv_next_request(ubd_queue); | 498 | __ubd_finish(req, bytes); |
502 | int n; | 499 | spin_unlock(&ubd_io_lock); |
503 | |||
504 | do_ubd = NULL; | ||
505 | intr_count++; | ||
506 | n = os_read_file(thread_fd, &req, sizeof(req)); | ||
507 | if(n != sizeof(req)){ | ||
508 | printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " | ||
509 | "err = %d\n", os_getpid(), -n); | ||
510 | spin_lock(&ubd_io_lock); | ||
511 | end_request(rq, 0); | ||
512 | spin_unlock(&ubd_io_lock); | ||
513 | return; | ||
514 | } | ||
515 | |||
516 | ubd_finish(rq, req.error); | ||
517 | reactivate_fd(thread_fd, UBD_IRQ); | ||
518 | do_ubd_request(ubd_queue); | ||
519 | } | 500 | } |
520 | 501 | ||
502 | struct bitmap_io { | ||
503 | atomic_t count; | ||
504 | struct aio_context aio; | ||
505 | }; | ||
506 | |||
507 | struct ubd_aio { | ||
508 | struct aio_context aio; | ||
509 | struct request *req; | ||
510 | int len; | ||
511 | struct bitmap_io *bitmap; | ||
512 | void *bitmap_buf; | ||
513 | }; | ||
514 | |||
515 | static int ubd_reply_fd = -1; | ||
516 | |||
521 | static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) | 517 | static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) |
522 | { | 518 | { |
523 | ubd_handler(); | 519 | struct aio_thread_reply reply; |
524 | return(IRQ_HANDLED); | 520 | struct ubd_aio *aio; |
525 | } | 521 | struct request *req; |
522 | int err, n, fd = (int) (long) dev; | ||
523 | |||
524 | while(1){ | ||
525 | err = os_read_file(fd, &reply, sizeof(reply)); | ||
526 | if(err == -EAGAIN) | ||
527 | break; | ||
528 | if(err < 0){ | ||
529 | printk("ubd_aio_handler - read returned err %d\n", | ||
530 | -err); | ||
531 | break; | ||
532 | } | ||
526 | 533 | ||
527 | /* Only changed by ubd_init, which is an initcall. */ | 534 | aio = container_of(reply.data, struct ubd_aio, aio); |
528 | static int io_pid = -1; | 535 | n = reply.err; |
529 | 536 | ||
530 | void kill_io_thread(void) | 537 | if(n == 0){ |
531 | { | 538 | req = aio->req; |
532 | if(io_pid != -1) | 539 | req->nr_sectors -= aio->len >> 9; |
533 | os_kill_process(io_pid, 1); | 540 | |
534 | } | 541 | if((aio->bitmap != NULL) && |
542 | (atomic_dec_and_test(&aio->bitmap->count))){ | ||
543 | aio->aio = aio->bitmap->aio; | ||
544 | aio->len = 0; | ||
545 | kfree(aio->bitmap); | ||
546 | aio->bitmap = NULL; | ||
547 | submit_aio(&aio->aio); | ||
548 | } | ||
549 | else { | ||
550 | if((req->nr_sectors == 0) && | ||
551 | (aio->bitmap == NULL)){ | ||
552 | int len = req->hard_nr_sectors << 9; | ||
553 | ubd_finish(req, len); | ||
554 | } | ||
555 | |||
556 | if(aio->bitmap_buf != NULL) | ||
557 | kfree(aio->bitmap_buf); | ||
558 | kfree(aio); | ||
559 | } | ||
560 | } | ||
561 | else if(n < 0){ | ||
562 | ubd_finish(aio->req, n); | ||
563 | if(aio->bitmap != NULL) | ||
564 | kfree(aio->bitmap); | ||
565 | if(aio->bitmap_buf != NULL) | ||
566 | kfree(aio->bitmap_buf); | ||
567 | kfree(aio); | ||
568 | } | ||
569 | } | ||
570 | reactivate_fd(fd, UBD_IRQ); | ||
535 | 571 | ||
536 | __uml_exitcall(kill_io_thread); | 572 | do_ubd_request(ubd_queue); |
573 | |||
574 | return(IRQ_HANDLED); | ||
575 | } | ||
537 | 576 | ||
538 | static int ubd_file_size(struct ubd *dev, __u64 *size_out) | 577 | static int ubd_file_size(struct ubd *dev, __u64 *size_out) |
539 | { | 578 | { |
@@ -569,7 +608,7 @@ static int ubd_open_dev(struct ubd *dev) | |||
569 | &dev->cow.data_offset, create_ptr); | 608 | &dev->cow.data_offset, create_ptr); |
570 | 609 | ||
571 | if((dev->fd == -ENOENT) && create_cow){ | 610 | if((dev->fd == -ENOENT) && create_cow){ |
572 | dev->fd = create_cow_file(dev->file, dev->cow.file, | 611 | dev->fd = create_cow_file(dev->file, dev->cow.file, |
573 | dev->openflags, 1 << 9, PAGE_SIZE, | 612 | dev->openflags, 1 << 9, PAGE_SIZE, |
574 | &dev->cow.bitmap_offset, | 613 | &dev->cow.bitmap_offset, |
575 | &dev->cow.bitmap_len, | 614 | &dev->cow.bitmap_len, |
@@ -668,21 +707,22 @@ static int ubd_add(int n) | |||
668 | struct ubd *dev = &ubd_dev[n]; | 707 | struct ubd *dev = &ubd_dev[n]; |
669 | int err; | 708 | int err; |
670 | 709 | ||
710 | err = -ENODEV; | ||
671 | if(dev->file == NULL) | 711 | if(dev->file == NULL) |
672 | return(-ENODEV); | 712 | goto out; |
673 | 713 | ||
674 | if (ubd_open_dev(dev)) | 714 | if (ubd_open_dev(dev)) |
675 | return(-ENODEV); | 715 | goto out; |
676 | 716 | ||
677 | err = ubd_file_size(dev, &dev->size); | 717 | err = ubd_file_size(dev, &dev->size); |
678 | if(err < 0) | 718 | if(err < 0) |
679 | return(err); | 719 | goto out_close; |
680 | 720 | ||
681 | dev->size = ROUND_BLOCK(dev->size); | 721 | dev->size = ROUND_BLOCK(dev->size); |
682 | 722 | ||
683 | err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); | 723 | err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); |
684 | if(err) | 724 | if(err) |
685 | return(err); | 725 | goto out_close; |
686 | 726 | ||
687 | if(fake_major != MAJOR_NR) | 727 | if(fake_major != MAJOR_NR) |
688 | ubd_new_disk(fake_major, dev->size, n, | 728 | ubd_new_disk(fake_major, dev->size, n, |
@@ -693,8 +733,11 @@ static int ubd_add(int n) | |||
693 | if (fake_ide) | 733 | if (fake_ide) |
694 | make_ide_entries(ubd_gendisk[n]->disk_name); | 734 | make_ide_entries(ubd_gendisk[n]->disk_name); |
695 | 735 | ||
736 | err = 0; | ||
737 | out_close: | ||
696 | ubd_close(dev); | 738 | ubd_close(dev); |
697 | return 0; | 739 | out: |
740 | return err; | ||
698 | } | 741 | } |
699 | 742 | ||
700 | static int ubd_config(char *str) | 743 | static int ubd_config(char *str) |
@@ -827,6 +870,10 @@ int ubd_init(void) | |||
827 | { | 870 | { |
828 | int i; | 871 | int i; |
829 | 872 | ||
873 | ubd_reply_fd = init_aio_irq(UBD_IRQ, "ubd", ubd_intr); | ||
874 | if(ubd_reply_fd < 0) | ||
875 | printk("Setting up ubd AIO failed, err = %d\n", ubd_reply_fd); | ||
876 | |||
830 | devfs_mk_dir("ubd"); | 877 | devfs_mk_dir("ubd"); |
831 | if (register_blkdev(MAJOR_NR, "ubd")) | 878 | if (register_blkdev(MAJOR_NR, "ubd")) |
832 | return -1; | 879 | return -1; |
@@ -837,6 +884,7 @@ int ubd_init(void) | |||
837 | return -1; | 884 | return -1; |
838 | } | 885 | } |
839 | 886 | ||
887 | blk_queue_max_hw_segments(ubd_queue, MAX_SG); | ||
840 | if (fake_major != MAJOR_NR) { | 888 | if (fake_major != MAJOR_NR) { |
841 | char name[sizeof("ubd_nnn\0")]; | 889 | char name[sizeof("ubd_nnn\0")]; |
842 | 890 | ||
@@ -848,40 +896,12 @@ int ubd_init(void) | |||
848 | driver_register(&ubd_driver); | 896 | driver_register(&ubd_driver); |
849 | for (i = 0; i < MAX_DEV; i++) | 897 | for (i = 0; i < MAX_DEV; i++) |
850 | ubd_add(i); | 898 | ubd_add(i); |
899 | |||
851 | return 0; | 900 | return 0; |
852 | } | 901 | } |
853 | 902 | ||
854 | late_initcall(ubd_init); | 903 | late_initcall(ubd_init); |
855 | 904 | ||
856 | int ubd_driver_init(void){ | ||
857 | unsigned long stack; | ||
858 | int err; | ||
859 | |||
860 | /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/ | ||
861 | if(global_openflags.s){ | ||
862 | printk(KERN_INFO "ubd: Synchronous mode\n"); | ||
863 | /* Letting ubd=sync be like using ubd#s= instead of ubd#= is | ||
864 | * enough. So use anyway the io thread. */ | ||
865 | } | ||
866 | stack = alloc_stack(0, 0); | ||
867 | io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), | ||
868 | &thread_fd); | ||
869 | if(io_pid < 0){ | ||
870 | printk(KERN_ERR | ||
871 | "ubd : Failed to start I/O thread (errno = %d) - " | ||
872 | "falling back to synchronous I/O\n", -io_pid); | ||
873 | io_pid = -1; | ||
874 | return(0); | ||
875 | } | ||
876 | err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, | ||
877 | SA_INTERRUPT, "ubd", ubd_dev); | ||
878 | if(err != 0) | ||
879 | printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); | ||
880 | return(err); | ||
881 | } | ||
882 | |||
883 | device_initcall(ubd_driver_init); | ||
884 | |||
885 | static int ubd_open(struct inode *inode, struct file *filp) | 905 | static int ubd_open(struct inode *inode, struct file *filp) |
886 | { | 906 | { |
887 | struct gendisk *disk = inode->i_bdev->bd_disk; | 907 | struct gendisk *disk = inode->i_bdev->bd_disk; |
@@ -919,105 +939,55 @@ static int ubd_release(struct inode * inode, struct file * file) | |||
919 | return(0); | 939 | return(0); |
920 | } | 940 | } |
921 | 941 | ||
922 | static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, | 942 | static void cowify_bitmap(struct io_thread_req *req, unsigned long *bitmap) |
923 | __u64 *cow_offset, unsigned long *bitmap, | ||
924 | __u64 bitmap_offset, unsigned long *bitmap_words, | ||
925 | __u64 bitmap_len) | ||
926 | { | 943 | { |
927 | __u64 sector = io_offset >> 9; | 944 | __u64 sector = req->offset / req->sectorsize; |
928 | int i, update_bitmap = 0; | 945 | int i; |
929 | |||
930 | for(i = 0; i < length >> 9; i++){ | ||
931 | if(cow_mask != NULL) | ||
932 | ubd_set_bit(i, (unsigned char *) cow_mask); | ||
933 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) | ||
934 | continue; | ||
935 | |||
936 | update_bitmap = 1; | ||
937 | ubd_set_bit(sector + i, (unsigned char *) bitmap); | ||
938 | } | ||
939 | |||
940 | if(!update_bitmap) | ||
941 | return; | ||
942 | |||
943 | *cow_offset = sector / (sizeof(unsigned long) * 8); | ||
944 | |||
945 | /* This takes care of the case where we're exactly at the end of the | ||
946 | * device, and *cow_offset + 1 is off the end. So, just back it up | ||
947 | * by one word. Thanks to Lynn Kerby for the fix and James McMechan | ||
948 | * for the original diagnosis. | ||
949 | */ | ||
950 | if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / | ||
951 | sizeof(unsigned long) - 1)) | ||
952 | (*cow_offset)--; | ||
953 | |||
954 | bitmap_words[0] = bitmap[*cow_offset]; | ||
955 | bitmap_words[1] = bitmap[*cow_offset + 1]; | ||
956 | |||
957 | *cow_offset *= sizeof(unsigned long); | ||
958 | *cow_offset += bitmap_offset; | ||
959 | } | ||
960 | 946 | ||
961 | static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, | 947 | for(i = 0; i < req->length / req->sectorsize; i++){ |
962 | __u64 bitmap_offset, __u64 bitmap_len) | 948 | if(ubd_test_bit(sector + i, bitmap)) |
963 | { | 949 | continue; |
964 | __u64 sector = req->offset >> 9; | ||
965 | int i; | ||
966 | 950 | ||
967 | if(req->length > (sizeof(req->sector_mask) * 8) << 9) | 951 | if(req->bitmap_start == -1) |
968 | panic("Operation too long"); | 952 | req->bitmap_start = sector + i; |
953 | req->bitmap_end = sector + i + 1; | ||
969 | 954 | ||
970 | if(req->op == UBD_READ) { | 955 | ubd_set_bit(sector + i, bitmap); |
971 | for(i = 0; i < req->length >> 9; i++){ | 956 | } |
972 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) | ||
973 | ubd_set_bit(i, (unsigned char *) | ||
974 | &req->sector_mask); | ||
975 | } | ||
976 | } | ||
977 | else cowify_bitmap(req->offset, req->length, &req->sector_mask, | ||
978 | &req->cow_offset, bitmap, bitmap_offset, | ||
979 | req->bitmap_words, bitmap_len); | ||
980 | } | 957 | } |
981 | 958 | ||
982 | /* Called with ubd_io_lock held */ | 959 | /* Called with ubd_io_lock held */ |
983 | static int prepare_request(struct request *req, struct io_thread_req *io_req) | 960 | static int prepare_request(struct request *req, struct io_thread_req *io_req, |
961 | unsigned long long offset, int page_offset, | ||
962 | int len, struct page *page) | ||
984 | { | 963 | { |
985 | struct gendisk *disk = req->rq_disk; | 964 | struct gendisk *disk = req->rq_disk; |
986 | struct ubd *dev = disk->private_data; | 965 | struct ubd *dev = disk->private_data; |
987 | __u64 offset; | ||
988 | int len; | ||
989 | |||
990 | if(req->rq_status == RQ_INACTIVE) return(1); | ||
991 | 966 | ||
992 | /* This should be impossible now */ | 967 | /* This should be impossible now */ |
993 | if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ | 968 | if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ |
994 | printk("Write attempted on readonly ubd device %s\n", | 969 | printk("Write attempted on readonly ubd device %s\n", |
995 | disk->disk_name); | 970 | disk->disk_name); |
996 | end_request(req, 0); | 971 | ubd_end_request(req, 0, 0); |
997 | return(1); | 972 | return(1); |
998 | } | 973 | } |
999 | 974 | ||
1000 | offset = ((__u64) req->sector) << 9; | ||
1001 | len = req->current_nr_sectors << 9; | ||
1002 | |||
1003 | io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; | 975 | io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; |
1004 | io_req->fds[1] = dev->fd; | 976 | io_req->fds[1] = dev->fd; |
1005 | io_req->cow_offset = -1; | ||
1006 | io_req->offset = offset; | 977 | io_req->offset = offset; |
1007 | io_req->length = len; | 978 | io_req->length = len; |
1008 | io_req->error = 0; | 979 | io_req->error = 0; |
1009 | io_req->sector_mask = 0; | 980 | io_req->op = (rq_data_dir(req) == READ) ? AIO_READ : AIO_WRITE; |
1010 | |||
1011 | io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; | ||
1012 | io_req->offsets[0] = 0; | 981 | io_req->offsets[0] = 0; |
1013 | io_req->offsets[1] = dev->cow.data_offset; | 982 | io_req->offsets[1] = dev->cow.data_offset; |
1014 | io_req->buffer = req->buffer; | 983 | io_req->buffer = page_address(page) + page_offset; |
1015 | io_req->sectorsize = 1 << 9; | 984 | io_req->sectorsize = 1 << 9; |
985 | io_req->bitmap_offset = dev->cow.bitmap_offset; | ||
986 | io_req->bitmap_start = -1; | ||
987 | io_req->bitmap_end = -1; | ||
1016 | 988 | ||
1017 | if(dev->cow.file != NULL) | 989 | if((dev->cow.file != NULL) && (io_req->op == UBD_WRITE)) |
1018 | cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset, | 990 | cowify_bitmap(io_req, dev->cow.bitmap); |
1019 | dev->cow.bitmap_len); | ||
1020 | |||
1021 | return(0); | 991 | return(0); |
1022 | } | 992 | } |
1023 | 993 | ||
@@ -1026,30 +996,36 @@ static void do_ubd_request(request_queue_t *q) | |||
1026 | { | 996 | { |
1027 | struct io_thread_req io_req; | 997 | struct io_thread_req io_req; |
1028 | struct request *req; | 998 | struct request *req; |
1029 | int err, n; | 999 | __u64 sector; |
1030 | 1000 | int err; | |
1031 | if(thread_fd == -1){ | 1001 | |
1032 | while((req = elv_next_request(q)) != NULL){ | 1002 | if(in_ubd) |
1033 | err = prepare_request(req, &io_req); | 1003 | return; |
1034 | if(!err){ | 1004 | in_ubd = 1; |
1035 | do_io(&io_req); | 1005 | while((req = elv_next_request(q)) != NULL){ |
1036 | __ubd_finish(req, io_req.error); | 1006 | struct gendisk *disk = req->rq_disk; |
1037 | } | 1007 | struct ubd *dev = disk->private_data; |
1038 | } | 1008 | int n, i; |
1039 | } | 1009 | |
1040 | else { | 1010 | blkdev_dequeue_request(req); |
1041 | if(do_ubd || (req = elv_next_request(q)) == NULL) | 1011 | |
1042 | return; | 1012 | sector = req->sector; |
1043 | err = prepare_request(req, &io_req); | 1013 | n = blk_rq_map_sg(q, req, dev->sg); |
1044 | if(!err){ | 1014 | |
1045 | do_ubd = ubd_handler; | 1015 | for(i = 0; i < n; i++){ |
1046 | n = os_write_file(thread_fd, (char *) &io_req, | 1016 | struct scatterlist *sg = &dev->sg[i]; |
1047 | sizeof(io_req)); | 1017 | |
1048 | if(n != sizeof(io_req)) | 1018 | err = prepare_request(req, &io_req, sector << 9, |
1049 | printk("write to io thread failed, " | 1019 | sg->offset, sg->length, |
1050 | "errno = %d\n", -n); | 1020 | sg->page); |
1021 | if(err) | ||
1022 | continue; | ||
1023 | |||
1024 | sector += sg->length >> 9; | ||
1025 | do_io(&io_req, req, dev->cow.bitmap); | ||
1051 | } | 1026 | } |
1052 | } | 1027 | } |
1028 | in_ubd = 0; | ||
1053 | } | 1029 | } |
1054 | 1030 | ||
1055 | static int ubd_ioctl(struct inode * inode, struct file * file, | 1031 | static int ubd_ioctl(struct inode * inode, struct file * file, |
@@ -1265,131 +1241,95 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, | |||
1265 | return(err); | 1241 | return(err); |
1266 | } | 1242 | } |
1267 | 1243 | ||
1268 | static int update_bitmap(struct io_thread_req *req) | 1244 | void do_io(struct io_thread_req *req, struct request *r, unsigned long *bitmap) |
1269 | { | ||
1270 | int n; | ||
1271 | |||
1272 | if(req->cow_offset == -1) | ||
1273 | return(0); | ||
1274 | |||
1275 | n = os_seek_file(req->fds[1], req->cow_offset); | ||
1276 | if(n < 0){ | ||
1277 | printk("do_io - bitmap lseek failed : err = %d\n", -n); | ||
1278 | return(1); | ||
1279 | } | ||
1280 | |||
1281 | n = os_write_file(req->fds[1], &req->bitmap_words, | ||
1282 | sizeof(req->bitmap_words)); | ||
1283 | if(n != sizeof(req->bitmap_words)){ | ||
1284 | printk("do_io - bitmap update failed, err = %d fd = %d\n", -n, | ||
1285 | req->fds[1]); | ||
1286 | return(1); | ||
1287 | } | ||
1288 | |||
1289 | return(0); | ||
1290 | } | ||
1291 | |||
1292 | void do_io(struct io_thread_req *req) | ||
1293 | { | 1245 | { |
1294 | char *buf; | 1246 | struct ubd_aio *aio; |
1295 | unsigned long len; | 1247 | struct bitmap_io *bitmap_io = NULL; |
1296 | int n, nsectors, start, end, bit; | 1248 | char *buf; |
1297 | int err; | 1249 | void *bitmap_buf = NULL; |
1298 | __u64 off; | 1250 | unsigned long len, sector; |
1299 | 1251 | int nsectors, start, end, bit, err; | |
1300 | nsectors = req->length / req->sectorsize; | 1252 | __u64 off; |
1301 | start = 0; | 1253 | |
1302 | do { | 1254 | if(req->bitmap_start != -1){ |
1303 | bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask); | 1255 | /* Round up to the nearest word */ |
1304 | end = start; | 1256 | int round = sizeof(unsigned long); |
1305 | while((end < nsectors) && | 1257 | len = (req->bitmap_end - req->bitmap_start + |
1306 | (ubd_test_bit(end, (unsigned char *) | 1258 | round * 8 - 1) / (round * 8); |
1307 | &req->sector_mask) == bit)) | 1259 | len *= round; |
1308 | end++; | 1260 | |
1309 | 1261 | off = req->bitmap_start / (8 * round); | |
1310 | off = req->offset + req->offsets[bit] + | 1262 | off *= round; |
1311 | start * req->sectorsize; | 1263 | |
1312 | len = (end - start) * req->sectorsize; | 1264 | bitmap_io = kmalloc(sizeof(*bitmap_io), GFP_KERNEL); |
1313 | buf = &req->buffer[start * req->sectorsize]; | 1265 | if(bitmap_io == NULL){ |
1314 | 1266 | printk("Failed to kmalloc bitmap IO\n"); | |
1315 | err = os_seek_file(req->fds[bit], off); | 1267 | req->error = 1; |
1316 | if(err < 0){ | 1268 | return; |
1317 | printk("do_io - lseek failed : err = %d\n", -err); | 1269 | } |
1318 | req->error = 1; | ||
1319 | return; | ||
1320 | } | ||
1321 | if(req->op == UBD_READ){ | ||
1322 | n = 0; | ||
1323 | do { | ||
1324 | buf = &buf[n]; | ||
1325 | len -= n; | ||
1326 | n = os_read_file(req->fds[bit], buf, len); | ||
1327 | if (n < 0) { | ||
1328 | printk("do_io - read failed, err = %d " | ||
1329 | "fd = %d\n", -n, req->fds[bit]); | ||
1330 | req->error = 1; | ||
1331 | return; | ||
1332 | } | ||
1333 | } while((n < len) && (n != 0)); | ||
1334 | if (n < len) memset(&buf[n], 0, len - n); | ||
1335 | } else { | ||
1336 | n = os_write_file(req->fds[bit], buf, len); | ||
1337 | if(n != len){ | ||
1338 | printk("do_io - write failed err = %d " | ||
1339 | "fd = %d\n", -n, req->fds[bit]); | ||
1340 | req->error = 1; | ||
1341 | return; | ||
1342 | } | ||
1343 | } | ||
1344 | 1270 | ||
1345 | start = end; | 1271 | bitmap_buf = kmalloc(len, GFP_KERNEL); |
1346 | } while(start < nsectors); | 1272 | if(bitmap_buf == NULL){ |
1273 | printk("do_io : kmalloc of bitmap chunk " | ||
1274 | "failed\n"); | ||
1275 | kfree(bitmap_io); | ||
1276 | req->error = 1; | ||
1277 | return; | ||
1278 | } | ||
1279 | memcpy(bitmap_buf, &bitmap[off / sizeof(bitmap[0])], len); | ||
1280 | |||
1281 | *bitmap_io = ((struct bitmap_io) | ||
1282 | { .count = ATOMIC_INIT(0), | ||
1283 | .aio = INIT_AIO(AIO_WRITE, req->fds[1], | ||
1284 | bitmap_buf, len, | ||
1285 | req->bitmap_offset + off, | ||
1286 | ubd_reply_fd) } ); | ||
1287 | } | ||
1347 | 1288 | ||
1348 | req->error = update_bitmap(req); | 1289 | nsectors = req->length / req->sectorsize; |
1349 | } | 1290 | start = 0; |
1291 | end = nsectors; | ||
1292 | bit = 0; | ||
1293 | do { | ||
1294 | if(bitmap != NULL){ | ||
1295 | sector = req->offset / req->sectorsize; | ||
1296 | bit = ubd_test_bit(sector + start, bitmap); | ||
1297 | end = start; | ||
1298 | while((end < nsectors) && | ||
1299 | (ubd_test_bit(sector + end, bitmap) == bit)) | ||
1300 | end++; | ||
1301 | } | ||
1350 | 1302 | ||
1351 | /* Changed in start_io_thread, which is serialized by being called only | 1303 | off = req->offsets[bit] + req->offset + |
1352 | * from ubd_init, which is an initcall. | 1304 | start * req->sectorsize; |
1353 | */ | 1305 | len = (end - start) * req->sectorsize; |
1354 | int kernel_fd = -1; | 1306 | buf = &req->buffer[start * req->sectorsize]; |
1355 | 1307 | ||
1356 | /* Only changed by the io thread */ | 1308 | aio = kmalloc(sizeof(*aio), GFP_KERNEL); |
1357 | int io_count = 0; | 1309 | if(aio == NULL){ |
1310 | req->error = 1; | ||
1311 | return; | ||
1312 | } | ||
1358 | 1313 | ||
1359 | int io_thread(void *arg) | 1314 | *aio = ((struct ubd_aio) |
1360 | { | 1315 | { .aio = INIT_AIO(req->op, req->fds[bit], buf, |
1361 | struct io_thread_req req; | 1316 | len, off, ubd_reply_fd), |
1362 | int n; | 1317 | .len = len, |
1318 | .req = r, | ||
1319 | .bitmap = bitmap_io, | ||
1320 | .bitmap_buf = bitmap_buf }); | ||
1321 | |||
1322 | if(aio->bitmap != NULL) | ||
1323 | atomic_inc(&aio->bitmap->count); | ||
1324 | |||
1325 | err = submit_aio(&aio->aio); | ||
1326 | if(err){ | ||
1327 | printk("do_io - submit_aio failed, " | ||
1328 | "err = %d\n", err); | ||
1329 | req->error = 1; | ||
1330 | return; | ||
1331 | } | ||
1363 | 1332 | ||
1364 | ignore_sigwinch_sig(); | 1333 | start = end; |
1365 | while(1){ | 1334 | } while(start < nsectors); |
1366 | n = os_read_file(kernel_fd, &req, sizeof(req)); | ||
1367 | if(n != sizeof(req)){ | ||
1368 | if(n < 0) | ||
1369 | printk("io_thread - read failed, fd = %d, " | ||
1370 | "err = %d\n", kernel_fd, -n); | ||
1371 | else { | ||
1372 | printk("io_thread - short read, fd = %d, " | ||
1373 | "length = %d\n", kernel_fd, n); | ||
1374 | } | ||
1375 | continue; | ||
1376 | } | ||
1377 | io_count++; | ||
1378 | do_io(&req); | ||
1379 | n = os_write_file(kernel_fd, &req, sizeof(req)); | ||
1380 | if(n != sizeof(req)) | ||
1381 | printk("io_thread - write failed, fd = %d, err = %d\n", | ||
1382 | kernel_fd, -n); | ||
1383 | } | ||
1384 | } | 1335 | } |
1385 | |||
1386 | /* | ||
1387 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
1388 | * Emacs will notice this stuff at the end of the file and automatically | ||
1389 | * adjust the settings for this buffer only. This must remain at the end | ||
1390 | * of the file. | ||
1391 | * --------------------------------------------------------------------------- | ||
1392 | * Local variables: | ||
1393 | * c-file-style: "linux" | ||
1394 | * End: | ||
1395 | */ | ||
diff --git a/arch/um/include/aio.h b/arch/um/include/aio.h new file mode 100644 index 000000000000..83f16877ab08 --- /dev/null +++ b/arch/um/include/aio.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef AIO_H__ | ||
7 | #define AIO_H__ | ||
8 | |||
9 | enum aio_type { AIO_READ, AIO_WRITE, AIO_MMAP }; | ||
10 | |||
11 | struct aio_thread_reply { | ||
12 | void *data; | ||
13 | int err; | ||
14 | }; | ||
15 | |||
16 | struct aio_context { | ||
17 | enum aio_type type; | ||
18 | int fd; | ||
19 | void *data; | ||
20 | int len; | ||
21 | unsigned long long offset; | ||
22 | int reply_fd; | ||
23 | struct aio_context *next; | ||
24 | }; | ||
25 | |||
26 | #define INIT_AIO(aio_type, aio_fd, aio_data, aio_len, aio_offset, \ | ||
27 | aio_reply_fd) \ | ||
28 | { .type = aio_type, \ | ||
29 | .fd = aio_fd, \ | ||
30 | .data = aio_data, \ | ||
31 | .len = aio_len, \ | ||
32 | .offset = aio_offset, \ | ||
33 | .reply_fd = aio_reply_fd } | ||
34 | |||
35 | #define INIT_AIO_CONTEXT { .reply_fd = -1, \ | ||
36 | .next = NULL } | ||
37 | |||
38 | extern int submit_aio(struct aio_context *aio); | ||
39 | |||
40 | #endif | ||
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h index d705daa2d854..0aa620970adb 100644 --- a/arch/um/include/common-offsets.h +++ b/arch/um/include/common-offsets.h | |||
@@ -12,3 +12,4 @@ DEFINE_STR(UM_KERN_WARNING, KERN_WARNING); | |||
12 | DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE); | 12 | DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE); |
13 | DEFINE_STR(UM_KERN_INFO, KERN_INFO); | 13 | DEFINE_STR(UM_KERN_INFO, KERN_INFO); |
14 | DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG); | 14 | DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG); |
15 | DEFINE(HOST_ELF_CLASS, ELF_CLASS); | ||
diff --git a/arch/um/include/init.h b/arch/um/include/init.h index 55c2693f8778..cbd79a8d213d 100644 --- a/arch/um/include/init.h +++ b/arch/um/include/init.h | |||
@@ -111,7 +111,15 @@ extern struct uml_param __uml_setup_start, __uml_setup_end; | |||
111 | 111 | ||
112 | #ifndef __KERNEL__ | 112 | #ifndef __KERNEL__ |
113 | 113 | ||
114 | #define __initcall(fn) static initcall_t __initcall_##fn __init_call = fn | 114 | #define __define_initcall(level,fn) \ |
115 | static initcall_t __initcall_##fn __attribute_used__ \ | ||
116 | __attribute__((__section__(".initcall" level ".init"))) = fn | ||
117 | |||
118 | /* Userspace initcalls shouldn't depend on anything in the kernel, so we'll | ||
119 | * make them run first. | ||
120 | */ | ||
121 | #define __initcall(fn) __define_initcall("1", fn) | ||
122 | |||
115 | #define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn | 123 | #define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn |
116 | 124 | ||
117 | #define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) | 125 | #define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) |
diff --git a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h index 3af52a634c4c..c222d56b1494 100644 --- a/arch/um/include/irq_kern.h +++ b/arch/um/include/irq_kern.h | |||
@@ -7,12 +7,15 @@ | |||
7 | #define __IRQ_KERN_H__ | 7 | #define __IRQ_KERN_H__ |
8 | 8 | ||
9 | #include "linux/interrupt.h" | 9 | #include "linux/interrupt.h" |
10 | #include "asm/ptrace.h" | ||
10 | 11 | ||
11 | extern int um_request_irq(unsigned int irq, int fd, int type, | 12 | extern int um_request_irq(unsigned int irq, int fd, int type, |
12 | irqreturn_t (*handler)(int, void *, | 13 | irqreturn_t (*handler)(int, void *, |
13 | struct pt_regs *), | 14 | struct pt_regs *), |
14 | unsigned long irqflags, const char * devname, | 15 | unsigned long irqflags, const char * devname, |
15 | void *dev_id); | 16 | void *dev_id); |
17 | extern int init_aio_irq(int irq, char *name, | ||
18 | irqreturn_t (*handler)(int, void *, struct pt_regs *)); | ||
16 | 19 | ||
17 | #endif | 20 | #endif |
18 | 21 | ||
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 881d2988d2d8..4c362458052c 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -153,6 +153,11 @@ extern int os_file_type(char *file); | |||
153 | extern int os_file_mode(char *file, struct openflags *mode_out); | 153 | extern int os_file_mode(char *file, struct openflags *mode_out); |
154 | extern int os_lock_file(int fd, int excl); | 154 | extern int os_lock_file(int fd, int excl); |
155 | 155 | ||
156 | /* start_up.c */ | ||
157 | extern void os_early_checks(void); | ||
158 | extern int can_do_skas(void); | ||
159 | |||
160 | /* process.c */ | ||
156 | extern unsigned long os_process_pc(int pid); | 161 | extern unsigned long os_process_pc(int pid); |
157 | extern int os_process_parent(int pid); | 162 | extern int os_process_parent(int pid); |
158 | extern void os_stop_process(int pid); | 163 | extern void os_stop_process(int pid); |
@@ -161,6 +166,9 @@ extern void os_kill_ptraced_process(int pid, int reap_child); | |||
161 | extern void os_usr1_process(int pid); | 166 | extern void os_usr1_process(int pid); |
162 | extern int os_getpid(void); | 167 | extern int os_getpid(void); |
163 | extern int os_getpgrp(void); | 168 | extern int os_getpgrp(void); |
169 | extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); | ||
170 | extern void init_new_thread_signals(int altstack); | ||
171 | extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); | ||
164 | 172 | ||
165 | extern int os_map_memory(void *virt, int fd, unsigned long long off, | 173 | extern int os_map_memory(void *virt, int fd, unsigned long long off, |
166 | unsigned long len, int r, int w, int x); | 174 | unsigned long len, int r, int w, int x); |
@@ -170,6 +178,13 @@ extern int os_unmap_memory(void *addr, int len); | |||
170 | extern void os_flush_stdout(void); | 178 | extern void os_flush_stdout(void); |
171 | extern unsigned long long os_usecs(void); | 179 | extern unsigned long long os_usecs(void); |
172 | 180 | ||
181 | /* tt.c | ||
182 | * for tt mode only (will be deleted in future...) | ||
183 | */ | ||
184 | extern void forward_pending_sigio(int target); | ||
185 | extern int start_fork_tramp(void *arg, unsigned long temp_stack, | ||
186 | int clone_flags, int (*tramp)(void *)); | ||
187 | |||
173 | #endif | 188 | #endif |
174 | 189 | ||
175 | /* | 190 | /* |
diff --git a/arch/um/include/syscall.h b/arch/um/include/syscall.h new file mode 100644 index 000000000000..dda1df901a08 --- /dev/null +++ b/arch/um/include/syscall.h | |||
@@ -0,0 +1,12 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SYSCALL_USER_H | ||
7 | #define __SYSCALL_USER_H | ||
8 | |||
9 | extern int record_syscall_start(int syscall); | ||
10 | extern void record_syscall_end(int index, long result); | ||
11 | |||
12 | #endif | ||
diff --git a/arch/um/include/syscall_user.h b/arch/um/include/syscall_user.h deleted file mode 100644 index 811d0ec2445e..000000000000 --- a/arch/um/include/syscall_user.h +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SYSCALL_USER_H | ||
7 | #define __SYSCALL_USER_H | ||
8 | |||
9 | extern int record_syscall_start(int syscall); | ||
10 | extern void record_syscall_end(int index, long result); | ||
11 | |||
12 | #endif | ||
13 | |||
14 | /* | ||
15 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
16 | * Emacs will notice this stuff at the end of the file and automatically | ||
17 | * adjust the settings for this buffer only. This must remain at the end | ||
18 | * of the file. | ||
19 | * --------------------------------------------------------------------------- | ||
20 | * Local variables: | ||
21 | * c-file-style: "linux" | ||
22 | * End: | ||
23 | */ | ||
diff --git a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h index be0a3e3469eb..a0d5b74d3731 100644 --- a/arch/um/include/sysdep-i386/syscalls.h +++ b/arch/um/include/sysdep-i386/syscalls.h | |||
@@ -16,6 +16,8 @@ extern syscall_handler_t sys_rt_sigaction; | |||
16 | 16 | ||
17 | extern syscall_handler_t old_mmap_i386; | 17 | extern syscall_handler_t old_mmap_i386; |
18 | 18 | ||
19 | extern syscall_handler_t *sys_call_table[]; | ||
20 | |||
19 | #define EXECUTE_SYSCALL(syscall, regs) \ | 21 | #define EXECUTE_SYSCALL(syscall, regs) \ |
20 | ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) | 22 | ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) |
21 | 23 | ||
diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h index be8acd5efd97..331aa2d1f3f5 100644 --- a/arch/um/include/sysdep-x86_64/ptrace.h +++ b/arch/um/include/sysdep-x86_64/ptrace.h | |||
@@ -227,7 +227,7 @@ struct syscall_args { | |||
227 | panic("Bad register in UPT_SET : %d\n", reg); \ | 227 | panic("Bad register in UPT_SET : %d\n", reg); \ |
228 | break; \ | 228 | break; \ |
229 | } \ | 229 | } \ |
230 | val; \ | 230 | __upt_val; \ |
231 | }) | 231 | }) |
232 | 232 | ||
233 | #define UPT_SET_SYSCALL_RETURN(r, res) \ | 233 | #define UPT_SET_SYSCALL_RETURN(r, res) \ |
diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h index 67923cca5691..e06f83e80f4a 100644 --- a/arch/um/include/sysdep-x86_64/syscalls.h +++ b/arch/um/include/sysdep-x86_64/syscalls.h | |||
@@ -14,6 +14,8 @@ typedef long syscall_handler_t(void); | |||
14 | 14 | ||
15 | extern syscall_handler_t *ia32_sys_call_table[]; | 15 | extern syscall_handler_t *ia32_sys_call_table[]; |
16 | 16 | ||
17 | extern syscall_handler_t *sys_call_table[]; | ||
18 | |||
17 | #define EXECUTE_SYSCALL(syscall, regs) \ | 19 | #define EXECUTE_SYSCALL(syscall, regs) \ |
18 | (((long (*)(long, long, long, long, long, long)) \ | 20 | (((long (*)(long, long, long, long, long, long)) \ |
19 | (*sys_call_table[syscall]))(UPT_SYSCALL_ARG1(®s->regs), \ | 21 | (*sys_call_table[syscall]))(UPT_SYSCALL_ARG1(®s->regs), \ |
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h index c6f9628f39bf..45d7da6c3b2c 100644 --- a/arch/um/include/tlb.h +++ b/arch/um/include/tlb.h | |||
@@ -9,7 +9,7 @@ | |||
9 | #include "um_mmu.h" | 9 | #include "um_mmu.h" |
10 | 10 | ||
11 | struct host_vm_op { | 11 | struct host_vm_op { |
12 | enum { MMAP, MUNMAP, MPROTECT } type; | 12 | enum { NONE, MMAP, MUNMAP, MPROTECT } type; |
13 | union { | 13 | union { |
14 | struct { | 14 | struct { |
15 | unsigned long addr; | 15 | unsigned long addr; |
@@ -38,24 +38,10 @@ extern void mprotect_kernel_vm(int w); | |||
38 | extern void force_flush_all(void); | 38 | extern void force_flush_all(void); |
39 | extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr, | 39 | extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr, |
40 | unsigned long end_addr, int force, | 40 | unsigned long end_addr, int force, |
41 | void (*do_ops)(union mm_context *, | 41 | int (*do_ops)(union mm_context *, |
42 | struct host_vm_op *, int)); | 42 | struct host_vm_op *, int, int, |
43 | void **)); | ||
43 | extern int flush_tlb_kernel_range_common(unsigned long start, | 44 | extern int flush_tlb_kernel_range_common(unsigned long start, |
44 | unsigned long end); | 45 | unsigned long end); |
45 | 46 | ||
46 | extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, | ||
47 | int r, int w, int x, struct host_vm_op *ops, int index, | ||
48 | int last_filled, union mm_context *mmu, | ||
49 | void (*do_ops)(union mm_context *, struct host_vm_op *, | ||
50 | int)); | ||
51 | extern int add_munmap(unsigned long addr, unsigned long len, | ||
52 | struct host_vm_op *ops, int index, int last_filled, | ||
53 | union mm_context *mmu, | ||
54 | void (*do_ops)(union mm_context *, struct host_vm_op *, | ||
55 | int)); | ||
56 | extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w, | ||
57 | int x, struct host_vm_op *ops, int index, | ||
58 | int last_filled, union mm_context *mmu, | ||
59 | void (*do_ops)(union mm_context *, struct host_vm_op *, | ||
60 | int)); | ||
61 | #endif | 47 | #endif |
diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h index 6e348cb6de24..84c0868cd561 100644 --- a/arch/um/include/um_uaccess.h +++ b/arch/um/include/um_uaccess.h | |||
@@ -20,13 +20,6 @@ | |||
20 | #define access_ok(type, addr, size) \ | 20 | #define access_ok(type, addr, size) \ |
21 | CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size) | 21 | CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size) |
22 | 22 | ||
23 | /* this function will go away soon - use access_ok() instead */ | ||
24 | static inline int __deprecated verify_area(int type, const void __user *addr, unsigned long size) | ||
25 | { | ||
26 | return (CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr, | ||
27 | size)); | ||
28 | } | ||
29 | |||
30 | static inline int copy_from_user(void *to, const void __user *from, int n) | 23 | static inline int copy_from_user(void *to, const void __user *from, int n) |
31 | { | 24 | { |
32 | return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to, | 25 | return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to, |
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index 7b6a24dfd302..bb505e01d994 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h | |||
@@ -54,8 +54,6 @@ extern void stack_protections(unsigned long address); | |||
54 | extern void task_protections(unsigned long address); | 54 | extern void task_protections(unsigned long address); |
55 | extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); | 55 | extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); |
56 | extern void *add_signal_handler(int sig, void (*handler)(int)); | 56 | extern void *add_signal_handler(int sig, void (*handler)(int)); |
57 | extern int start_fork_tramp(void *arg, unsigned long temp_stack, | ||
58 | int clone_flags, int (*tramp)(void *)); | ||
59 | extern int linux_main(int argc, char **argv); | 57 | extern int linux_main(int argc, char **argv); |
60 | extern void set_cmdline(char *cmd); | 58 | extern void set_cmdline(char *cmd); |
61 | extern void input_cb(void (*proc)(void *), void *arg, int arg_len); | 59 | extern void input_cb(void (*proc)(void *), void *arg, int arg_len); |
@@ -64,8 +62,6 @@ extern void *um_kmalloc(int size); | |||
64 | extern int switcheroo(int fd, int prot, void *from, void *to, int size); | 62 | extern int switcheroo(int fd, int prot, void *from, void *to, int size); |
65 | extern void setup_machinename(char *machine_out); | 63 | extern void setup_machinename(char *machine_out); |
66 | extern void setup_hostinfo(void); | 64 | extern void setup_hostinfo(void); |
67 | extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); | ||
68 | extern void init_new_thread_signals(int altstack); | ||
69 | extern void do_exec(int old_pid, int new_pid); | 65 | extern void do_exec(int old_pid, int new_pid); |
70 | extern void tracer_panic(char *msg, ...); | 66 | extern void tracer_panic(char *msg, ...); |
71 | extern char *get_umid(int only_if_set); | 67 | extern char *get_umid(int only_if_set); |
@@ -74,16 +70,12 @@ extern int detach(int pid, int sig); | |||
74 | extern int attach(int pid); | 70 | extern int attach(int pid); |
75 | extern void kill_child_dead(int pid); | 71 | extern void kill_child_dead(int pid); |
76 | extern int cont(int pid); | 72 | extern int cont(int pid); |
77 | extern void check_ptrace(void); | ||
78 | extern void check_sigio(void); | 73 | extern void check_sigio(void); |
79 | extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); | ||
80 | extern void write_sigio_workaround(void); | 74 | extern void write_sigio_workaround(void); |
81 | extern void arch_check_bugs(void); | 75 | extern void arch_check_bugs(void); |
82 | extern int cpu_feature(char *what, char *buf, int len); | 76 | extern int cpu_feature(char *what, char *buf, int len); |
83 | extern int arch_handle_signal(int sig, union uml_pt_regs *regs); | 77 | extern int arch_handle_signal(int sig, union uml_pt_regs *regs); |
84 | extern int arch_fixup(unsigned long address, void *sc_ptr); | 78 | extern int arch_fixup(unsigned long address, void *sc_ptr); |
85 | extern void forward_pending_sigio(int target); | ||
86 | extern int can_do_skas(void); | ||
87 | extern void arch_init_thread(void); | 79 | extern void arch_init_thread(void); |
88 | extern int setjmp_wrapper(void (*proc)(void *, void *), ...); | 80 | extern int setjmp_wrapper(void (*proc)(void *, void *), ...); |
89 | extern int raw(int fd); | 81 | extern int raw(int fd); |
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index a8918e80df96..614b8ebeb0ed 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile | |||
@@ -8,25 +8,24 @@ clean-files := | |||
8 | 8 | ||
9 | obj-y = config.o exec_kern.o exitcode.o \ | 9 | obj-y = config.o exec_kern.o exitcode.o \ |
10 | helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \ | 10 | helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \ |
11 | physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \ | 11 | physmem.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ |
12 | sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ | 12 | sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o \ |
13 | syscall_kern.o sysrq.o tempfile.o time.o time_kern.o \ | 13 | tempfile.o time.o time_kern.o tlb.o trap_kern.o trap_user.o \ |
14 | tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o umid.o \ | 14 | uaccess_user.o um_arch.o umid.o user_util.o |
15 | user_util.o | ||
16 | 15 | ||
17 | obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o | 16 | obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o |
18 | obj-$(CONFIG_GPROF) += gprof_syms.o | 17 | obj-$(CONFIG_GPROF) += gprof_syms.o |
19 | obj-$(CONFIG_GCOV) += gmon_syms.o | 18 | obj-$(CONFIG_GCOV) += gmon_syms.o |
20 | obj-$(CONFIG_TTY_LOG) += tty_log.o | 19 | obj-$(CONFIG_TTY_LOG) += tty_log.o |
21 | obj-$(CONFIG_SYSCALL_DEBUG) += syscall_user.o | 20 | obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o |
22 | 21 | ||
23 | obj-$(CONFIG_MODE_TT) += tt/ | 22 | obj-$(CONFIG_MODE_TT) += tt/ |
24 | obj-$(CONFIG_MODE_SKAS) += skas/ | 23 | obj-$(CONFIG_MODE_SKAS) += skas/ |
25 | 24 | ||
26 | user-objs-$(CONFIG_TTY_LOG) += tty_log.o | 25 | user-objs-$(CONFIG_TTY_LOG) += tty_log.o |
27 | 26 | ||
28 | USER_OBJS := $(user-objs-y) config.o helper.o main.o process.o tempfile.o \ | 27 | USER_OBJS := $(user-objs-y) config.o helper.o main.o tempfile.o time.o \ |
29 | time.o tty_log.o umid.o user_util.o | 28 | tty_log.o umid.o user_util.o |
30 | 29 | ||
31 | include arch/um/scripts/Makefile.rules | 30 | include arch/um/scripts/Makefile.rules |
32 | 31 | ||
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 9f18061ef4c9..dcd814971995 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include "kern_util.h" | 31 | #include "kern_util.h" |
32 | #include "irq_user.h" | 32 | #include "irq_user.h" |
33 | #include "irq_kern.h" | 33 | #include "irq_kern.h" |
34 | 34 | #include "os.h" | |
35 | 35 | ||
36 | /* | 36 | /* |
37 | * Generic, controller-independent functions: | 37 | * Generic, controller-independent functions: |
@@ -168,13 +168,32 @@ void __init init_IRQ(void) | |||
168 | } | 168 | } |
169 | } | 169 | } |
170 | 170 | ||
171 | /* | 171 | int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *, |
172 | * Overrides for Emacs so that we follow Linus's tabbing style. | 172 | struct pt_regs *)) |
173 | * Emacs will notice this stuff at the end of the file and automatically | 173 | { |
174 | * adjust the settings for this buffer only. This must remain at the end | 174 | int fds[2], err; |
175 | * of the file. | 175 | |
176 | * --------------------------------------------------------------------------- | 176 | err = os_pipe(fds, 1, 1); |
177 | * Local variables: | 177 | if(err){ |
178 | * c-file-style: "linux" | 178 | printk("init_aio_irq - os_pipe failed, err = %d\n", -err); |
179 | * End: | 179 | goto out; |
180 | */ | 180 | } |
181 | |||
182 | err = um_request_irq(irq, fds[0], IRQ_READ, handler, | ||
183 | SA_INTERRUPT | SA_SAMPLE_RANDOM, name, | ||
184 | (void *) (long) fds[0]); | ||
185 | if(err){ | ||
186 | printk("init_aio_irq - : um_request_irq failed, err = %d\n", | ||
187 | err); | ||
188 | goto out_close; | ||
189 | } | ||
190 | |||
191 | err = fds[1]; | ||
192 | goto out; | ||
193 | |||
194 | out_close: | ||
195 | os_close_file(fds[0]); | ||
196 | os_close_file(fds[1]); | ||
197 | out: | ||
198 | return(err); | ||
199 | } | ||
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 99439fa15ef4..32d3076dd220 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c | |||
@@ -114,22 +114,3 @@ extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); | |||
114 | EXPORT_SYMBOL(__read_lock_failed); | 114 | EXPORT_SYMBOL(__read_lock_failed); |
115 | 115 | ||
116 | #endif | 116 | #endif |
117 | |||
118 | #ifdef CONFIG_HIGHMEM | ||
119 | EXPORT_SYMBOL(kmap); | ||
120 | EXPORT_SYMBOL(kunmap); | ||
121 | EXPORT_SYMBOL(kmap_atomic); | ||
122 | EXPORT_SYMBOL(kunmap_atomic); | ||
123 | EXPORT_SYMBOL(kmap_atomic_to_page); | ||
124 | #endif | ||
125 | |||
126 | /* | ||
127 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
128 | * Emacs will notice this stuff at the end of the file and automatically | ||
129 | * adjust the settings for this buffer only. This must remain at the end | ||
130 | * of the file. | ||
131 | * --------------------------------------------------------------------------- | ||
132 | * Local variables: | ||
133 | * c-file-style: "linux" | ||
134 | * End: | ||
135 | */ | ||
diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c index 1e1a87f1c510..d31027f0fe39 100644 --- a/arch/um/kernel/main.c +++ b/arch/um/kernel/main.c | |||
@@ -97,7 +97,7 @@ int main(int argc, char **argv, char **envp) | |||
97 | exit(1); | 97 | exit(1); |
98 | } | 98 | } |
99 | 99 | ||
100 | #ifdef UML_CONFIG_MODE_TT | 100 | #ifdef UML_CONFIG_CMDLINE_ON_HOST |
101 | /* Allocate memory for thread command lines */ | 101 | /* Allocate memory for thread command lines */ |
102 | if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){ | 102 | if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){ |
103 | 103 | ||
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 5597bd39e6b5..64fa062cc119 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c | |||
@@ -196,7 +196,7 @@ static void init_highmem(void) | |||
196 | 196 | ||
197 | static void __init fixaddr_user_init( void) | 197 | static void __init fixaddr_user_init( void) |
198 | { | 198 | { |
199 | #if CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA | 199 | #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA |
200 | long size = FIXADDR_USER_END - FIXADDR_USER_START; | 200 | long size = FIXADDR_USER_END - FIXADDR_USER_START; |
201 | pgd_t *pgd; | 201 | pgd_t *pgd; |
202 | pud_t *pud; | 202 | pud_t *pud; |
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index d296d55ade4b..db36c7c95940 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ | 6 | obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ |
7 | syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \ | 7 | syscall.o tlb.o trap_user.o uaccess.o |
8 | 8 | ||
9 | subdir- := util | 9 | subdir- := util |
10 | 10 | ||
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h index 278b72f1d9ad..09536f81ee42 100644 --- a/arch/um/kernel/skas/include/mmu-skas.h +++ b/arch/um/kernel/skas/include/mmu-skas.h | |||
@@ -6,11 +6,15 @@ | |||
6 | #ifndef __SKAS_MMU_H | 6 | #ifndef __SKAS_MMU_H |
7 | #define __SKAS_MMU_H | 7 | #define __SKAS_MMU_H |
8 | 8 | ||
9 | #include "linux/config.h" | ||
9 | #include "mm_id.h" | 10 | #include "mm_id.h" |
10 | 11 | ||
11 | struct mmu_context_skas { | 12 | struct mmu_context_skas { |
12 | struct mm_id id; | 13 | struct mm_id id; |
13 | unsigned long last_page_table; | 14 | unsigned long last_page_table; |
15 | #ifdef CONFIG_3_LEVEL_PGTABLES | ||
16 | unsigned long last_pmd; | ||
17 | #endif | ||
14 | }; | 18 | }; |
15 | 19 | ||
16 | extern void switch_mm_skas(struct mm_id * mm_idp); | 20 | extern void switch_mm_skas(struct mm_id * mm_idp); |
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index d983ea842547..060934740f9f 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h | |||
@@ -24,28 +24,26 @@ extern void new_thread_proc(void *stack, void (*handler)(int sig)); | |||
24 | extern void remove_sigstack(void); | 24 | extern void remove_sigstack(void); |
25 | extern void new_thread_handler(int sig); | 25 | extern void new_thread_handler(int sig); |
26 | extern void handle_syscall(union uml_pt_regs *regs); | 26 | extern void handle_syscall(union uml_pt_regs *regs); |
27 | extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, | 27 | extern int map(struct mm_id * mm_idp, unsigned long virt, |
28 | int r, int w, int x, int phys_fd, unsigned long long offset); | 28 | unsigned long len, int r, int w, int x, int phys_fd, |
29 | extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len); | 29 | unsigned long long offset, int done, void **data); |
30 | extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, | ||
31 | int done, void **data); | ||
30 | extern int protect(struct mm_id * mm_idp, unsigned long addr, | 32 | extern int protect(struct mm_id * mm_idp, unsigned long addr, |
31 | unsigned long len, int r, int w, int x); | 33 | unsigned long len, int r, int w, int x, int done, |
34 | void **data); | ||
32 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); | 35 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); |
33 | extern int new_mm(int from); | 36 | extern int new_mm(int from, unsigned long stack); |
34 | extern int start_userspace(unsigned long stub_stack); | 37 | extern int start_userspace(unsigned long stub_stack); |
35 | extern int copy_context_skas0(unsigned long stack, int pid); | 38 | extern int copy_context_skas0(unsigned long stack, int pid); |
36 | extern void get_skas_faultinfo(int pid, struct faultinfo * fi); | 39 | extern void get_skas_faultinfo(int pid, struct faultinfo * fi); |
37 | extern long execute_syscall_skas(void *r); | 40 | extern long execute_syscall_skas(void *r); |
38 | extern unsigned long current_stub_stack(void); | 41 | extern unsigned long current_stub_stack(void); |
42 | extern long run_syscall_stub(struct mm_id * mm_idp, | ||
43 | int syscall, unsigned long *args, long expected, | ||
44 | void **addr, int done); | ||
45 | extern long syscall_stub_data(struct mm_id * mm_idp, | ||
46 | unsigned long *data, int data_count, | ||
47 | void **addr, void **stub_addr); | ||
39 | 48 | ||
40 | #endif | 49 | #endif |
41 | |||
42 | /* | ||
43 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
44 | * Emacs will notice this stuff at the end of the file and automatically | ||
45 | * adjust the settings for this buffer only. This must remain at the end | ||
46 | * of the file. | ||
47 | * --------------------------------------------------------------------------- | ||
48 | * Local variables: | ||
49 | * c-file-style: "linux" | ||
50 | * End: | ||
51 | */ | ||
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c index b0980ff3bd95..1d89640bd502 100644 --- a/arch/um/kernel/skas/mem_user.c +++ b/arch/um/kernel/skas/mem_user.c | |||
@@ -5,13 +5,14 @@ | |||
5 | 5 | ||
6 | #include <signal.h> | 6 | #include <signal.h> |
7 | #include <errno.h> | 7 | #include <errno.h> |
8 | #include <string.h> | ||
8 | #include <sys/mman.h> | 9 | #include <sys/mman.h> |
9 | #include <sys/wait.h> | 10 | #include <sys/wait.h> |
10 | #include <asm/page.h> | 11 | #include <asm/page.h> |
11 | #include <asm/unistd.h> | 12 | #include <asm/unistd.h> |
12 | #include "mem_user.h" | 13 | #include "mem_user.h" |
13 | #include "mem.h" | 14 | #include "mem.h" |
14 | #include "mm_id.h" | 15 | #include "skas.h" |
15 | #include "user.h" | 16 | #include "user.h" |
16 | #include "os.h" | 17 | #include "os.h" |
17 | #include "proc_mm.h" | 18 | #include "proc_mm.h" |
@@ -23,46 +24,155 @@ | |||
23 | #include "uml-config.h" | 24 | #include "uml-config.h" |
24 | #include "sysdep/ptrace.h" | 25 | #include "sysdep/ptrace.h" |
25 | #include "sysdep/stub.h" | 26 | #include "sysdep/stub.h" |
26 | #include "skas.h" | ||
27 | 27 | ||
28 | extern unsigned long syscall_stub, __syscall_stub_start; | 28 | extern unsigned long batch_syscall_stub, __syscall_stub_start; |
29 | 29 | ||
30 | extern void wait_stub_done(int pid, int sig, char * fname); | 30 | extern void wait_stub_done(int pid, int sig, char * fname); |
31 | 31 | ||
32 | static long run_syscall_stub(struct mm_id * mm_idp, int syscall, | 32 | static inline unsigned long *check_init_stack(struct mm_id * mm_idp, |
33 | unsigned long *args) | 33 | unsigned long *stack) |
34 | { | ||
35 | if(stack == NULL){ | ||
36 | stack = (unsigned long *) mm_idp->stack + 2; | ||
37 | *stack = 0; | ||
38 | } | ||
39 | return stack; | ||
40 | } | ||
41 | |||
42 | extern int proc_mm; | ||
43 | |||
44 | int single_count = 0; | ||
45 | int multi_count = 0; | ||
46 | int multi_op_count = 0; | ||
47 | |||
48 | static long do_syscall_stub(struct mm_id *mm_idp, void **addr) | ||
34 | { | 49 | { |
50 | unsigned long regs[MAX_REG_NR]; | ||
51 | unsigned long *data; | ||
52 | unsigned long *syscall; | ||
53 | long ret, offset; | ||
35 | int n, pid = mm_idp->u.pid; | 54 | int n, pid = mm_idp->u.pid; |
36 | unsigned long regs[MAX_REG_NR]; | 55 | |
56 | if(proc_mm) | ||
57 | #warning Need to look up userspace_pid by cpu | ||
58 | pid = userspace_pid[0]; | ||
59 | |||
60 | multi_count++; | ||
37 | 61 | ||
38 | get_safe_registers(regs); | 62 | get_safe_registers(regs); |
39 | regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + | 63 | regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + |
40 | ((unsigned long) &syscall_stub - | 64 | ((unsigned long) &batch_syscall_stub - |
41 | (unsigned long) &__syscall_stub_start); | 65 | (unsigned long) &__syscall_stub_start); |
42 | /* XXX Don't have a define for starting a syscall */ | 66 | n = ptrace_setregs(pid, regs); |
43 | regs[REGS_SYSCALL_NR] = syscall; | 67 | if(n < 0) |
44 | regs[REGS_SYSCALL_ARG1] = args[0]; | 68 | panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", |
45 | regs[REGS_SYSCALL_ARG2] = args[1]; | 69 | n); |
46 | regs[REGS_SYSCALL_ARG3] = args[2]; | 70 | |
47 | regs[REGS_SYSCALL_ARG4] = args[3]; | 71 | wait_stub_done(pid, 0, "do_syscall_stub"); |
48 | regs[REGS_SYSCALL_ARG5] = args[4]; | 72 | |
49 | regs[REGS_SYSCALL_ARG6] = args[5]; | 73 | /* When the stub stops, we find the following values on the |
50 | n = ptrace_setregs(pid, regs); | 74 | * beginning of the stack: |
51 | if(n < 0){ | 75 | * (long )return_value |
52 | printk("run_syscall_stub : PTRACE_SETREGS failed, " | 76 | * (long )offset to failed sycall-data (0, if no error) |
53 | "errno = %d\n", n); | 77 | */ |
54 | return(n); | 78 | ret = *((unsigned long *) mm_idp->stack); |
79 | offset = *((unsigned long *) mm_idp->stack + 1); | ||
80 | if (offset) { | ||
81 | data = (unsigned long *)(mm_idp->stack + | ||
82 | offset - UML_CONFIG_STUB_DATA); | ||
83 | syscall = (unsigned long *)((unsigned long)data + data[0]); | ||
84 | printk("do_syscall_stub: syscall %ld failed, return value = " | ||
85 | "0x%lx, expected return value = 0x%lx\n", | ||
86 | syscall[0], ret, syscall[7]); | ||
87 | printk(" syscall parameters: " | ||
88 | "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", | ||
89 | syscall[1], syscall[2], syscall[3], | ||
90 | syscall[4], syscall[5], syscall[6]); | ||
91 | for(n = 1; n < data[0]/sizeof(long); n++) { | ||
92 | if(n == 1) | ||
93 | printk(" additional syscall data:"); | ||
94 | if(n % 4 == 1) | ||
95 | printk("\n "); | ||
96 | printk(" 0x%lx", data[n]); | ||
97 | } | ||
98 | if(n > 1) | ||
99 | printk("\n"); | ||
100 | } | ||
101 | else ret = 0; | ||
102 | |||
103 | *addr = check_init_stack(mm_idp, NULL); | ||
104 | |||
105 | return ret; | ||
106 | } | ||
107 | |||
108 | long run_syscall_stub(struct mm_id * mm_idp, int syscall, | ||
109 | unsigned long *args, long expected, void **addr, | ||
110 | int done) | ||
111 | { | ||
112 | unsigned long *stack = check_init_stack(mm_idp, *addr); | ||
113 | |||
114 | if(done && *addr == NULL) | ||
115 | single_count++; | ||
116 | |||
117 | *stack += sizeof(long); | ||
118 | stack += *stack / sizeof(long); | ||
119 | |||
120 | *stack++ = syscall; | ||
121 | *stack++ = args[0]; | ||
122 | *stack++ = args[1]; | ||
123 | *stack++ = args[2]; | ||
124 | *stack++ = args[3]; | ||
125 | *stack++ = args[4]; | ||
126 | *stack++ = args[5]; | ||
127 | *stack++ = expected; | ||
128 | *stack = 0; | ||
129 | multi_op_count++; | ||
130 | |||
131 | if(!done && ((((unsigned long) stack) & ~PAGE_MASK) < | ||
132 | PAGE_SIZE - 10 * sizeof(long))){ | ||
133 | *addr = stack; | ||
134 | return 0; | ||
55 | } | 135 | } |
56 | 136 | ||
57 | wait_stub_done(pid, 0, "run_syscall_stub"); | 137 | return do_syscall_stub(mm_idp, addr); |
138 | } | ||
139 | |||
140 | long syscall_stub_data(struct mm_id * mm_idp, | ||
141 | unsigned long *data, int data_count, | ||
142 | void **addr, void **stub_addr) | ||
143 | { | ||
144 | unsigned long *stack; | ||
145 | int ret = 0; | ||
58 | 146 | ||
59 | return(*((unsigned long *) mm_idp->stack)); | 147 | /* If *addr still is uninitialized, it *must* contain NULL. |
148 | * Thus in this case do_syscall_stub correctly won't be called. | ||
149 | */ | ||
150 | if((((unsigned long) *addr) & ~PAGE_MASK) >= | ||
151 | PAGE_SIZE - (10 + data_count) * sizeof(long)) { | ||
152 | ret = do_syscall_stub(mm_idp, addr); | ||
153 | /* in case of error, don't overwrite data on stack */ | ||
154 | if(ret) | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | stack = check_init_stack(mm_idp, *addr); | ||
159 | *addr = stack; | ||
160 | |||
161 | *stack = data_count * sizeof(long); | ||
162 | |||
163 | memcpy(stack + 1, data, data_count * sizeof(long)); | ||
164 | |||
165 | *stub_addr = (void *)(((unsigned long)(stack + 1) & ~PAGE_MASK) + | ||
166 | UML_CONFIG_STUB_DATA); | ||
167 | |||
168 | return 0; | ||
60 | } | 169 | } |
61 | 170 | ||
62 | int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, | 171 | int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, |
63 | int r, int w, int x, int phys_fd, unsigned long long offset) | 172 | int r, int w, int x, int phys_fd, unsigned long long offset, |
173 | int done, void **data) | ||
64 | { | 174 | { |
65 | int prot, n; | 175 | int prot, ret; |
66 | 176 | ||
67 | prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | | 177 | prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | |
68 | (x ? PROT_EXEC : 0); | 178 | (x ? PROT_EXEC : 0); |
@@ -70,6 +180,7 @@ int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, | |||
70 | if(proc_mm){ | 180 | if(proc_mm){ |
71 | struct proc_mm_op map; | 181 | struct proc_mm_op map; |
72 | int fd = mm_idp->u.mm_fd; | 182 | int fd = mm_idp->u.mm_fd; |
183 | |||
73 | map = ((struct proc_mm_op) { .op = MM_MMAP, | 184 | map = ((struct proc_mm_op) { .op = MM_MMAP, |
74 | .u = | 185 | .u = |
75 | { .mmap = | 186 | { .mmap = |
@@ -81,63 +192,61 @@ int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, | |||
81 | .fd = phys_fd, | 192 | .fd = phys_fd, |
82 | .offset= offset | 193 | .offset= offset |
83 | } } } ); | 194 | } } } ); |
84 | n = os_write_file(fd, &map, sizeof(map)); | 195 | ret = os_write_file(fd, &map, sizeof(map)); |
85 | if(n != sizeof(map)) | 196 | if(ret != sizeof(map)) |
86 | printk("map : /proc/mm map failed, err = %d\n", -n); | 197 | printk("map : /proc/mm map failed, err = %d\n", -ret); |
198 | else ret = 0; | ||
87 | } | 199 | } |
88 | else { | 200 | else { |
89 | long res; | ||
90 | unsigned long args[] = { virt, len, prot, | 201 | unsigned long args[] = { virt, len, prot, |
91 | MAP_SHARED | MAP_FIXED, phys_fd, | 202 | MAP_SHARED | MAP_FIXED, phys_fd, |
92 | MMAP_OFFSET(offset) }; | 203 | MMAP_OFFSET(offset) }; |
93 | 204 | ||
94 | res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args); | 205 | ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, |
95 | if((void *) res == MAP_FAILED) | 206 | data, done); |
96 | printk("mmap stub failed, errno = %d\n", res); | ||
97 | } | 207 | } |
98 | 208 | ||
99 | return 0; | 209 | return ret; |
100 | } | 210 | } |
101 | 211 | ||
102 | int unmap(struct mm_id *mm_idp, void *addr, unsigned long len) | 212 | int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, |
213 | void **data) | ||
103 | { | 214 | { |
104 | int n; | 215 | int ret; |
105 | 216 | ||
106 | if(proc_mm){ | 217 | if(proc_mm){ |
107 | struct proc_mm_op unmap; | 218 | struct proc_mm_op unmap; |
108 | int fd = mm_idp->u.mm_fd; | 219 | int fd = mm_idp->u.mm_fd; |
220 | |||
109 | unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, | 221 | unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, |
110 | .u = | 222 | .u = |
111 | { .munmap = | 223 | { .munmap = |
112 | { .addr = | 224 | { .addr = |
113 | (unsigned long) addr, | 225 | (unsigned long) addr, |
114 | .len = len } } } ); | 226 | .len = len } } } ); |
115 | n = os_write_file(fd, &unmap, sizeof(unmap)); | 227 | ret = os_write_file(fd, &unmap, sizeof(unmap)); |
116 | if(n != sizeof(unmap)) { | 228 | if(ret != sizeof(unmap)) |
117 | if(n < 0) | 229 | printk("unmap - proc_mm write returned %d\n", ret); |
118 | return(n); | 230 | else ret = 0; |
119 | else if(n > 0) | ||
120 | return(-EIO); | ||
121 | } | ||
122 | } | 231 | } |
123 | else { | 232 | else { |
124 | int res; | ||
125 | unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, | 233 | unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, |
126 | 0 }; | 234 | 0 }; |
127 | 235 | ||
128 | res = run_syscall_stub(mm_idp, __NR_munmap, args); | 236 | ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, |
129 | if(res < 0) | 237 | data, done); |
130 | printk("munmap stub failed, errno = %d\n", res); | 238 | if(ret < 0) |
239 | printk("munmap stub failed, errno = %d\n", ret); | ||
131 | } | 240 | } |
132 | 241 | ||
133 | return(0); | 242 | return ret; |
134 | } | 243 | } |
135 | 244 | ||
136 | int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len, | 245 | int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, |
137 | int r, int w, int x) | 246 | int r, int w, int x, int done, void **data) |
138 | { | 247 | { |
139 | struct proc_mm_op protect; | 248 | struct proc_mm_op protect; |
140 | int prot, n; | 249 | int prot, ret; |
141 | 250 | ||
142 | prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | | 251 | prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | |
143 | (x ? PROT_EXEC : 0); | 252 | (x ? PROT_EXEC : 0); |
@@ -152,20 +261,19 @@ int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len, | |||
152 | .len = len, | 261 | .len = len, |
153 | .prot = prot } } } ); | 262 | .prot = prot } } } ); |
154 | 263 | ||
155 | n = os_write_file(fd, &protect, sizeof(protect)); | 264 | ret = os_write_file(fd, &protect, sizeof(protect)); |
156 | if(n != sizeof(protect)) | 265 | if(ret != sizeof(protect)) |
157 | panic("protect failed, err = %d", -n); | 266 | printk("protect failed, err = %d", -ret); |
267 | else ret = 0; | ||
158 | } | 268 | } |
159 | else { | 269 | else { |
160 | int res; | ||
161 | unsigned long args[] = { addr, len, prot, 0, 0, 0 }; | 270 | unsigned long args[] = { addr, len, prot, 0, 0, 0 }; |
162 | 271 | ||
163 | res = run_syscall_stub(mm_idp, __NR_mprotect, args); | 272 | ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, |
164 | if(res < 0) | 273 | data, done); |
165 | panic("mprotect stub failed, errno = %d\n", res); | ||
166 | } | 274 | } |
167 | 275 | ||
168 | return(0); | 276 | return ret; |
169 | } | 277 | } |
170 | 278 | ||
171 | void before_mem_skas(unsigned long unused) | 279 | void before_mem_skas(unsigned long unused) |
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index d232daa42c31..240143b616a2 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c | |||
@@ -56,6 +56,9 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc, | |||
56 | */ | 56 | */ |
57 | 57 | ||
58 | mm->context.skas.last_page_table = pmd_page_kernel(*pmd); | 58 | mm->context.skas.last_page_table = pmd_page_kernel(*pmd); |
59 | #ifdef CONFIG_3_LEVEL_PGTABLES | ||
60 | mm->context.skas.last_pmd = (unsigned long) __va(pud_val(*pud)); | ||
61 | #endif | ||
59 | 62 | ||
60 | *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT)); | 63 | *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT)); |
61 | *pte = pte_mkexec(*pte); | 64 | *pte = pte_mkexec(*pte); |
@@ -77,23 +80,14 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) | |||
77 | struct mm_struct *cur_mm = current->mm; | 80 | struct mm_struct *cur_mm = current->mm; |
78 | struct mm_id *cur_mm_id = &cur_mm->context.skas.id; | 81 | struct mm_id *cur_mm_id = &cur_mm->context.skas.id; |
79 | struct mm_id *mm_id = &mm->context.skas.id; | 82 | struct mm_id *mm_id = &mm->context.skas.id; |
80 | unsigned long stack; | 83 | unsigned long stack = 0; |
81 | int from, ret; | 84 | int from, ret = -ENOMEM; |
82 | 85 | ||
83 | if(proc_mm){ | 86 | if(!proc_mm || !ptrace_faultinfo){ |
84 | if((cur_mm != NULL) && (cur_mm != &init_mm)) | 87 | stack = get_zeroed_page(GFP_KERNEL); |
85 | from = cur_mm->context.skas.id.u.mm_fd; | 88 | if(stack == 0) |
86 | else from = -1; | 89 | goto out; |
87 | 90 | ||
88 | ret = new_mm(from); | ||
89 | if(ret < 0){ | ||
90 | printk("init_new_context_skas - new_mm failed, " | ||
91 | "errno = %d\n", ret); | ||
92 | return ret; | ||
93 | } | ||
94 | mm_id->u.mm_fd = ret; | ||
95 | } | ||
96 | else { | ||
97 | /* This zeros the entry that pgd_alloc didn't, needed since | 91 | /* This zeros the entry that pgd_alloc didn't, needed since |
98 | * we are about to reinitialize it, and want mm.nr_ptes to | 92 | * we are about to reinitialize it, and want mm.nr_ptes to |
99 | * be accurate. | 93 | * be accurate. |
@@ -103,20 +97,30 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) | |||
103 | ret = init_stub_pte(mm, CONFIG_STUB_CODE, | 97 | ret = init_stub_pte(mm, CONFIG_STUB_CODE, |
104 | (unsigned long) &__syscall_stub_start); | 98 | (unsigned long) &__syscall_stub_start); |
105 | if(ret) | 99 | if(ret) |
106 | goto out; | 100 | goto out_free; |
107 | |||
108 | ret = -ENOMEM; | ||
109 | stack = get_zeroed_page(GFP_KERNEL); | ||
110 | if(stack == 0) | ||
111 | goto out; | ||
112 | mm_id->stack = stack; | ||
113 | 101 | ||
114 | ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack); | 102 | ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack); |
115 | if(ret) | 103 | if(ret) |
116 | goto out_free; | 104 | goto out_free; |
117 | 105 | ||
118 | mm->nr_ptes--; | 106 | mm->nr_ptes--; |
107 | } | ||
108 | mm_id->stack = stack; | ||
119 | 109 | ||
110 | if(proc_mm){ | ||
111 | if((cur_mm != NULL) && (cur_mm != &init_mm)) | ||
112 | from = cur_mm_id->u.mm_fd; | ||
113 | else from = -1; | ||
114 | |||
115 | ret = new_mm(from, stack); | ||
116 | if(ret < 0){ | ||
117 | printk("init_new_context_skas - new_mm failed, " | ||
118 | "errno = %d\n", ret); | ||
119 | goto out_free; | ||
120 | } | ||
121 | mm_id->u.mm_fd = ret; | ||
122 | } | ||
123 | else { | ||
120 | if((cur_mm != NULL) && (cur_mm != &init_mm)) | 124 | if((cur_mm != NULL) && (cur_mm != &init_mm)) |
121 | mm_id->u.pid = copy_context_skas0(stack, | 125 | mm_id->u.pid = copy_context_skas0(stack, |
122 | cur_mm_id->u.pid); | 126 | cur_mm_id->u.pid); |
@@ -126,7 +130,8 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) | |||
126 | return 0; | 130 | return 0; |
127 | 131 | ||
128 | out_free: | 132 | out_free: |
129 | free_page(mm_id->stack); | 133 | if(mm_id->stack != 0) |
134 | free_page(mm_id->stack); | ||
130 | out: | 135 | out: |
131 | return ret; | 136 | return ret; |
132 | } | 137 | } |
@@ -137,9 +142,15 @@ void destroy_context_skas(struct mm_struct *mm) | |||
137 | 142 | ||
138 | if(proc_mm) | 143 | if(proc_mm) |
139 | os_close_file(mmu->id.u.mm_fd); | 144 | os_close_file(mmu->id.u.mm_fd); |
140 | else { | 145 | else |
141 | os_kill_ptraced_process(mmu->id.u.pid, 1); | 146 | os_kill_ptraced_process(mmu->id.u.pid, 1); |
147 | |||
148 | if(!proc_mm || !ptrace_faultinfo){ | ||
142 | free_page(mmu->id.stack); | 149 | free_page(mmu->id.stack); |
143 | free_page(mmu->last_page_table); | 150 | pte_free_kernel((pte_t *) mmu->last_page_table); |
151 | dec_page_state(nr_page_table_pages); | ||
152 | #ifdef CONFIG_3_LEVEL_PGTABLES | ||
153 | pmd_free((pmd_t *) mmu->last_pmd); | ||
154 | #endif | ||
144 | } | 155 | } |
145 | } | 156 | } |
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index f228f8b54194..5cd0e9929789 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c | |||
@@ -138,6 +138,8 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu | |||
138 | } | 138 | } |
139 | 139 | ||
140 | extern int __syscall_stub_start; | 140 | extern int __syscall_stub_start; |
141 | int stub_code_fd = -1; | ||
142 | __u64 stub_code_offset; | ||
141 | 143 | ||
142 | static int userspace_tramp(void *stack) | 144 | static int userspace_tramp(void *stack) |
143 | { | 145 | { |
@@ -152,31 +154,31 @@ static int userspace_tramp(void *stack) | |||
152 | /* This has a pte, but it can't be mapped in with the usual | 154 | /* This has a pte, but it can't be mapped in with the usual |
153 | * tlb_flush mechanism because this is part of that mechanism | 155 | * tlb_flush mechanism because this is part of that mechanism |
154 | */ | 156 | */ |
155 | int fd; | ||
156 | __u64 offset; | ||
157 | |||
158 | fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); | ||
159 | addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(), | 157 | addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(), |
160 | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); | 158 | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, |
159 | stub_code_fd, stub_code_offset); | ||
161 | if(addr == MAP_FAILED){ | 160 | if(addr == MAP_FAILED){ |
162 | printk("mapping mmap stub failed, errno = %d\n", | 161 | printk("mapping stub code failed, errno = %d\n", |
163 | errno); | 162 | errno); |
164 | exit(1); | 163 | exit(1); |
165 | } | 164 | } |
166 | 165 | ||
167 | if(stack != NULL){ | 166 | if(stack != NULL){ |
167 | int fd; | ||
168 | __u64 offset; | ||
169 | |||
168 | fd = phys_mapping(to_phys(stack), &offset); | 170 | fd = phys_mapping(to_phys(stack), &offset); |
169 | addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(), | 171 | addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(), |
170 | PROT_READ | PROT_WRITE, | 172 | PROT_READ | PROT_WRITE, |
171 | MAP_FIXED | MAP_SHARED, fd, offset); | 173 | MAP_FIXED | MAP_SHARED, fd, offset); |
172 | if(addr == MAP_FAILED){ | 174 | if(addr == MAP_FAILED){ |
173 | printk("mapping segfault stack failed, " | 175 | printk("mapping stub stack failed, " |
174 | "errno = %d\n", errno); | 176 | "errno = %d\n", errno); |
175 | exit(1); | 177 | exit(1); |
176 | } | 178 | } |
177 | } | 179 | } |
178 | } | 180 | } |
179 | if(!ptrace_faultinfo && (stack != NULL)){ | 181 | if(!ptrace_faultinfo){ |
180 | unsigned long v = UML_CONFIG_STUB_CODE + | 182 | unsigned long v = UML_CONFIG_STUB_CODE + |
181 | (unsigned long) stub_segv_handler - | 183 | (unsigned long) stub_segv_handler - |
182 | (unsigned long) &__syscall_stub_start; | 184 | (unsigned long) &__syscall_stub_start; |
@@ -202,6 +204,10 @@ int start_userspace(unsigned long stub_stack) | |||
202 | unsigned long sp; | 204 | unsigned long sp; |
203 | int pid, status, n, flags; | 205 | int pid, status, n, flags; |
204 | 206 | ||
207 | if ( stub_code_fd == -1 ) | ||
208 | stub_code_fd = phys_mapping(to_phys(&__syscall_stub_start), | ||
209 | &stub_code_offset); | ||
210 | |||
205 | stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, | 211 | stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, |
206 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 212 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
207 | if(stack == MAP_FAILED) | 213 | if(stack == MAP_FAILED) |
@@ -363,6 +369,53 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
363 | return pid; | 369 | return pid; |
364 | } | 370 | } |
365 | 371 | ||
372 | /* | ||
373 | * This is used only, if proc_mm is available, while PTRACE_FAULTINFO | ||
374 | * isn't. Opening /proc/mm creates a new mm_context, which lacks the stub-pages | ||
375 | * Thus, we map them using /proc/mm-fd | ||
376 | */ | ||
377 | void map_stub_pages(int fd, unsigned long code, | ||
378 | unsigned long data, unsigned long stack) | ||
379 | { | ||
380 | struct proc_mm_op mmop; | ||
381 | int n; | ||
382 | |||
383 | mmop = ((struct proc_mm_op) { .op = MM_MMAP, | ||
384 | .u = | ||
385 | { .mmap = | ||
386 | { .addr = code, | ||
387 | .len = PAGE_SIZE, | ||
388 | .prot = PROT_EXEC, | ||
389 | .flags = MAP_FIXED | MAP_PRIVATE, | ||
390 | .fd = stub_code_fd, | ||
391 | .offset = stub_code_offset | ||
392 | } } }); | ||
393 | n = os_write_file(fd, &mmop, sizeof(mmop)); | ||
394 | if(n != sizeof(mmop)) | ||
395 | panic("map_stub_pages : /proc/mm map for code failed, " | ||
396 | "err = %d\n", -n); | ||
397 | |||
398 | if ( stack ) { | ||
399 | __u64 map_offset; | ||
400 | int map_fd = phys_mapping(to_phys((void *)stack), &map_offset); | ||
401 | mmop = ((struct proc_mm_op) | ||
402 | { .op = MM_MMAP, | ||
403 | .u = | ||
404 | { .mmap = | ||
405 | { .addr = data, | ||
406 | .len = PAGE_SIZE, | ||
407 | .prot = PROT_READ | PROT_WRITE, | ||
408 | .flags = MAP_FIXED | MAP_SHARED, | ||
409 | .fd = map_fd, | ||
410 | .offset = map_offset | ||
411 | } } }); | ||
412 | n = os_write_file(fd, &mmop, sizeof(mmop)); | ||
413 | if(n != sizeof(mmop)) | ||
414 | panic("map_stub_pages : /proc/mm map for data failed, " | ||
415 | "err = %d\n", -n); | ||
416 | } | ||
417 | } | ||
418 | |||
366 | void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, | 419 | void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, |
367 | void (*handler)(int)) | 420 | void (*handler)(int)) |
368 | { | 421 | { |
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index cbabab104ac3..3d1b227226e6 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c | |||
@@ -129,7 +129,9 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, | |||
129 | return(0); | 129 | return(0); |
130 | } | 130 | } |
131 | 131 | ||
132 | int new_mm(int from) | 132 | extern void map_stub_pages(int fd, unsigned long code, |
133 | unsigned long data, unsigned long stack); | ||
134 | int new_mm(int from, unsigned long stack) | ||
133 | { | 135 | { |
134 | struct proc_mm_op copy; | 136 | struct proc_mm_op copy; |
135 | int n, fd; | 137 | int n, fd; |
@@ -148,6 +150,9 @@ int new_mm(int from) | |||
148 | "err = %d\n", -n); | 150 | "err = %d\n", -n); |
149 | } | 151 | } |
150 | 152 | ||
153 | if(!ptrace_faultinfo) | ||
154 | map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack); | ||
155 | |||
151 | return(fd); | 156 | return(fd); |
152 | } | 157 | } |
153 | 158 | ||
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c new file mode 100644 index 000000000000..51fb94076fcf --- /dev/null +++ b/arch/um/kernel/skas/syscall.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include "linux/sys.h" | ||
7 | #include "linux/ptrace.h" | ||
8 | #include "asm/errno.h" | ||
9 | #include "asm/unistd.h" | ||
10 | #include "asm/ptrace.h" | ||
11 | #include "asm/current.h" | ||
12 | #include "sysdep/syscalls.h" | ||
13 | #include "kern_util.h" | ||
14 | #include "syscall.h" | ||
15 | |||
16 | void handle_syscall(union uml_pt_regs *r) | ||
17 | { | ||
18 | struct pt_regs *regs = container_of(r, struct pt_regs, regs); | ||
19 | long result; | ||
20 | int syscall; | ||
21 | #ifdef UML_CONFIG_SYSCALL_DEBUG | ||
22 | int index; | ||
23 | |||
24 | index = record_syscall_start(UPT_SYSCALL_NR(r)); | ||
25 | #endif | ||
26 | syscall_trace(r, 0); | ||
27 | |||
28 | current->thread.nsyscalls++; | ||
29 | nsyscalls++; | ||
30 | |||
31 | /* This should go in the declaration of syscall, but when I do that, | ||
32 | * strace -f -c bash -c 'ls ; ls' breaks, sometimes not tracing | ||
33 | * children at all, sometimes hanging when bash doesn't see the first | ||
34 | * ls exit. | ||
35 | * The assembly looks functionally the same to me. This is | ||
36 | * gcc version 4.0.1 20050727 (Red Hat 4.0.1-5) | ||
37 | * in case it's a compiler bug. | ||
38 | */ | ||
39 | syscall = UPT_SYSCALL_NR(r); | ||
40 | if((syscall >= NR_syscalls) || (syscall < 0)) | ||
41 | result = -ENOSYS; | ||
42 | else result = EXECUTE_SYSCALL(syscall, regs); | ||
43 | |||
44 | REGS_SET_SYSCALL_RETURN(r->skas.regs, result); | ||
45 | |||
46 | syscall_trace(r, 1); | ||
47 | #ifdef UML_CONFIG_SYSCALL_DEBUG | ||
48 | record_syscall_end(index, result); | ||
49 | #endif | ||
50 | } | ||
diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c deleted file mode 100644 index bdf040ce5b8e..000000000000 --- a/arch/um/kernel/skas/syscall_kern.c +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include "linux/sys.h" | ||
7 | #include "linux/ptrace.h" | ||
8 | #include "asm/errno.h" | ||
9 | #include "asm/unistd.h" | ||
10 | #include "asm/ptrace.h" | ||
11 | #include "asm/current.h" | ||
12 | #include "sysdep/syscalls.h" | ||
13 | #include "kern_util.h" | ||
14 | |||
15 | extern syscall_handler_t *sys_call_table[]; | ||
16 | |||
17 | long execute_syscall_skas(void *r) | ||
18 | { | ||
19 | struct pt_regs *regs = r; | ||
20 | long res; | ||
21 | int syscall; | ||
22 | |||
23 | current->thread.nsyscalls++; | ||
24 | nsyscalls++; | ||
25 | syscall = UPT_SYSCALL_NR(®s->regs); | ||
26 | |||
27 | if((syscall >= NR_syscalls) || (syscall < 0)) | ||
28 | res = -ENOSYS; | ||
29 | else res = EXECUTE_SYSCALL(syscall, regs); | ||
30 | |||
31 | return(res); | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
36 | * Emacs will notice this stuff at the end of the file and automatically | ||
37 | * adjust the settings for this buffer only. This must remain at the end | ||
38 | * of the file. | ||
39 | * --------------------------------------------------------------------------- | ||
40 | * Local variables: | ||
41 | * c-file-style: "linux" | ||
42 | * End: | ||
43 | */ | ||
diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c deleted file mode 100644 index 6b0664970147..000000000000 --- a/arch/um/kernel/skas/syscall_user.c +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <signal.h> | ||
8 | #include "kern_util.h" | ||
9 | #include "uml-config.h" | ||
10 | #include "syscall_user.h" | ||
11 | #include "sysdep/ptrace.h" | ||
12 | #include "sysdep/sigcontext.h" | ||
13 | #include "skas.h" | ||
14 | |||
15 | void handle_syscall(union uml_pt_regs *regs) | ||
16 | { | ||
17 | long result; | ||
18 | #ifdef UML_CONFIG_SYSCALL_DEBUG | ||
19 | int index; | ||
20 | |||
21 | index = record_syscall_start(UPT_SYSCALL_NR(regs)); | ||
22 | #endif | ||
23 | |||
24 | syscall_trace(regs, 0); | ||
25 | result = execute_syscall_skas(regs); | ||
26 | |||
27 | REGS_SET_SYSCALL_RETURN(regs->skas.regs, result); | ||
28 | |||
29 | syscall_trace(regs, 1); | ||
30 | #ifdef UML_CONFIG_SYSCALL_DEBUG | ||
31 | record_syscall_end(index, result); | ||
32 | #endif | ||
33 | } | ||
34 | |||
35 | /* | ||
36 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
37 | * Emacs will notice this stuff at the end of the file and automatically | ||
38 | * adjust the settings for this buffer only. This must remain at the end | ||
39 | * of the file. | ||
40 | * --------------------------------------------------------------------------- | ||
41 | * Local variables: | ||
42 | * c-file-style: "linux" | ||
43 | * End: | ||
44 | */ | ||
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c index 6230999c672c..6e84963dfc29 100644 --- a/arch/um/kernel/skas/tlb.c +++ b/arch/um/kernel/skas/tlb.c | |||
@@ -18,33 +18,39 @@ | |||
18 | #include "os.h" | 18 | #include "os.h" |
19 | #include "tlb.h" | 19 | #include "tlb.h" |
20 | 20 | ||
21 | static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last) | 21 | static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last, |
22 | int finished, void **flush) | ||
22 | { | 23 | { |
23 | struct host_vm_op *op; | 24 | struct host_vm_op *op; |
24 | int i; | 25 | int i, ret = 0; |
25 | 26 | ||
26 | for(i = 0; i <= last; i++){ | 27 | for(i = 0; i <= last && !ret; i++){ |
27 | op = &ops[i]; | 28 | op = &ops[i]; |
28 | switch(op->type){ | 29 | switch(op->type){ |
29 | case MMAP: | 30 | case MMAP: |
30 | map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len, | 31 | ret = map(&mmu->skas.id, op->u.mmap.addr, |
31 | op->u.mmap.r, op->u.mmap.w, op->u.mmap.x, | 32 | op->u.mmap.len, op->u.mmap.r, op->u.mmap.w, |
32 | op->u.mmap.fd, op->u.mmap.offset); | 33 | op->u.mmap.x, op->u.mmap.fd, |
34 | op->u.mmap.offset, finished, flush); | ||
33 | break; | 35 | break; |
34 | case MUNMAP: | 36 | case MUNMAP: |
35 | unmap(&mmu->skas.id, (void *) op->u.munmap.addr, | 37 | ret = unmap(&mmu->skas.id, |
36 | op->u.munmap.len); | 38 | (void *) op->u.munmap.addr, |
39 | op->u.munmap.len, finished, flush); | ||
37 | break; | 40 | break; |
38 | case MPROTECT: | 41 | case MPROTECT: |
39 | protect(&mmu->skas.id, op->u.mprotect.addr, | 42 | ret = protect(&mmu->skas.id, op->u.mprotect.addr, |
40 | op->u.mprotect.len, op->u.mprotect.r, | 43 | op->u.mprotect.len, op->u.mprotect.r, |
41 | op->u.mprotect.w, op->u.mprotect.x); | 44 | op->u.mprotect.w, op->u.mprotect.x, |
45 | finished, flush); | ||
42 | break; | 46 | break; |
43 | default: | 47 | default: |
44 | printk("Unknown op type %d in do_ops\n", op->type); | 48 | printk("Unknown op type %d in do_ops\n", op->type); |
45 | break; | 49 | break; |
46 | } | 50 | } |
47 | } | 51 | } |
52 | |||
53 | return ret; | ||
48 | } | 54 | } |
49 | 55 | ||
50 | extern int proc_mm; | 56 | extern int proc_mm; |
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c new file mode 100644 index 000000000000..1429c131879d --- /dev/null +++ b/arch/um/kernel/syscall.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include "kern_util.h" | ||
7 | #include "syscall.h" | ||
8 | #include "os.h" | ||
9 | |||
10 | struct { | ||
11 | int syscall; | ||
12 | int pid; | ||
13 | long result; | ||
14 | unsigned long long start; | ||
15 | unsigned long long end; | ||
16 | } syscall_record[1024]; | ||
17 | |||
18 | int record_syscall_start(int syscall) | ||
19 | { | ||
20 | int max, index; | ||
21 | |||
22 | max = sizeof(syscall_record)/sizeof(syscall_record[0]); | ||
23 | index = next_syscall_index(max); | ||
24 | |||
25 | syscall_record[index].syscall = syscall; | ||
26 | syscall_record[index].pid = current_pid(); | ||
27 | syscall_record[index].result = 0xdeadbeef; | ||
28 | syscall_record[index].start = os_usecs(); | ||
29 | return(index); | ||
30 | } | ||
31 | |||
32 | void record_syscall_end(int index, long result) | ||
33 | { | ||
34 | syscall_record[index].result = result; | ||
35 | syscall_record[index].end = os_usecs(); | ||
36 | } | ||
diff --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c deleted file mode 100644 index 01b711e00a85..000000000000 --- a/arch/um/kernel/syscall_user.c +++ /dev/null | |||
@@ -1,48 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <sys/time.h> | ||
8 | #include "kern_util.h" | ||
9 | #include "syscall_user.h" | ||
10 | |||
11 | struct { | ||
12 | int syscall; | ||
13 | int pid; | ||
14 | long result; | ||
15 | struct timeval start; | ||
16 | struct timeval end; | ||
17 | } syscall_record[1024]; | ||
18 | |||
19 | int record_syscall_start(int syscall) | ||
20 | { | ||
21 | int max, index; | ||
22 | |||
23 | max = sizeof(syscall_record)/sizeof(syscall_record[0]); | ||
24 | index = next_syscall_index(max); | ||
25 | |||
26 | syscall_record[index].syscall = syscall; | ||
27 | syscall_record[index].pid = current_pid(); | ||
28 | syscall_record[index].result = 0xdeadbeef; | ||
29 | gettimeofday(&syscall_record[index].start, NULL); | ||
30 | return(index); | ||
31 | } | ||
32 | |||
33 | void record_syscall_end(int index, long result) | ||
34 | { | ||
35 | syscall_record[index].result = result; | ||
36 | gettimeofday(&syscall_record[index].end, NULL); | ||
37 | } | ||
38 | |||
39 | /* | ||
40 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
41 | * Emacs will notice this stuff at the end of the file and automatically | ||
42 | * adjust the settings for this buffer only. This must remain at the end | ||
43 | * of the file. | ||
44 | * --------------------------------------------------------------------------- | ||
45 | * Local variables: | ||
46 | * c-file-style: "linux" | ||
47 | * End: | ||
48 | */ | ||
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index 83ec8d4747fd..80ed6188e8a2 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c | |||
@@ -15,12 +15,118 @@ | |||
15 | #include "mem_user.h" | 15 | #include "mem_user.h" |
16 | #include "os.h" | 16 | #include "os.h" |
17 | 17 | ||
18 | static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, | ||
19 | int r, int w, int x, struct host_vm_op *ops, int *index, | ||
20 | int last_filled, union mm_context *mmu, void **flush, | ||
21 | int (*do_ops)(union mm_context *, struct host_vm_op *, | ||
22 | int, int, void **)) | ||
23 | { | ||
24 | __u64 offset; | ||
25 | struct host_vm_op *last; | ||
26 | int fd, ret = 0; | ||
27 | |||
28 | fd = phys_mapping(phys, &offset); | ||
29 | if(*index != -1){ | ||
30 | last = &ops[*index]; | ||
31 | if((last->type == MMAP) && | ||
32 | (last->u.mmap.addr + last->u.mmap.len == virt) && | ||
33 | (last->u.mmap.r == r) && (last->u.mmap.w == w) && | ||
34 | (last->u.mmap.x == x) && (last->u.mmap.fd == fd) && | ||
35 | (last->u.mmap.offset + last->u.mmap.len == offset)){ | ||
36 | last->u.mmap.len += len; | ||
37 | return 0; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | if(*index == last_filled){ | ||
42 | ret = (*do_ops)(mmu, ops, last_filled, 0, flush); | ||
43 | *index = -1; | ||
44 | } | ||
45 | |||
46 | ops[++*index] = ((struct host_vm_op) { .type = MMAP, | ||
47 | .u = { .mmap = { | ||
48 | .addr = virt, | ||
49 | .len = len, | ||
50 | .r = r, | ||
51 | .w = w, | ||
52 | .x = x, | ||
53 | .fd = fd, | ||
54 | .offset = offset } | ||
55 | } }); | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | static int add_munmap(unsigned long addr, unsigned long len, | ||
60 | struct host_vm_op *ops, int *index, int last_filled, | ||
61 | union mm_context *mmu, void **flush, | ||
62 | int (*do_ops)(union mm_context *, struct host_vm_op *, | ||
63 | int, int, void **)) | ||
64 | { | ||
65 | struct host_vm_op *last; | ||
66 | int ret = 0; | ||
67 | |||
68 | if(*index != -1){ | ||
69 | last = &ops[*index]; | ||
70 | if((last->type == MUNMAP) && | ||
71 | (last->u.munmap.addr + last->u.mmap.len == addr)){ | ||
72 | last->u.munmap.len += len; | ||
73 | return 0; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | if(*index == last_filled){ | ||
78 | ret = (*do_ops)(mmu, ops, last_filled, 0, flush); | ||
79 | *index = -1; | ||
80 | } | ||
81 | |||
82 | ops[++*index] = ((struct host_vm_op) { .type = MUNMAP, | ||
83 | .u = { .munmap = { | ||
84 | .addr = addr, | ||
85 | .len = len } } }); | ||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | static int add_mprotect(unsigned long addr, unsigned long len, int r, int w, | ||
90 | int x, struct host_vm_op *ops, int *index, | ||
91 | int last_filled, union mm_context *mmu, void **flush, | ||
92 | int (*do_ops)(union mm_context *, struct host_vm_op *, | ||
93 | int, int, void **)) | ||
94 | { | ||
95 | struct host_vm_op *last; | ||
96 | int ret = 0; | ||
97 | |||
98 | if(*index != -1){ | ||
99 | last = &ops[*index]; | ||
100 | if((last->type == MPROTECT) && | ||
101 | (last->u.mprotect.addr + last->u.mprotect.len == addr) && | ||
102 | (last->u.mprotect.r == r) && (last->u.mprotect.w == w) && | ||
103 | (last->u.mprotect.x == x)){ | ||
104 | last->u.mprotect.len += len; | ||
105 | return 0; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | if(*index == last_filled){ | ||
110 | ret = (*do_ops)(mmu, ops, last_filled, 0, flush); | ||
111 | *index = -1; | ||
112 | } | ||
113 | |||
114 | ops[++*index] = ((struct host_vm_op) { .type = MPROTECT, | ||
115 | .u = { .mprotect = { | ||
116 | .addr = addr, | ||
117 | .len = len, | ||
118 | .r = r, | ||
119 | .w = w, | ||
120 | .x = x } } }); | ||
121 | return ret; | ||
122 | } | ||
123 | |||
18 | #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) | 124 | #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) |
19 | 125 | ||
20 | void fix_range_common(struct mm_struct *mm, unsigned long start_addr, | 126 | void fix_range_common(struct mm_struct *mm, unsigned long start_addr, |
21 | unsigned long end_addr, int force, | 127 | unsigned long end_addr, int force, |
22 | void (*do_ops)(union mm_context *, struct host_vm_op *, | 128 | int (*do_ops)(union mm_context *, struct host_vm_op *, |
23 | int)) | 129 | int, int, void **)) |
24 | { | 130 | { |
25 | pgd_t *npgd; | 131 | pgd_t *npgd; |
26 | pud_t *npud; | 132 | pud_t *npud; |
@@ -29,21 +135,24 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, | |||
29 | union mm_context *mmu = &mm->context; | 135 | union mm_context *mmu = &mm->context; |
30 | unsigned long addr, end; | 136 | unsigned long addr, end; |
31 | int r, w, x; | 137 | int r, w, x; |
32 | struct host_vm_op ops[16]; | 138 | struct host_vm_op ops[1]; |
139 | void *flush = NULL; | ||
33 | int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1; | 140 | int op_index = -1, last_op = sizeof(ops) / sizeof(ops[0]) - 1; |
141 | int ret = 0; | ||
34 | 142 | ||
35 | if(mm == NULL) return; | 143 | if(mm == NULL) return; |
36 | 144 | ||
37 | for(addr = start_addr; addr < end_addr;){ | 145 | ops[0].type = NONE; |
146 | for(addr = start_addr; addr < end_addr && !ret;){ | ||
38 | npgd = pgd_offset(mm, addr); | 147 | npgd = pgd_offset(mm, addr); |
39 | if(!pgd_present(*npgd)){ | 148 | if(!pgd_present(*npgd)){ |
40 | end = ADD_ROUND(addr, PGDIR_SIZE); | 149 | end = ADD_ROUND(addr, PGDIR_SIZE); |
41 | if(end > end_addr) | 150 | if(end > end_addr) |
42 | end = end_addr; | 151 | end = end_addr; |
43 | if(force || pgd_newpage(*npgd)){ | 152 | if(force || pgd_newpage(*npgd)){ |
44 | op_index = add_munmap(addr, end - addr, ops, | 153 | ret = add_munmap(addr, end - addr, ops, |
45 | op_index, last_op, mmu, | 154 | &op_index, last_op, mmu, |
46 | do_ops); | 155 | &flush, do_ops); |
47 | pgd_mkuptodate(*npgd); | 156 | pgd_mkuptodate(*npgd); |
48 | } | 157 | } |
49 | addr = end; | 158 | addr = end; |
@@ -56,9 +165,9 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, | |||
56 | if(end > end_addr) | 165 | if(end > end_addr) |
57 | end = end_addr; | 166 | end = end_addr; |
58 | if(force || pud_newpage(*npud)){ | 167 | if(force || pud_newpage(*npud)){ |
59 | op_index = add_munmap(addr, end - addr, ops, | 168 | ret = add_munmap(addr, end - addr, ops, |
60 | op_index, last_op, mmu, | 169 | &op_index, last_op, mmu, |
61 | do_ops); | 170 | &flush, do_ops); |
62 | pud_mkuptodate(*npud); | 171 | pud_mkuptodate(*npud); |
63 | } | 172 | } |
64 | addr = end; | 173 | addr = end; |
@@ -71,9 +180,9 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, | |||
71 | if(end > end_addr) | 180 | if(end > end_addr) |
72 | end = end_addr; | 181 | end = end_addr; |
73 | if(force || pmd_newpage(*npmd)){ | 182 | if(force || pmd_newpage(*npmd)){ |
74 | op_index = add_munmap(addr, end - addr, ops, | 183 | ret = add_munmap(addr, end - addr, ops, |
75 | op_index, last_op, mmu, | 184 | &op_index, last_op, mmu, |
76 | do_ops); | 185 | &flush, do_ops); |
77 | pmd_mkuptodate(*npmd); | 186 | pmd_mkuptodate(*npmd); |
78 | } | 187 | } |
79 | addr = end; | 188 | addr = end; |
@@ -92,24 +201,32 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, | |||
92 | } | 201 | } |
93 | if(force || pte_newpage(*npte)){ | 202 | if(force || pte_newpage(*npte)){ |
94 | if(pte_present(*npte)) | 203 | if(pte_present(*npte)) |
95 | op_index = add_mmap(addr, | 204 | ret = add_mmap(addr, |
96 | pte_val(*npte) & PAGE_MASK, | 205 | pte_val(*npte) & PAGE_MASK, |
97 | PAGE_SIZE, r, w, x, ops, | 206 | PAGE_SIZE, r, w, x, ops, |
98 | op_index, last_op, mmu, | 207 | &op_index, last_op, mmu, |
99 | do_ops); | 208 | &flush, do_ops); |
100 | else op_index = add_munmap(addr, PAGE_SIZE, ops, | 209 | else ret = add_munmap(addr, PAGE_SIZE, ops, |
101 | op_index, last_op, mmu, | 210 | &op_index, last_op, mmu, |
102 | do_ops); | 211 | &flush, do_ops); |
103 | } | 212 | } |
104 | else if(pte_newprot(*npte)) | 213 | else if(pte_newprot(*npte)) |
105 | op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops, | 214 | ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops, |
106 | op_index, last_op, mmu, | 215 | &op_index, last_op, mmu, |
107 | do_ops); | 216 | &flush, do_ops); |
108 | 217 | ||
109 | *npte = pte_mkuptodate(*npte); | 218 | *npte = pte_mkuptodate(*npte); |
110 | addr += PAGE_SIZE; | 219 | addr += PAGE_SIZE; |
111 | } | 220 | } |
112 | (*do_ops)(mmu, ops, op_index); | 221 | |
222 | if(!ret) | ||
223 | ret = (*do_ops)(mmu, ops, op_index, 1, &flush); | ||
224 | |||
225 | /* This is not an else because ret is modified above */ | ||
226 | if(ret) { | ||
227 | printk("fix_range_common: failed, killing current process\n"); | ||
228 | force_sig(SIGKILL, current); | ||
229 | } | ||
113 | } | 230 | } |
114 | 231 | ||
115 | int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) | 232 | int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) |
@@ -226,106 +343,6 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr) | |||
226 | return(pte_offset_map(pmd, addr)); | 343 | return(pte_offset_map(pmd, addr)); |
227 | } | 344 | } |
228 | 345 | ||
229 | int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, | ||
230 | int r, int w, int x, struct host_vm_op *ops, int index, | ||
231 | int last_filled, union mm_context *mmu, | ||
232 | void (*do_ops)(union mm_context *, struct host_vm_op *, int)) | ||
233 | { | ||
234 | __u64 offset; | ||
235 | struct host_vm_op *last; | ||
236 | int fd; | ||
237 | |||
238 | fd = phys_mapping(phys, &offset); | ||
239 | if(index != -1){ | ||
240 | last = &ops[index]; | ||
241 | if((last->type == MMAP) && | ||
242 | (last->u.mmap.addr + last->u.mmap.len == virt) && | ||
243 | (last->u.mmap.r == r) && (last->u.mmap.w == w) && | ||
244 | (last->u.mmap.x == x) && (last->u.mmap.fd == fd) && | ||
245 | (last->u.mmap.offset + last->u.mmap.len == offset)){ | ||
246 | last->u.mmap.len += len; | ||
247 | return(index); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | if(index == last_filled){ | ||
252 | (*do_ops)(mmu, ops, last_filled); | ||
253 | index = -1; | ||
254 | } | ||
255 | |||
256 | ops[++index] = ((struct host_vm_op) { .type = MMAP, | ||
257 | .u = { .mmap = { | ||
258 | .addr = virt, | ||
259 | .len = len, | ||
260 | .r = r, | ||
261 | .w = w, | ||
262 | .x = x, | ||
263 | .fd = fd, | ||
264 | .offset = offset } | ||
265 | } }); | ||
266 | return(index); | ||
267 | } | ||
268 | |||
269 | int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops, | ||
270 | int index, int last_filled, union mm_context *mmu, | ||
271 | void (*do_ops)(union mm_context *, struct host_vm_op *, int)) | ||
272 | { | ||
273 | struct host_vm_op *last; | ||
274 | |||
275 | if(index != -1){ | ||
276 | last = &ops[index]; | ||
277 | if((last->type == MUNMAP) && | ||
278 | (last->u.munmap.addr + last->u.mmap.len == addr)){ | ||
279 | last->u.munmap.len += len; | ||
280 | return(index); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | if(index == last_filled){ | ||
285 | (*do_ops)(mmu, ops, last_filled); | ||
286 | index = -1; | ||
287 | } | ||
288 | |||
289 | ops[++index] = ((struct host_vm_op) { .type = MUNMAP, | ||
290 | .u = { .munmap = { | ||
291 | .addr = addr, | ||
292 | .len = len } } }); | ||
293 | return(index); | ||
294 | } | ||
295 | |||
296 | int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, | ||
297 | struct host_vm_op *ops, int index, int last_filled, | ||
298 | union mm_context *mmu, | ||
299 | void (*do_ops)(union mm_context *, struct host_vm_op *, int)) | ||
300 | { | ||
301 | struct host_vm_op *last; | ||
302 | |||
303 | if(index != -1){ | ||
304 | last = &ops[index]; | ||
305 | if((last->type == MPROTECT) && | ||
306 | (last->u.mprotect.addr + last->u.mprotect.len == addr) && | ||
307 | (last->u.mprotect.r == r) && (last->u.mprotect.w == w) && | ||
308 | (last->u.mprotect.x == x)){ | ||
309 | last->u.mprotect.len += len; | ||
310 | return(index); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | if(index == last_filled){ | ||
315 | (*do_ops)(mmu, ops, last_filled); | ||
316 | index = -1; | ||
317 | } | ||
318 | |||
319 | ops[++index] = ((struct host_vm_op) { .type = MPROTECT, | ||
320 | .u = { .mprotect = { | ||
321 | .addr = addr, | ||
322 | .len = len, | ||
323 | .r = r, | ||
324 | .w = w, | ||
325 | .x = x } } }); | ||
326 | return(index); | ||
327 | } | ||
328 | |||
329 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) | 346 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) |
330 | { | 347 | { |
331 | address &= PAGE_MASK; | 348 | address &= PAGE_MASK; |
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index c20aef120598..b5fc89fe9eab 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "mem.h" | 26 | #include "mem.h" |
27 | #include "mem_kern.h" | 27 | #include "mem_kern.h" |
28 | 28 | ||
29 | /* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */ | ||
29 | int handle_page_fault(unsigned long address, unsigned long ip, | 30 | int handle_page_fault(unsigned long address, unsigned long ip, |
30 | int is_write, int is_user, int *code_out) | 31 | int is_write, int is_user, int *code_out) |
31 | { | 32 | { |
@@ -35,7 +36,6 @@ int handle_page_fault(unsigned long address, unsigned long ip, | |||
35 | pud_t *pud; | 36 | pud_t *pud; |
36 | pmd_t *pmd; | 37 | pmd_t *pmd; |
37 | pte_t *pte; | 38 | pte_t *pte; |
38 | unsigned long page; | ||
39 | int err = -EFAULT; | 39 | int err = -EFAULT; |
40 | 40 | ||
41 | *code_out = SEGV_MAPERR; | 41 | *code_out = SEGV_MAPERR; |
@@ -52,7 +52,7 @@ int handle_page_fault(unsigned long address, unsigned long ip, | |||
52 | else if(expand_stack(vma, address)) | 52 | else if(expand_stack(vma, address)) |
53 | goto out; | 53 | goto out; |
54 | 54 | ||
55 | good_area: | 55 | good_area: |
56 | *code_out = SEGV_ACCERR; | 56 | *code_out = SEGV_ACCERR; |
57 | if(is_write && !(vma->vm_flags & VM_WRITE)) | 57 | if(is_write && !(vma->vm_flags & VM_WRITE)) |
58 | goto out; | 58 | goto out; |
@@ -60,9 +60,8 @@ int handle_page_fault(unsigned long address, unsigned long ip, | |||
60 | if(!(vma->vm_flags & (VM_READ | VM_EXEC))) | 60 | if(!(vma->vm_flags & (VM_READ | VM_EXEC))) |
61 | goto out; | 61 | goto out; |
62 | 62 | ||
63 | page = address & PAGE_MASK; | ||
64 | do { | 63 | do { |
65 | survive: | 64 | survive: |
66 | switch (handle_mm_fault(mm, vma, address, is_write)){ | 65 | switch (handle_mm_fault(mm, vma, address, is_write)){ |
67 | case VM_FAULT_MINOR: | 66 | case VM_FAULT_MINOR: |
68 | current->min_flt++; | 67 | current->min_flt++; |
@@ -79,16 +78,16 @@ int handle_page_fault(unsigned long address, unsigned long ip, | |||
79 | default: | 78 | default: |
80 | BUG(); | 79 | BUG(); |
81 | } | 80 | } |
82 | pgd = pgd_offset(mm, page); | 81 | pgd = pgd_offset(mm, address); |
83 | pud = pud_offset(pgd, page); | 82 | pud = pud_offset(pgd, address); |
84 | pmd = pmd_offset(pud, page); | 83 | pmd = pmd_offset(pud, address); |
85 | pte = pte_offset_kernel(pmd, page); | 84 | pte = pte_offset_kernel(pmd, address); |
86 | } while(!pte_present(*pte)); | 85 | } while(!pte_present(*pte)); |
87 | err = 0; | 86 | err = 0; |
88 | *pte = pte_mkyoung(*pte); | 87 | *pte = pte_mkyoung(*pte); |
89 | if(pte_write(*pte)) *pte = pte_mkdirty(*pte); | 88 | if(pte_write(*pte)) *pte = pte_mkdirty(*pte); |
90 | flush_tlb_page(vma, page); | 89 | flush_tlb_page(vma, address); |
91 | out: | 90 | out: |
92 | up_read(&mm->mmap_sem); | 91 | up_read(&mm->mmap_sem); |
93 | return(err); | 92 | return(err); |
94 | 93 | ||
@@ -144,19 +143,18 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) | |||
144 | panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", | 143 | panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", |
145 | address, ip); | 144 | address, ip); |
146 | 145 | ||
147 | if(err == -EACCES){ | 146 | if (err == -EACCES) { |
148 | si.si_signo = SIGBUS; | 147 | si.si_signo = SIGBUS; |
149 | si.si_errno = 0; | 148 | si.si_errno = 0; |
150 | si.si_code = BUS_ADRERR; | 149 | si.si_code = BUS_ADRERR; |
151 | si.si_addr = (void *)address; | 150 | si.si_addr = (void *)address; |
152 | current->thread.arch.faultinfo = fi; | 151 | current->thread.arch.faultinfo = fi; |
153 | force_sig_info(SIGBUS, &si, current); | 152 | force_sig_info(SIGBUS, &si, current); |
154 | } | 153 | } else if (err == -ENOMEM) { |
155 | else if(err == -ENOMEM){ | ||
156 | printk("VM: killing process %s\n", current->comm); | 154 | printk("VM: killing process %s\n", current->comm); |
157 | do_exit(SIGKILL); | 155 | do_exit(SIGKILL); |
158 | } | 156 | } else { |
159 | else { | 157 | BUG_ON(err != -EFAULT); |
160 | si.si_signo = SIGSEGV; | 158 | si.si_signo = SIGSEGV; |
161 | si.si_addr = (void *) address; | 159 | si.si_addr = (void *) address; |
162 | current->thread.arch.faultinfo = fi; | 160 | current->thread.arch.faultinfo = fi; |
@@ -200,30 +198,3 @@ void winch(int sig, union uml_pt_regs *regs) | |||
200 | void trap_init(void) | 198 | void trap_init(void) |
201 | { | 199 | { |
202 | } | 200 | } |
203 | |||
204 | DEFINE_SPINLOCK(trap_lock); | ||
205 | |||
206 | static int trap_index = 0; | ||
207 | |||
208 | int next_trap_index(int limit) | ||
209 | { | ||
210 | int ret; | ||
211 | |||
212 | spin_lock(&trap_lock); | ||
213 | ret = trap_index; | ||
214 | if(++trap_index == limit) | ||
215 | trap_index = 0; | ||
216 | spin_unlock(&trap_lock); | ||
217 | return(ret); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
222 | * Emacs will notice this stuff at the end of the file and automatically | ||
223 | * adjust the settings for this buffer only. This must remain at the end | ||
224 | * of the file. | ||
225 | * --------------------------------------------------------------------------- | ||
226 | * Local variables: | ||
227 | * c-file-style: "linux" | ||
228 | * End: | ||
229 | */ | ||
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index f825a6eda3f5..e9ccd6b8d3c7 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c | |||
@@ -40,35 +40,14 @@ void kill_child_dead(int pid) | |||
40 | } while(1); | 40 | } while(1); |
41 | } | 41 | } |
42 | 42 | ||
43 | /* Unlocked - don't care if this is a bit off */ | ||
44 | int nsegfaults = 0; | ||
45 | |||
46 | struct { | ||
47 | unsigned long address; | ||
48 | int is_write; | ||
49 | int pid; | ||
50 | unsigned long sp; | ||
51 | int is_user; | ||
52 | } segfault_record[1024]; | ||
53 | |||
54 | void segv_handler(int sig, union uml_pt_regs *regs) | 43 | void segv_handler(int sig, union uml_pt_regs *regs) |
55 | { | 44 | { |
56 | int index, max; | ||
57 | struct faultinfo * fi = UPT_FAULTINFO(regs); | 45 | struct faultinfo * fi = UPT_FAULTINFO(regs); |
58 | 46 | ||
59 | if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){ | 47 | if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){ |
60 | bad_segv(*fi, UPT_IP(regs)); | 48 | bad_segv(*fi, UPT_IP(regs)); |
61 | return; | 49 | return; |
62 | } | 50 | } |
63 | max = sizeof(segfault_record)/sizeof(segfault_record[0]); | ||
64 | index = next_trap_index(max); | ||
65 | |||
66 | nsegfaults++; | ||
67 | segfault_record[index].address = FAULT_ADDRESS(*fi); | ||
68 | segfault_record[index].pid = os_getpid(); | ||
69 | segfault_record[index].is_write = FAULT_WRITE(*fi); | ||
70 | segfault_record[index].sp = UPT_SP(regs); | ||
71 | segfault_record[index].is_user = UPT_IS_USER(regs); | ||
72 | segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); | 51 | segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); |
73 | } | 52 | } |
74 | 53 | ||
diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c index 2650a628719e..3d29c90514cc 100644 --- a/arch/um/kernel/tt/syscall_kern.c +++ b/arch/um/kernel/tt/syscall_kern.c | |||
@@ -12,36 +12,41 @@ | |||
12 | #include "asm/uaccess.h" | 12 | #include "asm/uaccess.h" |
13 | #include "asm/stat.h" | 13 | #include "asm/stat.h" |
14 | #include "sysdep/syscalls.h" | 14 | #include "sysdep/syscalls.h" |
15 | #include "sysdep/sigcontext.h" | ||
15 | #include "kern_util.h" | 16 | #include "kern_util.h" |
17 | #include "syscall.h" | ||
16 | 18 | ||
17 | extern syscall_handler_t *sys_call_table[]; | 19 | void syscall_handler_tt(int sig, struct pt_regs *regs) |
18 | |||
19 | long execute_syscall_tt(void *r) | ||
20 | { | 20 | { |
21 | struct pt_regs *regs = r; | 21 | void *sc; |
22 | long res; | 22 | long result; |
23 | int syscall; | 23 | int syscall; |
24 | |||
25 | #ifdef CONFIG_SYSCALL_DEBUG | 24 | #ifdef CONFIG_SYSCALL_DEBUG |
25 | int index; | ||
26 | index = record_syscall_start(syscall); | ||
27 | #endif | ||
28 | sc = UPT_SC(®s->regs); | ||
29 | SC_START_SYSCALL(sc); | ||
30 | |||
31 | syscall_trace(®s->regs, 0); | ||
32 | |||
26 | current->thread.nsyscalls++; | 33 | current->thread.nsyscalls++; |
27 | nsyscalls++; | 34 | nsyscalls++; |
28 | #endif | ||
29 | syscall = UPT_SYSCALL_NR(®s->regs); | 35 | syscall = UPT_SYSCALL_NR(®s->regs); |
30 | 36 | ||
31 | if((syscall >= NR_syscalls) || (syscall < 0)) | 37 | if((syscall >= NR_syscalls) || (syscall < 0)) |
32 | res = -ENOSYS; | 38 | result = -ENOSYS; |
33 | else res = EXECUTE_SYSCALL(syscall, regs); | 39 | else result = EXECUTE_SYSCALL(syscall, regs); |
34 | 40 | ||
35 | return(res); | 41 | /* regs->sc may have changed while the system call ran (there may |
36 | } | 42 | * have been an interrupt or segfault), so it needs to be refreshed. |
43 | */ | ||
44 | UPT_SC(®s->regs) = sc; | ||
37 | 45 | ||
38 | /* | 46 | SC_SET_SYSCALL_RETURN(sc, result); |
39 | * Overrides for Emacs so that we follow Linus's tabbing style. | 47 | |
40 | * Emacs will notice this stuff at the end of the file and automatically | 48 | syscall_trace(®s->regs, 1); |
41 | * adjust the settings for this buffer only. This must remain at the end | 49 | #ifdef CONFIG_SYSCALL_DEBUG |
42 | * of the file. | 50 | record_syscall_end(index, result); |
43 | * --------------------------------------------------------------------------- | 51 | #endif |
44 | * Local variables: | 52 | } |
45 | * c-file-style: "linux" | ||
46 | * End: | ||
47 | */ | ||
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c index b218316cfdb2..902987bf379b 100644 --- a/arch/um/kernel/tt/syscall_user.c +++ b/arch/um/kernel/tt/syscall_user.c | |||
@@ -13,42 +13,9 @@ | |||
13 | #include "task.h" | 13 | #include "task.h" |
14 | #include "user_util.h" | 14 | #include "user_util.h" |
15 | #include "kern_util.h" | 15 | #include "kern_util.h" |
16 | #include "syscall_user.h" | 16 | #include "syscall.h" |
17 | #include "tt.h" | 17 | #include "tt.h" |
18 | 18 | ||
19 | |||
20 | void syscall_handler_tt(int sig, union uml_pt_regs *regs) | ||
21 | { | ||
22 | void *sc; | ||
23 | long result; | ||
24 | int syscall; | ||
25 | #ifdef UML_CONFIG_DEBUG_SYSCALL | ||
26 | int index; | ||
27 | #endif | ||
28 | |||
29 | syscall = UPT_SYSCALL_NR(regs); | ||
30 | sc = UPT_SC(regs); | ||
31 | SC_START_SYSCALL(sc); | ||
32 | |||
33 | #ifdef UML_CONFIG_DEBUG_SYSCALL | ||
34 | index = record_syscall_start(syscall); | ||
35 | #endif | ||
36 | syscall_trace(regs, 0); | ||
37 | result = execute_syscall_tt(regs); | ||
38 | |||
39 | /* regs->sc may have changed while the system call ran (there may | ||
40 | * have been an interrupt or segfault), so it needs to be refreshed. | ||
41 | */ | ||
42 | UPT_SC(regs) = sc; | ||
43 | |||
44 | SC_SET_SYSCALL_RETURN(sc, result); | ||
45 | |||
46 | syscall_trace(regs, 1); | ||
47 | #ifdef UML_CONFIG_DEBUG_SYSCALL | ||
48 | record_syscall_end(index, result); | ||
49 | #endif | ||
50 | } | ||
51 | |||
52 | void do_sigtrap(void *task) | 19 | void do_sigtrap(void *task) |
53 | { | 20 | { |
54 | UPT_SYSCALL_NR(TASK_REGS(task)) = -1; | 21 | UPT_SYSCALL_NR(TASK_REGS(task)) = -1; |
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c index 2eefb43bc9c2..f1d85dbb45b9 100644 --- a/arch/um/kernel/tt/tlb.c +++ b/arch/um/kernel/tt/tlb.c | |||
@@ -17,25 +17,31 @@ | |||
17 | #include "os.h" | 17 | #include "os.h" |
18 | #include "tlb.h" | 18 | #include "tlb.h" |
19 | 19 | ||
20 | static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last) | 20 | static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last, |
21 | int finished, void **flush) | ||
21 | { | 22 | { |
22 | struct host_vm_op *op; | 23 | struct host_vm_op *op; |
23 | int i; | 24 | int i, ret=0; |
24 | 25 | ||
25 | for(i = 0; i <= last; i++){ | 26 | for(i = 0; i <= last && !ret; i++){ |
26 | op = &ops[i]; | 27 | op = &ops[i]; |
27 | switch(op->type){ | 28 | switch(op->type){ |
28 | case MMAP: | 29 | case MMAP: |
29 | os_map_memory((void *) op->u.mmap.addr, op->u.mmap.fd, | 30 | ret = os_map_memory((void *) op->u.mmap.addr, |
30 | op->u.mmap.offset, op->u.mmap.len, | 31 | op->u.mmap.fd, op->u.mmap.offset, |
31 | op->u.mmap.r, op->u.mmap.w, | 32 | op->u.mmap.len, op->u.mmap.r, |
32 | op->u.mmap.x); | 33 | op->u.mmap.w, op->u.mmap.x); |
33 | break; | 34 | break; |
34 | case MUNMAP: | 35 | case MUNMAP: |
35 | os_unmap_memory((void *) op->u.munmap.addr, | 36 | ret = os_unmap_memory((void *) op->u.munmap.addr, |
36 | op->u.munmap.len); | 37 | op->u.munmap.len); |
37 | break; | 38 | break; |
38 | case MPROTECT: | 39 | case MPROTECT: |
40 | ret = protect_memory(op->u.mprotect.addr, | ||
41 | op->u.munmap.len, | ||
42 | op->u.mprotect.r, | ||
43 | op->u.mprotect.w, | ||
44 | op->u.mprotect.x, 1); | ||
39 | protect_memory(op->u.mprotect.addr, op->u.munmap.len, | 45 | protect_memory(op->u.mprotect.addr, op->u.munmap.len, |
40 | op->u.mprotect.r, op->u.mprotect.w, | 46 | op->u.mprotect.r, op->u.mprotect.w, |
41 | op->u.mprotect.x, 1); | 47 | op->u.mprotect.x, 1); |
@@ -45,6 +51,8 @@ static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last) | |||
45 | break; | 51 | break; |
46 | } | 52 | } |
47 | } | 53 | } |
54 | |||
55 | return ret; | ||
48 | } | 56 | } |
49 | 57 | ||
50 | static void fix_range(struct mm_struct *mm, unsigned long start_addr, | 58 | static void fix_range(struct mm_struct *mm, unsigned long start_addr, |
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index ca2bb6f09a7d..09f6f7ce4695 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c | |||
@@ -126,7 +126,7 @@ unsigned long start_vm; | |||
126 | unsigned long end_vm; | 126 | unsigned long end_vm; |
127 | int ncpus = 1; | 127 | int ncpus = 1; |
128 | 128 | ||
129 | #ifdef CONFIG_MODE_TT | 129 | #ifdef CONFIG_CMDLINE_ON_HOST |
130 | /* Pointer set in linux_main, the array itself is private to each thread, | 130 | /* Pointer set in linux_main, the array itself is private to each thread, |
131 | * and changed at address space creation time so this poses no concurrency | 131 | * and changed at address space creation time so this poses no concurrency |
132 | * problems. | 132 | * problems. |
@@ -141,7 +141,7 @@ long physmem_size = 32 * 1024 * 1024; | |||
141 | 141 | ||
142 | void set_cmdline(char *cmd) | 142 | void set_cmdline(char *cmd) |
143 | { | 143 | { |
144 | #ifdef CONFIG_MODE_TT | 144 | #ifdef CONFIG_CMDLINE_ON_HOST |
145 | char *umid, *ptr; | 145 | char *umid, *ptr; |
146 | 146 | ||
147 | if(CHOOSE_MODE(honeypot, 0)) return; | 147 | if(CHOOSE_MODE(honeypot, 0)) return; |
@@ -333,6 +333,7 @@ int linux_main(int argc, char **argv) | |||
333 | if(have_root == 0) | 333 | if(have_root == 0) |
334 | add_arg(DEFAULT_COMMAND_LINE); | 334 | add_arg(DEFAULT_COMMAND_LINE); |
335 | 335 | ||
336 | os_early_checks(); | ||
336 | mode_tt = force_tt ? 1 : !can_do_skas(); | 337 | mode_tt = force_tt ? 1 : !can_do_skas(); |
337 | #ifndef CONFIG_MODE_TT | 338 | #ifndef CONFIG_MODE_TT |
338 | if (mode_tt) { | 339 | if (mode_tt) { |
@@ -385,7 +386,7 @@ int linux_main(int argc, char **argv) | |||
385 | 386 | ||
386 | setup_machinename(system_utsname.machine); | 387 | setup_machinename(system_utsname.machine); |
387 | 388 | ||
388 | #ifdef CONFIG_MODE_TT | 389 | #ifdef CONFIG_CMDLINE_ON_HOST |
389 | argv1_begin = argv[1]; | 390 | argv1_begin = argv[1]; |
390 | argv1_end = &argv[1][strlen(argv[1])]; | 391 | argv1_end = &argv[1][strlen(argv[1])]; |
391 | #endif | 392 | #endif |
@@ -470,7 +471,6 @@ void __init setup_arch(char **cmdline_p) | |||
470 | void __init check_bugs(void) | 471 | void __init check_bugs(void) |
471 | { | 472 | { |
472 | arch_check_bugs(); | 473 | arch_check_bugs(); |
473 | check_ptrace(); | ||
474 | check_sigio(); | 474 | check_sigio(); |
475 | check_devanon(); | 475 | check_devanon(); |
476 | } | 476 | } |
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 4ddf540284ce..7a1662419c0c 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile | |||
@@ -3,11 +3,19 @@ | |||
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y = elf_aux.o file.o process.o signal.o time.o tty.o user_syms.o drivers/ \ | 6 | obj-y = aio.o elf_aux.o file.o process.o signal.o start_up.o time.o tt.o \ |
7 | sys-$(SUBARCH)/ | 7 | tty.o user_syms.o drivers/ sys-$(SUBARCH)/ |
8 | 8 | ||
9 | USER_OBJS := elf_aux.o file.o process.o signal.o time.o tty.o | 9 | USER_OBJS := aio.o elf_aux.o file.o process.o signal.o start_up.o time.o tt.o \ |
10 | tty.o | ||
11 | |||
12 | elf_aux.o: $(ARCH_DIR)/kernel-offsets.h | ||
13 | CFLAGS_elf_aux.o += -I$(objtree)/arch/um | ||
10 | 14 | ||
11 | CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) | 15 | CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) |
12 | 16 | ||
17 | HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \ | ||
18 | echo -DHAVE_AIO_ABI ) | ||
19 | CFLAGS_aio.o += $(HAVE_AIO_ABI) | ||
20 | |||
13 | include arch/um/scripts/Makefile.rules | 21 | include arch/um/scripts/Makefile.rules |
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c new file mode 100644 index 000000000000..b04897cd995d --- /dev/null +++ b/arch/um/os-Linux/aio.c | |||
@@ -0,0 +1,414 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <unistd.h> | ||
8 | #include <signal.h> | ||
9 | #include <string.h> | ||
10 | #include <errno.h> | ||
11 | #include <sched.h> | ||
12 | #include <sys/syscall.h> | ||
13 | #include "os.h" | ||
14 | #include "helper.h" | ||
15 | #include "aio.h" | ||
16 | #include "init.h" | ||
17 | #include "user.h" | ||
18 | #include "mode.h" | ||
19 | |||
20 | static int aio_req_fd_r = -1; | ||
21 | static int aio_req_fd_w = -1; | ||
22 | |||
23 | static int update_aio(struct aio_context *aio, int res) | ||
24 | { | ||
25 | if(res < 0) | ||
26 | aio->len = res; | ||
27 | else if((res == 0) && (aio->type == AIO_READ)){ | ||
28 | /* This is the EOF case - we have hit the end of the file | ||
29 | * and it ends in a partial block, so we fill the end of | ||
30 | * the block with zeros and claim success. | ||
31 | */ | ||
32 | memset(aio->data, 0, aio->len); | ||
33 | aio->len = 0; | ||
34 | } | ||
35 | else if(res > 0){ | ||
36 | aio->len -= res; | ||
37 | aio->data += res; | ||
38 | aio->offset += res; | ||
39 | return aio->len; | ||
40 | } | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | #if defined(HAVE_AIO_ABI) | ||
46 | #include <linux/aio_abi.h> | ||
47 | |||
48 | /* If we have the headers, we are going to build with AIO enabled. | ||
49 | * If we don't have aio in libc, we define the necessary stubs here. | ||
50 | */ | ||
51 | |||
52 | #if !defined(HAVE_AIO_LIBC) | ||
53 | |||
54 | static long io_setup(int n, aio_context_t *ctxp) | ||
55 | { | ||
56 | return syscall(__NR_io_setup, n, ctxp); | ||
57 | } | ||
58 | |||
59 | static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) | ||
60 | { | ||
61 | return syscall(__NR_io_submit, ctx, nr, iocbpp); | ||
62 | } | ||
63 | |||
64 | static long io_getevents(aio_context_t ctx_id, long min_nr, long nr, | ||
65 | struct io_event *events, struct timespec *timeout) | ||
66 | { | ||
67 | return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout); | ||
68 | } | ||
69 | |||
70 | #endif | ||
71 | |||
72 | /* The AIO_MMAP cases force the mmapped page into memory here | ||
73 | * rather than in whatever place first touches the data. I used | ||
74 | * to do this by touching the page, but that's delicate because | ||
75 | * gcc is prone to optimizing that away. So, what's done here | ||
76 | * is we read from the descriptor from which the page was | ||
77 | * mapped. The caller is required to pass an offset which is | ||
78 | * inside the page that was mapped. Thus, when the read | ||
79 | * returns, we know that the page is in the page cache, and | ||
80 | * that it now backs the mmapped area. | ||
81 | */ | ||
82 | |||
83 | static int do_aio(aio_context_t ctx, struct aio_context *aio) | ||
84 | { | ||
85 | struct iocb iocb, *iocbp = &iocb; | ||
86 | char c; | ||
87 | int err; | ||
88 | |||
89 | iocb = ((struct iocb) { .aio_data = (unsigned long) aio, | ||
90 | .aio_reqprio = 0, | ||
91 | .aio_fildes = aio->fd, | ||
92 | .aio_buf = (unsigned long) aio->data, | ||
93 | .aio_nbytes = aio->len, | ||
94 | .aio_offset = aio->offset, | ||
95 | .aio_reserved1 = 0, | ||
96 | .aio_reserved2 = 0, | ||
97 | .aio_reserved3 = 0 }); | ||
98 | |||
99 | switch(aio->type){ | ||
100 | case AIO_READ: | ||
101 | iocb.aio_lio_opcode = IOCB_CMD_PREAD; | ||
102 | break; | ||
103 | case AIO_WRITE: | ||
104 | iocb.aio_lio_opcode = IOCB_CMD_PWRITE; | ||
105 | break; | ||
106 | case AIO_MMAP: | ||
107 | iocb.aio_lio_opcode = IOCB_CMD_PREAD; | ||
108 | iocb.aio_buf = (unsigned long) &c; | ||
109 | iocb.aio_nbytes = sizeof(c); | ||
110 | break; | ||
111 | default: | ||
112 | printk("Bogus op in do_aio - %d\n", aio->type); | ||
113 | err = -EINVAL; | ||
114 | goto out; | ||
115 | } | ||
116 | |||
117 | err = io_submit(ctx, 1, &iocbp); | ||
118 | if(err > 0) | ||
119 | err = 0; | ||
120 | |||
121 | out: | ||
122 | return err; | ||
123 | } | ||
124 | |||
125 | static aio_context_t ctx = 0; | ||
126 | |||
127 | static int aio_thread(void *arg) | ||
128 | { | ||
129 | struct aio_thread_reply reply; | ||
130 | struct aio_context *aio; | ||
131 | struct io_event event; | ||
132 | int err, n; | ||
133 | |||
134 | signal(SIGWINCH, SIG_IGN); | ||
135 | |||
136 | while(1){ | ||
137 | n = io_getevents(ctx, 1, 1, &event, NULL); | ||
138 | if(n < 0){ | ||
139 | if(errno == EINTR) | ||
140 | continue; | ||
141 | printk("aio_thread - io_getevents failed, " | ||
142 | "errno = %d\n", errno); | ||
143 | } | ||
144 | else { | ||
145 | aio = (struct aio_context *) event.data; | ||
146 | if(update_aio(aio, event.res)){ | ||
147 | do_aio(ctx, aio); | ||
148 | continue; | ||
149 | } | ||
150 | |||
151 | reply = ((struct aio_thread_reply) | ||
152 | { .data = aio, | ||
153 | .err = aio->len }); | ||
154 | err = os_write_file(aio->reply_fd, &reply, | ||
155 | sizeof(reply)); | ||
156 | if(err != sizeof(reply)) | ||
157 | printk("aio_thread - write failed, " | ||
158 | "fd = %d, err = %d\n", aio->reply_fd, | ||
159 | -err); | ||
160 | } | ||
161 | } | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | #endif | ||
166 | |||
167 | static int do_not_aio(struct aio_context *aio) | ||
168 | { | ||
169 | char c; | ||
170 | int err; | ||
171 | |||
172 | switch(aio->type){ | ||
173 | case AIO_READ: | ||
174 | err = os_seek_file(aio->fd, aio->offset); | ||
175 | if(err) | ||
176 | goto out; | ||
177 | |||
178 | err = os_read_file(aio->fd, aio->data, aio->len); | ||
179 | break; | ||
180 | case AIO_WRITE: | ||
181 | err = os_seek_file(aio->fd, aio->offset); | ||
182 | if(err) | ||
183 | goto out; | ||
184 | |||
185 | err = os_write_file(aio->fd, aio->data, aio->len); | ||
186 | break; | ||
187 | case AIO_MMAP: | ||
188 | err = os_seek_file(aio->fd, aio->offset); | ||
189 | if(err) | ||
190 | goto out; | ||
191 | |||
192 | err = os_read_file(aio->fd, &c, sizeof(c)); | ||
193 | break; | ||
194 | default: | ||
195 | printk("do_not_aio - bad request type : %d\n", aio->type); | ||
196 | err = -EINVAL; | ||
197 | break; | ||
198 | } | ||
199 | |||
200 | out: | ||
201 | return err; | ||
202 | } | ||
203 | |||
204 | static int not_aio_thread(void *arg) | ||
205 | { | ||
206 | struct aio_context *aio; | ||
207 | struct aio_thread_reply reply; | ||
208 | int err; | ||
209 | |||
210 | signal(SIGWINCH, SIG_IGN); | ||
211 | while(1){ | ||
212 | err = os_read_file(aio_req_fd_r, &aio, sizeof(aio)); | ||
213 | if(err != sizeof(aio)){ | ||
214 | if(err < 0) | ||
215 | printk("not_aio_thread - read failed, " | ||
216 | "fd = %d, err = %d\n", aio_req_fd_r, | ||
217 | -err); | ||
218 | else { | ||
219 | printk("not_aio_thread - short read, fd = %d, " | ||
220 | "length = %d\n", aio_req_fd_r, err); | ||
221 | } | ||
222 | continue; | ||
223 | } | ||
224 | again: | ||
225 | err = do_not_aio(aio); | ||
226 | |||
227 | if(update_aio(aio, err)) | ||
228 | goto again; | ||
229 | |||
230 | reply = ((struct aio_thread_reply) { .data = aio, | ||
231 | .err = aio->len }); | ||
232 | err = os_write_file(aio->reply_fd, &reply, sizeof(reply)); | ||
233 | if(err != sizeof(reply)) | ||
234 | printk("not_aio_thread - write failed, fd = %d, " | ||
235 | "err = %d\n", aio_req_fd_r, -err); | ||
236 | } | ||
237 | } | ||
238 | |||
239 | static int submit_aio_24(struct aio_context *aio) | ||
240 | { | ||
241 | int err; | ||
242 | |||
243 | err = os_write_file(aio_req_fd_w, &aio, sizeof(aio)); | ||
244 | if(err == sizeof(aio)) | ||
245 | err = 0; | ||
246 | |||
247 | return err; | ||
248 | } | ||
249 | |||
250 | static int aio_pid = -1; | ||
251 | static int (*submit_proc)(struct aio_context *aio); | ||
252 | |||
253 | static int init_aio_24(void) | ||
254 | { | ||
255 | unsigned long stack; | ||
256 | int fds[2], err; | ||
257 | |||
258 | err = os_pipe(fds, 1, 1); | ||
259 | if(err) | ||
260 | goto out; | ||
261 | |||
262 | aio_req_fd_w = fds[0]; | ||
263 | aio_req_fd_r = fds[1]; | ||
264 | err = run_helper_thread(not_aio_thread, NULL, | ||
265 | CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0); | ||
266 | if(err < 0) | ||
267 | goto out_close_pipe; | ||
268 | |||
269 | aio_pid = err; | ||
270 | goto out; | ||
271 | |||
272 | out_close_pipe: | ||
273 | os_close_file(fds[0]); | ||
274 | os_close_file(fds[1]); | ||
275 | aio_req_fd_w = -1; | ||
276 | aio_req_fd_r = -1; | ||
277 | out: | ||
278 | #ifndef HAVE_AIO_ABI | ||
279 | printk("/usr/include/linux/aio_abi.h not present during build\n"); | ||
280 | #endif | ||
281 | printk("2.6 host AIO support not used - falling back to I/O " | ||
282 | "thread\n"); | ||
283 | |||
284 | submit_proc = submit_aio_24; | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | #ifdef HAVE_AIO_ABI | ||
290 | #define DEFAULT_24_AIO 0 | ||
291 | static int submit_aio_26(struct aio_context *aio) | ||
292 | { | ||
293 | struct aio_thread_reply reply; | ||
294 | int err; | ||
295 | |||
296 | err = do_aio(ctx, aio); | ||
297 | if(err){ | ||
298 | reply = ((struct aio_thread_reply) { .data = aio, | ||
299 | .err = err }); | ||
300 | err = os_write_file(aio->reply_fd, &reply, sizeof(reply)); | ||
301 | if(err != sizeof(reply)) | ||
302 | printk("submit_aio_26 - write failed, " | ||
303 | "fd = %d, err = %d\n", aio->reply_fd, -err); | ||
304 | else err = 0; | ||
305 | } | ||
306 | |||
307 | return err; | ||
308 | } | ||
309 | |||
310 | static int init_aio_26(void) | ||
311 | { | ||
312 | unsigned long stack; | ||
313 | int err; | ||
314 | |||
315 | if(io_setup(256, &ctx)){ | ||
316 | printk("aio_thread failed to initialize context, err = %d\n", | ||
317 | errno); | ||
318 | return -errno; | ||
319 | } | ||
320 | |||
321 | err = run_helper_thread(aio_thread, NULL, | ||
322 | CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0); | ||
323 | if(err < 0) | ||
324 | return -errno; | ||
325 | |||
326 | aio_pid = err; | ||
327 | |||
328 | printk("Using 2.6 host AIO\n"); | ||
329 | |||
330 | submit_proc = submit_aio_26; | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | #else | ||
336 | #define DEFAULT_24_AIO 1 | ||
337 | static int submit_aio_26(struct aio_context *aio) | ||
338 | { | ||
339 | return -ENOSYS; | ||
340 | } | ||
341 | |||
342 | static int init_aio_26(void) | ||
343 | { | ||
344 | submit_proc = submit_aio_26; | ||
345 | return -ENOSYS; | ||
346 | } | ||
347 | #endif | ||
348 | |||
349 | static int aio_24 = DEFAULT_24_AIO; | ||
350 | |||
351 | static int __init set_aio_24(char *name, int *add) | ||
352 | { | ||
353 | aio_24 = 1; | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | __uml_setup("aio=2.4", set_aio_24, | ||
358 | "aio=2.4\n" | ||
359 | " This is used to force UML to use 2.4-style AIO even when 2.6 AIO is\n" | ||
360 | " available. 2.4 AIO is a single thread that handles one request at a\n" | ||
361 | " time, synchronously. 2.6 AIO is a thread which uses the 2.6 AIO \n" | ||
362 | " interface to handle an arbitrary number of pending requests. 2.6 AIO \n" | ||
363 | " is not available in tt mode, on 2.4 hosts, or when UML is built with\n" | ||
364 | " /usr/include/linux/aio_abi.h not available. Many distributions don't\n" | ||
365 | " include aio_abi.h, so you will need to copy it from a kernel tree to\n" | ||
366 | " your /usr/include/linux in order to build an AIO-capable UML\n\n" | ||
367 | ); | ||
368 | |||
369 | static int init_aio(void) | ||
370 | { | ||
371 | int err; | ||
372 | |||
373 | CHOOSE_MODE(({ | ||
374 | if(!aio_24){ | ||
375 | printk("Disabling 2.6 AIO in tt mode\n"); | ||
376 | aio_24 = 1; | ||
377 | } }), (void) 0); | ||
378 | |||
379 | if(!aio_24){ | ||
380 | err = init_aio_26(); | ||
381 | if(err && (errno == ENOSYS)){ | ||
382 | printk("2.6 AIO not supported on the host - " | ||
383 | "reverting to 2.4 AIO\n"); | ||
384 | aio_24 = 1; | ||
385 | } | ||
386 | else return err; | ||
387 | } | ||
388 | |||
389 | if(aio_24) | ||
390 | return init_aio_24(); | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | /* The reason for the __initcall/__uml_exitcall asymmetry is that init_aio | ||
396 | * needs to be called when the kernel is running because it calls run_helper, | ||
397 | * which needs get_free_page. exit_aio is a __uml_exitcall because the generic | ||
398 | * kernel does not run __exitcalls on shutdown, and can't because many of them | ||
399 | * break when called outside of module unloading. | ||
400 | */ | ||
401 | __initcall(init_aio); | ||
402 | |||
403 | static void exit_aio(void) | ||
404 | { | ||
405 | if(aio_pid != -1) | ||
406 | os_kill_process(aio_pid, 1); | ||
407 | } | ||
408 | |||
409 | __uml_exitcall(exit_aio); | ||
410 | |||
411 | int submit_aio(struct aio_context *aio) | ||
412 | { | ||
413 | return (*submit_proc)(aio); | ||
414 | } | ||
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 4cca3e9c23fe..1399520a8588 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c | |||
@@ -12,8 +12,9 @@ | |||
12 | #include "init.h" | 12 | #include "init.h" |
13 | #include "elf_user.h" | 13 | #include "elf_user.h" |
14 | #include "mem_user.h" | 14 | #include "mem_user.h" |
15 | #include <kernel-offsets.h> | ||
15 | 16 | ||
16 | #if ELF_CLASS == ELFCLASS32 | 17 | #if HOST_ELF_CLASS == ELFCLASS32 |
17 | typedef Elf32_auxv_t elf_auxv_t; | 18 | typedef Elf32_auxv_t elf_auxv_t; |
18 | #else | 19 | #else |
19 | typedef Elf64_auxv_t elf_auxv_t; | 20 | typedef Elf64_auxv_t elf_auxv_t; |
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 1e126bfd31a7..d32413e4b4ce 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c | |||
@@ -3,10 +3,10 @@ | |||
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <unistd.h> | ||
7 | #include <stdio.h> | 6 | #include <stdio.h> |
8 | #include <errno.h> | 7 | #include <errno.h> |
9 | #include <signal.h> | 8 | #include <signal.h> |
9 | #include <setjmp.h> | ||
10 | #include <linux/unistd.h> | 10 | #include <linux/unistd.h> |
11 | #include <sys/mman.h> | 11 | #include <sys/mman.h> |
12 | #include <sys/wait.h> | 12 | #include <sys/wait.h> |
@@ -14,6 +14,10 @@ | |||
14 | #include "os.h" | 14 | #include "os.h" |
15 | #include "user.h" | 15 | #include "user.h" |
16 | #include "user_util.h" | 16 | #include "user_util.h" |
17 | #include "signal_user.h" | ||
18 | #include "process.h" | ||
19 | #include "irq_user.h" | ||
20 | #include "kern_util.h" | ||
17 | 21 | ||
18 | #define ARBITRARY_ADDR -1 | 22 | #define ARBITRARY_ADDR -1 |
19 | #define FAILURE_PID -1 | 23 | #define FAILURE_PID -1 |
@@ -114,8 +118,10 @@ void os_usr1_process(int pid) | |||
114 | kill(pid, SIGUSR1); | 118 | kill(pid, SIGUSR1); |
115 | } | 119 | } |
116 | 120 | ||
117 | /*Don't use the glibc version, which caches the result in TLS. It misses some | 121 | /* Don't use the glibc version, which caches the result in TLS. It misses some |
118 | * syscalls, and also breaks with clone(), which does not unshare the TLS.*/ | 122 | * syscalls, and also breaks with clone(), which does not unshare the TLS. |
123 | */ | ||
124 | |||
119 | inline _syscall0(pid_t, getpid) | 125 | inline _syscall0(pid_t, getpid) |
120 | 126 | ||
121 | int os_getpid(void) | 127 | int os_getpid(void) |
@@ -164,6 +170,52 @@ int os_unmap_memory(void *addr, int len) | |||
164 | return(0); | 170 | return(0); |
165 | } | 171 | } |
166 | 172 | ||
173 | void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) | ||
174 | { | ||
175 | int flags = 0, pages; | ||
176 | |||
177 | if(sig_stack != NULL){ | ||
178 | pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER); | ||
179 | set_sigstack(sig_stack, pages * page_size()); | ||
180 | flags = SA_ONSTACK; | ||
181 | } | ||
182 | if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); | ||
183 | } | ||
184 | |||
185 | void init_new_thread_signals(int altstack) | ||
186 | { | ||
187 | int flags = altstack ? SA_ONSTACK : 0; | ||
188 | |||
189 | set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, | ||
190 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
191 | set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, | ||
192 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
193 | set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, | ||
194 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
195 | set_handler(SIGILL, (__sighandler_t) sig_handler, flags, | ||
196 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
197 | set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, | ||
198 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
199 | set_handler(SIGUSR2, (__sighandler_t) sig_handler, | ||
200 | flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
201 | signal(SIGHUP, SIG_IGN); | ||
202 | |||
203 | init_irq_signals(altstack); | ||
204 | } | ||
205 | |||
206 | int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) | ||
207 | { | ||
208 | sigjmp_buf buf; | ||
209 | int n; | ||
210 | |||
211 | *jmp_ptr = &buf; | ||
212 | n = sigsetjmp(buf, 1); | ||
213 | if(n != 0) | ||
214 | return(n); | ||
215 | (*fn)(arg); | ||
216 | return(0); | ||
217 | } | ||
218 | |||
167 | /* | 219 | /* |
168 | * Overrides for Emacs so that we follow Linus's tabbing style. | 220 | * Overrides for Emacs so that we follow Linus's tabbing style. |
169 | * Emacs will notice this stuff at the end of the file and automatically | 221 | * Emacs will notice this stuff at the end of the file and automatically |
diff --git a/arch/um/kernel/process.c b/arch/um/os-Linux/start_up.c index 67acd92c5322..040cc1472bc7 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/os-Linux/start_up.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -19,7 +19,6 @@ | |||
19 | #include "user_util.h" | 19 | #include "user_util.h" |
20 | #include "kern_util.h" | 20 | #include "kern_util.h" |
21 | #include "user.h" | 21 | #include "user.h" |
22 | #include "process.h" | ||
23 | #include "signal_kern.h" | 22 | #include "signal_kern.h" |
24 | #include "signal_user.h" | 23 | #include "signal_user.h" |
25 | #include "sysdep/ptrace.h" | 24 | #include "sysdep/ptrace.h" |
@@ -39,98 +38,6 @@ | |||
39 | #include "registers.h" | 38 | #include "registers.h" |
40 | #endif | 39 | #endif |
41 | 40 | ||
42 | void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) | ||
43 | { | ||
44 | int flags = 0, pages; | ||
45 | |||
46 | if(sig_stack != NULL){ | ||
47 | pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER); | ||
48 | set_sigstack(sig_stack, pages * page_size()); | ||
49 | flags = SA_ONSTACK; | ||
50 | } | ||
51 | if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); | ||
52 | } | ||
53 | |||
54 | void init_new_thread_signals(int altstack) | ||
55 | { | ||
56 | int flags = altstack ? SA_ONSTACK : 0; | ||
57 | |||
58 | set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, | ||
59 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
60 | set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, | ||
61 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
62 | set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, | ||
63 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
64 | set_handler(SIGILL, (__sighandler_t) sig_handler, flags, | ||
65 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
66 | set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, | ||
67 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
68 | set_handler(SIGUSR2, (__sighandler_t) sig_handler, | ||
69 | flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
70 | signal(SIGHUP, SIG_IGN); | ||
71 | |||
72 | init_irq_signals(altstack); | ||
73 | } | ||
74 | |||
75 | struct tramp { | ||
76 | int (*tramp)(void *); | ||
77 | void *tramp_data; | ||
78 | unsigned long temp_stack; | ||
79 | int flags; | ||
80 | int pid; | ||
81 | }; | ||
82 | |||
83 | /* See above for why sigkill is here */ | ||
84 | |||
85 | int sigkill = SIGKILL; | ||
86 | |||
87 | int outer_tramp(void *arg) | ||
88 | { | ||
89 | struct tramp *t; | ||
90 | int sig = sigkill; | ||
91 | |||
92 | t = arg; | ||
93 | t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2, | ||
94 | t->flags, t->tramp_data); | ||
95 | if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL); | ||
96 | kill(os_getpid(), sig); | ||
97 | _exit(0); | ||
98 | } | ||
99 | |||
100 | int start_fork_tramp(void *thread_arg, unsigned long temp_stack, | ||
101 | int clone_flags, int (*tramp)(void *)) | ||
102 | { | ||
103 | struct tramp arg; | ||
104 | unsigned long sp; | ||
105 | int new_pid, status, err; | ||
106 | |||
107 | /* The trampoline will run on the temporary stack */ | ||
108 | sp = stack_sp(temp_stack); | ||
109 | |||
110 | clone_flags |= CLONE_FILES | SIGCHLD; | ||
111 | |||
112 | arg.tramp = tramp; | ||
113 | arg.tramp_data = thread_arg; | ||
114 | arg.temp_stack = temp_stack; | ||
115 | arg.flags = clone_flags; | ||
116 | |||
117 | /* Start the process and wait for it to kill itself */ | ||
118 | new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg); | ||
119 | if(new_pid < 0) | ||
120 | return(new_pid); | ||
121 | |||
122 | CATCH_EINTR(err = waitpid(new_pid, &status, 0)); | ||
123 | if(err < 0) | ||
124 | panic("Waiting for outer trampoline failed - errno = %d", | ||
125 | errno); | ||
126 | |||
127 | if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) | ||
128 | panic("outer trampoline didn't exit with SIGKILL, " | ||
129 | "status = %d", status); | ||
130 | |||
131 | return(arg.pid); | ||
132 | } | ||
133 | |||
134 | static int ptrace_child(void *arg) | 41 | static int ptrace_child(void *arg) |
135 | { | 42 | { |
136 | int ret; | 43 | int ret; |
@@ -165,7 +72,7 @@ static int start_ptraced_child(void **stack_out) | |||
165 | void *stack; | 72 | void *stack; |
166 | unsigned long sp; | 73 | unsigned long sp; |
167 | int pid, n, status; | 74 | int pid, n, status; |
168 | 75 | ||
169 | stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, | 76 | stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, |
170 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 77 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
171 | if(stack == MAP_FAILED) | 78 | if(stack == MAP_FAILED) |
@@ -173,10 +80,10 @@ static int start_ptraced_child(void **stack_out) | |||
173 | sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); | 80 | sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); |
174 | pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); | 81 | pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); |
175 | if(pid < 0) | 82 | if(pid < 0) |
176 | panic("check_ptrace : clone failed, errno = %d", errno); | 83 | panic("start_ptraced_child : clone failed, errno = %d", errno); |
177 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 84 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
178 | if(n < 0) | 85 | if(n < 0) |
179 | panic("check_ptrace : wait failed, errno = %d", errno); | 86 | panic("check_ptrace : clone failed, errno = %d", errno); |
180 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) | 87 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) |
181 | panic("check_ptrace : expected SIGSTOP, got status = %d", | 88 | panic("check_ptrace : expected SIGSTOP, got status = %d", |
182 | status); | 89 | status); |
@@ -185,11 +92,14 @@ static int start_ptraced_child(void **stack_out) | |||
185 | return(pid); | 92 | return(pid); |
186 | } | 93 | } |
187 | 94 | ||
188 | /* When testing for SYSEMU support, if it is one of the broken versions, we must | 95 | /* When testing for SYSEMU support, if it is one of the broken versions, we |
189 | * just avoid using sysemu, not panic, but only if SYSEMU features are broken. | 96 | * must just avoid using sysemu, not panic, but only if SYSEMU features are |
97 | * broken. | ||
190 | * So only for SYSEMU features we test mustpanic, while normal host features | 98 | * So only for SYSEMU features we test mustpanic, while normal host features |
191 | * must work anyway!*/ | 99 | * must work anyway! |
192 | static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic) | 100 | */ |
101 | static int stop_ptraced_child(int pid, void *stack, int exitcode, | ||
102 | int mustpanic) | ||
193 | { | 103 | { |
194 | int status, n, ret = 0; | 104 | int status, n, ret = 0; |
195 | 105 | ||
@@ -217,8 +127,6 @@ static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic) | |||
217 | return ret; | 127 | return ret; |
218 | } | 128 | } |
219 | 129 | ||
220 | static int force_sysemu_disabled = 0; | ||
221 | |||
222 | int ptrace_faultinfo = 1; | 130 | int ptrace_faultinfo = 1; |
223 | int proc_mm = 1; | 131 | int proc_mm = 1; |
224 | 132 | ||
@@ -228,29 +136,32 @@ static int __init skas0_cmd_param(char *str, int* add) | |||
228 | return 0; | 136 | return 0; |
229 | } | 137 | } |
230 | 138 | ||
139 | __uml_setup("skas0", skas0_cmd_param, | ||
140 | "skas0\n" | ||
141 | " Disables SKAS3 usage, so that SKAS0 is used, unless \n" | ||
142 | " you specify mode=tt.\n\n"); | ||
143 | |||
144 | static int force_sysemu_disabled = 0; | ||
145 | |||
231 | static int __init nosysemu_cmd_param(char *str, int* add) | 146 | static int __init nosysemu_cmd_param(char *str, int* add) |
232 | { | 147 | { |
233 | force_sysemu_disabled = 1; | 148 | force_sysemu_disabled = 1; |
234 | return 0; | 149 | return 0; |
235 | } | 150 | } |
236 | 151 | ||
237 | __uml_setup("skas0", skas0_cmd_param, | ||
238 | "skas0\n" | ||
239 | " Disables SKAS3 usage, so that SKAS0 is used, unless you \n" | ||
240 | " specify mode=tt.\n\n"); | ||
241 | |||
242 | __uml_setup("nosysemu", nosysemu_cmd_param, | 152 | __uml_setup("nosysemu", nosysemu_cmd_param, |
243 | "nosysemu\n" | 153 | "nosysemu\n" |
244 | " Turns off syscall emulation patch for ptrace (SYSEMU) on.\n" | 154 | " Turns off syscall emulation patch for ptrace (SYSEMU) on.\n" |
245 | " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n" | 155 | " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n" |
246 | " behaviour of ptrace() and helps reducing host context switch rate.\n" | 156 | " behaviour of ptrace() and helps reducing host context switch rate.\n" |
247 | " To make it working, you need a kernel patch for your host, too.\n" | 157 | " To make it working, you need a kernel patch for your host, too.\n" |
248 | " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n\n"); | 158 | " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n" |
159 | " information.\n\n"); | ||
249 | 160 | ||
250 | static void __init check_sysemu(void) | 161 | static void __init check_sysemu(void) |
251 | { | 162 | { |
252 | void *stack; | 163 | void *stack; |
253 | int pid, syscall, n, status, count=0; | 164 | int pid, n, status, count=0; |
254 | 165 | ||
255 | printk("Checking syscall emulation patch for ptrace..."); | 166 | printk("Checking syscall emulation patch for ptrace..."); |
256 | sysemu_supported = 0; | 167 | sysemu_supported = 0; |
@@ -281,6 +192,12 @@ static void __init check_sysemu(void) | |||
281 | 192 | ||
282 | printk("Checking advanced syscall emulation patch for ptrace..."); | 193 | printk("Checking advanced syscall emulation patch for ptrace..."); |
283 | pid = start_ptraced_child(&stack); | 194 | pid = start_ptraced_child(&stack); |
195 | |||
196 | if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, | ||
197 | (void *) PTRACE_O_TRACESYSGOOD) < 0) | ||
198 | panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", | ||
199 | errno); | ||
200 | |||
284 | while(1){ | 201 | while(1){ |
285 | count++; | 202 | count++; |
286 | if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0) | 203 | if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0) |
@@ -288,15 +205,10 @@ static void __init check_sysemu(void) | |||
288 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 205 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
289 | if(n < 0) | 206 | if(n < 0) |
290 | panic("check_ptrace : wait failed, errno = %d", errno); | 207 | panic("check_ptrace : wait failed, errno = %d", errno); |
291 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) | 208 | if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){ |
292 | panic("check_ptrace : expected (SIGTRAP|SYSCALL_TRAP), " | ||
293 | "got status = %d", status); | ||
294 | |||
295 | syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, | ||
296 | 0); | ||
297 | if(syscall == __NR_getpid){ | ||
298 | if (!count) | 209 | if (!count) |
299 | panic("check_ptrace : SYSEMU_SINGLESTEP doesn't singlestep"); | 210 | panic("check_ptrace : SYSEMU_SINGLESTEP " |
211 | "doesn't singlestep"); | ||
300 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, | 212 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, |
301 | os_getpid()); | 213 | os_getpid()); |
302 | if(n < 0) | 214 | if(n < 0) |
@@ -304,6 +216,11 @@ static void __init check_sysemu(void) | |||
304 | "call return, errno = %d", errno); | 216 | "call return, errno = %d", errno); |
305 | break; | 217 | break; |
306 | } | 218 | } |
219 | else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) | ||
220 | count++; | ||
221 | else | ||
222 | panic("check_ptrace : expected SIGTRAP or " | ||
223 | "(SIGTRAP|0x80), got status = %d", status); | ||
307 | } | 224 | } |
308 | if (stop_ptraced_child(pid, stack, 0, 0) < 0) | 225 | if (stop_ptraced_child(pid, stack, 0, 0) < 0) |
309 | goto fail_stopped; | 226 | goto fail_stopped; |
@@ -321,7 +238,7 @@ fail_stopped: | |||
321 | printk("missing\n"); | 238 | printk("missing\n"); |
322 | } | 239 | } |
323 | 240 | ||
324 | void __init check_ptrace(void) | 241 | static void __init check_ptrace(void) |
325 | { | 242 | { |
326 | void *stack; | 243 | void *stack; |
327 | int pid, syscall, n, status; | 244 | int pid, syscall, n, status; |
@@ -329,20 +246,20 @@ void __init check_ptrace(void) | |||
329 | printk("Checking that ptrace can change system call numbers..."); | 246 | printk("Checking that ptrace can change system call numbers..."); |
330 | pid = start_ptraced_child(&stack); | 247 | pid = start_ptraced_child(&stack); |
331 | 248 | ||
332 | if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) | 249 | if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) |
333 | panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno); | 250 | panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", errno); |
334 | 251 | ||
335 | while(1){ | 252 | while(1){ |
336 | if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) | 253 | if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) |
337 | panic("check_ptrace : ptrace failed, errno = %d", | 254 | panic("check_ptrace : ptrace failed, errno = %d", |
338 | errno); | 255 | errno); |
339 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 256 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
340 | if(n < 0) | 257 | if(n < 0) |
341 | panic("check_ptrace : wait failed, errno = %d", errno); | 258 | panic("check_ptrace : wait failed, errno = %d", errno); |
342 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP + 0x80)) | 259 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP|0x80))) |
343 | panic("check_ptrace : expected SIGTRAP + 0x80, " | 260 | panic("check_ptrace : expected (SIGTRAP|0x80), " |
344 | "got status = %d", status); | 261 | "got status = %d", status); |
345 | 262 | ||
346 | syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, | 263 | syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, |
347 | 0); | 264 | 0); |
348 | if(syscall == __NR_getpid){ | 265 | if(syscall == __NR_getpid){ |
@@ -359,33 +276,36 @@ void __init check_ptrace(void) | |||
359 | check_sysemu(); | 276 | check_sysemu(); |
360 | } | 277 | } |
361 | 278 | ||
362 | int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) | 279 | void os_early_checks(void) |
363 | { | 280 | { |
364 | sigjmp_buf buf; | 281 | check_ptrace(); |
365 | int n; | ||
366 | |||
367 | *jmp_ptr = &buf; | ||
368 | n = sigsetjmp(buf, 1); | ||
369 | if(n != 0) | ||
370 | return(n); | ||
371 | (*fn)(arg); | ||
372 | return(0); | ||
373 | } | 282 | } |
374 | 283 | ||
375 | void forward_pending_sigio(int target) | 284 | static int __init noprocmm_cmd_param(char *str, int* add) |
376 | { | 285 | { |
377 | sigset_t sigs; | 286 | proc_mm = 0; |
287 | return 0; | ||
288 | } | ||
289 | |||
290 | __uml_setup("noprocmm", noprocmm_cmd_param, | ||
291 | "noprocmm\n" | ||
292 | " Turns off usage of /proc/mm, even if host supports it.\n" | ||
293 | " To support /proc/mm, the host needs to be patched using\n" | ||
294 | " the current skas3 patch.\n\n"); | ||
378 | 295 | ||
379 | if(sigpending(&sigs)) | 296 | static int __init noptracefaultinfo_cmd_param(char *str, int* add) |
380 | panic("forward_pending_sigio : sigpending failed"); | 297 | { |
381 | if(sigismember(&sigs, SIGIO)) | 298 | ptrace_faultinfo = 0; |
382 | kill(target, SIGIO); | 299 | return 0; |
383 | } | 300 | } |
384 | 301 | ||
385 | extern void *__syscall_stub_start, __syscall_stub_end; | 302 | __uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param, |
303 | "noptracefaultinfo\n" | ||
304 | " Turns off usage of PTRACE_FAULTINFO, even if host supports\n" | ||
305 | " it. To support PTRACE_FAULTINFO, the host needs to be patched\n" | ||
306 | " using the current skas3 patch.\n\n"); | ||
386 | 307 | ||
387 | #ifdef UML_CONFIG_MODE_SKAS | 308 | #ifdef UML_CONFIG_MODE_SKAS |
388 | |||
389 | static inline void check_skas3_ptrace_support(void) | 309 | static inline void check_skas3_ptrace_support(void) |
390 | { | 310 | { |
391 | struct ptrace_faultinfo fi; | 311 | struct ptrace_faultinfo fi; |
@@ -400,9 +320,8 @@ static inline void check_skas3_ptrace_support(void) | |||
400 | ptrace_faultinfo = 0; | 320 | ptrace_faultinfo = 0; |
401 | if(errno == EIO) | 321 | if(errno == EIO) |
402 | printf("not found\n"); | 322 | printf("not found\n"); |
403 | else { | 323 | else |
404 | perror("not found"); | 324 | perror("not found"); |
405 | } | ||
406 | } | 325 | } |
407 | else { | 326 | else { |
408 | if (!ptrace_faultinfo) | 327 | if (!ptrace_faultinfo) |
@@ -419,9 +338,10 @@ int can_do_skas(void) | |||
419 | { | 338 | { |
420 | printf("Checking for /proc/mm..."); | 339 | printf("Checking for /proc/mm..."); |
421 | if (os_access("/proc/mm", OS_ACC_W_OK) < 0) { | 340 | if (os_access("/proc/mm", OS_ACC_W_OK) < 0) { |
422 | proc_mm = 0; | 341 | proc_mm = 0; |
423 | printf("not found\n"); | 342 | printf("not found\n"); |
424 | } else { | 343 | } |
344 | else { | ||
425 | if (!proc_mm) | 345 | if (!proc_mm) |
426 | printf("found but disabled on command line\n"); | 346 | printf("found but disabled on command line\n"); |
427 | else | 347 | else |
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c new file mode 100644 index 000000000000..5b047ab8416a --- /dev/null +++ b/arch/um/os-Linux/tt.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <stdio.h> | ||
7 | #include <unistd.h> | ||
8 | #include <signal.h> | ||
9 | #include <sched.h> | ||
10 | #include <errno.h> | ||
11 | #include <stdarg.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <setjmp.h> | ||
14 | #include <sys/time.h> | ||
15 | #include <sys/ptrace.h> | ||
16 | #include <linux/ptrace.h> | ||
17 | #include <sys/wait.h> | ||
18 | #include <sys/mman.h> | ||
19 | #include <asm/ptrace.h> | ||
20 | #include <asm/unistd.h> | ||
21 | #include <asm/page.h> | ||
22 | #include "user_util.h" | ||
23 | #include "kern_util.h" | ||
24 | #include "user.h" | ||
25 | #include "signal_kern.h" | ||
26 | #include "signal_user.h" | ||
27 | #include "sysdep/ptrace.h" | ||
28 | #include "sysdep/sigcontext.h" | ||
29 | #include "irq_user.h" | ||
30 | #include "ptrace_user.h" | ||
31 | #include "time_user.h" | ||
32 | #include "init.h" | ||
33 | #include "os.h" | ||
34 | #include "uml-config.h" | ||
35 | #include "choose-mode.h" | ||
36 | #include "mode.h" | ||
37 | #include "tempfile.h" | ||
38 | |||
39 | /* | ||
40 | *------------------------- | ||
41 | * only for tt mode (will be deleted in future...) | ||
42 | *------------------------- | ||
43 | */ | ||
44 | |||
45 | struct tramp { | ||
46 | int (*tramp)(void *); | ||
47 | void *tramp_data; | ||
48 | unsigned long temp_stack; | ||
49 | int flags; | ||
50 | int pid; | ||
51 | }; | ||
52 | |||
53 | /* See above for why sigkill is here */ | ||
54 | |||
55 | int sigkill = SIGKILL; | ||
56 | |||
57 | int outer_tramp(void *arg) | ||
58 | { | ||
59 | struct tramp *t; | ||
60 | int sig = sigkill; | ||
61 | |||
62 | t = arg; | ||
63 | t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2, | ||
64 | t->flags, t->tramp_data); | ||
65 | if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL); | ||
66 | kill(os_getpid(), sig); | ||
67 | _exit(0); | ||
68 | } | ||
69 | |||
70 | int start_fork_tramp(void *thread_arg, unsigned long temp_stack, | ||
71 | int clone_flags, int (*tramp)(void *)) | ||
72 | { | ||
73 | struct tramp arg; | ||
74 | unsigned long sp; | ||
75 | int new_pid, status, err; | ||
76 | |||
77 | /* The trampoline will run on the temporary stack */ | ||
78 | sp = stack_sp(temp_stack); | ||
79 | |||
80 | clone_flags |= CLONE_FILES | SIGCHLD; | ||
81 | |||
82 | arg.tramp = tramp; | ||
83 | arg.tramp_data = thread_arg; | ||
84 | arg.temp_stack = temp_stack; | ||
85 | arg.flags = clone_flags; | ||
86 | |||
87 | /* Start the process and wait for it to kill itself */ | ||
88 | new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg); | ||
89 | if(new_pid < 0) | ||
90 | return(new_pid); | ||
91 | |||
92 | CATCH_EINTR(err = waitpid(new_pid, &status, 0)); | ||
93 | if(err < 0) | ||
94 | panic("Waiting for outer trampoline failed - errno = %d", | ||
95 | errno); | ||
96 | |||
97 | if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) | ||
98 | panic("outer trampoline didn't exit with SIGKILL, " | ||
99 | "status = %d", status); | ||
100 | |||
101 | return(arg.pid); | ||
102 | } | ||
103 | |||
104 | void forward_pending_sigio(int target) | ||
105 | { | ||
106 | sigset_t sigs; | ||
107 | |||
108 | if(sigpending(&sigs)) | ||
109 | panic("forward_pending_sigio : sigpending failed"); | ||
110 | if(sigismember(&sigs, SIGIO)) | ||
111 | kill(target, SIGIO); | ||
112 | } | ||
113 | |||
diff --git a/arch/um/scripts/Makefile.unmap b/arch/um/scripts/Makefile.unmap index 802d027a1e13..b2165188d942 100644 --- a/arch/um/scripts/Makefile.unmap +++ b/arch/um/scripts/Makefile.unmap | |||
@@ -12,7 +12,7 @@ $(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS)) | |||
12 | 12 | ||
13 | quiet_cmd_wrapld = LD $@ | 13 | quiet_cmd_wrapld = LD $@ |
14 | define cmd_wrapld | 14 | define cmd_wrapld |
15 | $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) $(CFLAGS) -print-file-name=libc.a); \ | 15 | $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< ; \ |
16 | $(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo | 16 | $(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo |
17 | endef | 17 | endef |
18 | 18 | ||
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 77c3c4d29f55..4ca2a229da49 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile | |||
@@ -16,13 +16,7 @@ semaphore.c-dir = kernel | |||
16 | highmem.c-dir = mm | 16 | highmem.c-dir = mm |
17 | module.c-dir = kernel | 17 | module.c-dir = kernel |
18 | 18 | ||
19 | STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) | 19 | $(obj)/stub_segv.o : _c_flags = $(call unprofile,$(CFLAGS)) |
20 | |||
21 | # _cflags works with kernel files, not with userspace ones, but c_flags does, | ||
22 | # why ask why? | ||
23 | $(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS) | ||
24 | |||
25 | $(obj)/stub.o : a_flags = $(STUB_CFLAGS) | ||
26 | 20 | ||
27 | subdir- := util | 21 | subdir- := util |
28 | 22 | ||
diff --git a/arch/um/sys-i386/kernel-offsets.c b/arch/um/sys-i386/kernel-offsets.c index 9f8ecd1fdd96..a1070af2bcd8 100644 --- a/arch/um/sys-i386/kernel-offsets.c +++ b/arch/um/sys-i386/kernel-offsets.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <linux/stddef.h> | 2 | #include <linux/stddef.h> |
3 | #include <linux/sched.h> | 3 | #include <linux/sched.h> |
4 | #include <linux/time.h> | 4 | #include <linux/time.h> |
5 | #include <linux/elf.h> | ||
5 | #include <asm/page.h> | 6 | #include <asm/page.h> |
6 | 7 | ||
7 | #define DEFINE(sym, val) \ | 8 | #define DEFINE(sym, val) \ |
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 4efc69a039d7..16bc19928b3c 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c | |||
@@ -122,9 +122,9 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | |||
122 | int err; | 122 | int err; |
123 | 123 | ||
124 | to_fp = to->fpstate; | 124 | to_fp = to->fpstate; |
125 | from_fp = from->fpstate; | ||
126 | sigs = to->oldmask; | 125 | sigs = to->oldmask; |
127 | err = copy_from_user(to, from, sizeof(*to)); | 126 | err = copy_from_user(to, from, sizeof(*to)); |
127 | from_fp = to->fpstate; | ||
128 | to->oldmask = sigs; | 128 | to->oldmask = sigs; |
129 | to->fpstate = to_fp; | 129 | to->fpstate = to_fp; |
130 | if(to_fp != NULL) | 130 | if(to_fp != NULL) |
diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S index 2f2c70a8f043..6a70d9ab5c29 100644 --- a/arch/um/sys-i386/stub.S +++ b/arch/um/sys-i386/stub.S | |||
@@ -2,7 +2,50 @@ | |||
2 | 2 | ||
3 | .globl syscall_stub | 3 | .globl syscall_stub |
4 | .section .__syscall_stub, "x" | 4 | .section .__syscall_stub, "x" |
5 | syscall_stub: | 5 | |
6 | int $0x80 | 6 | .globl batch_syscall_stub |
7 | batch_syscall_stub: | ||
8 | /* load pointer to first operation */ | ||
9 | mov $(UML_CONFIG_STUB_DATA+8), %esp | ||
10 | |||
11 | again: | ||
12 | /* load length of additional data */ | ||
13 | mov 0x0(%esp), %eax | ||
14 | |||
15 | /* if(length == 0) : end of list */ | ||
16 | /* write possible 0 to header */ | ||
17 | mov %eax, UML_CONFIG_STUB_DATA+4 | ||
18 | cmpl $0, %eax | ||
19 | jz done | ||
20 | |||
21 | /* save current pointer */ | ||
22 | mov %esp, UML_CONFIG_STUB_DATA+4 | ||
23 | |||
24 | /* skip additional data */ | ||
25 | add %eax, %esp | ||
26 | |||
27 | /* load syscall-# */ | ||
28 | pop %eax | ||
29 | |||
30 | /* load syscall params */ | ||
31 | pop %ebx | ||
32 | pop %ecx | ||
33 | pop %edx | ||
34 | pop %esi | ||
35 | pop %edi | ||
36 | pop %ebp | ||
37 | |||
38 | /* execute syscall */ | ||
39 | int $0x80 | ||
40 | |||
41 | /* check return value */ | ||
42 | pop %ebx | ||
43 | cmp %ebx, %eax | ||
44 | je again | ||
45 | |||
46 | done: | ||
47 | /* save return value */ | ||
7 | mov %eax, UML_CONFIG_STUB_DATA | 48 | mov %eax, UML_CONFIG_STUB_DATA |
49 | |||
50 | /* stop */ | ||
8 | int3 | 51 | int3 |
diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c index 68aeabe3a654..1e88b275edac 100644 --- a/arch/um/sys-i386/stub_segv.c +++ b/arch/um/sys-i386/stub_segv.c | |||
@@ -3,8 +3,7 @@ | |||
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <signal.h> | 6 | #include <asm/signal.h> |
7 | #include <asm/sigcontext.h> | ||
8 | #include <asm/unistd.h> | 7 | #include <asm/unistd.h> |
9 | #include "uml-config.h" | 8 | #include "uml-config.h" |
10 | #include "sysdep/sigcontext.h" | 9 | #include "sysdep/sigcontext.h" |
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 7488206ce6f4..f0ab574d1e95 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | #XXX: why into lib-y? | 7 | #XXX: why into lib-y? |
8 | lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \ | 8 | lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \ |
9 | ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \ | 9 | ptrace.o ptrace_user.o sigcontext.o signal.o stub.o \ |
10 | stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o | 10 | stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o |
11 | 11 | ||
12 | obj-y := ksyms.o | 12 | obj-y := ksyms.o |
@@ -15,7 +15,7 @@ obj-$(CONFIG_MODULES) += module.o um_module.o | |||
15 | USER_OBJS := ptrace_user.o sigcontext.o | 15 | USER_OBJS := ptrace_user.o sigcontext.o |
16 | 16 | ||
17 | SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \ | 17 | SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \ |
18 | semaphore.c thunk.S module.c | 18 | thunk.S module.c |
19 | 19 | ||
20 | include arch/um/scripts/Makefile.rules | 20 | include arch/um/scripts/Makefile.rules |
21 | 21 | ||
@@ -24,17 +24,10 @@ csum-copy.S-dir = lib | |||
24 | csum-partial.c-dir = lib | 24 | csum-partial.c-dir = lib |
25 | csum-wrappers.c-dir = lib | 25 | csum-wrappers.c-dir = lib |
26 | memcpy.S-dir = lib | 26 | memcpy.S-dir = lib |
27 | semaphore.c-dir = kernel | ||
28 | thunk.S-dir = lib | 27 | thunk.S-dir = lib |
29 | module.c-dir = kernel | 28 | module.c-dir = kernel |
30 | 29 | ||
31 | STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) | 30 | $(obj)/stub_segv.o: _c_flags = $(call unprofile,$(CFLAGS)) |
32 | |||
33 | # _cflags works with kernel files, not with userspace ones, but c_flags does, | ||
34 | # why ask why? | ||
35 | $(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS) | ||
36 | |||
37 | $(obj)/stub.o : a_flags = $(STUB_CFLAGS) | ||
38 | 31 | ||
39 | subdir- := util | 32 | subdir- := util |
40 | 33 | ||
diff --git a/arch/um/sys-x86_64/kernel-offsets.c b/arch/um/sys-x86_64/kernel-offsets.c index 220e875cbe29..998541eade41 100644 --- a/arch/um/sys-x86_64/kernel-offsets.c +++ b/arch/um/sys-x86_64/kernel-offsets.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <linux/stddef.h> | 2 | #include <linux/stddef.h> |
3 | #include <linux/sched.h> | 3 | #include <linux/sched.h> |
4 | #include <linux/time.h> | 4 | #include <linux/time.h> |
5 | #include <linux/elf.h> | ||
5 | #include <asm/page.h> | 6 | #include <asm/page.h> |
6 | 7 | ||
7 | #define DEFINE(sym, val) \ | 8 | #define DEFINE(sym, val) \ |
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index 8fdaed06c10d..fe1d065332b1 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c | |||
@@ -104,28 +104,35 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
104 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | 104 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, |
105 | int fpsize) | 105 | int fpsize) |
106 | { | 106 | { |
107 | struct _fpstate *to_fp, *from_fp; | 107 | struct _fpstate *to_fp, *from_fp; |
108 | unsigned long sigs; | 108 | unsigned long sigs; |
109 | int err; | 109 | int err; |
110 | 110 | ||
111 | to_fp = to->fpstate; | 111 | to_fp = to->fpstate; |
112 | from_fp = from->fpstate; | 112 | sigs = to->oldmask; |
113 | sigs = to->oldmask; | 113 | err = copy_from_user(to, from, sizeof(*to)); |
114 | err = copy_from_user(to, from, sizeof(*to)); | 114 | from_fp = to->fpstate; |
115 | to->oldmask = sigs; | 115 | to->fpstate = to_fp; |
116 | return(err); | 116 | to->oldmask = sigs; |
117 | if(to_fp != NULL) | ||
118 | err |= copy_from_user(to_fp, from_fp, fpsize); | ||
119 | return(err); | ||
117 | } | 120 | } |
118 | 121 | ||
119 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | 122 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, |
120 | struct sigcontext *from, int fpsize) | 123 | struct sigcontext *from, int fpsize) |
121 | { | 124 | { |
122 | struct _fpstate *to_fp, *from_fp; | 125 | struct _fpstate *to_fp, *from_fp; |
123 | int err; | 126 | int err; |
124 | 127 | ||
125 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); | 128 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); |
126 | from_fp = from->fpstate; | 129 | from_fp = from->fpstate; |
127 | err = copy_to_user(to, from, sizeof(*to)); | 130 | err = copy_to_user(to, from, sizeof(*to)); |
128 | return(err); | 131 | if(from_fp != NULL){ |
132 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); | ||
133 | err |= copy_to_user(to_fp, from_fp, fpsize); | ||
134 | } | ||
135 | return(err); | ||
129 | } | 136 | } |
130 | 137 | ||
131 | #endif | 138 | #endif |
diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S index 31c14925716b..03c279735784 100644 --- a/arch/um/sys-x86_64/stub.S +++ b/arch/um/sys-x86_64/stub.S | |||
@@ -13,3 +13,54 @@ syscall_stub: | |||
13 | or %rcx, %rbx | 13 | or %rcx, %rbx |
14 | movq %rax, (%rbx) | 14 | movq %rax, (%rbx) |
15 | int3 | 15 | int3 |
16 | |||
17 | .globl batch_syscall_stub | ||
18 | batch_syscall_stub: | ||
19 | mov $(UML_CONFIG_STUB_DATA >> 32), %rbx | ||
20 | sal $32, %rbx | ||
21 | mov $(UML_CONFIG_STUB_DATA & 0xffffffff), %rax | ||
22 | or %rax, %rbx | ||
23 | /* load pointer to first operation */ | ||
24 | mov %rbx, %rsp | ||
25 | add $0x10, %rsp | ||
26 | again: | ||
27 | /* load length of additional data */ | ||
28 | mov 0x0(%rsp), %rax | ||
29 | |||
30 | /* if(length == 0) : end of list */ | ||
31 | /* write possible 0 to header */ | ||
32 | mov %rax, 8(%rbx) | ||
33 | cmp $0, %rax | ||
34 | jz done | ||
35 | |||
36 | /* save current pointer */ | ||
37 | mov %rsp, 8(%rbx) | ||
38 | |||
39 | /* skip additional data */ | ||
40 | add %rax, %rsp | ||
41 | |||
42 | /* load syscall-# */ | ||
43 | pop %rax | ||
44 | |||
45 | /* load syscall params */ | ||
46 | pop %rdi | ||
47 | pop %rsi | ||
48 | pop %rdx | ||
49 | pop %r10 | ||
50 | pop %r8 | ||
51 | pop %r9 | ||
52 | |||
53 | /* execute syscall */ | ||
54 | syscall | ||
55 | |||
56 | /* check return value */ | ||
57 | pop %rcx | ||
58 | cmp %rcx, %rax | ||
59 | je again | ||
60 | |||
61 | done: | ||
62 | /* save return value */ | ||
63 | mov %rax, (%rbx) | ||
64 | |||
65 | /* stop */ | ||
66 | int3 | ||
diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c index 161d1fe9c034..65a131b362b6 100644 --- a/arch/um/sys-x86_64/stub_segv.c +++ b/arch/um/sys-x86_64/stub_segv.c | |||
@@ -3,9 +3,10 @@ | |||
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <signal.h> | 6 | #include <asm/signal.h> |
7 | #include <linux/compiler.h> | 7 | #include <linux/compiler.h> |
8 | #include <asm/unistd.h> | 8 | #include <asm/unistd.h> |
9 | #include <asm/ucontext.h> | ||
9 | #include "uml-config.h" | 10 | #include "uml-config.h" |
10 | #include "sysdep/sigcontext.h" | 11 | #include "sysdep/sigcontext.h" |
11 | #include "sysdep/faultinfo.h" | 12 | #include "sysdep/faultinfo.h" |