diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-04-12 16:54:16 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-04-12 16:54:16 -0400 |
commit | 875999c5539999f61a45620aae0c3e5fb1d2b035 (patch) | |
tree | 4535032a8a10f5782c0aef6a620b1a624ea9f863 /arch/um | |
parent | 79072f38909e3d9883317238887460c39ddcc4cb (diff) | |
parent | 26ec634c31a11a003040e10b4d650495158632fd (diff) |
Merge branch 'upstream'
Diffstat (limited to 'arch/um')
66 files changed, 1124 insertions, 416 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 5982fe2753..05fbb20636 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig | |||
@@ -22,6 +22,9 @@ config SBUS | |||
22 | config PCI | 22 | config PCI |
23 | bool | 23 | bool |
24 | 24 | ||
25 | config PCMCIA | ||
26 | bool | ||
27 | |||
25 | config GENERIC_CALIBRATE_DELAY | 28 | config GENERIC_CALIBRATE_DELAY |
26 | bool | 29 | bool |
27 | default y | 30 | default y |
diff --git a/arch/um/Makefile b/arch/um/Makefile index 8d14c7a831..a508e7a028 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile | |||
@@ -20,7 +20,7 @@ core-y += $(ARCH_DIR)/kernel/ \ | |||
20 | 20 | ||
21 | # Have to precede the include because the included Makefiles reference them. | 21 | # Have to precede the include because the included Makefiles reference them. |
22 | SYMLINK_HEADERS := archparam.h system.h sigcontext.h processor.h ptrace.h \ | 22 | SYMLINK_HEADERS := archparam.h system.h sigcontext.h processor.h ptrace.h \ |
23 | module.h vm-flags.h elf.h ldt.h | 23 | module.h vm-flags.h elf.h host_ldt.h |
24 | SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header)) | 24 | SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header)) |
25 | 25 | ||
26 | # XXX: The "os" symlink is only used by arch/um/include/os.h, which includes | 26 | # XXX: The "os" symlink is only used by arch/um/include/os.h, which includes |
@@ -129,7 +129,7 @@ CPPFLAGS_vmlinux.lds = -U$(SUBARCH) \ | |||
129 | -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ | 129 | -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ |
130 | -DELF_FORMAT="$(ELF_FORMAT)" $(CPP_MODE-y) \ | 130 | -DELF_FORMAT="$(ELF_FORMAT)" $(CPP_MODE-y) \ |
131 | -DKERNEL_STACK_SIZE=$(STACK_SIZE) \ | 131 | -DKERNEL_STACK_SIZE=$(STACK_SIZE) \ |
132 | -DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap_fin.o | 132 | -DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap.o |
133 | 133 | ||
134 | #The wrappers will select whether using "malloc" or the kernel allocator. | 134 | #The wrappers will select whether using "malloc" or the kernel allocator. |
135 | LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc | 135 | LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc |
@@ -150,8 +150,7 @@ CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \ | |||
150 | $(ARCH_DIR)/include/user_constants.h \ | 150 | $(ARCH_DIR)/include/user_constants.h \ |
151 | $(ARCH_DIR)/include/kern_constants.h $(ARCH_DIR)/Kconfig.arch | 151 | $(ARCH_DIR)/include/kern_constants.h $(ARCH_DIR)/Kconfig.arch |
152 | 152 | ||
153 | MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ | 153 | MRPROPER_FILES += $(ARCH_SYMLINKS) |
154 | $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os | ||
155 | 154 | ||
156 | archclean: | 155 | archclean: |
157 | @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ | 156 | @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ |
@@ -160,6 +159,7 @@ archclean: | |||
160 | $(SYMLINK_HEADERS): | 159 | $(SYMLINK_HEADERS): |
161 | @echo ' SYMLINK $@' | 160 | @echo ' SYMLINK $@' |
162 | ifneq ($(KBUILD_SRC),) | 161 | ifneq ($(KBUILD_SRC),) |
162 | $(Q)mkdir -p $(objtree)/include/asm-um | ||
163 | $(Q)ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@ | 163 | $(Q)ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@ |
164 | else | 164 | else |
165 | $(Q)cd $(TOPDIR)/$(dir $@) ; \ | 165 | $(Q)cd $(TOPDIR)/$(dir $@) ; \ |
@@ -169,7 +169,7 @@ endif | |||
169 | include/asm-um/arch: | 169 | include/asm-um/arch: |
170 | @echo ' SYMLINK $@' | 170 | @echo ' SYMLINK $@' |
171 | ifneq ($(KBUILD_SRC),) | 171 | ifneq ($(KBUILD_SRC),) |
172 | $(Q)mkdir -p include/asm-um | 172 | $(Q)mkdir -p $(objtree)/include/asm-um |
173 | $(Q)ln -fsn $(srctree)/include/asm-$(SUBARCH) include/asm-um/arch | 173 | $(Q)ln -fsn $(srctree)/include/asm-$(SUBARCH) include/asm-um/arch |
174 | else | 174 | else |
175 | $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch | 175 | $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch |
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index 38df311e75..dfd88b652f 100644 --- a/arch/um/Makefile-x86_64 +++ b/arch/um/Makefile-x86_64 | |||
@@ -1,7 +1,7 @@ | |||
1 | # Copyright 2003 - 2004 Pathscale, Inc | 1 | # Copyright 2003 - 2004 Pathscale, Inc |
2 | # Released under the GPL | 2 | # Released under the GPL |
3 | 3 | ||
4 | libs-y += arch/um/sys-x86_64/ | 4 | core-y += arch/um/sys-x86_64/ |
5 | START := 0x60000000 | 5 | 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 |
diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h index 04e3958266..dc36b22210 100644 --- a/arch/um/drivers/cow.h +++ b/arch/um/drivers/cow.h | |||
@@ -46,7 +46,7 @@ extern int file_reader(__u64 offset, char *buf, int len, void *arg); | |||
46 | extern int read_cow_header(int (*reader)(__u64, char *, int, void *), | 46 | extern int read_cow_header(int (*reader)(__u64, char *, int, void *), |
47 | void *arg, __u32 *version_out, | 47 | void *arg, __u32 *version_out, |
48 | char **backing_file_out, time_t *mtime_out, | 48 | char **backing_file_out, time_t *mtime_out, |
49 | __u64 *size_out, int *sectorsize_out, | 49 | unsigned long long *size_out, int *sectorsize_out, |
50 | __u32 *align_out, int *bitmap_offset_out); | 50 | __u32 *align_out, int *bitmap_offset_out); |
51 | 51 | ||
52 | extern int write_cow_header(char *cow_file, int fd, char *backing_file, | 52 | extern int write_cow_header(char *cow_file, int fd, char *backing_file, |
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h index 94de4ead4f..7a5b4afde6 100644 --- a/arch/um/drivers/cow_sys.h +++ b/arch/um/drivers/cow_sys.h | |||
@@ -28,7 +28,7 @@ static inline int cow_seek_file(int fd, __u64 offset) | |||
28 | return(os_seek_file(fd, offset)); | 28 | return(os_seek_file(fd, offset)); |
29 | } | 29 | } |
30 | 30 | ||
31 | static inline int cow_file_size(char *file, __u64 *size_out) | 31 | static inline int cow_file_size(char *file, unsigned long long *size_out) |
32 | { | 32 | { |
33 | return(os_file_size(file, size_out)); | 33 | return(os_file_size(file, size_out)); |
34 | } | 34 | } |
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index 61951b7212..0ec4052db9 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c | |||
@@ -17,30 +17,34 @@ | |||
17 | 17 | ||
18 | #define PATH_LEN_V1 256 | 18 | #define PATH_LEN_V1 256 |
19 | 19 | ||
20 | typedef __u32 time32_t; | ||
21 | |||
20 | struct cow_header_v1 { | 22 | struct cow_header_v1 { |
21 | int magic; | 23 | __s32 magic; |
22 | int version; | 24 | __s32 version; |
23 | char backing_file[PATH_LEN_V1]; | 25 | char backing_file[PATH_LEN_V1]; |
24 | time_t mtime; | 26 | time32_t mtime; |
25 | __u64 size; | 27 | __u64 size; |
26 | int sectorsize; | 28 | __s32 sectorsize; |
27 | }; | 29 | } __attribute__((packed)); |
28 | 30 | ||
29 | #define PATH_LEN_V2 MAXPATHLEN | 31 | /* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in |
32 | * case other systems have different values for MAXPATHLEN. | ||
33 | * | ||
34 | * The same must hold for V2 - we want file format compatibility, not anything | ||
35 | * else. | ||
36 | */ | ||
37 | #define PATH_LEN_V3 4096 | ||
38 | #define PATH_LEN_V2 PATH_LEN_V3 | ||
30 | 39 | ||
31 | struct cow_header_v2 { | 40 | struct cow_header_v2 { |
32 | __u32 magic; | 41 | __u32 magic; |
33 | __u32 version; | 42 | __u32 version; |
34 | char backing_file[PATH_LEN_V2]; | 43 | char backing_file[PATH_LEN_V2]; |
35 | time_t mtime; | 44 | time32_t mtime; |
36 | __u64 size; | 45 | __u64 size; |
37 | int sectorsize; | 46 | __s32 sectorsize; |
38 | }; | 47 | } __attribute__((packed)); |
39 | |||
40 | /* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in | ||
41 | * case other systems have different values for MAXPATHLEN | ||
42 | */ | ||
43 | #define PATH_LEN_V3 4096 | ||
44 | 48 | ||
45 | /* Changes from V2 - | 49 | /* Changes from V2 - |
46 | * PATH_LEN_V3 as described above | 50 | * PATH_LEN_V3 as described above |
@@ -66,6 +70,15 @@ struct cow_header_v2 { | |||
66 | * Fixed (finally!) the rounding bug | 70 | * Fixed (finally!) the rounding bug |
67 | */ | 71 | */ |
68 | 72 | ||
73 | /* Until Dec2005, __attribute__((packed)) was left out from the below | ||
74 | * definition, leading on 64-bit systems to 4 bytes of padding after mtime, to | ||
75 | * align size to 8-byte alignment. This shifted all fields above (no padding | ||
76 | * was present on 32-bit, no other padding was added). | ||
77 | * | ||
78 | * However, this _can be detected_: it means that cow_format (always 0 until | ||
79 | * now) is shifted onto the first 4 bytes of backing_file, where it is otherwise | ||
80 | * impossible to find 4 zeros. -bb */ | ||
81 | |||
69 | struct cow_header_v3 { | 82 | struct cow_header_v3 { |
70 | __u32 magic; | 83 | __u32 magic; |
71 | __u32 version; | 84 | __u32 version; |
@@ -75,6 +88,18 @@ struct cow_header_v3 { | |||
75 | __u32 alignment; | 88 | __u32 alignment; |
76 | __u32 cow_format; | 89 | __u32 cow_format; |
77 | char backing_file[PATH_LEN_V3]; | 90 | char backing_file[PATH_LEN_V3]; |
91 | } __attribute__((packed)); | ||
92 | |||
93 | /* This is the broken layout used by some 64-bit binaries. */ | ||
94 | struct cow_header_v3_broken { | ||
95 | __u32 magic; | ||
96 | __u32 version; | ||
97 | __s64 mtime; | ||
98 | __u64 size; | ||
99 | __u32 sectorsize; | ||
100 | __u32 alignment; | ||
101 | __u32 cow_format; | ||
102 | char backing_file[PATH_LEN_V3]; | ||
78 | }; | 103 | }; |
79 | 104 | ||
80 | /* COW format definitions - for now, we have only the usual COW bitmap */ | 105 | /* COW format definitions - for now, we have only the usual COW bitmap */ |
@@ -84,6 +109,7 @@ union cow_header { | |||
84 | struct cow_header_v1 v1; | 109 | struct cow_header_v1 v1; |
85 | struct cow_header_v2 v2; | 110 | struct cow_header_v2 v2; |
86 | struct cow_header_v3 v3; | 111 | struct cow_header_v3 v3; |
112 | struct cow_header_v3_broken v3_b; | ||
87 | }; | 113 | }; |
88 | 114 | ||
89 | #define COW_MAGIC 0x4f4f4f4d /* MOOO */ | 115 | #define COW_MAGIC 0x4f4f4f4d /* MOOO */ |
@@ -184,8 +210,9 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, | |||
184 | 210 | ||
185 | err = -EINVAL; | 211 | err = -EINVAL; |
186 | if(strlen(backing_file) > sizeof(header->backing_file) - 1){ | 212 | if(strlen(backing_file) > sizeof(header->backing_file) - 1){ |
213 | /* Below, %zd is for a size_t value */ | ||
187 | cow_printf("Backing file name \"%s\" is too long - names are " | 214 | cow_printf("Backing file name \"%s\" is too long - names are " |
188 | "limited to %d characters\n", backing_file, | 215 | "limited to %zd characters\n", backing_file, |
189 | sizeof(header->backing_file) - 1); | 216 | sizeof(header->backing_file) - 1); |
190 | goto out_free; | 217 | goto out_free; |
191 | } | 218 | } |
@@ -300,7 +327,8 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, | |||
300 | *align_out = *sectorsize_out; | 327 | *align_out = *sectorsize_out; |
301 | file = header->v2.backing_file; | 328 | file = header->v2.backing_file; |
302 | } | 329 | } |
303 | else if(version == 3){ | 330 | /* This is very subtle - see above at union cow_header definition */ |
331 | else if(version == 3 && (*((int*)header->v3.backing_file) != 0)){ | ||
304 | if(n < sizeof(header->v3)){ | 332 | if(n < sizeof(header->v3)){ |
305 | cow_printf("read_cow_header - failed to read V3 " | 333 | cow_printf("read_cow_header - failed to read V3 " |
306 | "header\n"); | 334 | "header\n"); |
@@ -310,9 +338,43 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, | |||
310 | *size_out = ntohll(header->v3.size); | 338 | *size_out = ntohll(header->v3.size); |
311 | *sectorsize_out = ntohl(header->v3.sectorsize); | 339 | *sectorsize_out = ntohl(header->v3.sectorsize); |
312 | *align_out = ntohl(header->v3.alignment); | 340 | *align_out = ntohl(header->v3.alignment); |
341 | if (*align_out == 0) { | ||
342 | cow_printf("read_cow_header - invalid COW header, " | ||
343 | "align == 0\n"); | ||
344 | } | ||
313 | *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); | 345 | *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); |
314 | file = header->v3.backing_file; | 346 | file = header->v3.backing_file; |
315 | } | 347 | } |
348 | else if(version == 3){ | ||
349 | cow_printf("read_cow_header - broken V3 file with" | ||
350 | " 64-bit layout - recovering content.\n"); | ||
351 | |||
352 | if(n < sizeof(header->v3_b)){ | ||
353 | cow_printf("read_cow_header - failed to read V3 " | ||
354 | "header\n"); | ||
355 | goto out; | ||
356 | } | ||
357 | |||
358 | /* this was used until Dec2005 - 64bits are needed to represent | ||
359 | * 2038+. I.e. we can safely do this truncating cast. | ||
360 | * | ||
361 | * Additionally, we must use ntohl() instead of ntohll(), since | ||
362 | * the program used to use the former (tested - I got mtime | ||
363 | * mismatch "0 vs whatever"). | ||
364 | * | ||
365 | * Ever heard about bug-to-bug-compatibility ? ;-) */ | ||
366 | *mtime_out = (time32_t) ntohl(header->v3_b.mtime); | ||
367 | |||
368 | *size_out = ntohll(header->v3_b.size); | ||
369 | *sectorsize_out = ntohl(header->v3_b.sectorsize); | ||
370 | *align_out = ntohl(header->v3_b.alignment); | ||
371 | if (*align_out == 0) { | ||
372 | cow_printf("read_cow_header - invalid COW header, " | ||
373 | "align == 0\n"); | ||
374 | } | ||
375 | *bitmap_offset_out = ROUND_UP(sizeof(header->v3_b), *align_out); | ||
376 | file = header->v3_b.backing_file; | ||
377 | } | ||
316 | else { | 378 | else { |
317 | cow_printf("read_cow_header - invalid COW version\n"); | 379 | cow_printf("read_cow_header - invalid COW version\n"); |
318 | goto out; | 380 | goto out; |
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c index a61b7b46bc..53d09ed78b 100644 --- a/arch/um/drivers/daemon_kern.c +++ b/arch/um/drivers/daemon_kern.c | |||
@@ -95,18 +95,7 @@ static struct transport daemon_transport = { | |||
95 | static int register_daemon(void) | 95 | static int register_daemon(void) |
96 | { | 96 | { |
97 | register_transport(&daemon_transport); | 97 | register_transport(&daemon_transport); |
98 | return(1); | 98 | return 0; |
99 | } | 99 | } |
100 | 100 | ||
101 | __initcall(register_daemon); | 101 | __initcall(register_daemon); |
102 | |||
103 | /* | ||
104 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
105 | * Emacs will notice this stuff at the end of the file and automatically | ||
106 | * adjust the settings for this buffer only. This must remain at the end | ||
107 | * of the file. | ||
108 | * --------------------------------------------------------------------------- | ||
109 | * Local variables: | ||
110 | * c-file-style: "linux" | ||
111 | * End: | ||
112 | */ | ||
diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index 49acb2badf..d18a974735 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c | |||
@@ -104,7 +104,7 @@ static int harddog_release(struct inode *inode, struct file *file) | |||
104 | 104 | ||
105 | extern int ping_watchdog(int fd); | 105 | extern int ping_watchdog(int fd); |
106 | 106 | ||
107 | static ssize_t harddog_write(struct file *file, const char *data, size_t len, | 107 | static ssize_t harddog_write(struct file *file, const char __user *data, size_t len, |
108 | loff_t *ppos) | 108 | loff_t *ppos) |
109 | { | 109 | { |
110 | /* | 110 | /* |
@@ -118,6 +118,7 @@ static ssize_t harddog_write(struct file *file, const char *data, size_t len, | |||
118 | static int harddog_ioctl(struct inode *inode, struct file *file, | 118 | static int harddog_ioctl(struct inode *inode, struct file *file, |
119 | unsigned int cmd, unsigned long arg) | 119 | unsigned int cmd, unsigned long arg) |
120 | { | 120 | { |
121 | void __user *argp= (void __user *)arg; | ||
121 | static struct watchdog_info ident = { | 122 | static struct watchdog_info ident = { |
122 | WDIOC_SETTIMEOUT, | 123 | WDIOC_SETTIMEOUT, |
123 | 0, | 124 | 0, |
@@ -127,13 +128,12 @@ static int harddog_ioctl(struct inode *inode, struct file *file, | |||
127 | default: | 128 | default: |
128 | return -ENOTTY; | 129 | return -ENOTTY; |
129 | case WDIOC_GETSUPPORT: | 130 | case WDIOC_GETSUPPORT: |
130 | if(copy_to_user((struct harddog_info *)arg, &ident, | 131 | if(copy_to_user(argp, &ident, sizeof(ident))) |
131 | sizeof(ident))) | ||
132 | return -EFAULT; | 132 | return -EFAULT; |
133 | return 0; | 133 | return 0; |
134 | case WDIOC_GETSTATUS: | 134 | case WDIOC_GETSTATUS: |
135 | case WDIOC_GETBOOTSTATUS: | 135 | case WDIOC_GETBOOTSTATUS: |
136 | return put_user(0,(int *)arg); | 136 | return put_user(0,(int __user *)argp); |
137 | case WDIOC_KEEPALIVE: | 137 | case WDIOC_KEEPALIVE: |
138 | return(ping_watchdog(harddog_out_fd)); | 138 | return(ping_watchdog(harddog_out_fd)); |
139 | } | 139 | } |
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index 59602b81b2..37232f908c 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c | |||
@@ -67,8 +67,8 @@ MODULE_PARM_DESC(mixer, MIXER_HELP); | |||
67 | 67 | ||
68 | /* /dev/dsp file operations */ | 68 | /* /dev/dsp file operations */ |
69 | 69 | ||
70 | static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, | 70 | static ssize_t hostaudio_read(struct file *file, char __user *buffer, |
71 | loff_t *ppos) | 71 | size_t count, loff_t *ppos) |
72 | { | 72 | { |
73 | struct hostaudio_state *state = file->private_data; | 73 | struct hostaudio_state *state = file->private_data; |
74 | void *kbuf; | 74 | void *kbuf; |
@@ -94,7 +94,7 @@ static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, | |||
94 | return(err); | 94 | return(err); |
95 | } | 95 | } |
96 | 96 | ||
97 | static ssize_t hostaudio_write(struct file *file, const char *buffer, | 97 | static ssize_t hostaudio_write(struct file *file, const char __user *buffer, |
98 | size_t count, loff_t *ppos) | 98 | size_t count, loff_t *ppos) |
99 | { | 99 | { |
100 | struct hostaudio_state *state = file->private_data; | 100 | struct hostaudio_state *state = file->private_data; |
@@ -152,7 +152,7 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, | |||
152 | case SNDCTL_DSP_CHANNELS: | 152 | case SNDCTL_DSP_CHANNELS: |
153 | case SNDCTL_DSP_SUBDIVIDE: | 153 | case SNDCTL_DSP_SUBDIVIDE: |
154 | case SNDCTL_DSP_SETFRAGMENT: | 154 | case SNDCTL_DSP_SETFRAGMENT: |
155 | if(get_user(data, (int *) arg)) | 155 | if(get_user(data, (int __user *) arg)) |
156 | return(-EFAULT); | 156 | return(-EFAULT); |
157 | break; | 157 | break; |
158 | default: | 158 | default: |
@@ -168,7 +168,7 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, | |||
168 | case SNDCTL_DSP_CHANNELS: | 168 | case SNDCTL_DSP_CHANNELS: |
169 | case SNDCTL_DSP_SUBDIVIDE: | 169 | case SNDCTL_DSP_SUBDIVIDE: |
170 | case SNDCTL_DSP_SETFRAGMENT: | 170 | case SNDCTL_DSP_SETFRAGMENT: |
171 | if(put_user(data, (int *) arg)) | 171 | if(put_user(data, (int __user *) arg)) |
172 | return(-EFAULT); | 172 | return(-EFAULT); |
173 | break; | 173 | break; |
174 | default: | 174 | default: |
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index c9b078fba0..3a7af18cf9 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c | |||
@@ -124,18 +124,7 @@ static struct transport mcast_transport = { | |||
124 | static int register_mcast(void) | 124 | static int register_mcast(void) |
125 | { | 125 | { |
126 | register_transport(&mcast_transport); | 126 | register_transport(&mcast_transport); |
127 | return(1); | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | __initcall(register_mcast); | 130 | __initcall(register_mcast); |
131 | |||
132 | /* | ||
133 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
134 | * Emacs will notice this stuff at the end of the file and automatically | ||
135 | * adjust the settings for this buffer only. This must remain at the end | ||
136 | * of the file. | ||
137 | * --------------------------------------------------------------------------- | ||
138 | * Local variables: | ||
139 | * c-file-style: "linux" | ||
140 | * End: | ||
141 | */ | ||
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 1488816588..6d7173fc55 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include "linux/namei.h" | 20 | #include "linux/namei.h" |
21 | #include "linux/proc_fs.h" | 21 | #include "linux/proc_fs.h" |
22 | #include "linux/syscalls.h" | 22 | #include "linux/syscalls.h" |
23 | #include "linux/list.h" | ||
24 | #include "linux/mm.h" | ||
23 | #include "linux/console.h" | 25 | #include "linux/console.h" |
24 | #include "asm/irq.h" | 26 | #include "asm/irq.h" |
25 | #include "asm/uaccess.h" | 27 | #include "asm/uaccess.h" |
@@ -60,7 +62,7 @@ static void mc_work_proc(void *unused) | |||
60 | unsigned long flags; | 62 | unsigned long flags; |
61 | 63 | ||
62 | while(!list_empty(&mc_requests)){ | 64 | while(!list_empty(&mc_requests)){ |
63 | local_save_flags(flags); | 65 | local_irq_save(flags); |
64 | req = list_entry(mc_requests.next, struct mconsole_entry, | 66 | req = list_entry(mc_requests.next, struct mconsole_entry, |
65 | list); | 67 | list); |
66 | list_del(&req->list); | 68 | list_del(&req->list); |
@@ -85,7 +87,7 @@ static irqreturn_t mconsole_interrupt(int irq, void *dev_id, | |||
85 | if(req.cmd->context == MCONSOLE_INTR) | 87 | if(req.cmd->context == MCONSOLE_INTR) |
86 | (*req.cmd->handler)(&req); | 88 | (*req.cmd->handler)(&req); |
87 | else { | 89 | else { |
88 | new = kmalloc(sizeof(*new), GFP_ATOMIC); | 90 | new = kmalloc(sizeof(*new), GFP_NOWAIT); |
89 | if(new == NULL) | 91 | if(new == NULL) |
90 | mconsole_reply(&req, "Out of memory", 1, 0); | 92 | mconsole_reply(&req, "Out of memory", 1, 0); |
91 | else { | 93 | else { |
@@ -347,6 +349,141 @@ static struct mc_device *mconsole_find_dev(char *name) | |||
347 | return(NULL); | 349 | return(NULL); |
348 | } | 350 | } |
349 | 351 | ||
352 | #define UNPLUGGED_PER_PAGE \ | ||
353 | ((PAGE_SIZE - sizeof(struct list_head)) / sizeof(unsigned long)) | ||
354 | |||
355 | struct unplugged_pages { | ||
356 | struct list_head list; | ||
357 | void *pages[UNPLUGGED_PER_PAGE]; | ||
358 | }; | ||
359 | |||
360 | static unsigned long long unplugged_pages_count = 0; | ||
361 | static struct list_head unplugged_pages = LIST_HEAD_INIT(unplugged_pages); | ||
362 | static int unplug_index = UNPLUGGED_PER_PAGE; | ||
363 | |||
364 | static int mem_config(char *str) | ||
365 | { | ||
366 | unsigned long long diff; | ||
367 | int err = -EINVAL, i, add; | ||
368 | char *ret; | ||
369 | |||
370 | if(str[0] != '=') | ||
371 | goto out; | ||
372 | |||
373 | str++; | ||
374 | if(str[0] == '-') | ||
375 | add = 0; | ||
376 | else if(str[0] == '+'){ | ||
377 | add = 1; | ||
378 | } | ||
379 | else goto out; | ||
380 | |||
381 | str++; | ||
382 | diff = memparse(str, &ret); | ||
383 | if(*ret != '\0') | ||
384 | goto out; | ||
385 | |||
386 | diff /= PAGE_SIZE; | ||
387 | |||
388 | for(i = 0; i < diff; i++){ | ||
389 | struct unplugged_pages *unplugged; | ||
390 | void *addr; | ||
391 | |||
392 | if(add){ | ||
393 | if(list_empty(&unplugged_pages)) | ||
394 | break; | ||
395 | |||
396 | unplugged = list_entry(unplugged_pages.next, | ||
397 | struct unplugged_pages, list); | ||
398 | if(unplug_index > 0) | ||
399 | addr = unplugged->pages[--unplug_index]; | ||
400 | else { | ||
401 | list_del(&unplugged->list); | ||
402 | addr = unplugged; | ||
403 | unplug_index = UNPLUGGED_PER_PAGE; | ||
404 | } | ||
405 | |||
406 | free_page((unsigned long) addr); | ||
407 | unplugged_pages_count--; | ||
408 | } | ||
409 | else { | ||
410 | struct page *page; | ||
411 | |||
412 | page = alloc_page(GFP_ATOMIC); | ||
413 | if(page == NULL) | ||
414 | break; | ||
415 | |||
416 | unplugged = page_address(page); | ||
417 | if(unplug_index == UNPLUGGED_PER_PAGE){ | ||
418 | list_add(&unplugged->list, &unplugged_pages); | ||
419 | unplug_index = 0; | ||
420 | } | ||
421 | else { | ||
422 | struct list_head *entry = unplugged_pages.next; | ||
423 | addr = unplugged; | ||
424 | |||
425 | unplugged = list_entry(entry, | ||
426 | struct unplugged_pages, | ||
427 | list); | ||
428 | unplugged->pages[unplug_index++] = addr; | ||
429 | err = os_drop_memory(addr, PAGE_SIZE); | ||
430 | if(err) | ||
431 | printk("Failed to release memory - " | ||
432 | "errno = %d\n", err); | ||
433 | } | ||
434 | |||
435 | unplugged_pages_count++; | ||
436 | } | ||
437 | } | ||
438 | |||
439 | err = 0; | ||
440 | out: | ||
441 | return err; | ||
442 | } | ||
443 | |||
444 | static int mem_get_config(char *name, char *str, int size, char **error_out) | ||
445 | { | ||
446 | char buf[sizeof("18446744073709551615")]; | ||
447 | int len = 0; | ||
448 | |||
449 | sprintf(buf, "%ld", uml_physmem); | ||
450 | CONFIG_CHUNK(str, size, len, buf, 1); | ||
451 | |||
452 | return len; | ||
453 | } | ||
454 | |||
455 | static int mem_id(char **str, int *start_out, int *end_out) | ||
456 | { | ||
457 | *start_out = 0; | ||
458 | *end_out = 0; | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int mem_remove(int n) | ||
464 | { | ||
465 | return -EBUSY; | ||
466 | } | ||
467 | |||
468 | static struct mc_device mem_mc = { | ||
469 | .name = "mem", | ||
470 | .config = mem_config, | ||
471 | .get_config = mem_get_config, | ||
472 | .id = mem_id, | ||
473 | .remove = mem_remove, | ||
474 | }; | ||
475 | |||
476 | static int mem_mc_init(void) | ||
477 | { | ||
478 | if(can_drop_memory()) | ||
479 | mconsole_register_dev(&mem_mc); | ||
480 | else printk("Can't release memory to the host - memory hotplug won't " | ||
481 | "be supported\n"); | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | __initcall(mem_mc_init); | ||
486 | |||
350 | #define CONFIG_BUF_SIZE 64 | 487 | #define CONFIG_BUF_SIZE 64 |
351 | 488 | ||
352 | static void mconsole_get_config(int (*get_config)(char *, char *, int, | 489 | static void mconsole_get_config(int (*get_config)(char *, char *, int, |
@@ -478,7 +615,7 @@ static void console_write(struct console *console, const char *string, | |||
478 | return; | 615 | return; |
479 | 616 | ||
480 | while(1){ | 617 | while(1){ |
481 | n = min(len, ARRAY_SIZE(console_buf) - console_index); | 618 | n = min((size_t) len, ARRAY_SIZE(console_buf) - console_index); |
482 | strncpy(&console_buf[console_index], string, n); | 619 | strncpy(&console_buf[console_index], string, n); |
483 | console_index += n; | 620 | console_index += n; |
484 | string += n; | 621 | string += n; |
@@ -517,7 +654,6 @@ static void with_console(struct mc_request *req, void (*proc)(void *), | |||
517 | struct mconsole_entry entry; | 654 | struct mconsole_entry entry; |
518 | unsigned long flags; | 655 | unsigned long flags; |
519 | 656 | ||
520 | INIT_LIST_HEAD(&entry.list); | ||
521 | entry.request = *req; | 657 | entry.request = *req; |
522 | list_add(&entry.list, &clients); | 658 | list_add(&entry.list, &clients); |
523 | spin_lock_irqsave(&console_lock, flags); | 659 | spin_lock_irqsave(&console_lock, flags); |
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 0e2f06187e..0a7786e00c 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c | |||
@@ -182,7 +182,9 @@ static int change_tramp(char **argv, char *output, int output_len) | |||
182 | pe_data.stdout = fds[1]; | 182 | pe_data.stdout = fds[1]; |
183 | pid = run_helper(change_pre_exec, &pe_data, argv, NULL); | 183 | pid = run_helper(change_pre_exec, &pe_data, argv, NULL); |
184 | 184 | ||
185 | read_output(fds[0], output, output_len); | 185 | if (pid > 0) /* Avoid hang as we won't get data in failure case. */ |
186 | read_output(fds[0], output, output_len); | ||
187 | |||
186 | os_close_file(fds[0]); | 188 | os_close_file(fds[0]); |
187 | os_close_file(fds[1]); | 189 | os_close_file(fds[1]); |
188 | 190 | ||
diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c index 07c80f2156..466ff2c2f9 100644 --- a/arch/um/drivers/pcap_kern.c +++ b/arch/um/drivers/pcap_kern.c | |||
@@ -106,18 +106,7 @@ static struct transport pcap_transport = { | |||
106 | static int register_pcap(void) | 106 | static int register_pcap(void) |
107 | { | 107 | { |
108 | register_transport(&pcap_transport); | 108 | register_transport(&pcap_transport); |
109 | return(1); | 109 | return 0; |
110 | } | 110 | } |
111 | 111 | ||
112 | __initcall(register_pcap); | 112 | __initcall(register_pcap); |
113 | |||
114 | /* | ||
115 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
116 | * Emacs will notice this stuff at the end of the file and automatically | ||
117 | * adjust the settings for this buffer only. This must remain at the end | ||
118 | * of the file. | ||
119 | * --------------------------------------------------------------------------- | ||
120 | * Local variables: | ||
121 | * c-file-style: "linux" | ||
122 | * End: | ||
123 | */ | ||
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index a62f5ef445..163ee0d5f7 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c | |||
@@ -93,18 +93,7 @@ static struct transport slip_transport = { | |||
93 | static int register_slip(void) | 93 | static int register_slip(void) |
94 | { | 94 | { |
95 | register_transport(&slip_transport); | 95 | register_transport(&slip_transport); |
96 | return(1); | 96 | return 0; |
97 | } | 97 | } |
98 | 98 | ||
99 | __initcall(register_slip); | 99 | __initcall(register_slip); |
100 | |||
101 | /* | ||
102 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
103 | * Emacs will notice this stuff at the end of the file and automatically | ||
104 | * adjust the settings for this buffer only. This must remain at the end | ||
105 | * of the file. | ||
106 | * --------------------------------------------------------------------------- | ||
107 | * Local variables: | ||
108 | * c-file-style: "linux" | ||
109 | * End: | ||
110 | */ | ||
diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c index 33d7982be5..95e50c943e 100644 --- a/arch/um/drivers/slirp_kern.c +++ b/arch/um/drivers/slirp_kern.c | |||
@@ -77,7 +77,7 @@ static int slirp_setup(char *str, char **mac_out, void *data) | |||
77 | int i=0; | 77 | int i=0; |
78 | 78 | ||
79 | *init = ((struct slirp_init) | 79 | *init = ((struct slirp_init) |
80 | { argw : { { "slirp", NULL } } }); | 80 | { .argw = { { "slirp", NULL } } }); |
81 | 81 | ||
82 | str = split_if_spec(str, mac_out, NULL); | 82 | str = split_if_spec(str, mac_out, NULL); |
83 | 83 | ||
@@ -116,18 +116,7 @@ static struct transport slirp_transport = { | |||
116 | static int register_slirp(void) | 116 | static int register_slirp(void) |
117 | { | 117 | { |
118 | register_transport(&slirp_transport); | 118 | register_transport(&slirp_transport); |
119 | return(1); | 119 | return 0; |
120 | } | 120 | } |
121 | 121 | ||
122 | __initcall(register_slirp); | 122 | __initcall(register_slirp); |
123 | |||
124 | /* | ||
125 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
126 | * Emacs will notice this stuff at the end of the file and automatically | ||
127 | * adjust the settings for this buffer only. This must remain at the end | ||
128 | * of the file. | ||
129 | * --------------------------------------------------------------------------- | ||
130 | * Local variables: | ||
131 | * c-file-style: "linux" | ||
132 | * End: | ||
133 | */ | ||
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index b94c66114b..33c5f6e625 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c | |||
@@ -104,7 +104,7 @@ static void slirp_close(int fd, void *data) | |||
104 | } | 104 | } |
105 | 105 | ||
106 | if(err == 0) { | 106 | if(err == 0) { |
107 | printk("slirp_close: process %d has not exited\n"); | 107 | printk("slirp_close: process %d has not exited\n", pri->pid); |
108 | return; | 108 | return; |
109 | } | 109 | } |
110 | 110 | ||
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 0336575d24..0897852b09 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -891,7 +891,7 @@ int ubd_driver_init(void){ | |||
891 | SA_INTERRUPT, "ubd", ubd_dev); | 891 | SA_INTERRUPT, "ubd", ubd_dev); |
892 | if(err != 0) | 892 | if(err != 0) |
893 | printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); | 893 | printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); |
894 | return(err); | 894 | return 0; |
895 | } | 895 | } |
896 | 896 | ||
897 | device_initcall(ubd_driver_init); | 897 | device_initcall(ubd_driver_init); |
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 07176d92e1..efa3d33c0b 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h | |||
@@ -116,7 +116,7 @@ extern void *get_current(void); | |||
116 | extern struct task_struct *get_task(int pid, int require); | 116 | extern struct task_struct *get_task(int pid, int require); |
117 | extern void machine_halt(void); | 117 | extern void machine_halt(void); |
118 | extern int is_syscall(unsigned long addr); | 118 | extern int is_syscall(unsigned long addr); |
119 | extern void arch_switch(void); | 119 | |
120 | extern void free_irq(unsigned int, void *); | 120 | extern void free_irq(unsigned int, void *); |
121 | extern int cpu(void); | 121 | extern int cpu(void); |
122 | 122 | ||
diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 6f4d680dc1..6ac0f8252e 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h | |||
@@ -58,23 +58,17 @@ struct line { | |||
58 | }; | 58 | }; |
59 | 59 | ||
60 | #define LINE_INIT(str, d) \ | 60 | #define LINE_INIT(str, d) \ |
61 | { init_str : str, \ | 61 | { .init_str = str, \ |
62 | init_pri : INIT_STATIC, \ | 62 | .init_pri = INIT_STATIC, \ |
63 | valid : 1, \ | 63 | .valid = 1, \ |
64 | throttled : 0, \ | 64 | .lock = SPIN_LOCK_UNLOCKED, \ |
65 | lock : SPIN_LOCK_UNLOCKED, \ | 65 | .driver = d } |
66 | buffer : NULL, \ | ||
67 | head : NULL, \ | ||
68 | tail : NULL, \ | ||
69 | sigio : 0, \ | ||
70 | driver : d, \ | ||
71 | have_irq : 0 } | ||
72 | 66 | ||
73 | struct lines { | 67 | struct lines { |
74 | int num; | 68 | int num; |
75 | }; | 69 | }; |
76 | 70 | ||
77 | #define LINES_INIT(n) { num : n } | 71 | #define LINES_INIT(n) { .num = n } |
78 | 72 | ||
79 | extern void line_close(struct tty_struct *tty, struct file * filp); | 73 | extern void line_close(struct tty_struct *tty, struct file * filp); |
80 | extern int line_open(struct line *lines, struct tty_struct *tty); | 74 | extern int line_open(struct line *lines, struct tty_struct *tty); |
diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index a1064c5823..a54514d2cc 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/mem_user.h | |||
@@ -49,7 +49,6 @@ extern int iomem_size; | |||
49 | extern unsigned long host_task_size; | 49 | extern unsigned long host_task_size; |
50 | extern unsigned long task_size; | 50 | extern unsigned long task_size; |
51 | 51 | ||
52 | extern void check_devanon(void); | ||
53 | extern int init_mem_user(void); | 52 | extern int init_mem_user(void); |
54 | extern void setup_memory(void *entry); | 53 | extern void setup_memory(void *entry); |
55 | extern unsigned long find_iomem(char *driver, unsigned long *len_out); | 54 | extern unsigned long find_iomem(char *driver, unsigned long *len_out); |
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index d3d1bc6074..f88856c28a 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include "kern_util.h" | 13 | #include "kern_util.h" |
14 | #include "skas/mm_id.h" | 14 | #include "skas/mm_id.h" |
15 | #include "irq_user.h" | 15 | #include "irq_user.h" |
16 | #include "sysdep/tls.h" | ||
16 | 17 | ||
17 | #define OS_TYPE_FILE 1 | 18 | #define OS_TYPE_FILE 1 |
18 | #define OS_TYPE_DIR 2 | 19 | #define OS_TYPE_DIR 2 |
@@ -172,6 +173,7 @@ extern int os_fchange_dir(int fd); | |||
172 | extern void os_early_checks(void); | 173 | extern void os_early_checks(void); |
173 | extern int can_do_skas(void); | 174 | extern int can_do_skas(void); |
174 | extern void os_check_bugs(void); | 175 | extern void os_check_bugs(void); |
176 | extern void check_host_supports_tls(int *supports_tls, int *tls_min); | ||
175 | 177 | ||
176 | /* Make sure they are clear when running in TT mode. Required by | 178 | /* Make sure they are clear when running in TT mode. Required by |
177 | * SEGV_MAYBE_FIXABLE */ | 179 | * SEGV_MAYBE_FIXABLE */ |
@@ -205,6 +207,8 @@ extern int os_map_memory(void *virt, int fd, unsigned long long off, | |||
205 | extern int os_protect_memory(void *addr, unsigned long len, | 207 | extern int os_protect_memory(void *addr, unsigned long len, |
206 | int r, int w, int x); | 208 | int r, int w, int x); |
207 | extern int os_unmap_memory(void *addr, int len); | 209 | extern int os_unmap_memory(void *addr, int len); |
210 | extern int os_drop_memory(void *addr, int length); | ||
211 | extern int can_drop_memory(void); | ||
208 | extern void os_flush_stdout(void); | 212 | extern void os_flush_stdout(void); |
209 | 213 | ||
210 | /* tt.c | 214 | /* tt.c |
@@ -234,8 +238,12 @@ extern int run_helper_thread(int (*proc)(void *), void *arg, | |||
234 | int stack_order); | 238 | int stack_order); |
235 | extern int helper_wait(int pid); | 239 | extern int helper_wait(int pid); |
236 | 240 | ||
237 | /* umid.c */ | ||
238 | 241 | ||
242 | /* tls.c */ | ||
243 | extern int os_set_thread_area(user_desc_t *info, int pid); | ||
244 | extern int os_get_thread_area(user_desc_t *info, int pid); | ||
245 | |||
246 | /* umid.c */ | ||
239 | extern int umid_file_name(char *name, char *buf, int len); | 247 | extern int umid_file_name(char *name, char *buf, int len); |
240 | extern int set_umid(char *name); | 248 | extern int set_umid(char *name); |
241 | extern char *get_umid(void); | 249 | extern char *get_umid(void); |
diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h index 7d3d202d7f..052bb061a9 100644 --- a/arch/um/include/sysdep-i386/checksum.h +++ b/arch/um/include/sysdep-i386/checksum.h | |||
@@ -48,7 +48,8 @@ unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char * | |||
48 | */ | 48 | */ |
49 | 49 | ||
50 | static __inline__ | 50 | static __inline__ |
51 | unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, | 51 | unsigned int csum_partial_copy_from_user(const unsigned char __user *src, |
52 | unsigned char *dst, | ||
52 | int len, int sum, int *err_ptr) | 53 | int len, int sum, int *err_ptr) |
53 | { | 54 | { |
54 | if(copy_from_user(dst, src, len)){ | 55 | if(copy_from_user(dst, src, len)){ |
@@ -192,7 +193,7 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, | |||
192 | */ | 193 | */ |
193 | #define HAVE_CSUM_COPY_USER | 194 | #define HAVE_CSUM_COPY_USER |
194 | static __inline__ unsigned int csum_and_copy_to_user(const unsigned char *src, | 195 | static __inline__ unsigned int csum_and_copy_to_user(const unsigned char *src, |
195 | unsigned char *dst, | 196 | unsigned char __user *dst, |
196 | int len, int sum, int *err_ptr) | 197 | int len, int sum, int *err_ptr) |
197 | { | 198 | { |
198 | if (access_ok(VERIFY_WRITE, dst, len)){ | 199 | if (access_ok(VERIFY_WRITE, dst, len)){ |
diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h index c8ee9559f3..6670cc992e 100644 --- a/arch/um/include/sysdep-i386/ptrace.h +++ b/arch/um/include/sysdep-i386/ptrace.h | |||
@@ -14,7 +14,12 @@ | |||
14 | #define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long)) | 14 | #define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long)) |
15 | #define MAX_REG_OFFSET (UM_FRAME_SIZE) | 15 | #define MAX_REG_OFFSET (UM_FRAME_SIZE) |
16 | 16 | ||
17 | #ifdef UML_CONFIG_PT_PROXY | ||
17 | extern void update_debugregs(int seq); | 18 | extern void update_debugregs(int seq); |
19 | #else | ||
20 | static inline void update_debugregs(int seq) {} | ||
21 | #endif | ||
22 | |||
18 | 23 | ||
19 | /* syscall emulation path in ptrace */ | 24 | /* syscall emulation path in ptrace */ |
20 | 25 | ||
diff --git a/arch/um/include/sysdep-i386/tls.h b/arch/um/include/sysdep-i386/tls.h new file mode 100644 index 0000000000..918fd3c5ff --- /dev/null +++ b/arch/um/include/sysdep-i386/tls.h | |||
@@ -0,0 +1,32 @@ | |||
1 | #ifndef _SYSDEP_TLS_H | ||
2 | #define _SYSDEP_TLS_H | ||
3 | |||
4 | # ifndef __KERNEL__ | ||
5 | |||
6 | /* Change name to avoid conflicts with the original one from <asm/ldt.h>, which | ||
7 | * may be named user_desc (but in 2.4 and in header matching its API was named | ||
8 | * modify_ldt_ldt_s). */ | ||
9 | |||
10 | typedef struct um_dup_user_desc { | ||
11 | unsigned int entry_number; | ||
12 | unsigned int base_addr; | ||
13 | unsigned int limit; | ||
14 | unsigned int seg_32bit:1; | ||
15 | unsigned int contents:2; | ||
16 | unsigned int read_exec_only:1; | ||
17 | unsigned int limit_in_pages:1; | ||
18 | unsigned int seg_not_present:1; | ||
19 | unsigned int useable:1; | ||
20 | } user_desc_t; | ||
21 | |||
22 | # else /* __KERNEL__ */ | ||
23 | |||
24 | # include <asm/ldt.h> | ||
25 | typedef struct user_desc user_desc_t; | ||
26 | |||
27 | # endif /* __KERNEL__ */ | ||
28 | |||
29 | #define GDT_ENTRY_TLS_MIN_I386 6 | ||
30 | #define GDT_ENTRY_TLS_MIN_X86_64 12 | ||
31 | |||
32 | #endif /* _SYSDEP_TLS_H */ | ||
diff --git a/arch/um/include/sysdep-x86_64/tls.h b/arch/um/include/sysdep-x86_64/tls.h new file mode 100644 index 0000000000..35f19f25bd --- /dev/null +++ b/arch/um/include/sysdep-x86_64/tls.h | |||
@@ -0,0 +1,29 @@ | |||
1 | #ifndef _SYSDEP_TLS_H | ||
2 | #define _SYSDEP_TLS_H | ||
3 | |||
4 | # ifndef __KERNEL__ | ||
5 | |||
6 | /* Change name to avoid conflicts with the original one from <asm/ldt.h>, which | ||
7 | * may be named user_desc (but in 2.4 and in header matching its API was named | ||
8 | * modify_ldt_ldt_s). */ | ||
9 | |||
10 | typedef struct um_dup_user_desc { | ||
11 | unsigned int entry_number; | ||
12 | unsigned int base_addr; | ||
13 | unsigned int limit; | ||
14 | unsigned int seg_32bit:1; | ||
15 | unsigned int contents:2; | ||
16 | unsigned int read_exec_only:1; | ||
17 | unsigned int limit_in_pages:1; | ||
18 | unsigned int seg_not_present:1; | ||
19 | unsigned int useable:1; | ||
20 | unsigned int lm:1; | ||
21 | } user_desc_t; | ||
22 | |||
23 | # else /* __KERNEL__ */ | ||
24 | |||
25 | # include <asm/ldt.h> | ||
26 | typedef struct user_desc user_desc_t; | ||
27 | |||
28 | # endif /* __KERNEL__ */ | ||
29 | #endif /* _SYSDEP_TLS_H */ | ||
diff --git a/arch/um/include/tt/tt.h b/arch/um/include/tt/tt.h index 8085219801..acb8356e1f 100644 --- a/arch/um/include/tt/tt.h +++ b/arch/um/include/tt/tt.h | |||
@@ -19,7 +19,8 @@ extern int fork_tramp(void *sig_stack); | |||
19 | extern int do_proc_op(void *t, int proc_id); | 19 | extern int do_proc_op(void *t, int proc_id); |
20 | extern int tracer(int (*init_proc)(void *), void *sp); | 20 | extern int tracer(int (*init_proc)(void *), void *sp); |
21 | extern void attach_process(int pid); | 21 | extern void attach_process(int pid); |
22 | extern void tracer_panic(char *format, ...); | 22 | extern void tracer_panic(char *format, ...) |
23 | __attribute__ ((format (printf, 1, 2))); | ||
23 | extern void set_init_pid(int pid); | 24 | extern void set_init_pid(int pid); |
24 | extern int set_user_mode(void *task); | 25 | extern int set_user_mode(void *task); |
25 | extern void set_tracing(void *t, int tracing); | 26 | extern void set_tracing(void *t, int tracing); |
diff --git a/arch/um/include/user.h b/arch/um/include/user.h index 91b0ac4ad8..39f8c88010 100644 --- a/arch/um/include/user.h +++ b/arch/um/include/user.h | |||
@@ -6,8 +6,10 @@ | |||
6 | #ifndef __USER_H__ | 6 | #ifndef __USER_H__ |
7 | #define __USER_H__ | 7 | #define __USER_H__ |
8 | 8 | ||
9 | extern void panic(const char *fmt, ...); | 9 | extern void panic(const char *fmt, ...) |
10 | extern int printk(const char *fmt, ...); | 10 | __attribute__ ((format (printf, 1, 2))); |
11 | extern int printk(const char *fmt, ...) | ||
12 | __attribute__ ((format (printf, 1, 2))); | ||
11 | extern void schedule(void); | 13 | extern void schedule(void); |
12 | extern void *um_kmalloc(int size); | 14 | extern void *um_kmalloc(int size); |
13 | extern void *um_kmalloc_atomic(int size); | 15 | extern void *um_kmalloc_atomic(int size); |
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index 992a7e1e0f..802d784251 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h | |||
@@ -8,6 +8,9 @@ | |||
8 | 8 | ||
9 | #include "sysdep/ptrace.h" | 9 | #include "sysdep/ptrace.h" |
10 | 10 | ||
11 | /* Copied from kernel.h */ | ||
12 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
13 | |||
11 | #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) | 14 | #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) |
12 | 15 | ||
13 | extern int mode_tt; | 16 | extern int mode_tt; |
@@ -31,7 +34,7 @@ extern unsigned long uml_physmem; | |||
31 | extern unsigned long uml_reserved; | 34 | extern unsigned long uml_reserved; |
32 | extern unsigned long end_vm; | 35 | extern unsigned long end_vm; |
33 | extern unsigned long start_vm; | 36 | extern unsigned long start_vm; |
34 | extern unsigned long highmem; | 37 | extern unsigned long long highmem; |
35 | 38 | ||
36 | extern char host_info[]; | 39 | extern char host_info[]; |
37 | 40 | ||
@@ -52,7 +55,8 @@ extern int get_pty(void); | |||
52 | extern void *um_kmalloc(int size); | 55 | extern void *um_kmalloc(int size); |
53 | extern int switcheroo(int fd, int prot, void *from, void *to, int size); | 56 | extern int switcheroo(int fd, int prot, void *from, void *to, int size); |
54 | extern void do_exec(int old_pid, int new_pid); | 57 | extern void do_exec(int old_pid, int new_pid); |
55 | extern void tracer_panic(char *msg, ...); | 58 | extern void tracer_panic(char *msg, ...) |
59 | __attribute__ ((format (printf, 1, 2))); | ||
56 | extern int detach(int pid, int sig); | 60 | extern int detach(int pid, int sig); |
57 | extern int attach(int pid); | 61 | extern int attach(int pid); |
58 | extern void kill_child_dead(int pid); | 62 | extern void kill_child_dead(int pid); |
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index 1ca8431931..c0cb627bf5 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | void flush_thread(void) | 23 | void flush_thread(void) |
24 | { | 24 | { |
25 | arch_flush_thread(¤t->thread.arch); | ||
25 | CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); | 26 | CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); |
26 | } | 27 | } |
27 | 28 | ||
@@ -58,14 +59,14 @@ long um_execve(char *file, char __user *__user *argv, char __user *__user *env) | |||
58 | return(err); | 59 | return(err); |
59 | } | 60 | } |
60 | 61 | ||
61 | long sys_execve(char *file, char __user *__user *argv, | 62 | long sys_execve(char __user *file, char __user *__user *argv, |
62 | char __user *__user *env) | 63 | char __user *__user *env) |
63 | { | 64 | { |
64 | long error; | 65 | long error; |
65 | char *filename; | 66 | char *filename; |
66 | 67 | ||
67 | lock_kernel(); | 68 | lock_kernel(); |
68 | filename = getname((char __user *) file); | 69 | filename = getname(file); |
69 | error = PTR_ERR(filename); | 70 | error = PTR_ERR(filename); |
70 | if (IS_ERR(filename)) goto out; | 71 | if (IS_ERR(filename)) goto out; |
71 | error = execve1(filename, argv, env); | 72 | error = execve1(filename, argv, env); |
@@ -74,14 +75,3 @@ long sys_execve(char *file, char __user *__user *argv, | |||
74 | unlock_kernel(); | 75 | unlock_kernel(); |
75 | return(error); | 76 | return(error); |
76 | } | 77 | } |
77 | |||
78 | /* | ||
79 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
80 | * Emacs will notice this stuff at the end of the file and automatically | ||
81 | * adjust the settings for this buffer only. This must remain at the end | ||
82 | * of the file. | ||
83 | * --------------------------------------------------------------------------- | ||
84 | * Local variables: | ||
85 | * c-file-style: "linux" | ||
86 | * End: | ||
87 | */ | ||
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 7713e7a6f4..432cf0b97a 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c | |||
@@ -39,7 +39,6 @@ EXPORT_SYMBOL(um_virt_to_phys); | |||
39 | EXPORT_SYMBOL(mode_tt); | 39 | EXPORT_SYMBOL(mode_tt); |
40 | EXPORT_SYMBOL(handle_page_fault); | 40 | EXPORT_SYMBOL(handle_page_fault); |
41 | EXPORT_SYMBOL(find_iomem); | 41 | EXPORT_SYMBOL(find_iomem); |
42 | EXPORT_SYMBOL(end_iomem); | ||
43 | 42 | ||
44 | #ifdef CONFIG_MODE_TT | 43 | #ifdef CONFIG_MODE_TT |
45 | EXPORT_SYMBOL(strncpy_from_user_tt); | 44 | EXPORT_SYMBOL(strncpy_from_user_tt); |
@@ -89,12 +88,10 @@ EXPORT_SYMBOL(dump_thread); | |||
89 | EXPORT_SYMBOL(do_gettimeofday); | 88 | EXPORT_SYMBOL(do_gettimeofday); |
90 | EXPORT_SYMBOL(do_settimeofday); | 89 | EXPORT_SYMBOL(do_settimeofday); |
91 | 90 | ||
92 | /* This is here because UML expands open to sys_open, not to a system | 91 | /* This is here because UML expands lseek to sys_lseek, not to a system |
93 | * call instruction. | 92 | * call instruction. |
94 | */ | 93 | */ |
95 | EXPORT_SYMBOL(sys_open); | ||
96 | EXPORT_SYMBOL(sys_lseek); | 94 | EXPORT_SYMBOL(sys_lseek); |
97 | EXPORT_SYMBOL(sys_read); | ||
98 | EXPORT_SYMBOL(sys_wait4); | 95 | EXPORT_SYMBOL(sys_wait4); |
99 | 96 | ||
100 | #ifdef CONFIG_SMP | 97 | #ifdef CONFIG_SMP |
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 92cce96b5e..44e41a35f0 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c | |||
@@ -30,7 +30,7 @@ extern char __binary_start; | |||
30 | unsigned long *empty_zero_page = NULL; | 30 | unsigned long *empty_zero_page = NULL; |
31 | unsigned long *empty_bad_page = NULL; | 31 | unsigned long *empty_bad_page = NULL; |
32 | pgd_t swapper_pg_dir[PTRS_PER_PGD]; | 32 | pgd_t swapper_pg_dir[PTRS_PER_PGD]; |
33 | unsigned long highmem; | 33 | unsigned long long highmem; |
34 | int kmalloc_ok = 0; | 34 | int kmalloc_ok = 0; |
35 | 35 | ||
36 | static unsigned long brk_end; | 36 | static unsigned long brk_end; |
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 3113cab867..f6a5a50212 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c | |||
@@ -156,9 +156,25 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
156 | unsigned long stack_top, struct task_struct * p, | 156 | unsigned long stack_top, struct task_struct * p, |
157 | struct pt_regs *regs) | 157 | struct pt_regs *regs) |
158 | { | 158 | { |
159 | int ret; | ||
160 | |||
159 | p->thread = (struct thread_struct) INIT_THREAD; | 161 | p->thread = (struct thread_struct) INIT_THREAD; |
160 | return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, | 162 | ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, |
161 | clone_flags, sp, stack_top, p, regs)); | 163 | clone_flags, sp, stack_top, p, regs); |
164 | |||
165 | if (ret || !current->thread.forking) | ||
166 | goto out; | ||
167 | |||
168 | clear_flushed_tls(p); | ||
169 | |||
170 | /* | ||
171 | * Set a new TLS for the child thread? | ||
172 | */ | ||
173 | if (clone_flags & CLONE_SETTLS) | ||
174 | ret = arch_copy_tls(p); | ||
175 | |||
176 | out: | ||
177 | return ret; | ||
162 | } | 178 | } |
163 | 179 | ||
164 | void initial_thread_cb(void (*proc)(void *), void *arg) | 180 | void initial_thread_cb(void (*proc)(void *), void *arg) |
@@ -185,10 +201,6 @@ void default_idle(void) | |||
185 | { | 201 | { |
186 | CHOOSE_MODE(uml_idle_timer(), (void) 0); | 202 | CHOOSE_MODE(uml_idle_timer(), (void) 0); |
187 | 203 | ||
188 | atomic_inc(&init_mm.mm_count); | ||
189 | current->mm = &init_mm; | ||
190 | current->active_mm = &init_mm; | ||
191 | |||
192 | while(1){ | 204 | while(1){ |
193 | /* endless idle loop with no priority at all */ | 205 | /* endless idle loop with no priority at all */ |
194 | 206 | ||
@@ -407,7 +419,7 @@ static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int | |||
407 | return strlen(buf); | 419 | return strlen(buf); |
408 | } | 420 | } |
409 | 421 | ||
410 | static int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data) | 422 | static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned long count,void *data) |
411 | { | 423 | { |
412 | char tmp[2]; | 424 | char tmp[2]; |
413 | 425 | ||
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 98e09395c0..60d2eda995 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c | |||
@@ -46,6 +46,7 @@ extern int poke_user(struct task_struct * child, long addr, long data); | |||
46 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 46 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
47 | { | 47 | { |
48 | int i, ret; | 48 | int i, ret; |
49 | unsigned long __user *p = (void __user *)(unsigned long)data; | ||
49 | 50 | ||
50 | switch (request) { | 51 | switch (request) { |
51 | /* when I and D space are separate, these will need to be fixed. */ | 52 | /* when I and D space are separate, these will need to be fixed. */ |
@@ -58,7 +59,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
58 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); | 59 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); |
59 | if (copied != sizeof(tmp)) | 60 | if (copied != sizeof(tmp)) |
60 | break; | 61 | break; |
61 | ret = put_user(tmp, (unsigned long __user *) data); | 62 | ret = put_user(tmp, p); |
62 | break; | 63 | break; |
63 | } | 64 | } |
64 | 65 | ||
@@ -136,15 +137,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
136 | 137 | ||
137 | #ifdef PTRACE_GETREGS | 138 | #ifdef PTRACE_GETREGS |
138 | case PTRACE_GETREGS: { /* Get all gp regs from the child. */ | 139 | case PTRACE_GETREGS: { /* Get all gp regs from the child. */ |
139 | if (!access_ok(VERIFY_WRITE, (unsigned long *)data, | 140 | if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) { |
140 | MAX_REG_OFFSET)) { | ||
141 | ret = -EIO; | 141 | ret = -EIO; |
142 | break; | 142 | break; |
143 | } | 143 | } |
144 | for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { | 144 | for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { |
145 | __put_user(getreg(child, i), | 145 | __put_user(getreg(child, i), p); |
146 | (unsigned long __user *) data); | 146 | p++; |
147 | data += sizeof(long); | ||
148 | } | 147 | } |
149 | ret = 0; | 148 | ret = 0; |
150 | break; | 149 | break; |
@@ -153,15 +152,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
153 | #ifdef PTRACE_SETREGS | 152 | #ifdef PTRACE_SETREGS |
154 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ | 153 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ |
155 | unsigned long tmp = 0; | 154 | unsigned long tmp = 0; |
156 | if (!access_ok(VERIFY_READ, (unsigned *)data, | 155 | if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) { |
157 | MAX_REG_OFFSET)) { | ||
158 | ret = -EIO; | 156 | ret = -EIO; |
159 | break; | 157 | break; |
160 | } | 158 | } |
161 | for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { | 159 | for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { |
162 | __get_user(tmp, (unsigned long __user *) data); | 160 | __get_user(tmp, p); |
163 | putreg(child, i, tmp); | 161 | putreg(child, i, tmp); |
164 | data += sizeof(long); | 162 | p++; |
165 | } | 163 | } |
166 | ret = 0; | 164 | ret = 0; |
167 | break; | 165 | break; |
@@ -187,14 +185,23 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
187 | ret = set_fpxregs(data, child); | 185 | ret = set_fpxregs(data, child); |
188 | break; | 186 | break; |
189 | #endif | 187 | #endif |
188 | case PTRACE_GET_THREAD_AREA: | ||
189 | ret = ptrace_get_thread_area(child, addr, | ||
190 | (struct user_desc __user *) data); | ||
191 | break; | ||
192 | |||
193 | case PTRACE_SET_THREAD_AREA: | ||
194 | ret = ptrace_set_thread_area(child, addr, | ||
195 | (struct user_desc __user *) data); | ||
196 | break; | ||
197 | |||
190 | case PTRACE_FAULTINFO: { | 198 | case PTRACE_FAULTINFO: { |
191 | /* Take the info from thread->arch->faultinfo, | 199 | /* Take the info from thread->arch->faultinfo, |
192 | * but transfer max. sizeof(struct ptrace_faultinfo). | 200 | * but transfer max. sizeof(struct ptrace_faultinfo). |
193 | * On i386, ptrace_faultinfo is smaller! | 201 | * On i386, ptrace_faultinfo is smaller! |
194 | */ | 202 | */ |
195 | ret = copy_to_user((unsigned long __user *) data, | 203 | ret = copy_to_user(p, &child->thread.arch.faultinfo, |
196 | &child->thread.arch.faultinfo, | 204 | sizeof(struct ptrace_faultinfo)); |
197 | sizeof(struct ptrace_faultinfo)); | ||
198 | if(ret) | 205 | if(ret) |
199 | break; | 206 | break; |
200 | break; | 207 | break; |
@@ -204,8 +211,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
204 | case PTRACE_LDT: { | 211 | case PTRACE_LDT: { |
205 | struct ptrace_ldt ldt; | 212 | struct ptrace_ldt ldt; |
206 | 213 | ||
207 | if(copy_from_user(&ldt, (unsigned long __user *) data, | 214 | if(copy_from_user(&ldt, p, sizeof(ldt))){ |
208 | sizeof(ldt))){ | ||
209 | ret = -EIO; | 215 | ret = -EIO; |
210 | break; | 216 | break; |
211 | } | 217 | } |
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 3f70a2e12f..2135eaf98a 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c | |||
@@ -35,6 +35,8 @@ void switch_to_skas(void *prev, void *next) | |||
35 | switch_threads(&from->thread.mode.skas.switch_buf, | 35 | switch_threads(&from->thread.mode.skas.switch_buf, |
36 | to->thread.mode.skas.switch_buf); | 36 | to->thread.mode.skas.switch_buf); |
37 | 37 | ||
38 | arch_switch_to_skas(current->thread.prev_sched, current); | ||
39 | |||
38 | if(current->pid == 0) | 40 | if(current->pid == 0) |
39 | switch_timers(1); | 41 | switch_timers(1); |
40 | } | 42 | } |
@@ -89,10 +91,17 @@ void fork_handler(int sig) | |||
89 | panic("blech"); | 91 | panic("blech"); |
90 | 92 | ||
91 | schedule_tail(current->thread.prev_sched); | 93 | schedule_tail(current->thread.prev_sched); |
94 | |||
95 | /* XXX: if interrupt_end() calls schedule, this call to | ||
96 | * arch_switch_to_skas isn't needed. We could want to apply this to | ||
97 | * improve performance. -bb */ | ||
98 | arch_switch_to_skas(current->thread.prev_sched, current); | ||
99 | |||
92 | current->thread.prev_sched = NULL; | 100 | current->thread.prev_sched = NULL; |
93 | 101 | ||
94 | /* Handle any immediate reschedules or signals */ | 102 | /* Handle any immediate reschedules or signals */ |
95 | interrupt_end(); | 103 | interrupt_end(); |
104 | |||
96 | userspace(¤t->thread.regs.regs); | 105 | userspace(¤t->thread.regs.regs); |
97 | } | 106 | } |
98 | 107 | ||
@@ -109,6 +118,8 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, | |||
109 | if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp; | 118 | if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp; |
110 | 119 | ||
111 | handler = fork_handler; | 120 | handler = fork_handler; |
121 | |||
122 | arch_copy_thread(¤t->thread.arch, &p->thread.arch); | ||
112 | } | 123 | } |
113 | else { | 124 | else { |
114 | init_thread_registers(&p->thread.regs.regs); | 125 | init_thread_registers(&p->thread.regs.regs); |
diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index 8e1a3501ff..37d3978337 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c | |||
@@ -104,7 +104,7 @@ long sys_pipe(unsigned long __user * fildes) | |||
104 | } | 104 | } |
105 | 105 | ||
106 | 106 | ||
107 | long sys_uname(struct old_utsname * name) | 107 | long sys_uname(struct old_utsname __user * name) |
108 | { | 108 | { |
109 | long err; | 109 | long err; |
110 | if (!name) | 110 | if (!name) |
@@ -115,7 +115,7 @@ long sys_uname(struct old_utsname * name) | |||
115 | return err?-EFAULT:0; | 115 | return err?-EFAULT:0; |
116 | } | 116 | } |
117 | 117 | ||
118 | long sys_olduname(struct oldold_utsname * name) | 118 | long sys_olduname(struct oldold_utsname __user * name) |
119 | { | 119 | { |
120 | long error; | 120 | long error; |
121 | 121 | ||
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index d56046c2ab..02f6d4d8dc 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c | |||
@@ -198,7 +198,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) | |||
198 | si.si_signo = SIGBUS; | 198 | si.si_signo = SIGBUS; |
199 | si.si_errno = 0; | 199 | si.si_errno = 0; |
200 | si.si_code = BUS_ADRERR; | 200 | si.si_code = BUS_ADRERR; |
201 | si.si_addr = (void *)address; | 201 | si.si_addr = (void __user *)address; |
202 | current->thread.arch.faultinfo = fi; | 202 | current->thread.arch.faultinfo = fi; |
203 | force_sig_info(SIGBUS, &si, current); | 203 | force_sig_info(SIGBUS, &si, current); |
204 | } else if (err == -ENOMEM) { | 204 | } else if (err == -ENOMEM) { |
@@ -207,7 +207,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) | |||
207 | } else { | 207 | } else { |
208 | BUG_ON(err != -EFAULT); | 208 | BUG_ON(err != -EFAULT); |
209 | si.si_signo = SIGSEGV; | 209 | si.si_signo = SIGSEGV; |
210 | si.si_addr = (void *) address; | 210 | si.si_addr = (void __user *) address; |
211 | current->thread.arch.faultinfo = fi; | 211 | current->thread.arch.faultinfo = fi; |
212 | force_sig_info(SIGSEGV, &si, current); | 212 | force_sig_info(SIGSEGV, &si, current); |
213 | } | 213 | } |
@@ -220,8 +220,8 @@ void bad_segv(struct faultinfo fi, unsigned long ip) | |||
220 | 220 | ||
221 | si.si_signo = SIGSEGV; | 221 | si.si_signo = SIGSEGV; |
222 | si.si_code = SEGV_ACCERR; | 222 | si.si_code = SEGV_ACCERR; |
223 | si.si_addr = (void *) FAULT_ADDRESS(fi); | 223 | si.si_addr = (void __user *) FAULT_ADDRESS(fi); |
224 | current->thread.arch.faultinfo = fi; | 224 | current->thread.arch.faultinfo = fi; |
225 | force_sig_info(SIGSEGV, &si, current); | 225 | force_sig_info(SIGSEGV, &si, current); |
226 | } | 226 | } |
227 | 227 | ||
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index 295c1ac817..a9c1443fc5 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c | |||
@@ -51,6 +51,13 @@ void switch_to_tt(void *prev, void *next) | |||
51 | 51 | ||
52 | c = 0; | 52 | c = 0; |
53 | 53 | ||
54 | /* Notice that here we "up" the semaphore on which "to" is waiting, and | ||
55 | * below (the read) we wait on this semaphore (which is implemented by | ||
56 | * switch_pipe) and go sleeping. Thus, after that, we have resumed in | ||
57 | * "to", and can't use any more the value of "from" (which is outdated), | ||
58 | * nor the value in "to" (since it was the task which stole us the CPU, | ||
59 | * which we don't care about). */ | ||
60 | |||
54 | err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); | 61 | err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); |
55 | if(err != sizeof(c)) | 62 | if(err != sizeof(c)) |
56 | panic("write of switch_pipe failed, err = %d", -err); | 63 | panic("write of switch_pipe failed, err = %d", -err); |
@@ -77,7 +84,7 @@ void switch_to_tt(void *prev, void *next) | |||
77 | change_sig(SIGALRM, alrm); | 84 | change_sig(SIGALRM, alrm); |
78 | change_sig(SIGPROF, prof); | 85 | change_sig(SIGPROF, prof); |
79 | 86 | ||
80 | arch_switch(); | 87 | arch_switch_to_tt(prev_sched, current); |
81 | 88 | ||
82 | flush_tlb_all(); | 89 | flush_tlb_all(); |
83 | local_irq_restore(flags); | 90 | local_irq_restore(flags); |
@@ -141,7 +148,6 @@ static void new_thread_handler(int sig) | |||
141 | set_cmdline("(kernel thread)"); | 148 | set_cmdline("(kernel thread)"); |
142 | 149 | ||
143 | change_sig(SIGUSR1, 1); | 150 | change_sig(SIGUSR1, 1); |
144 | change_sig(SIGVTALRM, 1); | ||
145 | change_sig(SIGPROF, 1); | 151 | change_sig(SIGPROF, 1); |
146 | local_irq_enable(); | 152 | local_irq_enable(); |
147 | if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) | 153 | if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) |
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 1659386b42..f4bfc4c7cc 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ | 6 | obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ |
7 | signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o \ | 7 | signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o tls.o \ |
8 | user_syms.o util.o drivers/ sys-$(SUBARCH)/ | 8 | user_syms.o util.o drivers/ sys-$(SUBARCH)/ |
9 | 9 | ||
10 | obj-$(CONFIG_MODE_SKAS) += skas/ | 10 | obj-$(CONFIG_MODE_SKAS) += skas/ |
@@ -12,12 +12,9 @@ obj-$(CONFIG_TTY_LOG) += tty_log.o | |||
12 | user-objs-$(CONFIG_TTY_LOG) += tty_log.o | 12 | user-objs-$(CONFIG_TTY_LOG) += tty_log.o |
13 | 13 | ||
14 | USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \ | 14 | USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \ |
15 | process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o \ | 15 | process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o tls.o \ |
16 | uaccess.o umid.o util.o | 16 | uaccess.o umid.o util.o |
17 | 17 | ||
18 | elf_aux.o: $(ARCH_DIR)/kernel-offsets.h | ||
19 | CFLAGS_elf_aux.o += -I$(objtree)/arch/um | ||
20 | |||
21 | CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) | 18 | CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) |
22 | 19 | ||
23 | HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \ | 20 | HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \ |
diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c index 6ae4b19d9f..768606bec2 100644 --- a/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/arch/um/os-Linux/drivers/ethertap_kern.c | |||
@@ -102,18 +102,7 @@ static struct transport ethertap_transport = { | |||
102 | static int register_ethertap(void) | 102 | static int register_ethertap(void) |
103 | { | 103 | { |
104 | register_transport(ðertap_transport); | 104 | register_transport(ðertap_transport); |
105 | return(1); | 105 | return 0; |
106 | } | 106 | } |
107 | 107 | ||
108 | __initcall(register_ethertap); | 108 | __initcall(register_ethertap); |
109 | |||
110 | /* | ||
111 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
112 | * Emacs will notice this stuff at the end of the file and automatically | ||
113 | * adjust the settings for this buffer only. This must remain at the end | ||
114 | * of the file. | ||
115 | * --------------------------------------------------------------------------- | ||
116 | * Local variables: | ||
117 | * c-file-style: "linux" | ||
118 | * End: | ||
119 | */ | ||
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index 901b85e8a1..8f49507e64 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c | |||
@@ -40,7 +40,7 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask, | |||
40 | int fd) | 40 | int fd) |
41 | { | 41 | { |
42 | struct addr_change change; | 42 | struct addr_change change; |
43 | void *output; | 43 | char *output; |
44 | int n; | 44 | int n; |
45 | 45 | ||
46 | change.what = op; | 46 | change.what = op; |
diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index 4202b9ebad..190009a6f8 100644 --- a/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/arch/um/os-Linux/drivers/tuntap_kern.c | |||
@@ -87,18 +87,7 @@ static struct transport tuntap_transport = { | |||
87 | static int register_tuntap(void) | 87 | static int register_tuntap(void) |
88 | { | 88 | { |
89 | register_transport(&tuntap_transport); | 89 | register_transport(&tuntap_transport); |
90 | return(1); | 90 | return 0; |
91 | } | 91 | } |
92 | 92 | ||
93 | __initcall(register_tuntap); | 93 | __initcall(register_tuntap); |
94 | |||
95 | /* | ||
96 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
97 | * Emacs will notice this stuff at the end of the file and automatically | ||
98 | * adjust the settings for this buffer only. This must remain at the end | ||
99 | * of the file. | ||
100 | * --------------------------------------------------------------------------- | ||
101 | * Local variables: | ||
102 | * c-file-style: "linux" | ||
103 | * End: | ||
104 | */ | ||
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 6490a4ff40..6987d1d247 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c | |||
@@ -43,7 +43,7 @@ static int helper_child(void *arg) | |||
43 | (*data->pre_exec)(data->pre_data); | 43 | (*data->pre_exec)(data->pre_data); |
44 | execvp(argv[0], argv); | 44 | execvp(argv[0], argv); |
45 | errval = errno; | 45 | errval = errno; |
46 | printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); | 46 | printk("helper_child - execve of '%s' failed - errno = %d\n", argv[0], errno); |
47 | os_write_file(data->fd, &errval, sizeof(errval)); | 47 | os_write_file(data->fd, &errval, sizeof(errval)); |
48 | kill(os_getpid(), SIGKILL); | 48 | kill(os_getpid(), SIGKILL); |
49 | return(0); | 49 | return(0); |
@@ -92,15 +92,15 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, | |||
92 | close(fds[1]); | 92 | close(fds[1]); |
93 | fds[1] = -1; | 93 | fds[1] = -1; |
94 | 94 | ||
95 | /*Read the errno value from the child.*/ | 95 | /* Read the errno value from the child, if the exec failed, or get 0 if |
96 | * the exec succeeded because the pipe fd was set as close-on-exec. */ | ||
96 | n = os_read_file(fds[0], &ret, sizeof(ret)); | 97 | n = os_read_file(fds[0], &ret, sizeof(ret)); |
97 | if(n < 0){ | 98 | if (n < 0) { |
98 | printk("run_helper : read on pipe failed, ret = %d\n", -n); | 99 | printk("run_helper : read on pipe failed, ret = %d\n", -n); |
99 | ret = n; | 100 | ret = n; |
100 | kill(pid, SIGKILL); | 101 | kill(pid, SIGKILL); |
101 | CATCH_EINTR(waitpid(pid, NULL, 0)); | 102 | CATCH_EINTR(waitpid(pid, NULL, 0)); |
102 | } | 103 | } else if(n != 0){ |
103 | else if(n != 0){ | ||
104 | CATCH_EINTR(n = waitpid(pid, NULL, 0)); | 104 | CATCH_EINTR(n = waitpid(pid, NULL, 0)); |
105 | ret = -errno; | 105 | ret = -errno; |
106 | } else { | 106 | } else { |
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 9d7d69a523..71bb90a760 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c | |||
@@ -53,33 +53,36 @@ static void __init find_tempdir(void) | |||
53 | */ | 53 | */ |
54 | int make_tempfile(const char *template, char **out_tempname, int do_unlink) | 54 | int make_tempfile(const char *template, char **out_tempname, int do_unlink) |
55 | { | 55 | { |
56 | char tempname[MAXPATHLEN]; | 56 | char *tempname; |
57 | int fd; | 57 | int fd; |
58 | 58 | ||
59 | tempname = malloc(MAXPATHLEN); | ||
60 | |||
59 | find_tempdir(); | 61 | find_tempdir(); |
60 | if (*template != '/') | 62 | if (template[0] != '/') |
61 | strcpy(tempname, tempdir); | 63 | strcpy(tempname, tempdir); |
62 | else | 64 | else |
63 | *tempname = 0; | 65 | tempname[0] = '\0'; |
64 | strcat(tempname, template); | 66 | strcat(tempname, template); |
65 | fd = mkstemp(tempname); | 67 | fd = mkstemp(tempname); |
66 | if(fd < 0){ | 68 | if(fd < 0){ |
67 | fprintf(stderr, "open - cannot create %s: %s\n", tempname, | 69 | fprintf(stderr, "open - cannot create %s: %s\n", tempname, |
68 | strerror(errno)); | 70 | strerror(errno)); |
69 | return -1; | 71 | goto out; |
70 | } | 72 | } |
71 | if(do_unlink && (unlink(tempname) < 0)){ | 73 | if(do_unlink && (unlink(tempname) < 0)){ |
72 | perror("unlink"); | 74 | perror("unlink"); |
73 | return -1; | 75 | goto out; |
74 | } | 76 | } |
75 | if(out_tempname){ | 77 | if(out_tempname){ |
76 | *out_tempname = strdup(tempname); | 78 | *out_tempname = tempname; |
77 | if(*out_tempname == NULL){ | 79 | } else { |
78 | perror("strdup"); | 80 | free(tempname); |
79 | return -1; | ||
80 | } | ||
81 | } | 81 | } |
82 | return(fd); | 82 | return(fd); |
83 | out: | ||
84 | free(tempname); | ||
85 | return -1; | ||
83 | } | 86 | } |
84 | 87 | ||
85 | #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" | 88 | #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" |
@@ -121,36 +124,11 @@ int create_tmp_file(unsigned long long len) | |||
121 | return(fd); | 124 | return(fd); |
122 | } | 125 | } |
123 | 126 | ||
124 | static int create_anon_file(unsigned long long len) | ||
125 | { | ||
126 | void *addr; | ||
127 | int fd; | ||
128 | |||
129 | fd = open("/dev/anon", O_RDWR); | ||
130 | if(fd < 0) { | ||
131 | perror("opening /dev/anon"); | ||
132 | exit(1); | ||
133 | } | ||
134 | |||
135 | addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); | ||
136 | if(addr == MAP_FAILED){ | ||
137 | perror("mapping physmem file"); | ||
138 | exit(1); | ||
139 | } | ||
140 | munmap(addr, len); | ||
141 | |||
142 | return(fd); | ||
143 | } | ||
144 | |||
145 | extern int have_devanon; | ||
146 | |||
147 | int create_mem_file(unsigned long long len) | 127 | int create_mem_file(unsigned long long len) |
148 | { | 128 | { |
149 | int err, fd; | 129 | int err, fd; |
150 | 130 | ||
151 | if(have_devanon) | 131 | fd = create_tmp_file(len); |
152 | fd = create_anon_file(len); | ||
153 | else fd = create_tmp_file(len); | ||
154 | 132 | ||
155 | err = os_set_exec_close(fd, 1); | 133 | err = os_set_exec_close(fd, 1); |
156 | if(err < 0){ | 134 | if(err < 0){ |
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index d261888f39..8176b0b520 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/unistd.h> | 11 | #include <linux/unistd.h> |
12 | #include <sys/mman.h> | 12 | #include <sys/mman.h> |
13 | #include <sys/wait.h> | 13 | #include <sys/wait.h> |
14 | #include <sys/mman.h> | ||
14 | #include "ptrace_user.h" | 15 | #include "ptrace_user.h" |
15 | #include "os.h" | 16 | #include "os.h" |
16 | #include "user.h" | 17 | #include "user.h" |
@@ -20,6 +21,7 @@ | |||
20 | #include "kern_util.h" | 21 | #include "kern_util.h" |
21 | #include "longjmp.h" | 22 | #include "longjmp.h" |
22 | #include "skas_ptrace.h" | 23 | #include "skas_ptrace.h" |
24 | #include "kern_constants.h" | ||
23 | 25 | ||
24 | #define ARBITRARY_ADDR -1 | 26 | #define ARBITRARY_ADDR -1 |
25 | #define FAILURE_PID -1 | 27 | #define FAILURE_PID -1 |
@@ -187,6 +189,48 @@ int os_unmap_memory(void *addr, int len) | |||
187 | return(0); | 189 | return(0); |
188 | } | 190 | } |
189 | 191 | ||
192 | #ifndef MADV_REMOVE | ||
193 | #define MADV_REMOVE 0x5 /* remove these pages & resources */ | ||
194 | #endif | ||
195 | |||
196 | int os_drop_memory(void *addr, int length) | ||
197 | { | ||
198 | int err; | ||
199 | |||
200 | err = madvise(addr, length, MADV_REMOVE); | ||
201 | if(err < 0) | ||
202 | err = -errno; | ||
203 | return err; | ||
204 | } | ||
205 | |||
206 | int can_drop_memory(void) | ||
207 | { | ||
208 | void *addr; | ||
209 | int fd; | ||
210 | |||
211 | printk("Checking host MADV_REMOVE support..."); | ||
212 | fd = create_mem_file(UM_KERN_PAGE_SIZE); | ||
213 | if(fd < 0){ | ||
214 | printk("Creating test memory file failed, err = %d\n", -fd); | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, | ||
219 | MAP_PRIVATE, fd, 0); | ||
220 | if(addr == MAP_FAILED){ | ||
221 | printk("Mapping test memory file failed, err = %d\n", -errno); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | if(madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0){ | ||
226 | printk("MADV_REMOVE failed, err = %d\n", -errno); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | printk("OK\n"); | ||
231 | return 1; | ||
232 | } | ||
233 | |||
190 | void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) | 234 | void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) |
191 | { | 235 | { |
192 | int flags = 0, pages; | 236 | int flags = 0, pages; |
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 9ba9429471..00e9388e94 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c | |||
@@ -304,8 +304,8 @@ out_clear_poll: | |||
304 | .size = 0, | 304 | .size = 0, |
305 | .used = 0 }); | 305 | .used = 0 }); |
306 | out_free: | 306 | out_free: |
307 | kfree(p); | ||
308 | sigio_unlock(); | 307 | sigio_unlock(); |
308 | kfree(p); | ||
309 | out_close2: | 309 | out_close2: |
310 | close(l_sigio_private[0]); | 310 | close(l_sigio_private[0]); |
311 | close(l_sigio_private[1]); | 311 | close(l_sigio_private[1]); |
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c index fbb080c2fc..b3c11cfa99 100644 --- a/arch/um/os-Linux/skas/mem.c +++ b/arch/um/os-Linux/skas/mem.c | |||
@@ -82,8 +82,8 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) | |||
82 | if (offset) { | 82 | if (offset) { |
83 | data = (unsigned long *)(mm_idp->stack + | 83 | data = (unsigned long *)(mm_idp->stack + |
84 | offset - UML_CONFIG_STUB_DATA); | 84 | offset - UML_CONFIG_STUB_DATA); |
85 | printk("do_syscall_stub : ret = %d, offset = %d, " | 85 | printk("do_syscall_stub : ret = %ld, offset = %ld, " |
86 | "data = 0x%x\n", ret, offset, data); | 86 | "data = %p\n", ret, offset, data); |
87 | syscall = (unsigned long *)((unsigned long)data + data[0]); | 87 | syscall = (unsigned long *)((unsigned long)data + data[0]); |
88 | printk("do_syscall_stub: syscall %ld failed, return value = " | 88 | printk("do_syscall_stub: syscall %ld failed, return value = " |
89 | "0x%lx, expected return value = 0x%lx\n", | 89 | "0x%lx, expected return value = 0x%lx\n", |
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index bbf34cb91c..045ae00374 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -265,7 +265,7 @@ void userspace(union uml_pt_regs *regs) | |||
265 | if(err) | 265 | if(err) |
266 | panic("userspace - could not resume userspace process, " | 266 | panic("userspace - could not resume userspace process, " |
267 | "pid=%d, ptrace operation = %d, errno = %d\n", | 267 | "pid=%d, ptrace operation = %d, errno = %d\n", |
268 | op, errno); | 268 | pid, op, errno); |
269 | 269 | ||
270 | CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); | 270 | CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); |
271 | if(err < 0) | 271 | if(err < 0) |
@@ -369,7 +369,7 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
369 | */ | 369 | */ |
370 | wait_stub_done(pid, -1, "copy_context_skas0"); | 370 | wait_stub_done(pid, -1, "copy_context_skas0"); |
371 | if (child_data->err != UML_CONFIG_STUB_DATA) | 371 | if (child_data->err != UML_CONFIG_STUB_DATA) |
372 | panic("copy_context_skas0 - stub-child reports error %d\n", | 372 | panic("copy_context_skas0 - stub-child reports error %ld\n", |
373 | child_data->err); | 373 | child_data->err); |
374 | 374 | ||
375 | if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, | 375 | if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, |
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 32753131f8..387e26af30 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c | |||
@@ -470,25 +470,6 @@ int can_do_skas(void) | |||
470 | } | 470 | } |
471 | #endif | 471 | #endif |
472 | 472 | ||
473 | int have_devanon = 0; | ||
474 | |||
475 | /* Runs on boot kernel stack - already safe to use printk. */ | ||
476 | |||
477 | void check_devanon(void) | ||
478 | { | ||
479 | int fd; | ||
480 | |||
481 | printk("Checking for /dev/anon on the host..."); | ||
482 | fd = open("/dev/anon", O_RDWR); | ||
483 | if(fd < 0){ | ||
484 | printk("Not available (open failed with errno %d)\n", errno); | ||
485 | return; | ||
486 | } | ||
487 | |||
488 | printk("OK\n"); | ||
489 | have_devanon = 1; | ||
490 | } | ||
491 | |||
492 | int __init parse_iomem(char *str, int *add) | 473 | int __init parse_iomem(char *str, int *add) |
493 | { | 474 | { |
494 | struct iomem_region *new; | 475 | struct iomem_region *new; |
@@ -664,6 +645,5 @@ void os_check_bugs(void) | |||
664 | { | 645 | { |
665 | check_ptrace(); | 646 | check_ptrace(); |
666 | check_sigio(); | 647 | check_sigio(); |
667 | check_devanon(); | ||
668 | } | 648 | } |
669 | 649 | ||
diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile index 340ef26f59..b3213613c4 100644 --- a/arch/um/os-Linux/sys-i386/Makefile +++ b/arch/um/os-Linux/sys-i386/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-$(CONFIG_MODE_SKAS) = registers.o | 6 | obj-$(CONFIG_MODE_SKAS) = registers.o tls.o |
7 | 7 | ||
8 | USER_OBJS := $(obj-y) | 8 | USER_OBJS := $(obj-y) |
9 | 9 | ||
diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c new file mode 100644 index 0000000000..120abbe4e3 --- /dev/null +++ b/arch/um/os-Linux/sys-i386/tls.c | |||
@@ -0,0 +1,34 @@ | |||
1 | #include <errno.h> | ||
2 | #include <linux/unistd.h> | ||
3 | #include "sysdep/tls.h" | ||
4 | #include "user_util.h" | ||
5 | |||
6 | static _syscall1(int, get_thread_area, user_desc_t *, u_info); | ||
7 | |||
8 | /* Checks whether host supports TLS, and sets *tls_min according to the value | ||
9 | * valid on the host. | ||
10 | * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ | ||
11 | void check_host_supports_tls(int *supports_tls, int *tls_min) { | ||
12 | /* Values for x86 and x86_64.*/ | ||
13 | int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64}; | ||
14 | int i; | ||
15 | |||
16 | for (i = 0; i < ARRAY_SIZE(val); i++) { | ||
17 | user_desc_t info; | ||
18 | info.entry_number = val[i]; | ||
19 | |||
20 | if (get_thread_area(&info) == 0) { | ||
21 | *tls_min = val[i]; | ||
22 | *supports_tls = 1; | ||
23 | return; | ||
24 | } else { | ||
25 | if (errno == EINVAL) | ||
26 | continue; | ||
27 | else if (errno == ENOSYS) | ||
28 | *supports_tls = 0; | ||
29 | return; | ||
30 | } | ||
31 | } | ||
32 | |||
33 | *supports_tls = 0; | ||
34 | } | ||
diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c new file mode 100644 index 0000000000..9cb09a4554 --- /dev/null +++ b/arch/um/os-Linux/tls.c | |||
@@ -0,0 +1,76 @@ | |||
1 | #include <errno.h> | ||
2 | #include <sys/ptrace.h> | ||
3 | #include <asm/ldt.h> | ||
4 | #include "sysdep/tls.h" | ||
5 | #include "uml-config.h" | ||
6 | |||
7 | /* TLS support - we basically rely on the host's one.*/ | ||
8 | |||
9 | /* In TT mode, this should be called only by the tracing thread, and makes sense | ||
10 | * only for PTRACE_SET_THREAD_AREA. In SKAS mode, it's used normally. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef PTRACE_GET_THREAD_AREA | ||
15 | #define PTRACE_GET_THREAD_AREA 25 | ||
16 | #endif | ||
17 | |||
18 | #ifndef PTRACE_SET_THREAD_AREA | ||
19 | #define PTRACE_SET_THREAD_AREA 26 | ||
20 | #endif | ||
21 | |||
22 | int os_set_thread_area(user_desc_t *info, int pid) | ||
23 | { | ||
24 | int ret; | ||
25 | |||
26 | ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number, | ||
27 | (unsigned long) info); | ||
28 | if (ret < 0) | ||
29 | ret = -errno; | ||
30 | return ret; | ||
31 | } | ||
32 | |||
33 | #ifdef UML_CONFIG_MODE_SKAS | ||
34 | |||
35 | int os_get_thread_area(user_desc_t *info, int pid) | ||
36 | { | ||
37 | int ret; | ||
38 | |||
39 | ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number, | ||
40 | (unsigned long) info); | ||
41 | if (ret < 0) | ||
42 | ret = -errno; | ||
43 | return ret; | ||
44 | } | ||
45 | |||
46 | #endif | ||
47 | |||
48 | #ifdef UML_CONFIG_MODE_TT | ||
49 | #include "linux/unistd.h" | ||
50 | |||
51 | static _syscall1(int, get_thread_area, user_desc_t *, u_info); | ||
52 | static _syscall1(int, set_thread_area, user_desc_t *, u_info); | ||
53 | |||
54 | int do_set_thread_area_tt(user_desc_t *info) | ||
55 | { | ||
56 | int ret; | ||
57 | |||
58 | ret = set_thread_area(info); | ||
59 | if (ret < 0) { | ||
60 | ret = -errno; | ||
61 | } | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | int do_get_thread_area_tt(user_desc_t *info) | ||
66 | { | ||
67 | int ret; | ||
68 | |||
69 | ret = get_thread_area(info); | ||
70 | if (ret < 0) { | ||
71 | ret = -errno; | ||
72 | } | ||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | #endif /* UML_CONFIG_MODE_TT */ | ||
diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index 198e591632..34bfc1bb9e 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c | |||
@@ -120,7 +120,8 @@ static int not_dead_yet(char *dir) | |||
120 | 120 | ||
121 | dead = 0; | 121 | dead = 0; |
122 | fd = open(file, O_RDONLY); | 122 | fd = open(file, O_RDONLY); |
123 | if(fd < 0){ | 123 | if(fd < 0) { |
124 | fd = -errno; | ||
124 | if(fd != -ENOENT){ | 125 | if(fd != -ENOENT){ |
125 | printk("not_dead_yet : couldn't open pid file '%s', " | 126 | printk("not_dead_yet : couldn't open pid file '%s', " |
126 | "err = %d\n", file, -fd); | 127 | "err = %d\n", file, -fd); |
@@ -130,9 +131,13 @@ static int not_dead_yet(char *dir) | |||
130 | 131 | ||
131 | err = 0; | 132 | err = 0; |
132 | n = read(fd, pid, sizeof(pid)); | 133 | n = read(fd, pid, sizeof(pid)); |
133 | if(n <= 0){ | 134 | if(n < 0){ |
135 | printk("not_dead_yet : couldn't read pid file '%s', " | ||
136 | "err = %d\n", file, errno); | ||
137 | goto out_close; | ||
138 | } else if(n == 0){ | ||
134 | printk("not_dead_yet : couldn't read pid file '%s', " | 139 | printk("not_dead_yet : couldn't read pid file '%s', " |
135 | "err = %d\n", file, -n); | 140 | "0-byte read\n", file); |
136 | goto out_close; | 141 | goto out_close; |
137 | } | 142 | } |
138 | 143 | ||
@@ -155,9 +160,9 @@ static int not_dead_yet(char *dir) | |||
155 | 160 | ||
156 | return err; | 161 | return err; |
157 | 162 | ||
158 | out_close: | 163 | out_close: |
159 | close(fd); | 164 | close(fd); |
160 | out: | 165 | out: |
161 | return 0; | 166 | return 0; |
162 | } | 167 | } |
163 | 168 | ||
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index 8da6ab3115..2598158e1f 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c | |||
@@ -18,14 +18,19 @@ extern void *memmove(void *, const void *, size_t); | |||
18 | extern void *memset(void *, int, size_t); | 18 | extern void *memset(void *, int, size_t); |
19 | extern int printf(const char *, ...); | 19 | extern int printf(const char *, ...); |
20 | 20 | ||
21 | /* If they're not defined, the export is included in lib/string.c.*/ | ||
22 | #ifdef __HAVE_ARCH_STRLEN | ||
21 | EXPORT_SYMBOL(strlen); | 23 | EXPORT_SYMBOL(strlen); |
24 | #endif | ||
25 | #ifdef __HAVE_ARCH_STRSTR | ||
26 | EXPORT_SYMBOL(strstr); | ||
27 | #endif | ||
28 | |||
22 | EXPORT_SYMBOL(memcpy); | 29 | EXPORT_SYMBOL(memcpy); |
23 | EXPORT_SYMBOL(memmove); | 30 | EXPORT_SYMBOL(memmove); |
24 | EXPORT_SYMBOL(memset); | 31 | EXPORT_SYMBOL(memset); |
25 | EXPORT_SYMBOL(printf); | 32 | EXPORT_SYMBOL(printf); |
26 | 33 | ||
27 | EXPORT_SYMBOL(strstr); | ||
28 | |||
29 | /* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. | 34 | /* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. |
30 | * However, the modules will use the CRC defined *here*, no matter if it is | 35 | * However, the modules will use the CRC defined *here*, no matter if it is |
31 | * good; so the versions of these symbols will always match | 36 | * good; so the versions of these symbols will always match |
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 2e41cabd3d..5e7a9c310a 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules | |||
@@ -9,10 +9,8 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) | |||
9 | 9 | ||
10 | $(USER_OBJS) $(USER_OBJS:.o=.i) $(USER_OBJS:.o=.s) $(USER_OBJS:.o=.lst): \ | 10 | $(USER_OBJS) $(USER_OBJS:.o=.i) $(USER_OBJS:.o=.s) $(USER_OBJS:.o=.lst): \ |
11 | c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(notdir $@)) | 11 | c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(notdir $@)) |
12 | $(USER_OBJS): cmd_checksrc = | 12 | $(USER_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ |
13 | $(USER_OBJS): quiet_cmd_checksrc = | 13 | -Dunix -D__unix__ -D__$(SUBARCH)__ |
14 | $(USER_OBJS): cmd_force_checksrc = | ||
15 | $(USER_OBJS): quiet_cmd_force_checksrc = | ||
16 | 14 | ||
17 | 15 | ||
18 | # The stubs and unmap.o can't try to call mcount or update basic block data | 16 | # The stubs and unmap.o can't try to call mcount or update basic block data |
@@ -20,25 +18,7 @@ define unprofile | |||
20 | $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) | 18 | $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) |
21 | endef | 19 | endef |
22 | 20 | ||
23 | 21 | ifdef subarch-obj-y | |
24 | # cmd_make_link checks to see if the $(foo-dir) variable starts with a /. If | 22 | obj-y += subarch.o |
25 | # so, it's considered to be a path relative to $(srcdir) rather than | 23 | subarch-y = $(addprefix ../../$(SUBARCH)/,$(subarch-obj-y)) |
26 | # $(srcdir)/arch/$(SUBARCH). This is because x86_64 wants to get ldt.c from | 24 | endif |
27 | # arch/um/sys-i386 rather than arch/i386 like the other borrowed files. So, | ||
28 | # it sets $(ldt.c-dir) to /arch/um/sys-i386. | ||
29 | quiet_cmd_make_link = SYMLINK $@ | ||
30 | cmd_make_link = rm -f $@; ln -sf $(srctree)$(if $(filter-out /%,$($(notdir $@)-dir)),/arch/$(SUBARCH))/$($(notdir $@)-dir)/$(notdir $@) $@ | ||
31 | |||
32 | # this needs to be before the foreach, because targets does not accept | ||
33 | # complete paths like $(obj)/$(f). To make sure this works, use a := assignment | ||
34 | # or we will get $(obj)/$(f) in the "targets" value. | ||
35 | # Also, this forces you to use the := syntax when assigning to targets. | ||
36 | # Otherwise the line below will cause an infinite loop (if you don't know why, | ||
37 | # just do it). | ||
38 | |||
39 | targets := $(targets) $(SYMLINKS) | ||
40 | |||
41 | SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$(f)) | ||
42 | |||
43 | $(SYMLINKS): FORCE | ||
44 | $(call if_changed,make_link) | ||
diff --git a/arch/um/scripts/Makefile.unmap b/arch/um/scripts/Makefile.unmap deleted file mode 100644 index b2165188d9..0000000000 --- a/arch/um/scripts/Makefile.unmap +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | clean-files += unmap_tmp.o unmap_fin.o unmap.o | ||
2 | |||
3 | ifdef CONFIG_MODE_TT | ||
4 | |||
5 | #Always build unmap_fin.o | ||
6 | extra-y += unmap_fin.o | ||
7 | #Do dependency tracking for unmap.o (it will be always built, but won't get the tracking unless we use this). | ||
8 | targets += unmap.o | ||
9 | |||
10 | #XXX: partially copied from arch/um/scripts/Makefile.rules | ||
11 | $(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS)) | ||
12 | |||
13 | quiet_cmd_wrapld = LD $@ | ||
14 | define cmd_wrapld | ||
15 | $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< ; \ | ||
16 | $(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo | ||
17 | endef | ||
18 | |||
19 | $(obj)/unmap_fin.o : $(obj)/unmap.o FORCE | ||
20 | $(call if_changed,wrapld) | ||
21 | |||
22 | endif | ||
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index f5fd5b0156..98b20b7bba 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile | |||
@@ -1,23 +1,18 @@ | |||
1 | obj-y := bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ | 1 | obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ |
2 | ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \ | 2 | ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o \ |
3 | sys_call_table.o | 3 | sys_call_table.o tls.o |
4 | 4 | ||
5 | obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o | 5 | obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o |
6 | 6 | ||
7 | obj-$(CONFIG_HIGHMEM) += highmem.o | 7 | subarch-obj-y = lib/bitops.o kernel/semaphore.o |
8 | obj-$(CONFIG_MODULES) += module.o | 8 | subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o |
9 | subarch-obj-$(CONFIG_MODULES) += kernel/module.o | ||
9 | 10 | ||
10 | USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o stub_segv.o | 11 | USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o stub_segv.o |
11 | 12 | ||
12 | SYMLINKS = bitops.c semaphore.c highmem.c module.c | ||
13 | |||
14 | include arch/um/scripts/Makefile.rules | 13 | include arch/um/scripts/Makefile.rules |
15 | 14 | ||
16 | bitops.c-dir = lib | 15 | extra-$(CONFIG_MODE_TT) += unmap.o |
17 | semaphore.c-dir = kernel | ||
18 | highmem.c-dir = mm | ||
19 | module.c-dir = kernel | ||
20 | |||
21 | $(obj)/stub_segv.o : _c_flags = $(call unprofile,$(CFLAGS)) | ||
22 | 16 | ||
23 | include arch/um/scripts/Makefile.unmap | 17 | $(obj)/stub_segv.o $(obj)/unmap.o: \ |
18 | _c_flags = $(call unprofile,$(CFLAGS)) | ||
diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c index db524ab3f7..2a1eac1859 100644 --- a/arch/um/sys-i386/ksyms.c +++ b/arch/um/sys-i386/ksyms.c | |||
@@ -15,7 +15,3 @@ EXPORT_SYMBOL(__up_wakeup); | |||
15 | 15 | ||
16 | /* Networking helper routines. */ | 16 | /* Networking helper routines. */ |
17 | EXPORT_SYMBOL(csum_partial); | 17 | EXPORT_SYMBOL(csum_partial); |
18 | |||
19 | /* delay core functions */ | ||
20 | EXPORT_SYMBOL(__const_udelay); | ||
21 | EXPORT_SYMBOL(__udelay); | ||
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index 8032a10594..6028bc7cc0 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c | |||
@@ -15,9 +15,22 @@ | |||
15 | #include "sysdep/sigcontext.h" | 15 | #include "sysdep/sigcontext.h" |
16 | #include "sysdep/sc.h" | 16 | #include "sysdep/sc.h" |
17 | 17 | ||
18 | void arch_switch(void) | 18 | void arch_switch_to_tt(struct task_struct *from, struct task_struct *to) |
19 | { | 19 | { |
20 | update_debugregs(current->thread.arch.debugregs_seq); | 20 | update_debugregs(to->thread.arch.debugregs_seq); |
21 | arch_switch_tls_tt(from, to); | ||
22 | } | ||
23 | |||
24 | void arch_switch_to_skas(struct task_struct *from, struct task_struct *to) | ||
25 | { | ||
26 | int err = arch_switch_tls_skas(from, to); | ||
27 | if (!err) | ||
28 | return; | ||
29 | |||
30 | if (err != -EINVAL) | ||
31 | printk(KERN_WARNING "arch_switch_tls_skas failed, errno %d, not EINVAL\n", -err); | ||
32 | else | ||
33 | printk(KERN_WARNING "arch_switch_tls_skas failed, errno = EINVAL\n"); | ||
21 | } | 34 | } |
22 | 35 | ||
23 | int is_syscall(unsigned long addr) | 36 | int is_syscall(unsigned long addr) |
@@ -124,22 +137,22 @@ unsigned long getreg(struct task_struct *child, int regno) | |||
124 | int peek_user(struct task_struct *child, long addr, long data) | 137 | int peek_user(struct task_struct *child, long addr, long data) |
125 | { | 138 | { |
126 | /* read the word at location addr in the USER area. */ | 139 | /* read the word at location addr in the USER area. */ |
127 | unsigned long tmp; | 140 | unsigned long tmp; |
128 | 141 | ||
129 | if ((addr & 3) || addr < 0) | 142 | if ((addr & 3) || addr < 0) |
130 | return -EIO; | 143 | return -EIO; |
131 | 144 | ||
132 | tmp = 0; /* Default return condition */ | 145 | tmp = 0; /* Default return condition */ |
133 | if(addr < MAX_REG_OFFSET){ | 146 | if(addr < MAX_REG_OFFSET){ |
134 | tmp = getreg(child, addr); | 147 | tmp = getreg(child, addr); |
135 | } | 148 | } |
136 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | 149 | else if((addr >= offsetof(struct user, u_debugreg[0])) && |
137 | (addr <= offsetof(struct user, u_debugreg[7]))){ | 150 | (addr <= offsetof(struct user, u_debugreg[7]))){ |
138 | addr -= offsetof(struct user, u_debugreg[0]); | 151 | addr -= offsetof(struct user, u_debugreg[0]); |
139 | addr = addr >> 2; | 152 | addr = addr >> 2; |
140 | tmp = child->thread.arch.debugregs[addr]; | 153 | tmp = child->thread.arch.debugregs[addr]; |
141 | } | 154 | } |
142 | return put_user(tmp, (unsigned long *) data); | 155 | return put_user(tmp, (unsigned long __user *) data); |
143 | } | 156 | } |
144 | 157 | ||
145 | struct i387_fxsave_struct { | 158 | struct i387_fxsave_struct { |
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c index 7c376c95de..40aa885314 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "sysdep/thread.h" | 14 | #include "sysdep/thread.h" |
15 | #include "user.h" | 15 | #include "user.h" |
16 | #include "os.h" | 16 | #include "os.h" |
17 | #include "uml-config.h" | ||
17 | 18 | ||
18 | int ptrace_getregs(long pid, unsigned long *regs_out) | 19 | int ptrace_getregs(long pid, unsigned long *regs_out) |
19 | { | 20 | { |
@@ -43,6 +44,7 @@ int ptrace_setfpregs(long pid, unsigned long *regs) | |||
43 | return 0; | 44 | return 0; |
44 | } | 45 | } |
45 | 46 | ||
47 | /* All the below stuff is of interest for TT mode only */ | ||
46 | static void write_debugregs(int pid, unsigned long *regs) | 48 | static void write_debugregs(int pid, unsigned long *regs) |
47 | { | 49 | { |
48 | struct user *dummy; | 50 | struct user *dummy; |
@@ -55,7 +57,7 @@ static void write_debugregs(int pid, unsigned long *regs) | |||
55 | if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], | 57 | if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], |
56 | regs[i]) < 0) | 58 | regs[i]) < 0) |
57 | printk("write_debugregs - ptrace failed on " | 59 | printk("write_debugregs - ptrace failed on " |
58 | "register %d, value = 0x%x, errno = %d\n", i, | 60 | "register %d, value = 0x%lx, errno = %d\n", i, |
59 | regs[i], errno); | 61 | regs[i], errno); |
60 | } | 62 | } |
61 | } | 63 | } |
@@ -75,7 +77,6 @@ static void read_debugregs(int pid, unsigned long *regs) | |||
75 | 77 | ||
76 | /* Accessed only by the tracing thread */ | 78 | /* Accessed only by the tracing thread */ |
77 | static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; | 79 | static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; |
78 | static int debugregs_seq = 0; | ||
79 | 80 | ||
80 | void arch_enter_kernel(void *task, int pid) | 81 | void arch_enter_kernel(void *task, int pid) |
81 | { | 82 | { |
@@ -89,6 +90,11 @@ void arch_leave_kernel(void *task, int pid) | |||
89 | write_debugregs(pid, TASK_DEBUGREGS(task)); | 90 | write_debugregs(pid, TASK_DEBUGREGS(task)); |
90 | } | 91 | } |
91 | 92 | ||
93 | #ifdef UML_CONFIG_PT_PROXY | ||
94 | /* Accessed only by the tracing thread */ | ||
95 | static int debugregs_seq; | ||
96 | |||
97 | /* Only called by the ptrace proxy */ | ||
92 | void ptrace_pokeuser(unsigned long addr, unsigned long data) | 98 | void ptrace_pokeuser(unsigned long addr, unsigned long data) |
93 | { | 99 | { |
94 | if((addr < offsetof(struct user, u_debugreg[0])) || | 100 | if((addr < offsetof(struct user, u_debugreg[0])) || |
@@ -109,6 +115,7 @@ static void update_debugregs_cb(void *arg) | |||
109 | write_debugregs(pid, kernel_debugregs); | 115 | write_debugregs(pid, kernel_debugregs); |
110 | } | 116 | } |
111 | 117 | ||
118 | /* Optimized out in its header when not defined */ | ||
112 | void update_debugregs(int seq) | 119 | void update_debugregs(int seq) |
113 | { | 120 | { |
114 | int me; | 121 | int me; |
@@ -118,6 +125,7 @@ void update_debugregs(int seq) | |||
118 | me = os_getpid(); | 125 | me = os_getpid(); |
119 | initial_thread_cb(update_debugregs_cb, &me); | 126 | initial_thread_cb(update_debugregs_cb, &me); |
120 | } | 127 | } |
128 | #endif | ||
121 | 129 | ||
122 | /* | 130 | /* |
123 | * Overrides for Emacs so that we follow Linus's tabbing style. | 131 | * Overrides for Emacs so that we follow Linus's tabbing style. |
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 33a40f5ef0..618fd85946 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include "skas.h" | 19 | #include "skas.h" |
20 | 20 | ||
21 | static int copy_sc_from_user_skas(struct pt_regs *regs, | 21 | static int copy_sc_from_user_skas(struct pt_regs *regs, |
22 | struct sigcontext *from) | 22 | struct sigcontext __user *from) |
23 | { | 23 | { |
24 | struct sigcontext sc; | 24 | struct sigcontext sc; |
25 | unsigned long fpregs[HOST_FP_SIZE]; | 25 | unsigned long fpregs[HOST_FP_SIZE]; |
@@ -57,7 +57,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, | |||
57 | return(0); | 57 | return(0); |
58 | } | 58 | } |
59 | 59 | ||
60 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | 60 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate __user *to_fp, |
61 | struct pt_regs *regs, unsigned long sp) | 61 | struct pt_regs *regs, unsigned long sp) |
62 | { | 62 | { |
63 | struct sigcontext sc; | 63 | struct sigcontext sc; |
@@ -92,7 +92,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
92 | "errno = %d\n", err); | 92 | "errno = %d\n", err); |
93 | return(1); | 93 | return(1); |
94 | } | 94 | } |
95 | to_fp = (to_fp ? to_fp : (struct _fpstate *) (to + 1)); | 95 | to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1)); |
96 | sc.fpstate = to_fp; | 96 | sc.fpstate = to_fp; |
97 | 97 | ||
98 | if(err) | 98 | if(err) |
@@ -113,10 +113,11 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
113 | * saved pointer is in the kernel, but the sigcontext is in userspace, so we | 113 | * saved pointer is in the kernel, but the sigcontext is in userspace, so we |
114 | * copy_to_user it. | 114 | * copy_to_user it. |
115 | */ | 115 | */ |
116 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | 116 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from, |
117 | int fpsize) | 117 | int fpsize) |
118 | { | 118 | { |
119 | struct _fpstate *to_fp, *from_fp; | 119 | struct _fpstate *to_fp; |
120 | struct _fpstate __user *from_fp; | ||
120 | unsigned long sigs; | 121 | unsigned long sigs; |
121 | int err; | 122 | int err; |
122 | 123 | ||
@@ -131,13 +132,14 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | |||
131 | return(err); | 132 | return(err); |
132 | } | 133 | } |
133 | 134 | ||
134 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | 135 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate __user *fp, |
135 | struct sigcontext *from, int fpsize, unsigned long sp) | 136 | struct sigcontext *from, int fpsize, unsigned long sp) |
136 | { | 137 | { |
137 | struct _fpstate *to_fp, *from_fp; | 138 | struct _fpstate __user *to_fp; |
139 | struct _fpstate *from_fp; | ||
138 | int err; | 140 | int err; |
139 | 141 | ||
140 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); | 142 | to_fp = (fp ? fp : (struct _fpstate __user *) (to + 1)); |
141 | from_fp = from->fpstate; | 143 | from_fp = from->fpstate; |
142 | err = copy_to_user(to, from, sizeof(*to)); | 144 | err = copy_to_user(to, from, sizeof(*to)); |
143 | 145 | ||
@@ -145,7 +147,7 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | |||
145 | * delivery. The sp passed in is the original, and this needs | 147 | * delivery. The sp passed in is the original, and this needs |
146 | * to be restored, so we stick it in separately. | 148 | * to be restored, so we stick it in separately. |
147 | */ | 149 | */ |
148 | err |= copy_to_user(&SC_SP(to), sp, sizeof(sp)); | 150 | err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp)); |
149 | 151 | ||
150 | if(from_fp != NULL){ | 152 | if(from_fp != NULL){ |
151 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); | 153 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); |
@@ -165,7 +167,7 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) | |||
165 | return(ret); | 167 | return(ret); |
166 | } | 168 | } |
167 | 169 | ||
168 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, | 170 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate __user *fp, |
169 | struct pt_regs *from, unsigned long sp) | 171 | struct pt_regs *from, unsigned long sp) |
170 | { | 172 | { |
171 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), | 173 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), |
@@ -173,7 +175,7 @@ static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, | |||
173 | copy_sc_to_user_skas(to, fp, from, sp))); | 175 | copy_sc_to_user_skas(to, fp, from, sp))); |
174 | } | 176 | } |
175 | 177 | ||
176 | static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, | 178 | static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp, |
177 | sigset_t *set, unsigned long sp) | 179 | sigset_t *set, unsigned long sp) |
178 | { | 180 | { |
179 | int err = 0; | 181 | int err = 0; |
@@ -188,7 +190,7 @@ static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, | |||
188 | 190 | ||
189 | struct sigframe | 191 | struct sigframe |
190 | { | 192 | { |
191 | char *pretcode; | 193 | char __user *pretcode; |
192 | int sig; | 194 | int sig; |
193 | struct sigcontext sc; | 195 | struct sigcontext sc; |
194 | struct _fpstate fpstate; | 196 | struct _fpstate fpstate; |
@@ -198,10 +200,10 @@ struct sigframe | |||
198 | 200 | ||
199 | struct rt_sigframe | 201 | struct rt_sigframe |
200 | { | 202 | { |
201 | char *pretcode; | 203 | char __user *pretcode; |
202 | int sig; | 204 | int sig; |
203 | struct siginfo *pinfo; | 205 | struct siginfo __user *pinfo; |
204 | void *puc; | 206 | void __user *puc; |
205 | struct siginfo info; | 207 | struct siginfo info; |
206 | struct ucontext uc; | 208 | struct ucontext uc; |
207 | struct _fpstate fpstate; | 209 | struct _fpstate fpstate; |
@@ -213,16 +215,16 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, | |||
213 | sigset_t *mask) | 215 | sigset_t *mask) |
214 | { | 216 | { |
215 | struct sigframe __user *frame; | 217 | struct sigframe __user *frame; |
216 | void *restorer; | 218 | void __user *restorer; |
217 | unsigned long save_sp = PT_REGS_SP(regs); | 219 | unsigned long save_sp = PT_REGS_SP(regs); |
218 | int err = 0; | 220 | int err = 0; |
219 | 221 | ||
220 | stack_top &= -8UL; | 222 | stack_top &= -8UL; |
221 | frame = (struct sigframe *) stack_top - 1; | 223 | frame = (struct sigframe __user *) stack_top - 1; |
222 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 224 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
223 | return 1; | 225 | return 1; |
224 | 226 | ||
225 | restorer = (void *) frame->retcode; | 227 | restorer = frame->retcode; |
226 | if(ka->sa.sa_flags & SA_RESTORER) | 228 | if(ka->sa.sa_flags & SA_RESTORER) |
227 | restorer = ka->sa.sa_restorer; | 229 | restorer = ka->sa.sa_restorer; |
228 | 230 | ||
@@ -278,16 +280,16 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
278 | siginfo_t *info, sigset_t *mask) | 280 | siginfo_t *info, sigset_t *mask) |
279 | { | 281 | { |
280 | struct rt_sigframe __user *frame; | 282 | struct rt_sigframe __user *frame; |
281 | void *restorer; | 283 | void __user *restorer; |
282 | unsigned long save_sp = PT_REGS_SP(regs); | 284 | unsigned long save_sp = PT_REGS_SP(regs); |
283 | int err = 0; | 285 | int err = 0; |
284 | 286 | ||
285 | stack_top &= -8UL; | 287 | stack_top &= -8UL; |
286 | frame = (struct rt_sigframe *) stack_top - 1; | 288 | frame = (struct rt_sigframe __user *) stack_top - 1; |
287 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 289 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
288 | return 1; | 290 | return 1; |
289 | 291 | ||
290 | restorer = (void *) frame->retcode; | 292 | restorer = frame->retcode; |
291 | if(ka->sa.sa_flags & SA_RESTORER) | 293 | if(ka->sa.sa_flags & SA_RESTORER) |
292 | restorer = ka->sa.sa_restorer; | 294 | restorer = ka->sa.sa_restorer; |
293 | 295 | ||
@@ -333,7 +335,7 @@ err: | |||
333 | long sys_sigreturn(struct pt_regs regs) | 335 | long sys_sigreturn(struct pt_regs regs) |
334 | { | 336 | { |
335 | unsigned long sp = PT_REGS_SP(¤t->thread.regs); | 337 | unsigned long sp = PT_REGS_SP(¤t->thread.regs); |
336 | struct sigframe __user *frame = (struct sigframe *)(sp - 8); | 338 | struct sigframe __user *frame = (struct sigframe __user *)(sp - 8); |
337 | sigset_t set; | 339 | sigset_t set; |
338 | struct sigcontext __user *sc = &frame->sc; | 340 | struct sigcontext __user *sc = &frame->sc; |
339 | unsigned long __user *oldmask = &sc->oldmask; | 341 | unsigned long __user *oldmask = &sc->oldmask; |
@@ -365,8 +367,8 @@ long sys_sigreturn(struct pt_regs regs) | |||
365 | 367 | ||
366 | long sys_rt_sigreturn(struct pt_regs regs) | 368 | long sys_rt_sigreturn(struct pt_regs regs) |
367 | { | 369 | { |
368 | unsigned long __user sp = PT_REGS_SP(¤t->thread.regs); | 370 | unsigned long sp = PT_REGS_SP(¤t->thread.regs); |
369 | struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4); | 371 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (sp - 4); |
370 | sigset_t set; | 372 | sigset_t set; |
371 | struct ucontext __user *uc = &frame->uc; | 373 | struct ucontext __user *uc = &frame->uc; |
372 | int sig_size = _NSIG_WORDS * sizeof(unsigned long); | 374 | int sig_size = _NSIG_WORDS * sizeof(unsigned long); |
diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S index ad75c27afe..1ff61474b2 100644 --- a/arch/um/sys-i386/sys_call_table.S +++ b/arch/um/sys-i386/sys_call_table.S | |||
@@ -6,8 +6,6 @@ | |||
6 | 6 | ||
7 | #define sys_vm86old sys_ni_syscall | 7 | #define sys_vm86old sys_ni_syscall |
8 | #define sys_vm86 sys_ni_syscall | 8 | #define sys_vm86 sys_ni_syscall |
9 | #define sys_set_thread_area sys_ni_syscall | ||
10 | #define sys_get_thread_area sys_ni_syscall | ||
11 | 9 | ||
12 | #define sys_stime um_stime | 10 | #define sys_stime um_stime |
13 | #define sys_time um_time | 11 | #define sys_time um_time |
diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c index 83e9be820a..749dd1bfe6 100644 --- a/arch/um/sys-i386/syscalls.c +++ b/arch/um/sys-i386/syscalls.c | |||
@@ -61,21 +61,27 @@ long old_select(struct sel_arg_struct __user *arg) | |||
61 | return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); | 61 | return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); |
62 | } | 62 | } |
63 | 63 | ||
64 | /* The i386 version skips reading from %esi, the fourth argument. So we must do | 64 | /* |
65 | * this, too. | 65 | * The prototype on i386 is: |
66 | * | ||
67 | * int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr) | ||
68 | * | ||
69 | * and the "newtls" arg. on i386 is read by copy_thread directly from the | ||
70 | * register saved on the stack. | ||
66 | */ | 71 | */ |
67 | long sys_clone(unsigned long clone_flags, unsigned long newsp, | 72 | long sys_clone(unsigned long clone_flags, unsigned long newsp, |
68 | int __user *parent_tid, int unused, int __user *child_tid) | 73 | int __user *parent_tid, void *newtls, int __user *child_tid) |
69 | { | 74 | { |
70 | long ret; | 75 | long ret; |
71 | 76 | ||
72 | if (!newsp) | 77 | if (!newsp) |
73 | newsp = UPT_SP(¤t->thread.regs.regs); | 78 | newsp = UPT_SP(¤t->thread.regs.regs); |
79 | |||
74 | current->thread.forking = 1; | 80 | current->thread.forking = 1; |
75 | ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, | 81 | ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, |
76 | child_tid); | 82 | child_tid); |
77 | current->thread.forking = 0; | 83 | current->thread.forking = 0; |
78 | return(ret); | 84 | return ret; |
79 | } | 85 | } |
80 | 86 | ||
81 | /* | 87 | /* |
@@ -104,7 +110,7 @@ long sys_ipc (uint call, int first, int second, | |||
104 | union semun fourth; | 110 | union semun fourth; |
105 | if (!ptr) | 111 | if (!ptr) |
106 | return -EINVAL; | 112 | return -EINVAL; |
107 | if (get_user(fourth.__pad, (void **) ptr)) | 113 | if (get_user(fourth.__pad, (void __user * __user *) ptr)) |
108 | return -EFAULT; | 114 | return -EFAULT; |
109 | return sys_semctl (first, second, third, fourth); | 115 | return sys_semctl (first, second, third, fourth); |
110 | } | 116 | } |
diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c new file mode 100644 index 0000000000..71b9796258 --- /dev/null +++ b/arch/um/sys-i386/tls.c | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include "linux/config.h" | ||
7 | #include "linux/kernel.h" | ||
8 | #include "linux/sched.h" | ||
9 | #include "linux/slab.h" | ||
10 | #include "linux/types.h" | ||
11 | #include "asm/uaccess.h" | ||
12 | #include "asm/ptrace.h" | ||
13 | #include "asm/segment.h" | ||
14 | #include "asm/smp.h" | ||
15 | #include "asm/desc.h" | ||
16 | #include "choose-mode.h" | ||
17 | #include "kern.h" | ||
18 | #include "kern_util.h" | ||
19 | #include "mode_kern.h" | ||
20 | #include "os.h" | ||
21 | #include "mode.h" | ||
22 | |||
23 | #ifdef CONFIG_MODE_SKAS | ||
24 | #include "skas.h" | ||
25 | #endif | ||
26 | |||
27 | /* If needed we can detect when it's uninitialized. */ | ||
28 | static int host_supports_tls = -1; | ||
29 | int host_gdt_entry_tls_min = -1; | ||
30 | |||
31 | #ifdef CONFIG_MODE_SKAS | ||
32 | int do_set_thread_area_skas(struct user_desc *info) | ||
33 | { | ||
34 | int ret; | ||
35 | u32 cpu; | ||
36 | |||
37 | cpu = get_cpu(); | ||
38 | ret = os_set_thread_area(info, userspace_pid[cpu]); | ||
39 | put_cpu(); | ||
40 | return ret; | ||
41 | } | ||
42 | |||
43 | int do_get_thread_area_skas(struct user_desc *info) | ||
44 | { | ||
45 | int ret; | ||
46 | u32 cpu; | ||
47 | |||
48 | cpu = get_cpu(); | ||
49 | ret = os_get_thread_area(info, userspace_pid[cpu]); | ||
50 | put_cpu(); | ||
51 | return ret; | ||
52 | } | ||
53 | #endif | ||
54 | |||
55 | /* | ||
56 | * sys_get_thread_area: get a yet unused TLS descriptor index. | ||
57 | * XXX: Consider leaving one free slot for glibc usage at first place. This must | ||
58 | * be done here (and by changing GDT_ENTRY_TLS_* macros) and nowhere else. | ||
59 | * | ||
60 | * Also, this must be tested when compiling in SKAS mode with dinamic linking | ||
61 | * and running against NPTL. | ||
62 | */ | ||
63 | static int get_free_idx(struct task_struct* task) | ||
64 | { | ||
65 | struct thread_struct *t = &task->thread; | ||
66 | int idx; | ||
67 | |||
68 | if (!t->arch.tls_array) | ||
69 | return GDT_ENTRY_TLS_MIN; | ||
70 | |||
71 | for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) | ||
72 | if (!t->arch.tls_array[idx].present) | ||
73 | return idx + GDT_ENTRY_TLS_MIN; | ||
74 | return -ESRCH; | ||
75 | } | ||
76 | |||
77 | static inline void clear_user_desc(struct user_desc* info) | ||
78 | { | ||
79 | /* Postcondition: LDT_empty(info) returns true. */ | ||
80 | memset(info, 0, sizeof(*info)); | ||
81 | |||
82 | /* Check the LDT_empty or the i386 sys_get_thread_area code - we obtain | ||
83 | * indeed an empty user_desc. | ||
84 | */ | ||
85 | info->read_exec_only = 1; | ||
86 | info->seg_not_present = 1; | ||
87 | } | ||
88 | |||
89 | #define O_FORCE 1 | ||
90 | |||
91 | static int load_TLS(int flags, struct task_struct *to) | ||
92 | { | ||
93 | int ret = 0; | ||
94 | int idx; | ||
95 | |||
96 | for (idx = GDT_ENTRY_TLS_MIN; idx < GDT_ENTRY_TLS_MAX; idx++) { | ||
97 | struct uml_tls_struct* curr = &to->thread.arch.tls_array[idx - GDT_ENTRY_TLS_MIN]; | ||
98 | |||
99 | /* Actually, now if it wasn't flushed it gets cleared and | ||
100 | * flushed to the host, which will clear it.*/ | ||
101 | if (!curr->present) { | ||
102 | if (!curr->flushed) { | ||
103 | clear_user_desc(&curr->tls); | ||
104 | curr->tls.entry_number = idx; | ||
105 | } else { | ||
106 | WARN_ON(!LDT_empty(&curr->tls)); | ||
107 | continue; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | if (!(flags & O_FORCE) && curr->flushed) | ||
112 | continue; | ||
113 | |||
114 | ret = do_set_thread_area(&curr->tls); | ||
115 | if (ret) | ||
116 | goto out; | ||
117 | |||
118 | curr->flushed = 1; | ||
119 | } | ||
120 | out: | ||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | /* Verify if we need to do a flush for the new process, i.e. if there are any | ||
125 | * present desc's, only if they haven't been flushed. | ||
126 | */ | ||
127 | static inline int needs_TLS_update(struct task_struct *task) | ||
128 | { | ||
129 | int i; | ||
130 | int ret = 0; | ||
131 | |||
132 | for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { | ||
133 | struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; | ||
134 | |||
135 | /* Can't test curr->present, we may need to clear a descriptor | ||
136 | * which had a value. */ | ||
137 | if (curr->flushed) | ||
138 | continue; | ||
139 | ret = 1; | ||
140 | break; | ||
141 | } | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | /* On a newly forked process, the TLS descriptors haven't yet been flushed. So | ||
146 | * we mark them as such and the first switch_to will do the job. | ||
147 | */ | ||
148 | void clear_flushed_tls(struct task_struct *task) | ||
149 | { | ||
150 | int i; | ||
151 | |||
152 | for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { | ||
153 | struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; | ||
154 | |||
155 | /* Still correct to do this, if it wasn't present on the host it | ||
156 | * will remain as flushed as it was. */ | ||
157 | if (!curr->present) | ||
158 | continue; | ||
159 | |||
160 | curr->flushed = 0; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | /* In SKAS0 mode, currently, multiple guest threads sharing the same ->mm have a | ||
165 | * common host process. So this is needed in SKAS0 too. | ||
166 | * | ||
167 | * However, if each thread had a different host process (and this was discussed | ||
168 | * for SMP support) this won't be needed. | ||
169 | * | ||
170 | * And this will not need be used when (and if) we'll add support to the host | ||
171 | * SKAS patch. */ | ||
172 | |||
173 | int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to) | ||
174 | { | ||
175 | if (!host_supports_tls) | ||
176 | return 0; | ||
177 | |||
178 | /* We have no need whatsoever to switch TLS for kernel threads; beyond | ||
179 | * that, that would also result in us calling os_set_thread_area with | ||
180 | * userspace_pid[cpu] == 0, which gives an error. */ | ||
181 | if (likely(to->mm)) | ||
182 | return load_TLS(O_FORCE, to); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to) | ||
188 | { | ||
189 | if (!host_supports_tls) | ||
190 | return 0; | ||
191 | |||
192 | if (needs_TLS_update(to)) | ||
193 | return load_TLS(0, to); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int set_tls_entry(struct task_struct* task, struct user_desc *info, | ||
199 | int idx, int flushed) | ||
200 | { | ||
201 | struct thread_struct *t = &task->thread; | ||
202 | |||
203 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | ||
204 | return -EINVAL; | ||
205 | |||
206 | t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls = *info; | ||
207 | t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present = 1; | ||
208 | t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed = flushed; | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | int arch_copy_tls(struct task_struct *new) | ||
214 | { | ||
215 | struct user_desc info; | ||
216 | int idx, ret = -EFAULT; | ||
217 | |||
218 | if (copy_from_user(&info, | ||
219 | (void __user *) UPT_ESI(&new->thread.regs.regs), | ||
220 | sizeof(info))) | ||
221 | goto out; | ||
222 | |||
223 | ret = -EINVAL; | ||
224 | if (LDT_empty(&info)) | ||
225 | goto out; | ||
226 | |||
227 | idx = info.entry_number; | ||
228 | |||
229 | ret = set_tls_entry(new, &info, idx, 0); | ||
230 | out: | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | /* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */ | ||
235 | static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx) | ||
236 | { | ||
237 | struct thread_struct *t = &task->thread; | ||
238 | |||
239 | if (!t->arch.tls_array) | ||
240 | goto clear; | ||
241 | |||
242 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | ||
243 | return -EINVAL; | ||
244 | |||
245 | if (!t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present) | ||
246 | goto clear; | ||
247 | |||
248 | *info = t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls; | ||
249 | |||
250 | out: | ||
251 | /* Temporary debugging check, to make sure that things have been | ||
252 | * flushed. This could be triggered if load_TLS() failed. | ||
253 | */ | ||
254 | if (unlikely(task == current && !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) { | ||
255 | printk(KERN_ERR "get_tls_entry: task with pid %d got here " | ||
256 | "without flushed TLS.", current->pid); | ||
257 | } | ||
258 | |||
259 | return 0; | ||
260 | clear: | ||
261 | /* When the TLS entry has not been set, the values read to user in the | ||
262 | * tls_array are 0 (because it's cleared at boot, see | ||
263 | * arch/i386/kernel/head.S:cpu_gdt_table). Emulate that. | ||
264 | */ | ||
265 | clear_user_desc(info); | ||
266 | info->entry_number = idx; | ||
267 | goto out; | ||
268 | } | ||
269 | |||
270 | asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc) | ||
271 | { | ||
272 | struct user_desc info; | ||
273 | int idx, ret; | ||
274 | |||
275 | if (!host_supports_tls) | ||
276 | return -ENOSYS; | ||
277 | |||
278 | if (copy_from_user(&info, user_desc, sizeof(info))) | ||
279 | return -EFAULT; | ||
280 | |||
281 | idx = info.entry_number; | ||
282 | |||
283 | if (idx == -1) { | ||
284 | idx = get_free_idx(current); | ||
285 | if (idx < 0) | ||
286 | return idx; | ||
287 | info.entry_number = idx; | ||
288 | /* Tell the user which slot we chose for him.*/ | ||
289 | if (put_user(idx, &user_desc->entry_number)) | ||
290 | return -EFAULT; | ||
291 | } | ||
292 | |||
293 | ret = CHOOSE_MODE_PROC(do_set_thread_area_tt, do_set_thread_area_skas, &info); | ||
294 | if (ret) | ||
295 | return ret; | ||
296 | return set_tls_entry(current, &info, idx, 1); | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * Perform set_thread_area on behalf of the traced child. | ||
301 | * Note: error handling is not done on the deferred load, and this differ from | ||
302 | * i386. However the only possible error are caused by bugs. | ||
303 | */ | ||
304 | int ptrace_set_thread_area(struct task_struct *child, int idx, | ||
305 | struct user_desc __user *user_desc) | ||
306 | { | ||
307 | struct user_desc info; | ||
308 | |||
309 | if (!host_supports_tls) | ||
310 | return -EIO; | ||
311 | |||
312 | if (copy_from_user(&info, user_desc, sizeof(info))) | ||
313 | return -EFAULT; | ||
314 | |||
315 | return set_tls_entry(child, &info, idx, 0); | ||
316 | } | ||
317 | |||
318 | asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc) | ||
319 | { | ||
320 | struct user_desc info; | ||
321 | int idx, ret; | ||
322 | |||
323 | if (!host_supports_tls) | ||
324 | return -ENOSYS; | ||
325 | |||
326 | if (get_user(idx, &user_desc->entry_number)) | ||
327 | return -EFAULT; | ||
328 | |||
329 | ret = get_tls_entry(current, &info, idx); | ||
330 | if (ret < 0) | ||
331 | goto out; | ||
332 | |||
333 | if (copy_to_user(user_desc, &info, sizeof(info))) | ||
334 | ret = -EFAULT; | ||
335 | |||
336 | out: | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * Perform get_thread_area on behalf of the traced child. | ||
342 | */ | ||
343 | int ptrace_get_thread_area(struct task_struct *child, int idx, | ||
344 | struct user_desc __user *user_desc) | ||
345 | { | ||
346 | struct user_desc info; | ||
347 | int ret; | ||
348 | |||
349 | if (!host_supports_tls) | ||
350 | return -EIO; | ||
351 | |||
352 | ret = get_tls_entry(child, &info, idx); | ||
353 | if (ret < 0) | ||
354 | goto out; | ||
355 | |||
356 | if (copy_to_user(user_desc, &info, sizeof(info))) | ||
357 | ret = -EFAULT; | ||
358 | out: | ||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | |||
363 | /* XXX: This part is probably common to i386 and x86-64. Don't create a common | ||
364 | * file for now, do that when implementing x86-64 support.*/ | ||
365 | static int __init __setup_host_supports_tls(void) { | ||
366 | check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min); | ||
367 | if (host_supports_tls) { | ||
368 | printk(KERN_INFO "Host TLS support detected\n"); | ||
369 | printk(KERN_INFO "Detected host type: "); | ||
370 | switch (host_gdt_entry_tls_min) { | ||
371 | case GDT_ENTRY_TLS_MIN_I386: | ||
372 | printk("i386\n"); | ||
373 | break; | ||
374 | case GDT_ENTRY_TLS_MIN_X86_64: | ||
375 | printk("x86_64\n"); | ||
376 | break; | ||
377 | } | ||
378 | } else | ||
379 | printk(KERN_ERR " Host TLS support NOT detected! " | ||
380 | "TLS support inside UML will not work\n"); | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | __initcall(__setup_host_supports_tls); | ||
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index a351091fbd..b5fc22babd 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile | |||
@@ -4,31 +4,23 @@ | |||
4 | # Licensed under the GPL | 4 | # Licensed under the GPL |
5 | # | 5 | # |
6 | 6 | ||
7 | #XXX: why into lib-y? | 7 | obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ |
8 | lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o ldt.o mem.o memcpy.o \ | 8 | sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o ksyms.o \ |
9 | ptrace.o ptrace_user.o sigcontext.o signal.o syscalls.o \ | 9 | tls.o |
10 | syscall_table.o sysrq.o thunk.o | ||
11 | lib-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o | ||
12 | 10 | ||
13 | obj-y := ksyms.o | 11 | obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o |
14 | obj-$(CONFIG_MODULES) += module.o um_module.o | 12 | obj-$(CONFIG_MODULES) += um_module.o |
15 | 13 | ||
16 | USER_OBJS := ptrace_user.o sigcontext.o stub_segv.o | 14 | subarch-obj-y = lib/bitops.o lib/csum-partial.o lib/memcpy.o lib/thunk.o |
15 | subarch-obj-$(CONFIG_MODULES) += kernel/module.o | ||
17 | 16 | ||
18 | SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c ldt.c memcpy.S \ | 17 | ldt-y = ../sys-i386/ldt.o |
19 | thunk.S module.c | ||
20 | 18 | ||
21 | include arch/um/scripts/Makefile.rules | 19 | USER_OBJS := ptrace_user.o sigcontext.o stub_segv.o |
22 | 20 | ||
23 | bitops.c-dir = lib | 21 | include arch/um/scripts/Makefile.rules |
24 | csum-copy.S-dir = lib | ||
25 | csum-partial.c-dir = lib | ||
26 | csum-wrappers.c-dir = lib | ||
27 | ldt.c-dir = /arch/um/sys-i386 | ||
28 | memcpy.S-dir = lib | ||
29 | thunk.S-dir = lib | ||
30 | module.c-dir = kernel | ||
31 | 22 | ||
32 | $(obj)/stub_segv.o: _c_flags = $(call unprofile,$(CFLAGS)) | 23 | extra-$(CONFIG_MODE_TT) += unmap.o |
33 | 24 | ||
34 | include arch/um/scripts/Makefile.unmap | 25 | $(obj)/stub_segv.o $(obj)/unmap.o: \ |
26 | _c_flags = $(call unprofile,$(CFLAGS)) | ||
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index e75c4e1838..a4c46a8af0 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c | |||
@@ -137,7 +137,7 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | |||
137 | * delivery. The sp passed in is the original, and this needs | 137 | * delivery. The sp passed in is the original, and this needs |
138 | * to be restored, so we stick it in separately. | 138 | * to be restored, so we stick it in separately. |
139 | */ | 139 | */ |
140 | err |= copy_to_user(&SC_SP(to), sp, sizeof(sp)); | 140 | err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp)); |
141 | 141 | ||
142 | if(from_fp != NULL){ | 142 | if(from_fp != NULL){ |
143 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); | 143 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); |
diff --git a/arch/um/sys-x86_64/tls.c b/arch/um/sys-x86_64/tls.c new file mode 100644 index 0000000000..ce1bf1b81c --- /dev/null +++ b/arch/um/sys-x86_64/tls.c | |||
@@ -0,0 +1,14 @@ | |||
1 | #include "linux/sched.h" | ||
2 | |||
3 | void debug_arch_force_load_TLS(void) | ||
4 | { | ||
5 | } | ||
6 | |||
7 | void clear_flushed_tls(struct task_struct *task) | ||
8 | { | ||
9 | } | ||
10 | |||
11 | int arch_copy_tls(struct task_struct *t) | ||
12 | { | ||
13 | return 0; | ||
14 | } | ||