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 | } | ||
