diff options
Diffstat (limited to 'arch/um')
49 files changed, 985 insertions, 345 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 5982fe2753e0..05fbb20636cb 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 8d14c7a831be..24790bed2054 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' \ |
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index 38df311e75dc..dfd88b652fbe 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/daemon_kern.c b/arch/um/drivers/daemon_kern.c index a61b7b46bc02..53d09ed78b42 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 49acb2badf32..d18a974735e6 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 59602b81b240..37232f908cd7 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 c9b078fba03e..3a7af18cf944 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 1488816588ea..28e3760e8b98 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" |
@@ -347,6 +349,142 @@ 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 | INIT_LIST_HEAD(&unplugged->list); | ||
419 | list_add(&unplugged->list, &unplugged_pages); | ||
420 | unplug_index = 0; | ||
421 | } | ||
422 | else { | ||
423 | struct list_head *entry = unplugged_pages.next; | ||
424 | addr = unplugged; | ||
425 | |||
426 | unplugged = list_entry(entry, | ||
427 | struct unplugged_pages, | ||
428 | list); | ||
429 | unplugged->pages[unplug_index++] = addr; | ||
430 | err = os_drop_memory(addr, PAGE_SIZE); | ||
431 | if(err) | ||
432 | printk("Failed to release memory - " | ||
433 | "errno = %d\n", err); | ||
434 | } | ||
435 | |||
436 | unplugged_pages_count++; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | err = 0; | ||
441 | out: | ||
442 | return err; | ||
443 | } | ||
444 | |||
445 | static int mem_get_config(char *name, char *str, int size, char **error_out) | ||
446 | { | ||
447 | char buf[sizeof("18446744073709551615")]; | ||
448 | int len = 0; | ||
449 | |||
450 | sprintf(buf, "%ld", uml_physmem); | ||
451 | CONFIG_CHUNK(str, size, len, buf, 1); | ||
452 | |||
453 | return len; | ||
454 | } | ||
455 | |||
456 | static int mem_id(char **str, int *start_out, int *end_out) | ||
457 | { | ||
458 | *start_out = 0; | ||
459 | *end_out = 0; | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static int mem_remove(int n) | ||
465 | { | ||
466 | return -EBUSY; | ||
467 | } | ||
468 | |||
469 | static struct mc_device mem_mc = { | ||
470 | .name = "mem", | ||
471 | .config = mem_config, | ||
472 | .get_config = mem_get_config, | ||
473 | .id = mem_id, | ||
474 | .remove = mem_remove, | ||
475 | }; | ||
476 | |||
477 | static int mem_mc_init(void) | ||
478 | { | ||
479 | if(can_drop_memory()) | ||
480 | mconsole_register_dev(&mem_mc); | ||
481 | else printk("Can't release memory to the host - memory hotplug won't " | ||
482 | "be supported\n"); | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | __initcall(mem_mc_init); | ||
487 | |||
350 | #define CONFIG_BUF_SIZE 64 | 488 | #define CONFIG_BUF_SIZE 64 |
351 | 489 | ||
352 | static void mconsole_get_config(int (*get_config)(char *, char *, int, | 490 | static void mconsole_get_config(int (*get_config)(char *, char *, int, |
@@ -478,7 +616,7 @@ static void console_write(struct console *console, const char *string, | |||
478 | return; | 616 | return; |
479 | 617 | ||
480 | while(1){ | 618 | while(1){ |
481 | n = min(len, ARRAY_SIZE(console_buf) - console_index); | 619 | n = min((size_t)len, ARRAY_SIZE(console_buf) - console_index); |
482 | strncpy(&console_buf[console_index], string, n); | 620 | strncpy(&console_buf[console_index], string, n); |
483 | console_index += n; | 621 | console_index += n; |
484 | string += n; | 622 | string += n; |
diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c index 07c80f2156ef..466ff2c2f918 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 a62f5ef445cf..163ee0d5f75e 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 33d7982be5d3..95e50c943e14 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/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 0336575d2448..0897852b09a3 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 07176d92e1c9..42557130a408 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h | |||
@@ -116,7 +116,11 @@ 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 arch_switch_to_tt(struct task_struct *from, struct task_struct *to); | ||
121 | |||
122 | extern void arch_switch_to_skas(struct task_struct *from, struct task_struct *to); | ||
123 | |||
120 | extern void free_irq(unsigned int, void *); | 124 | extern void free_irq(unsigned int, void *); |
121 | extern int cpu(void); | 125 | extern int cpu(void); |
122 | 126 | ||
diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 6f4d680dc1d4..6ac0f8252e21 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 a1064c5823bf..a54514d2cc3a 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 d3d1bc6074ef..f88856c28a66 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 7d3d202d7fff..052bb061a978 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 c8ee9559f3ab..6670cc992ecb 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 000000000000..918fd3c5ff9c --- /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 000000000000..35f19f25bd3b --- /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/user_util.h b/arch/um/include/user_util.h index 992a7e1e0fca..fe0c29b5144d 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 | ||
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index 1ca84319317d..c0cb627bf594 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/mem.c b/arch/um/kernel/mem.c index 92cce96b5e24..44e41a35f000 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 3113cab8675e..f6a5a502120b 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 98e09395c093..60d2eda995c1 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 3f70a2e12f06..2135eaf98a93 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 8e1a3501ff46..37d3978337d8 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 d56046c2aba2..02f6d4d8dc3a 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 295c1ac817b3..a9c1443fc548 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 1659386b42bb..f4bfc4c7ccac 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 6ae4b19d9f50..768606bec233 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/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index 4202b9ebad4c..190009a6f89c 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/mem.c b/arch/um/os-Linux/mem.c index 9d7d69a523bb..6ab372da9657 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c | |||
@@ -121,36 +121,11 @@ int create_tmp_file(unsigned long long len) | |||
121 | return(fd); | 121 | return(fd); |
122 | } | 122 | } |
123 | 123 | ||
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) | 124 | int create_mem_file(unsigned long long len) |
148 | { | 125 | { |
149 | int err, fd; | 126 | int err, fd; |
150 | 127 | ||
151 | if(have_devanon) | 128 | fd = create_tmp_file(len); |
152 | fd = create_anon_file(len); | ||
153 | else fd = create_tmp_file(len); | ||
154 | 129 | ||
155 | err = os_set_exec_close(fd, 1); | 130 | err = os_set_exec_close(fd, 1); |
156 | if(err < 0){ | 131 | if(err < 0){ |
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index d261888f39c4..8176b0b52047 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/start_up.c b/arch/um/os-Linux/start_up.c index 32753131f8d8..387e26af301a 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 340ef26f5944..b3213613c41c 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 000000000000..ba21f0e04a2f --- /dev/null +++ b/arch/um/os-Linux/sys-i386/tls.c | |||
@@ -0,0 +1,33 @@ | |||
1 | #include <linux/unistd.h> | ||
2 | #include "sysdep/tls.h" | ||
3 | #include "user_util.h" | ||
4 | |||
5 | static _syscall1(int, get_thread_area, user_desc_t *, u_info); | ||
6 | |||
7 | /* Checks whether host supports TLS, and sets *tls_min according to the value | ||
8 | * valid on the host. | ||
9 | * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ | ||
10 | void check_host_supports_tls(int *supports_tls, int *tls_min) { | ||
11 | /* Values for x86 and x86_64.*/ | ||
12 | int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64}; | ||
13 | int i; | ||
14 | |||
15 | for (i = 0; i < ARRAY_SIZE(val); i++) { | ||
16 | user_desc_t info; | ||
17 | info.entry_number = val[i]; | ||
18 | |||
19 | if (get_thread_area(&info) == 0) { | ||
20 | *tls_min = val[i]; | ||
21 | *supports_tls = 1; | ||
22 | return; | ||
23 | } else { | ||
24 | if (errno == EINVAL) | ||
25 | continue; | ||
26 | else if (errno == ENOSYS) | ||
27 | *supports_tls = 0; | ||
28 | return; | ||
29 | } | ||
30 | } | ||
31 | |||
32 | *supports_tls = 0; | ||
33 | } | ||
diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c new file mode 100644 index 000000000000..9cb09a45546b --- /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/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 2e41cabd3d93..b696b451774c 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules | |||
@@ -20,25 +20,7 @@ define unprofile | |||
20 | $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) | 20 | $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) |
21 | endef | 21 | endef |
22 | 22 | ||
23 | 23 | ifdef subarch-obj-y | |
24 | # cmd_make_link checks to see if the $(foo-dir) variable starts with a /. If | 24 | obj-y += subarch.o |
25 | # so, it's considered to be a path relative to $(srcdir) rather than | 25 | subarch-y = $(addprefix ../../$(SUBARCH)/,$(subarch-obj-y)) |
26 | # $(srcdir)/arch/$(SUBARCH). This is because x86_64 wants to get ldt.c from | 26 | 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 b2165188d942..000000000000 --- 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 f5fd5b0156d0..98b20b7bba4f 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/ptrace.c b/arch/um/sys-i386/ptrace.c index 8032a105949a..6028bc7cc01b 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 7c376c95de50..9f3bd8ed78f5 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; |
@@ -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 33a40f5ef0d2..f5d0e1c37ea2 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 | ||
@@ -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 ad75c27afe38..1ff61474b25c 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 83e9be820a86..749dd1bfe60f 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 000000000000..a3188e861cc7 --- /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 1; | ||
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 a351091fbd99..b5fc22babddf 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/tls.c b/arch/um/sys-x86_64/tls.c new file mode 100644 index 000000000000..ce1bf1b81c43 --- /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 | } | ||