diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/um/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/um/asm/barrier.h | 11 | ||||
-rw-r--r-- | arch/x86/um/asm/elf.h | 2 | ||||
-rw-r--r-- | arch/x86/um/ldt.c | 227 | ||||
-rw-r--r-- | arch/x86/um/shared/sysdep/faultinfo_32.h | 3 | ||||
-rw-r--r-- | arch/x86/um/shared/sysdep/faultinfo_64.h | 3 | ||||
-rw-r--r-- | arch/x86/um/shared/sysdep/skas_ptrace.h | 22 |
7 files changed, 49 insertions, 220 deletions
diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile index eafa324eb7a5..acb384d24669 100644 --- a/arch/x86/um/Makefile +++ b/arch/x86/um/Makefile | |||
@@ -21,7 +21,6 @@ obj-$(CONFIG_BINFMT_ELF) += elfcore.o | |||
21 | 21 | ||
22 | subarch-y = ../lib/string_32.o ../lib/atomic64_32.o ../lib/atomic64_cx8_32.o | 22 | subarch-y = ../lib/string_32.o ../lib/atomic64_32.o ../lib/atomic64_cx8_32.o |
23 | subarch-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += ../lib/rwsem.o | 23 | subarch-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += ../lib/rwsem.o |
24 | subarch-$(CONFIG_HIGHMEM) += ../mm/highmem_32.o | ||
25 | 24 | ||
26 | else | 25 | else |
27 | 26 | ||
diff --git a/arch/x86/um/asm/barrier.h b/arch/x86/um/asm/barrier.h index 8ffd2146fa6a..7e8a1a650435 100644 --- a/arch/x86/um/asm/barrier.h +++ b/arch/x86/um/asm/barrier.h | |||
@@ -36,22 +36,11 @@ | |||
36 | #endif /* CONFIG_X86_PPRO_FENCE */ | 36 | #endif /* CONFIG_X86_PPRO_FENCE */ |
37 | #define dma_wmb() barrier() | 37 | #define dma_wmb() barrier() |
38 | 38 | ||
39 | #ifdef CONFIG_SMP | ||
40 | |||
41 | #define smp_mb() mb() | ||
42 | #define smp_rmb() dma_rmb() | ||
43 | #define smp_wmb() barrier() | ||
44 | #define set_mb(var, value) do { (void)xchg(&var, value); } while (0) | ||
45 | |||
46 | #else /* CONFIG_SMP */ | ||
47 | |||
48 | #define smp_mb() barrier() | 39 | #define smp_mb() barrier() |
49 | #define smp_rmb() barrier() | 40 | #define smp_rmb() barrier() |
50 | #define smp_wmb() barrier() | 41 | #define smp_wmb() barrier() |
51 | #define set_mb(var, value) do { var = value; barrier(); } while (0) | 42 | #define set_mb(var, value) do { var = value; barrier(); } while (0) |
52 | 43 | ||
53 | #endif /* CONFIG_SMP */ | ||
54 | |||
55 | #define read_barrier_depends() do { } while (0) | 44 | #define read_barrier_depends() do { } while (0) |
56 | #define smp_read_barrier_depends() do { } while (0) | 45 | #define smp_read_barrier_depends() do { } while (0) |
57 | 46 | ||
diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h index 25a1022dd793..0a656b727b1a 100644 --- a/arch/x86/um/asm/elf.h +++ b/arch/x86/um/asm/elf.h | |||
@@ -210,7 +210,7 @@ extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu); | |||
210 | 210 | ||
211 | #define ELF_EXEC_PAGESIZE 4096 | 211 | #define ELF_EXEC_PAGESIZE 4096 |
212 | 212 | ||
213 | #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) | 213 | #define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) |
214 | 214 | ||
215 | extern long elf_aux_hwcap; | 215 | extern long elf_aux_hwcap; |
216 | #define ELF_HWCAP (elf_aux_hwcap) | 216 | #define ELF_HWCAP (elf_aux_hwcap) |
diff --git a/arch/x86/um/ldt.c b/arch/x86/um/ldt.c index 8e08176f0bcb..5c0b711d2433 100644 --- a/arch/x86/um/ldt.c +++ b/arch/x86/um/ldt.c | |||
@@ -8,9 +8,7 @@ | |||
8 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
9 | #include <asm/unistd.h> | 9 | #include <asm/unistd.h> |
10 | #include <os.h> | 10 | #include <os.h> |
11 | #include <proc_mm.h> | ||
12 | #include <skas.h> | 11 | #include <skas.h> |
13 | #include <skas_ptrace.h> | ||
14 | #include <sysdep/tls.h> | 12 | #include <sysdep/tls.h> |
15 | 13 | ||
16 | extern int modify_ldt(int func, void *ptr, unsigned long bytecount); | 14 | extern int modify_ldt(int func, void *ptr, unsigned long bytecount); |
@@ -19,105 +17,20 @@ static long write_ldt_entry(struct mm_id *mm_idp, int func, | |||
19 | struct user_desc *desc, void **addr, int done) | 17 | struct user_desc *desc, void **addr, int done) |
20 | { | 18 | { |
21 | long res; | 19 | long res; |
22 | 20 | void *stub_addr; | |
23 | if (proc_mm) { | 21 | res = syscall_stub_data(mm_idp, (unsigned long *)desc, |
24 | /* | 22 | (sizeof(*desc) + sizeof(long) - 1) & |
25 | * This is a special handling for the case, that the mm to | 23 | ~(sizeof(long) - 1), |
26 | * modify isn't current->active_mm. | 24 | addr, &stub_addr); |
27 | * If this is called directly by modify_ldt, | 25 | if (!res) { |
28 | * (current->active_mm->context.skas.u == mm_idp) | 26 | unsigned long args[] = { func, |
29 | * will be true. So no call to __switch_mm(mm_idp) is done. | 27 | (unsigned long)stub_addr, |
30 | * If this is called in case of init_new_ldt or PTRACE_LDT, | 28 | sizeof(*desc), |
31 | * mm_idp won't belong to current->active_mm, but child->mm. | 29 | 0, 0, 0 }; |
32 | * So we need to switch child's mm into our userspace, then | 30 | res = run_syscall_stub(mm_idp, __NR_modify_ldt, args, |
33 | * later switch back. | 31 | 0, addr, done); |
34 | * | ||
35 | * Note: I'm unsure: should interrupts be disabled here? | ||
36 | */ | ||
37 | if (!current->active_mm || current->active_mm == &init_mm || | ||
38 | mm_idp != ¤t->active_mm->context.id) | ||
39 | __switch_mm(mm_idp); | ||
40 | } | ||
41 | |||
42 | if (ptrace_ldt) { | ||
43 | struct ptrace_ldt ldt_op = (struct ptrace_ldt) { | ||
44 | .func = func, | ||
45 | .ptr = desc, | ||
46 | .bytecount = sizeof(*desc)}; | ||
47 | u32 cpu; | ||
48 | int pid; | ||
49 | |||
50 | if (!proc_mm) | ||
51 | pid = mm_idp->u.pid; | ||
52 | else { | ||
53 | cpu = get_cpu(); | ||
54 | pid = userspace_pid[cpu]; | ||
55 | } | ||
56 | |||
57 | res = os_ptrace_ldt(pid, 0, (unsigned long) &ldt_op); | ||
58 | |||
59 | if (proc_mm) | ||
60 | put_cpu(); | ||
61 | } | ||
62 | else { | ||
63 | void *stub_addr; | ||
64 | res = syscall_stub_data(mm_idp, (unsigned long *)desc, | ||
65 | (sizeof(*desc) + sizeof(long) - 1) & | ||
66 | ~(sizeof(long) - 1), | ||
67 | addr, &stub_addr); | ||
68 | if (!res) { | ||
69 | unsigned long args[] = { func, | ||
70 | (unsigned long)stub_addr, | ||
71 | sizeof(*desc), | ||
72 | 0, 0, 0 }; | ||
73 | res = run_syscall_stub(mm_idp, __NR_modify_ldt, args, | ||
74 | 0, addr, done); | ||
75 | } | ||
76 | } | 32 | } |
77 | 33 | ||
78 | if (proc_mm) { | ||
79 | /* | ||
80 | * This is the second part of special handling, that makes | ||
81 | * PTRACE_LDT possible to implement. | ||
82 | */ | ||
83 | if (current->active_mm && current->active_mm != &init_mm && | ||
84 | mm_idp != ¤t->active_mm->context.id) | ||
85 | __switch_mm(¤t->active_mm->context.id); | ||
86 | } | ||
87 | |||
88 | return res; | ||
89 | } | ||
90 | |||
91 | static long read_ldt_from_host(void __user * ptr, unsigned long bytecount) | ||
92 | { | ||
93 | int res, n; | ||
94 | struct ptrace_ldt ptrace_ldt = (struct ptrace_ldt) { | ||
95 | .func = 0, | ||
96 | .bytecount = bytecount, | ||
97 | .ptr = kmalloc(bytecount, GFP_KERNEL)}; | ||
98 | u32 cpu; | ||
99 | |||
100 | if (ptrace_ldt.ptr == NULL) | ||
101 | return -ENOMEM; | ||
102 | |||
103 | /* | ||
104 | * This is called from sys_modify_ldt only, so userspace_pid gives | ||
105 | * us the right number | ||
106 | */ | ||
107 | |||
108 | cpu = get_cpu(); | ||
109 | res = os_ptrace_ldt(userspace_pid[cpu], 0, (unsigned long) &ptrace_ldt); | ||
110 | put_cpu(); | ||
111 | if (res < 0) | ||
112 | goto out; | ||
113 | |||
114 | n = copy_to_user(ptr, ptrace_ldt.ptr, res); | ||
115 | if (n != 0) | ||
116 | res = -EFAULT; | ||
117 | |||
118 | out: | ||
119 | kfree(ptrace_ldt.ptr); | ||
120 | |||
121 | return res; | 34 | return res; |
122 | } | 35 | } |
123 | 36 | ||
@@ -145,9 +58,6 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) | |||
145 | bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; | 58 | bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; |
146 | err = bytecount; | 59 | err = bytecount; |
147 | 60 | ||
148 | if (ptrace_ldt) | ||
149 | return read_ldt_from_host(ptr, bytecount); | ||
150 | |||
151 | mutex_lock(&ldt->lock); | 61 | mutex_lock(&ldt->lock); |
152 | if (ldt->entry_count <= LDT_DIRECT_ENTRIES) { | 62 | if (ldt->entry_count <= LDT_DIRECT_ENTRIES) { |
153 | size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES; | 63 | size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES; |
@@ -229,17 +139,11 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func) | |||
229 | goto out; | 139 | goto out; |
230 | } | 140 | } |
231 | 141 | ||
232 | if (!ptrace_ldt) | 142 | mutex_lock(&ldt->lock); |
233 | mutex_lock(&ldt->lock); | ||
234 | 143 | ||
235 | err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); | 144 | err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); |
236 | if (err) | 145 | if (err) |
237 | goto out_unlock; | 146 | goto out_unlock; |
238 | else if (ptrace_ldt) { | ||
239 | /* With PTRACE_LDT available, this is used as a flag only */ | ||
240 | ldt->entry_count = 1; | ||
241 | goto out; | ||
242 | } | ||
243 | 147 | ||
244 | if (ldt_info.entry_number >= ldt->entry_count && | 148 | if (ldt_info.entry_number >= ldt->entry_count && |
245 | ldt_info.entry_number >= LDT_DIRECT_ENTRIES) { | 149 | ldt_info.entry_number >= LDT_DIRECT_ENTRIES) { |
@@ -393,91 +297,56 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm) | |||
393 | int i; | 297 | int i; |
394 | long page, err=0; | 298 | long page, err=0; |
395 | void *addr = NULL; | 299 | void *addr = NULL; |
396 | struct proc_mm_op copy; | ||
397 | 300 | ||
398 | 301 | ||
399 | if (!ptrace_ldt) | 302 | mutex_init(&new_mm->arch.ldt.lock); |
400 | mutex_init(&new_mm->arch.ldt.lock); | ||
401 | 303 | ||
402 | if (!from_mm) { | 304 | if (!from_mm) { |
403 | memset(&desc, 0, sizeof(desc)); | 305 | memset(&desc, 0, sizeof(desc)); |
404 | /* | 306 | /* |
405 | * We have to initialize a clean ldt. | 307 | * Now we try to retrieve info about the ldt, we |
308 | * inherited from the host. All ldt-entries found | ||
309 | * will be reset in the following loop | ||
406 | */ | 310 | */ |
407 | if (proc_mm) { | 311 | ldt_get_host_info(); |
408 | /* | 312 | for (num_p=host_ldt_entries; *num_p != -1; num_p++) { |
409 | * If the new mm was created using proc_mm, host's | 313 | desc.entry_number = *num_p; |
410 | * default-ldt currently is assigned, which normally | 314 | err = write_ldt_entry(&new_mm->id, 1, &desc, |
411 | * contains the call-gates for lcall7 and lcall27. | 315 | &addr, *(num_p + 1) == -1); |
412 | * To remove these gates, we simply write an empty | 316 | if (err) |
413 | * entry as number 0 to the host. | 317 | break; |
414 | */ | ||
415 | err = write_ldt_entry(&new_mm->id, 1, &desc, &addr, 1); | ||
416 | } | ||
417 | else{ | ||
418 | /* | ||
419 | * Now we try to retrieve info about the ldt, we | ||
420 | * inherited from the host. All ldt-entries found | ||
421 | * will be reset in the following loop | ||
422 | */ | ||
423 | ldt_get_host_info(); | ||
424 | for (num_p=host_ldt_entries; *num_p != -1; num_p++) { | ||
425 | desc.entry_number = *num_p; | ||
426 | err = write_ldt_entry(&new_mm->id, 1, &desc, | ||
427 | &addr, *(num_p + 1) == -1); | ||
428 | if (err) | ||
429 | break; | ||
430 | } | ||
431 | } | 318 | } |
432 | new_mm->arch.ldt.entry_count = 0; | 319 | new_mm->arch.ldt.entry_count = 0; |
433 | 320 | ||
434 | goto out; | 321 | goto out; |
435 | } | 322 | } |
436 | 323 | ||
437 | if (proc_mm) { | 324 | /* |
438 | /* | 325 | * Our local LDT is used to supply the data for |
439 | * We have a valid from_mm, so we now have to copy the LDT of | 326 | * modify_ldt(READLDT), if PTRACE_LDT isn't available, |
440 | * from_mm to new_mm, because using proc_mm an new mm with | 327 | * i.e., we have to use the stub for modify_ldt, which |
441 | * an empty/default LDT was created in new_mm() | 328 | * can't handle the big read buffer of up to 64kB. |
442 | */ | 329 | */ |
443 | copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, | 330 | mutex_lock(&from_mm->arch.ldt.lock); |
444 | .u = | 331 | if (from_mm->arch.ldt.entry_count <= LDT_DIRECT_ENTRIES) |
445 | { .copy_segments = | 332 | memcpy(new_mm->arch.ldt.u.entries, from_mm->arch.ldt.u.entries, |
446 | from_mm->id.u.mm_fd } } ); | 333 | sizeof(new_mm->arch.ldt.u.entries)); |
447 | i = os_write_file(new_mm->id.u.mm_fd, ©, sizeof(copy)); | 334 | else { |
448 | if (i != sizeof(copy)) | 335 | i = from_mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE; |
449 | printk(KERN_ERR "new_mm : /proc/mm copy_segments " | 336 | while (i-->0) { |
450 | "failed, err = %d\n", -i); | 337 | page = __get_free_page(GFP_KERNEL|__GFP_ZERO); |
451 | } | 338 | if (!page) { |
452 | 339 | err = -ENOMEM; | |
453 | if (!ptrace_ldt) { | 340 | break; |
454 | /* | ||
455 | * Our local LDT is used to supply the data for | ||
456 | * modify_ldt(READLDT), if PTRACE_LDT isn't available, | ||
457 | * i.e., we have to use the stub for modify_ldt, which | ||
458 | * can't handle the big read buffer of up to 64kB. | ||
459 | */ | ||
460 | mutex_lock(&from_mm->arch.ldt.lock); | ||
461 | if (from_mm->arch.ldt.entry_count <= LDT_DIRECT_ENTRIES) | ||
462 | memcpy(new_mm->arch.ldt.u.entries, from_mm->arch.ldt.u.entries, | ||
463 | sizeof(new_mm->arch.ldt.u.entries)); | ||
464 | else { | ||
465 | i = from_mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE; | ||
466 | while (i-->0) { | ||
467 | page = __get_free_page(GFP_KERNEL|__GFP_ZERO); | ||
468 | if (!page) { | ||
469 | err = -ENOMEM; | ||
470 | break; | ||
471 | } | ||
472 | new_mm->arch.ldt.u.pages[i] = | ||
473 | (struct ldt_entry *) page; | ||
474 | memcpy(new_mm->arch.ldt.u.pages[i], | ||
475 | from_mm->arch.ldt.u.pages[i], PAGE_SIZE); | ||
476 | } | 341 | } |
342 | new_mm->arch.ldt.u.pages[i] = | ||
343 | (struct ldt_entry *) page; | ||
344 | memcpy(new_mm->arch.ldt.u.pages[i], | ||
345 | from_mm->arch.ldt.u.pages[i], PAGE_SIZE); | ||
477 | } | 346 | } |
478 | new_mm->arch.ldt.entry_count = from_mm->arch.ldt.entry_count; | ||
479 | mutex_unlock(&from_mm->arch.ldt.lock); | ||
480 | } | 347 | } |
348 | new_mm->arch.ldt.entry_count = from_mm->arch.ldt.entry_count; | ||
349 | mutex_unlock(&from_mm->arch.ldt.lock); | ||
481 | 350 | ||
482 | out: | 351 | out: |
483 | return err; | 352 | return err; |
@@ -488,7 +357,7 @@ void free_ldt(struct mm_context *mm) | |||
488 | { | 357 | { |
489 | int i; | 358 | int i; |
490 | 359 | ||
491 | if (!ptrace_ldt && mm->arch.ldt.entry_count > LDT_DIRECT_ENTRIES) { | 360 | if (mm->arch.ldt.entry_count > LDT_DIRECT_ENTRIES) { |
492 | i = mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE; | 361 | i = mm->arch.ldt.entry_count / LDT_ENTRIES_PER_PAGE; |
493 | while (i-- > 0) | 362 | while (i-- > 0) |
494 | free_page((long) mm->arch.ldt.u.pages[i]); | 363 | free_page((long) mm->arch.ldt.u.pages[i]); |
diff --git a/arch/x86/um/shared/sysdep/faultinfo_32.h b/arch/x86/um/shared/sysdep/faultinfo_32.h index a26086b8a800..b6f2437ec29c 100644 --- a/arch/x86/um/shared/sysdep/faultinfo_32.h +++ b/arch/x86/um/shared/sysdep/faultinfo_32.h | |||
@@ -27,9 +27,6 @@ struct faultinfo { | |||
27 | /* This is Page Fault */ | 27 | /* This is Page Fault */ |
28 | #define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) | 28 | #define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) |
29 | 29 | ||
30 | /* SKAS3 has no trap_no on i386, but get_skas_faultinfo() sets it to 0. */ | ||
31 | #define SEGV_MAYBE_FIXABLE(fi) ((fi)->trap_no == 0 && ptrace_faultinfo) | ||
32 | |||
33 | #define PTRACE_FULL_FAULTINFO 0 | 30 | #define PTRACE_FULL_FAULTINFO 0 |
34 | 31 | ||
35 | #endif | 32 | #endif |
diff --git a/arch/x86/um/shared/sysdep/faultinfo_64.h b/arch/x86/um/shared/sysdep/faultinfo_64.h index f811cbe15d62..ee88f88974ea 100644 --- a/arch/x86/um/shared/sysdep/faultinfo_64.h +++ b/arch/x86/um/shared/sysdep/faultinfo_64.h | |||
@@ -27,9 +27,6 @@ struct faultinfo { | |||
27 | /* This is Page Fault */ | 27 | /* This is Page Fault */ |
28 | #define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) | 28 | #define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) |
29 | 29 | ||
30 | /* No broken SKAS API, which doesn't pass trap_no, here. */ | ||
31 | #define SEGV_MAYBE_FIXABLE(fi) 0 | ||
32 | |||
33 | #define PTRACE_FULL_FAULTINFO 1 | 30 | #define PTRACE_FULL_FAULTINFO 1 |
34 | 31 | ||
35 | #endif | 32 | #endif |
diff --git a/arch/x86/um/shared/sysdep/skas_ptrace.h b/arch/x86/um/shared/sysdep/skas_ptrace.h deleted file mode 100644 index 453febe98993..000000000000 --- a/arch/x86/um/shared/sysdep/skas_ptrace.h +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SYSDEP_X86_SKAS_PTRACE_H | ||
7 | #define __SYSDEP_X86_SKAS_PTRACE_H | ||
8 | |||
9 | struct ptrace_faultinfo { | ||
10 | int is_write; | ||
11 | unsigned long addr; | ||
12 | }; | ||
13 | |||
14 | struct ptrace_ldt { | ||
15 | int func; | ||
16 | void *ptr; | ||
17 | unsigned long bytecount; | ||
18 | }; | ||
19 | |||
20 | #define PTRACE_LDT 54 | ||
21 | |||
22 | #endif | ||