aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2005-07-07 20:56:49 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-07 21:23:44 -0400
commitd67b569f5f620c0fb95d5212642746b7ba9d29e4 (patch)
treec7ef10c906dd83911e10988c6cea6d7d5644e072 /arch/um/kernel
parent1322ad41513f8f9196801f53cc0851df056f3478 (diff)
[PATCH] uml: skas0 - separate kernel address space on stock hosts
UML has had two modes of operation - an insecure, slow mode (tt mode) in which the kernel is mapped into every process address space which requires no host kernel modifications, and a secure, faster mode (skas mode) in which the UML kernel is in a separate host address space, which requires a patch to the host kernel. This patch implements something very close to skas mode for hosts which don't support skas - I'm calling this skas0. It provides the security of the skas host patch, and some of the performance gains. The two main things that are provided by the skas patch, /proc/mm and PTRACE_FAULTINFO, are implemented in a way that require no host patch. For the remote address space changing stuff (mmap, munmap, and mprotect), we set aside two pages in the process above its stack, one of which contains a little bit of code which can call mmap et al. To update the address space, the system call information (system call number and arguments) are written to the stub page above the code. The %esp is set to the beginning of the data, the %eip is set the the start of the stub, and it repeatedly pops the information into its registers and makes the system call until it sees a system call number of zero. This is to amortize the cost of the context switch across multiple address space updates. When the updates are done, it SIGSTOPs itself, and the kernel process continues what it was doing. For a PTRACE_FAULTINFO replacement, we set up a SIGSEGV handler in the child, and let it handle segfaults rather than nullifying them. The handler is in the same page as the mmap stub. The second page is used as the stack. The handler reads cr2 and err from the sigcontext, sticks them at the base of the stack in a faultinfo struct, and SIGSTOPs itself. The kernel then reads the faultinfo and handles the fault. A complication on x86_64 is that this involves resetting the registers to the segfault values when the process is inside the kill system call. This breaks on x86_64 because %rcx will contain %rip because you tell SYSRET where to return to by putting the value in %rcx. So, this corrupts $rcx on return from the segfault. To work around this, I added an arch_finish_segv, which on x86 does nothing, but which on x86_64 ptraces the child back through the sigreturn. This causes %rcx to be restored by sigreturn and avoids the corruption. Ultimately, I think I will replace this with the trick of having it send itself a blocked signal which will be unblocked by the sigreturn. This will allow it to be stopped just after the sigreturn, and PTRACE_SYSCALLed without all the back-and-forth of PTRACE_SYSCALLing it through sigreturn. This runs on a stock host, so theoretically (and hopefully), tt mode isn't needed any more. We need to make sure that this is better in every way than tt mode, though. I'm concerned about the speed of address space updates and page fault handling, since they involve extra round-trips to the child. We can amortize the round-trip cost for large address space updates by writing all of the operations to the data page and having the child execute them all at the same time. This will help fork and exec, but not page faults, since they involve only one page. I can't think of any way to help page faults, except to add something like PTRACE_FAULTINFO to the host. There is PTRACE_SIGINFO, but UML doesn't use siginfo for SIGSEGV (or anything else) because there isn't enough information in the siginfo struct to handle page faults (the faulting operation type is missing). Adding that would make PTRACE_SIGINFO a usable equivalent to PTRACE_FAULTINFO. As for the code itself: - The system call stub is in arch/um/kernel/sys-$(SUBARCH)/stub.S. It is put in its own section of the binary along with stub_segv_handler in arch/um/kernel/skas/process.c. This is manipulated with run_syscall_stub in arch/um/kernel/skas/mem_user.c. syscall_stub will execute any system call at all, but it's only used for mmap, munmap, and mprotect. - The x86_64 stub calls sigreturn by hand rather than allowing the normal sigreturn to happen, because the normal sigreturn is a SA_RESTORER in UML's address space provided by libc. Needless to say, this is not available in the child's address space. Also, it does a couple of odd pops before that which restore the stack to the state it was in at the time the signal handler was called. - There is a new field in the arch mmu_context, which is now a union. This is the pid to be manipulated rather than the /proc/mm file descriptor. Code which deals with this now checks proc_mm to see whether it should use the usual skas code or the new code. - userspace_tramp is now used to create a new host process for every UML process, rather than one per UML processor. It checks proc_mm and ptrace_faultinfo to decide whether to map in the pages above its stack. - start_userspace now makes CLONE_VM conditional on proc_mm since we need separate address spaces now. - switch_mm_skas now just sets userspace_pid[0] to the new pid rather than PTRACE_SWITCH_MM. There is an addition to userspace which updates its idea of the pid being manipulated each time around the loop. This is important on exec, when the pid will change underneath userspace(). - The stub page has a pte, but it can't be mapped in using tlb_flush because it is part of tlb_flush. This is why it's required for it to be mapped in by userspace_tramp. Other random things: - The stub section in uml.lds.S is page aligned. This page is written out to the backing vm file in setup_physmem because it is mapped from there into user processes. - There's some confusion with TASK_SIZE now that there are a couple of extra pages that the process can't use. TASK_SIZE is considered by the elf code to be the usable process memory, which is reasonable, so it is decreased by two pages. This confuses the definition of USER_PGDS_IN_LAST_PML4, making it too small because of the rounding down of the uneven division. So we round it to the nearest PGDIR_SIZE rather than the lower one. - I added a missing PT_SYSCALL_ARG6_OFFSET macro. - um_mmu.h was made into a userspace-usable file. - proc_mm and ptrace_faultinfo are globals which say whether the host supports these features. - There is a bad interaction between the mm.nr_ptes check at the end of exit_mmap, stack randomization, and skas0. exit_mmap will stop freeing pages at the PGDIR_SIZE boundary after the last vma. If the stack isn't on the last page table page, the last pte page won't be freed, as it should be since the stub ptes are there, and exit_mmap will BUG because there is an unfreed page. To get around this, TASK_SIZE is set to the next lowest PGDIR_SIZE boundary and mm->nr_ptes is decremented after the calls to init_stub_pte. This ensures that we know the process stack (and all other process mappings) will be below the top page table page, and thus we know that mm->nr_ptes will be one too many, and can be decremented. Things that need fixing: - We may need better assurrences that the stub code is PIC. - The stub pte is set up in init_new_context_skas. - alloc_pgdir is probably the right place. Signed-off-by: Jeff Dike <jdike@addtoit.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/um/kernel')
-rw-r--r--arch/um/kernel/dyn.lds.S6
-rw-r--r--arch/um/kernel/physmem.c8
-rw-r--r--arch/um/kernel/process.c28
-rw-r--r--arch/um/kernel/skas/exec_kern.c2
-rw-r--r--arch/um/kernel/skas/include/mm_id.h17
-rw-r--r--arch/um/kernel/skas/include/mmu-skas.h7
-rw-r--r--arch/um/kernel/skas/include/skas.h15
-rw-r--r--arch/um/kernel/skas/mem.c6
-rw-r--r--arch/um/kernel/skas/mem_user.c225
-rw-r--r--arch/um/kernel/skas/mmu.c136
-rw-r--r--arch/um/kernel/skas/process.c153
-rw-r--r--arch/um/kernel/skas/process_kern.c33
-rw-r--r--arch/um/kernel/skas/tlb.c28
-rw-r--r--arch/um/kernel/tlb.c132
-rw-r--r--arch/um/kernel/tt/tlb.c4
-rw-r--r--arch/um/kernel/uml.lds.S7
16 files changed, 577 insertions, 230 deletions
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 715b0838a68c..3942a5f245de 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -67,6 +67,12 @@ SECTIONS
67 *(.stub .text.* .gnu.linkonce.t.*) 67 *(.stub .text.* .gnu.linkonce.t.*)
68 /* .gnu.warning sections are handled specially by elf32.em. */ 68 /* .gnu.warning sections are handled specially by elf32.em. */
69 *(.gnu.warning) 69 *(.gnu.warning)
70
71 . = ALIGN(4096);
72 __syscall_stub_start = .;
73 *(.__syscall_stub*)
74 __syscall_stub_end = .;
75 . = ALIGN(4096);
70 } =0x90909090 76 } =0x90909090
71 .fini : { 77 .fini : {
72 KEEP (*(.fini)) 78 KEEP (*(.fini))
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 420e6d51fa0f..a24e3b7f4bf0 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -353,6 +353,8 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
353 353
354#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) 354#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
355 355
356extern int __syscall_stub_start, __binary_start;
357
356void setup_physmem(unsigned long start, unsigned long reserve_end, 358void setup_physmem(unsigned long start, unsigned long reserve_end,
357 unsigned long len, unsigned long highmem) 359 unsigned long len, unsigned long highmem)
358{ 360{
@@ -371,6 +373,12 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
371 exit(1); 373 exit(1);
372 } 374 }
373 375
376 /* Special kludge - This page will be mapped in to userspace processes
377 * from physmem_fd, so it needs to be written out there.
378 */
379 os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
380 os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
381
374 bootmap_size = init_bootmem(pfn, pfn + delta); 382 bootmap_size = init_bootmem(pfn, pfn + delta);
375 free_bootmem(__pa(reserve_end) + bootmap_size, 383 free_bootmem(__pa(reserve_end) + bootmap_size,
376 len - bootmap_size - reserve); 384 len - bootmap_size - reserve);
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 1b5ef3e96c71..c45a60e9c92d 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -32,6 +32,7 @@
32#include "uml-config.h" 32#include "uml-config.h"
33#include "choose-mode.h" 33#include "choose-mode.h"
34#include "mode.h" 34#include "mode.h"
35#include "tempfile.h"
35#ifdef UML_CONFIG_MODE_SKAS 36#ifdef UML_CONFIG_MODE_SKAS
36#include "skas.h" 37#include "skas.h"
37#include "skas_ptrace.h" 38#include "skas_ptrace.h"
@@ -358,11 +359,16 @@ void forward_pending_sigio(int target)
358 kill(target, SIGIO); 359 kill(target, SIGIO);
359} 360}
360 361
362int ptrace_faultinfo = 0;
363int proc_mm = 1;
364
365extern void *__syscall_stub_start, __syscall_stub_end;
366
361#ifdef UML_CONFIG_MODE_SKAS 367#ifdef UML_CONFIG_MODE_SKAS
362static inline int check_skas3_ptrace_support(void) 368static inline void check_skas3_ptrace_support(void)
363{ 369{
364 struct ptrace_faultinfo fi; 370 struct ptrace_faultinfo fi;
365 int pid, n, ret = 1; 371 int pid, n;
366 372
367 printf("Checking for the skas3 patch in the host..."); 373 printf("Checking for the skas3 patch in the host...");
368 pid = start_ptraced_child(); 374 pid = start_ptraced_child();
@@ -374,33 +380,31 @@ static inline int check_skas3_ptrace_support(void)
374 else { 380 else {
375 perror("not found"); 381 perror("not found");
376 } 382 }
377 ret = 0; 383 }
378 } else { 384 else {
385 ptrace_faultinfo = 1;
379 printf("found\n"); 386 printf("found\n");
380 } 387 }
381 388
382 init_registers(pid); 389 init_registers(pid);
383 stop_ptraced_child(pid, 1, 1); 390 stop_ptraced_child(pid, 1, 1);
384
385 return(ret);
386} 391}
387 392
388int can_do_skas(void) 393int can_do_skas(void)
389{ 394{
390 int ret = 1;
391
392 printf("Checking for /proc/mm..."); 395 printf("Checking for /proc/mm...");
393 if (os_access("/proc/mm", OS_ACC_W_OK) < 0) { 396 if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
397 proc_mm = 0;
394 printf("not found\n"); 398 printf("not found\n");
395 ret = 0;
396 goto out; 399 goto out;
397 } else { 400 }
401 else {
398 printf("found\n"); 402 printf("found\n");
399 } 403 }
400 404
401 ret = check_skas3_ptrace_support();
402out: 405out:
403 return ret; 406 check_skas3_ptrace_support();
407 return 1;
404} 408}
405#else 409#else
406int can_do_skas(void) 410int can_do_skas(void)
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
index c6b4d5dba789..77ed7bbab219 100644
--- a/arch/um/kernel/skas/exec_kern.c
+++ b/arch/um/kernel/skas/exec_kern.c
@@ -18,7 +18,7 @@
18void flush_thread_skas(void) 18void flush_thread_skas(void)
19{ 19{
20 force_flush_all(); 20 force_flush_all();
21 switch_mm_skas(current->mm->context.skas.mm_fd); 21 switch_mm_skas(&current->mm->context.skas.id);
22} 22}
23 23
24void start_thread_skas(struct pt_regs *regs, unsigned long eip, 24void start_thread_skas(struct pt_regs *regs, unsigned long eip,
diff --git a/arch/um/kernel/skas/include/mm_id.h b/arch/um/kernel/skas/include/mm_id.h
new file mode 100644
index 000000000000..48dd0989ddaa
--- /dev/null
+++ b/arch/um/kernel/skas/include/mm_id.h
@@ -0,0 +1,17 @@
1/*
2 * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MM_ID_H
7#define __MM_ID_H
8
9struct mm_id {
10 union {
11 int mm_fd;
12 int pid;
13 } u;
14 unsigned long stack;
15};
16
17#endif
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
index 4cd60d7213f3..278b72f1d9ad 100644
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -6,10 +6,15 @@
6#ifndef __SKAS_MMU_H 6#ifndef __SKAS_MMU_H
7#define __SKAS_MMU_H 7#define __SKAS_MMU_H
8 8
9#include "mm_id.h"
10
9struct mmu_context_skas { 11struct mmu_context_skas {
10 int mm_fd; 12 struct mm_id id;
13 unsigned long last_page_table;
11}; 14};
12 15
16extern void switch_mm_skas(struct mm_id * mm_idp);
17
13#endif 18#endif
14 19
15/* 20/*
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
index 96b51dba3471..d91a60f3830a 100644
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -6,9 +6,11 @@
6#ifndef __SKAS_H 6#ifndef __SKAS_H
7#define __SKAS_H 7#define __SKAS_H
8 8
9#include "mm_id.h"
9#include "sysdep/ptrace.h" 10#include "sysdep/ptrace.h"
10 11
11extern int userspace_pid[]; 12extern int userspace_pid[];
13extern int proc_mm, ptrace_faultinfo;
12 14
13extern void switch_threads(void *me, void *next); 15extern void switch_threads(void *me, void *next);
14extern void thread_wait(void *sw, void *fb); 16extern void thread_wait(void *sw, void *fb);
@@ -22,16 +24,17 @@ extern void new_thread_proc(void *stack, void (*handler)(int sig));
22extern void remove_sigstack(void); 24extern void remove_sigstack(void);
23extern void new_thread_handler(int sig); 25extern void new_thread_handler(int sig);
24extern void handle_syscall(union uml_pt_regs *regs); 26extern void handle_syscall(union uml_pt_regs *regs);
25extern void map(int fd, unsigned long virt, unsigned long len, int r, int w, 27extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
26 int x, int phys_fd, unsigned long long offset); 28 int r, int w, int x, int phys_fd, unsigned long long offset);
27extern int unmap(int fd, void *addr, unsigned long len); 29extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
28extern int protect(int fd, unsigned long addr, unsigned long len, 30extern int protect(struct mm_id * mm_idp, unsigned long addr,
29 int r, int w, int x); 31 unsigned long len, int r, int w, int x);
30extern void user_signal(int sig, union uml_pt_regs *regs, int pid); 32extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
31extern int new_mm(int from); 33extern int new_mm(int from);
32extern void start_userspace(int cpu); 34extern int start_userspace(unsigned long stub_stack);
33extern void get_skas_faultinfo(int pid, struct faultinfo * fi); 35extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
34extern long execute_syscall_skas(void *r); 36extern long execute_syscall_skas(void *r);
37extern unsigned long current_stub_stack(void);
35 38
36#endif 39#endif
37 40
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
index 438db2f43456..147466d7ff4f 100644
--- a/arch/um/kernel/skas/mem.c
+++ b/arch/um/kernel/skas/mem.c
@@ -5,7 +5,9 @@
5 5
6#include "linux/config.h" 6#include "linux/config.h"
7#include "linux/mm.h" 7#include "linux/mm.h"
8#include "asm/pgtable.h"
8#include "mem_user.h" 9#include "mem_user.h"
10#include "skas.h"
9 11
10unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, 12unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
11 unsigned long *task_size_out) 13 unsigned long *task_size_out)
@@ -18,7 +20,9 @@ unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
18 *task_size_out = CONFIG_HOST_TASK_SIZE; 20 *task_size_out = CONFIG_HOST_TASK_SIZE;
19#else 21#else
20 *host_size_out = top; 22 *host_size_out = top;
21 *task_size_out = top; 23 if (proc_mm && ptrace_faultinfo)
24 *task_size_out = top;
25 else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
22#endif 26#endif
23 return(((unsigned long) set_task_sizes_skas) & ~0xffffff); 27 return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
24} 28}
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
index 1310bf1e88d1..b0980ff3bd95 100644
--- a/arch/um/kernel/skas/mem_user.c
+++ b/arch/um/kernel/skas/mem_user.c
@@ -3,100 +3,171 @@
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
5 5
6#include <signal.h>
6#include <errno.h> 7#include <errno.h>
7#include <sys/mman.h> 8#include <sys/mman.h>
9#include <sys/wait.h>
10#include <asm/page.h>
11#include <asm/unistd.h>
8#include "mem_user.h" 12#include "mem_user.h"
9#include "mem.h" 13#include "mem.h"
14#include "mm_id.h"
10#include "user.h" 15#include "user.h"
11#include "os.h" 16#include "os.h"
12#include "proc_mm.h" 17#include "proc_mm.h"
13 18#include "ptrace_user.h"
14void map(int fd, unsigned long virt, unsigned long len, int r, int w, 19#include "user_util.h"
15 int x, int phys_fd, unsigned long long offset) 20#include "kern_util.h"
21#include "task.h"
22#include "registers.h"
23#include "uml-config.h"
24#include "sysdep/ptrace.h"
25#include "sysdep/stub.h"
26#include "skas.h"
27
28extern unsigned long syscall_stub, __syscall_stub_start;
29
30extern void wait_stub_done(int pid, int sig, char * fname);
31
32static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
33 unsigned long *args)
16{ 34{
17 struct proc_mm_op map; 35 int n, pid = mm_idp->u.pid;
18 int prot, n; 36 unsigned long regs[MAX_REG_NR];
19 37
20 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 38 get_safe_registers(regs);
21 (x ? PROT_EXEC : 0); 39 regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
22 40 ((unsigned long) &syscall_stub -
23 map = ((struct proc_mm_op) { .op = MM_MMAP, 41 (unsigned long) &__syscall_stub_start);
24 .u = 42 /* XXX Don't have a define for starting a syscall */
25 { .mmap = 43 regs[REGS_SYSCALL_NR] = syscall;
26 { .addr = virt, 44 regs[REGS_SYSCALL_ARG1] = args[0];
27 .len = len, 45 regs[REGS_SYSCALL_ARG2] = args[1];
28 .prot = prot, 46 regs[REGS_SYSCALL_ARG3] = args[2];
29 .flags = MAP_SHARED | 47 regs[REGS_SYSCALL_ARG4] = args[3];
30 MAP_FIXED, 48 regs[REGS_SYSCALL_ARG5] = args[4];
31 .fd = phys_fd, 49 regs[REGS_SYSCALL_ARG6] = args[5];
32 .offset = offset 50 n = ptrace_setregs(pid, regs);
33 } } } ); 51 if(n < 0){
34 n = os_write_file(fd, &map, sizeof(map)); 52 printk("run_syscall_stub : PTRACE_SETREGS failed, "
35 if(n != sizeof(map)) 53 "errno = %d\n", n);
36 printk("map : /proc/mm map failed, err = %d\n", -n); 54 return(n);
55 }
56
57 wait_stub_done(pid, 0, "run_syscall_stub");
58
59 return(*((unsigned long *) mm_idp->stack));
37} 60}
38 61
39int unmap(int fd, void *addr, unsigned long len) 62int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
63 int r, int w, int x, int phys_fd, unsigned long long offset)
40{ 64{
41 struct proc_mm_op unmap; 65 int prot, n;
42 int n; 66
43 67 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
44 unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, 68 (x ? PROT_EXEC : 0);
45 .u = 69
46 { .munmap = 70 if(proc_mm){
47 { .addr = (unsigned long) addr, 71 struct proc_mm_op map;
48 .len = len } } } ); 72 int fd = mm_idp->u.mm_fd;
49 n = os_write_file(fd, &unmap, sizeof(unmap)); 73 map = ((struct proc_mm_op) { .op = MM_MMAP,
50 if(n != sizeof(unmap)) { 74 .u =
51 if(n < 0) 75 { .mmap =
52 return(n); 76 { .addr = virt,
53 else if(n > 0) 77 .len = len,
54 return(-EIO); 78 .prot = prot,
55 } 79 .flags = MAP_SHARED |
56 80 MAP_FIXED,
57 return(0); 81 .fd = phys_fd,
82 .offset= offset
83 } } } );
84 n = os_write_file(fd, &map, sizeof(map));
85 if(n != sizeof(map))
86 printk("map : /proc/mm map failed, err = %d\n", -n);
87 }
88 else {
89 long res;
90 unsigned long args[] = { virt, len, prot,
91 MAP_SHARED | MAP_FIXED, phys_fd,
92 MMAP_OFFSET(offset) };
93
94 res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
95 if((void *) res == MAP_FAILED)
96 printk("mmap stub failed, errno = %d\n", res);
97 }
98
99 return 0;
58} 100}
59 101
60int protect(int fd, unsigned long addr, unsigned long len, int r, int w, 102int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
61 int x, int must_succeed)
62{ 103{
63 struct proc_mm_op protect; 104 int n;
64 int prot, n; 105
65 106 if(proc_mm){
66 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 107 struct proc_mm_op unmap;
67 (x ? PROT_EXEC : 0); 108 int fd = mm_idp->u.mm_fd;
68 109 unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
69 protect = ((struct proc_mm_op) { .op = MM_MPROTECT, 110 .u =
70 .u = 111 { .munmap =
71 { .mprotect = 112 { .addr =
72 { .addr = (unsigned long) addr, 113 (unsigned long) addr,
73 .len = len, 114 .len = len } } } );
74 .prot = prot } } } ); 115 n = os_write_file(fd, &unmap, sizeof(unmap));
75 116 if(n != sizeof(unmap)) {
76 n = os_write_file(fd, &protect, sizeof(protect)); 117 if(n < 0)
77 if(n != sizeof(protect)) { 118 return(n);
78 if(n == 0) return(0); 119 else if(n > 0)
79 120 return(-EIO);
80 if(must_succeed) 121 }
81 panic("protect failed, err = %d", -n); 122 }
82 123 else {
83 return(-EIO); 124 int res;
84 } 125 unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
126 0 };
127
128 res = run_syscall_stub(mm_idp, __NR_munmap, args);
129 if(res < 0)
130 printk("munmap stub failed, errno = %d\n", res);
131 }
132
133 return(0);
134}
85 135
86 return(0); 136int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
137 int r, int w, int x)
138{
139 struct proc_mm_op protect;
140 int prot, n;
141
142 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
143 (x ? PROT_EXEC : 0);
144
145 if(proc_mm){
146 int fd = mm_idp->u.mm_fd;
147 protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
148 .u =
149 { .mprotect =
150 { .addr =
151 (unsigned long) addr,
152 .len = len,
153 .prot = prot } } } );
154
155 n = os_write_file(fd, &protect, sizeof(protect));
156 if(n != sizeof(protect))
157 panic("protect failed, err = %d", -n);
158 }
159 else {
160 int res;
161 unsigned long args[] = { addr, len, prot, 0, 0, 0 };
162
163 res = run_syscall_stub(mm_idp, __NR_mprotect, args);
164 if(res < 0)
165 panic("mprotect stub failed, errno = %d\n", res);
166 }
167
168 return(0);
87} 169}
88 170
89void before_mem_skas(unsigned long unused) 171void before_mem_skas(unsigned long unused)
90{ 172{
91} 173}
92
93/*
94 * Overrides for Emacs so that we follow Linus's tabbing style.
95 * Emacs will notice this stuff at the end of the file and automatically
96 * adjust the settings for this buffer only. This must remain at the end
97 * of the file.
98 * ---------------------------------------------------------------------------
99 * Local variables:
100 * c-file-style: "linux"
101 * End:
102 */
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 6cb9a6d028a9..511a855c9ec0 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -3,46 +3,138 @@
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
5 5
6#include "linux/config.h"
6#include "linux/sched.h" 7#include "linux/sched.h"
7#include "linux/list.h" 8#include "linux/list.h"
8#include "linux/spinlock.h" 9#include "linux/spinlock.h"
9#include "linux/slab.h" 10#include "linux/slab.h"
11#include "linux/errno.h"
12#include "linux/mm.h"
10#include "asm/current.h" 13#include "asm/current.h"
11#include "asm/segment.h" 14#include "asm/segment.h"
12#include "asm/mmu.h" 15#include "asm/mmu.h"
16#include "asm/pgalloc.h"
17#include "asm/pgtable.h"
13#include "os.h" 18#include "os.h"
14#include "skas.h" 19#include "skas.h"
15 20
21extern int __syscall_stub_start;
22
23static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
24 unsigned long kernel)
25{
26 pgd_t *pgd;
27 pud_t *pud;
28 pmd_t *pmd;
29 pte_t *pte;
30
31 spin_lock(&mm->page_table_lock);
32 pgd = pgd_offset(mm, proc);
33 pud = pud_alloc(mm, pgd, proc);
34 if (!pud)
35 goto out;
36
37 pmd = pmd_alloc(mm, pud, proc);
38 if (!pmd)
39 goto out_pmd;
40
41 pte = pte_alloc_map(mm, pmd, proc);
42 if (!pte)
43 goto out_pte;
44
45 /* There's an interaction between the skas0 stub pages, stack
46 * randomization, and the BUG at the end of exit_mmap. exit_mmap
47 * checks that the number of page tables freed is the same as had
48 * been allocated. If the stack is on the last page table page,
49 * then the stack pte page will be freed, and if not, it won't. To
50 * avoid having to know where the stack is, or if the process mapped
51 * something at the top of its address space for some other reason,
52 * we set TASK_SIZE to end at the start of the last page table.
53 * This keeps exit_mmap off the last page, but introduces a leak
54 * of that page. So, we hang onto it here and free it in
55 * destroy_context_skas.
56 */
57
58 mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
59
60 *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
61 *pte = pte_mkexec(*pte);
62 *pte = pte_wrprotect(*pte);
63 spin_unlock(&mm->page_table_lock);
64 return(0);
65
66 out_pmd:
67 pud_free(pud);
68 out_pte:
69 pmd_free(pmd);
70 out:
71 spin_unlock(&mm->page_table_lock);
72 return(-ENOMEM);
73}
74
16int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) 75int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
17{ 76{
18 int from; 77 struct mm_struct *cur_mm = current->mm;
78 struct mm_id *mm_id = &mm->context.skas.id;
79 unsigned long stack;
80 int from, ret;
19 81
20 if((current->mm != NULL) && (current->mm != &init_mm)) 82 if(proc_mm){
21 from = current->mm->context.skas.mm_fd; 83 if((cur_mm != NULL) && (cur_mm != &init_mm))
22 else from = -1; 84 from = cur_mm->context.skas.id.u.mm_fd;
85 else from = -1;
23 86
24 mm->context.skas.mm_fd = new_mm(from); 87 ret = new_mm(from);
25 if(mm->context.skas.mm_fd < 0){ 88 if(ret < 0){
26 printk("init_new_context_skas - new_mm failed, errno = %d\n", 89 printk("init_new_context_skas - new_mm failed, "
27 mm->context.skas.mm_fd); 90 "errno = %d\n", ret);
28 return(mm->context.skas.mm_fd); 91 return ret;
92 }
93 mm_id->u.mm_fd = ret;
29 } 94 }
95 else {
96 /* This zeros the entry that pgd_alloc didn't, needed since
97 * we are about to reinitialize it, and want mm.nr_ptes to
98 * be accurate.
99 */
100 mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
30 101
31 return(0); 102 ret = init_stub_pte(mm, CONFIG_STUB_CODE,
103 (unsigned long) &__syscall_stub_start);
104 if(ret)
105 goto out;
106
107 ret = -ENOMEM;
108 stack = get_zeroed_page(GFP_KERNEL);
109 if(stack == 0)
110 goto out;
111 mm_id->stack = stack;
112
113 ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
114 if(ret)
115 goto out_free;
116
117 mm->nr_ptes--;
118 mm_id->u.pid = start_userspace(stack);
119 }
120
121 return 0;
122
123 out_free:
124 free_page(mm_id->stack);
125 out:
126 return ret;
32} 127}
33 128
34void destroy_context_skas(struct mm_struct *mm) 129void destroy_context_skas(struct mm_struct *mm)
35{ 130{
36 os_close_file(mm->context.skas.mm_fd); 131 struct mmu_context_skas *mmu = &mm->context.skas;
37}
38 132
39/* 133 if(proc_mm)
40 * Overrides for Emacs so that we follow Linus's tabbing style. 134 os_close_file(mmu->id.u.mm_fd);
41 * Emacs will notice this stuff at the end of the file and automatically 135 else {
42 * adjust the settings for this buffer only. This must remain at the end 136 os_kill_ptraced_process(mmu->id.u.pid, 1);
43 * of the file. 137 free_page(mmu->id.stack);
44 * --------------------------------------------------------------------------- 138 free_page(mmu->last_page_table);
45 * Local variables: 139 }
46 * c-file-style: "linux" 140}
47 * End:
48 */
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 773cd2b525fc..1647abb0d1aa 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) 2 * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
5 5
@@ -14,6 +14,7 @@
14#include <sys/mman.h> 14#include <sys/mman.h>
15#include <sys/user.h> 15#include <sys/user.h>
16#include <asm/unistd.h> 16#include <asm/unistd.h>
17#include <asm/types.h>
17#include "user.h" 18#include "user.h"
18#include "ptrace_user.h" 19#include "ptrace_user.h"
19#include "time_user.h" 20#include "time_user.h"
@@ -21,13 +22,17 @@
21#include "user_util.h" 22#include "user_util.h"
22#include "kern_util.h" 23#include "kern_util.h"
23#include "skas.h" 24#include "skas.h"
25#include "mm_id.h"
24#include "sysdep/sigcontext.h" 26#include "sysdep/sigcontext.h"
27#include "sysdep/stub.h"
25#include "os.h" 28#include "os.h"
26#include "proc_mm.h" 29#include "proc_mm.h"
27#include "skas_ptrace.h" 30#include "skas_ptrace.h"
28#include "chan_user.h" 31#include "chan_user.h"
29#include "signal_user.h" 32#include "signal_user.h"
30#include "registers.h" 33#include "registers.h"
34#include "mem.h"
35#include "uml-config.h"
31#include "process.h" 36#include "process.h"
32 37
33int is_skas_winch(int pid, int fd, void *data) 38int is_skas_winch(int pid, int fd, void *data)
@@ -39,20 +44,55 @@ int is_skas_winch(int pid, int fd, void *data)
39 return(1); 44 return(1);
40} 45}
41 46
42void get_skas_faultinfo(int pid, struct faultinfo * fi) 47void wait_stub_done(int pid, int sig, char * fname)
43{ 48{
44 int err; 49 int n, status, err;
45 50
46 err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); 51 do {
47 if(err) 52 if ( sig != -1 ) {
48 panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " 53 err = ptrace(PTRACE_CONT, pid, 0, sig);
49 "errno = %d\n", errno); 54 if(err)
55 panic("%s : continue failed, errno = %d\n",
56 fname, errno);
57 }
58 sig = 0;
59
60 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
61 } while((n >= 0) && WIFSTOPPED(status) &&
62 (WSTOPSIG(status) == SIGVTALRM));
63
64 if((n < 0) || !WIFSTOPPED(status) ||
65 (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status != SIGTRAP))){
66 panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
67 "pid = %d, n = %d, errno = %d, status = 0x%x\n",
68 fname, pid, n, errno, status);
69 }
70}
50 71
51 /* Special handling for i386, which has different structs */ 72void get_skas_faultinfo(int pid, struct faultinfo * fi)
52 if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) 73{
53 memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, 74 int err;
54 sizeof(struct faultinfo) - 75
55 sizeof(struct ptrace_faultinfo)); 76 if(ptrace_faultinfo){
77 err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
78 if(err)
79 panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
80 "errno = %d\n", errno);
81
82 /* Special handling for i386, which has different structs */
83 if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
84 memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
85 sizeof(struct faultinfo) -
86 sizeof(struct ptrace_faultinfo));
87 }
88 else {
89 wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
90
91 /* faultinfo is prepared by the stub-segv-handler at start of
92 * the stub stack page. We just have to copy it.
93 */
94 memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
95 }
56} 96}
57 97
58static void handle_segv(int pid, union uml_pt_regs * regs) 98static void handle_segv(int pid, union uml_pt_regs * regs)
@@ -91,11 +131,56 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
91 handle_syscall(regs); 131 handle_syscall(regs);
92} 132}
93 133
94static int userspace_tramp(void *arg) 134extern int __syscall_stub_start;
135
136static int userspace_tramp(void *stack)
95{ 137{
96 init_new_thread_signals(0); 138 void *addr;
97 enable_timer(); 139
98 ptrace(PTRACE_TRACEME, 0, 0, 0); 140 ptrace(PTRACE_TRACEME, 0, 0, 0);
141
142 init_new_thread_signals(1);
143 enable_timer();
144
145 if(!proc_mm){
146 /* This has a pte, but it can't be mapped in with the usual
147 * tlb_flush mechanism because this is part of that mechanism
148 */
149 int fd;
150 __u64 offset;
151
152 fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
153 addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
154 PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
155 if(addr == MAP_FAILED){
156 printk("mapping mmap stub failed, errno = %d\n",
157 errno);
158 exit(1);
159 }
160
161 if(stack != NULL){
162 fd = phys_mapping(to_phys(stack), &offset);
163 addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
164 PROT_READ | PROT_WRITE,
165 MAP_FIXED | MAP_SHARED, fd, offset);
166 if(addr == MAP_FAILED){
167 printk("mapping segfault stack failed, "
168 "errno = %d\n", errno);
169 exit(1);
170 }
171 }
172 }
173 if(!ptrace_faultinfo && (stack != NULL)){
174 unsigned long v = UML_CONFIG_STUB_CODE +
175 (unsigned long) stub_segv_handler -
176 (unsigned long) &__syscall_stub_start;
177
178 set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
179 set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
180 SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
181 SIGUSR1, -1);
182 }
183
99 os_stop_process(os_getpid()); 184 os_stop_process(os_getpid());
100 return(0); 185 return(0);
101} 186}
@@ -105,11 +190,11 @@ static int userspace_tramp(void *arg)
105#define NR_CPUS 1 190#define NR_CPUS 1
106int userspace_pid[NR_CPUS]; 191int userspace_pid[NR_CPUS];
107 192
108void start_userspace(int cpu) 193int start_userspace(unsigned long stub_stack)
109{ 194{
110 void *stack; 195 void *stack;
111 unsigned long sp; 196 unsigned long sp;
112 int pid, status, n; 197 int pid, status, n, flags;
113 198
114 stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, 199 stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
115 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 200 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -117,8 +202,9 @@ void start_userspace(int cpu)
117 panic("start_userspace : mmap failed, errno = %d", errno); 202 panic("start_userspace : mmap failed, errno = %d", errno);
118 sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); 203 sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
119 204
120 pid = clone(userspace_tramp, (void *) sp, 205 flags = CLONE_FILES | SIGCHLD;
121 CLONE_FILES | CLONE_VM | SIGCHLD, NULL); 206 if(proc_mm) flags |= CLONE_VM;
207 pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
122 if(pid < 0) 208 if(pid < 0)
123 panic("start_userspace : clone failed, errno = %d", errno); 209 panic("start_userspace : clone failed, errno = %d", errno);
124 210
@@ -140,7 +226,7 @@ void start_userspace(int cpu)
140 if(munmap(stack, PAGE_SIZE) < 0) 226 if(munmap(stack, PAGE_SIZE) < 0)
141 panic("start_userspace : munmap failed, errno = %d\n", errno); 227 panic("start_userspace : munmap failed, errno = %d\n", errno);
142 228
143 userspace_pid[cpu] = pid; 229 return(pid);
144} 230}
145 231
146void userspace(union uml_pt_regs *regs) 232void userspace(union uml_pt_regs *regs)
@@ -174,7 +260,9 @@ void userspace(union uml_pt_regs *regs)
174 if(WIFSTOPPED(status)){ 260 if(WIFSTOPPED(status)){
175 switch(WSTOPSIG(status)){ 261 switch(WSTOPSIG(status)){
176 case SIGSEGV: 262 case SIGSEGV:
177 handle_segv(pid, regs); 263 if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
264 user_signal(SIGSEGV, regs, pid);
265 else handle_segv(pid, regs);
178 break; 266 break;
179 case SIGTRAP + 0x80: 267 case SIGTRAP + 0x80:
180 handle_trap(pid, regs, local_using_sysemu); 268 handle_trap(pid, regs, local_using_sysemu);
@@ -194,6 +282,7 @@ void userspace(union uml_pt_regs *regs)
194 printk("userspace - child stopped with signal " 282 printk("userspace - child stopped with signal "
195 "%d\n", WSTOPSIG(status)); 283 "%d\n", WSTOPSIG(status));
196 } 284 }
285 pid = userspace_pid[0];
197 interrupt_end(); 286 interrupt_end();
198 287
199 /* Avoid -ERESTARTSYS handling in host */ 288 /* Avoid -ERESTARTSYS handling in host */
@@ -334,21 +423,19 @@ void reboot_skas(void)
334 siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT); 423 siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
335} 424}
336 425
337void switch_mm_skas(int mm_fd) 426void switch_mm_skas(struct mm_id *mm_idp)
338{ 427{
339 int err; 428 int err;
340 429
341#warning need cpu pid in switch_mm_skas 430#warning need cpu pid in switch_mm_skas
342 err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd); 431 if(proc_mm){
343 if(err) 432 err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
344 panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", 433 mm_idp->u.mm_fd);
345 errno); 434 if(err)
346} 435 panic("switch_mm_skas - PTRACE_SWITCH_MM failed, "
347 436 "errno = %d\n", errno);
348void kill_off_processes_skas(void) 437 }
349{ 438 else userspace_pid[0] = mm_idp->u.pid;
350#warning need to loop over userspace_pids in kill_off_processes_skas
351 os_kill_ptraced_process(userspace_pid[0], 1);
352} 439}
353 440
354/* 441/*
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index 0a7b8aa55db8..cbabab104ac3 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -175,9 +175,12 @@ static int start_kernel_proc(void *unused)
175 return(0); 175 return(0);
176} 176}
177 177
178extern int userspace_pid[];
179
178int start_uml_skas(void) 180int start_uml_skas(void)
179{ 181{
180 start_userspace(0); 182 if(proc_mm)
183 userspace_pid[0] = start_userspace(0);
181 184
182 init_new_thread_signals(1); 185 init_new_thread_signals(1);
183 186
@@ -199,3 +202,31 @@ int thread_pid_skas(struct task_struct *task)
199#warning Need to look up userspace_pid by cpu 202#warning Need to look up userspace_pid by cpu
200 return(userspace_pid[0]); 203 return(userspace_pid[0]);
201} 204}
205
206void kill_off_processes_skas(void)
207{
208 if(proc_mm)
209#warning need to loop over userspace_pids in kill_off_processes_skas
210 os_kill_ptraced_process(userspace_pid[0], 1);
211 else {
212 struct task_struct *p;
213 int pid, me;
214
215 me = os_getpid();
216 for_each_process(p){
217 if(p->mm == NULL)
218 continue;
219
220 pid = p->mm->context.skas.id.u.pid;
221 os_kill_ptraced_process(pid, 1);
222 }
223 }
224}
225
226unsigned long current_stub_stack(void)
227{
228 if(current->mm == NULL)
229 return(0);
230
231 return(current->mm->context.skas.id.stack);
232}
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index 18f9a7711de1..6230999c672c 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -6,6 +6,7 @@
6 6
7#include "linux/stddef.h" 7#include "linux/stddef.h"
8#include "linux/sched.h" 8#include "linux/sched.h"
9#include "linux/config.h"
9#include "linux/mm.h" 10#include "linux/mm.h"
10#include "asm/page.h" 11#include "asm/page.h"
11#include "asm/pgtable.h" 12#include "asm/pgtable.h"
@@ -17,7 +18,7 @@
17#include "os.h" 18#include "os.h"
18#include "tlb.h" 19#include "tlb.h"
19 20
20static void do_ops(int fd, struct host_vm_op *ops, int last) 21static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
21{ 22{
22 struct host_vm_op *op; 23 struct host_vm_op *op;
23 int i; 24 int i;
@@ -26,18 +27,18 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
26 op = &ops[i]; 27 op = &ops[i];
27 switch(op->type){ 28 switch(op->type){
28 case MMAP: 29 case MMAP:
29 map(fd, op->u.mmap.addr, op->u.mmap.len, 30 map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len,
30 op->u.mmap.r, op->u.mmap.w, op->u.mmap.x, 31 op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
31 op->u.mmap.fd, op->u.mmap.offset); 32 op->u.mmap.fd, op->u.mmap.offset);
32 break; 33 break;
33 case MUNMAP: 34 case MUNMAP:
34 unmap(fd, (void *) op->u.munmap.addr, 35 unmap(&mmu->skas.id, (void *) op->u.munmap.addr,
35 op->u.munmap.len); 36 op->u.munmap.len);
36 break; 37 break;
37 case MPROTECT: 38 case MPROTECT:
38 protect(fd, op->u.mprotect.addr, op->u.mprotect.len, 39 protect(&mmu->skas.id, op->u.mprotect.addr,
39 op->u.mprotect.r, op->u.mprotect.w, 40 op->u.mprotect.len, op->u.mprotect.r,
40 op->u.mprotect.x); 41 op->u.mprotect.w, op->u.mprotect.x);
41 break; 42 break;
42 default: 43 default:
43 printk("Unknown op type %d in do_ops\n", op->type); 44 printk("Unknown op type %d in do_ops\n", op->type);
@@ -46,12 +47,15 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
46 } 47 }
47} 48}
48 49
50extern int proc_mm;
51
49static void fix_range(struct mm_struct *mm, unsigned long start_addr, 52static void fix_range(struct mm_struct *mm, unsigned long start_addr,
50 unsigned long end_addr, int force) 53 unsigned long end_addr, int force)
51{ 54{
52 int fd = mm->context.skas.mm_fd; 55 if(!proc_mm && (end_addr > CONFIG_STUB_START))
56 end_addr = CONFIG_STUB_START;
53 57
54 fix_range_common(mm, start_addr, end_addr, force, fd, do_ops); 58 fix_range_common(mm, start_addr, end_addr, force, do_ops);
55} 59}
56 60
57void __flush_tlb_one_skas(unsigned long addr) 61void __flush_tlb_one_skas(unsigned long addr)
@@ -69,16 +73,20 @@ void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start,
69 73
70void flush_tlb_mm_skas(struct mm_struct *mm) 74void flush_tlb_mm_skas(struct mm_struct *mm)
71{ 75{
76 unsigned long end;
77
72 /* Don't bother flushing if this address space is about to be 78 /* Don't bother flushing if this address space is about to be
73 * destroyed. 79 * destroyed.
74 */ 80 */
75 if(atomic_read(&mm->mm_users) == 0) 81 if(atomic_read(&mm->mm_users) == 0)
76 return; 82 return;
77 83
78 fix_range(mm, 0, host_task_size, 0); 84 end = proc_mm ? task_size : CONFIG_STUB_START;
85 fix_range(mm, 0, end, 0);
79} 86}
80 87
81void force_flush_all_skas(void) 88void force_flush_all_skas(void)
82{ 89{
83 fix_range(current->mm, 0, host_task_size, 1); 90 unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
91 fix_range(current->mm, 0, end, 1);
84} 92}
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index eda477edfdf5..83ec8d4747fd 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -18,13 +18,15 @@
18#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) 18#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
19 19
20void fix_range_common(struct mm_struct *mm, unsigned long start_addr, 20void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
21 unsigned long end_addr, int force, int data, 21 unsigned long end_addr, int force,
22 void (*do_ops)(int, struct host_vm_op *, int)) 22 void (*do_ops)(union mm_context *, struct host_vm_op *,
23 int))
23{ 24{
24 pgd_t *npgd; 25 pgd_t *npgd;
25 pud_t *npud; 26 pud_t *npud;
26 pmd_t *npmd; 27 pmd_t *npmd;
27 pte_t *npte; 28 pte_t *npte;
29 union mm_context *mmu = &mm->context;
28 unsigned long addr, end; 30 unsigned long addr, end;
29 int r, w, x; 31 int r, w, x;
30 struct host_vm_op ops[16]; 32 struct host_vm_op ops[16];
@@ -40,7 +42,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
40 end = end_addr; 42 end = end_addr;
41 if(force || pgd_newpage(*npgd)){ 43 if(force || pgd_newpage(*npgd)){
42 op_index = add_munmap(addr, end - addr, ops, 44 op_index = add_munmap(addr, end - addr, ops,
43 op_index, last_op, data, 45 op_index, last_op, mmu,
44 do_ops); 46 do_ops);
45 pgd_mkuptodate(*npgd); 47 pgd_mkuptodate(*npgd);
46 } 48 }
@@ -55,7 +57,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
55 end = end_addr; 57 end = end_addr;
56 if(force || pud_newpage(*npud)){ 58 if(force || pud_newpage(*npud)){
57 op_index = add_munmap(addr, end - addr, ops, 59 op_index = add_munmap(addr, end - addr, ops,
58 op_index, last_op, data, 60 op_index, last_op, mmu,
59 do_ops); 61 do_ops);
60 pud_mkuptodate(*npud); 62 pud_mkuptodate(*npud);
61 } 63 }
@@ -70,7 +72,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
70 end = end_addr; 72 end = end_addr;
71 if(force || pmd_newpage(*npmd)){ 73 if(force || pmd_newpage(*npmd)){
72 op_index = add_munmap(addr, end - addr, ops, 74 op_index = add_munmap(addr, end - addr, ops,
73 op_index, last_op, data, 75 op_index, last_op, mmu,
74 do_ops); 76 do_ops);
75 pmd_mkuptodate(*npmd); 77 pmd_mkuptodate(*npmd);
76 } 78 }
@@ -93,21 +95,21 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
93 op_index = add_mmap(addr, 95 op_index = add_mmap(addr,
94 pte_val(*npte) & PAGE_MASK, 96 pte_val(*npte) & PAGE_MASK,
95 PAGE_SIZE, r, w, x, ops, 97 PAGE_SIZE, r, w, x, ops,
96 op_index, last_op, data, 98 op_index, last_op, mmu,
97 do_ops); 99 do_ops);
98 else op_index = add_munmap(addr, PAGE_SIZE, ops, 100 else op_index = add_munmap(addr, PAGE_SIZE, ops,
99 op_index, last_op, data, 101 op_index, last_op, mmu,
100 do_ops); 102 do_ops);
101 } 103 }
102 else if(pte_newprot(*npte)) 104 else if(pte_newprot(*npte))
103 op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops, 105 op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
104 op_index, last_op, data, 106 op_index, last_op, mmu,
105 do_ops); 107 do_ops);
106 108
107 *npte = pte_mkuptodate(*npte); 109 *npte = pte_mkuptodate(*npte);
108 addr += PAGE_SIZE; 110 addr += PAGE_SIZE;
109 } 111 }
110 (*do_ops)(data, ops, op_index); 112 (*do_ops)(mmu, ops, op_index);
111} 113}
112 114
113int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) 115int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
@@ -195,51 +197,6 @@ int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
195 return(updated); 197 return(updated);
196} 198}
197 199
198void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
199{
200 address &= PAGE_MASK;
201 flush_tlb_range(vma, address, address + PAGE_SIZE);
202}
203
204void flush_tlb_all(void)
205{
206 flush_tlb_mm(current->mm);
207}
208
209void flush_tlb_kernel_range(unsigned long start, unsigned long end)
210{
211 CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
212 flush_tlb_kernel_range_common, start, end);
213}
214
215void flush_tlb_kernel_vm(void)
216{
217 CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
218 flush_tlb_kernel_range_common(start_vm, end_vm));
219}
220
221void __flush_tlb_one(unsigned long addr)
222{
223 CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
224}
225
226void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
227 unsigned long end)
228{
229 CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
230 end);
231}
232
233void flush_tlb_mm(struct mm_struct *mm)
234{
235 CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
236}
237
238void force_flush_all(void)
239{
240 CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
241}
242
243pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) 200pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
244{ 201{
245 return(pgd_offset(mm, address)); 202 return(pgd_offset(mm, address));
@@ -270,9 +227,9 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr)
270} 227}
271 228
272int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, 229int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
273 int r, int w, int x, struct host_vm_op *ops, int index, 230 int r, int w, int x, struct host_vm_op *ops, int index,
274 int last_filled, int data, 231 int last_filled, union mm_context *mmu,
275 void (*do_ops)(int, struct host_vm_op *, int)) 232 void (*do_ops)(union mm_context *, struct host_vm_op *, int))
276{ 233{
277 __u64 offset; 234 __u64 offset;
278 struct host_vm_op *last; 235 struct host_vm_op *last;
@@ -292,7 +249,7 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
292 } 249 }
293 250
294 if(index == last_filled){ 251 if(index == last_filled){
295 (*do_ops)(data, ops, last_filled); 252 (*do_ops)(mmu, ops, last_filled);
296 index = -1; 253 index = -1;
297 } 254 }
298 255
@@ -310,8 +267,8 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
310} 267}
311 268
312int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops, 269int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
313 int index, int last_filled, int data, 270 int index, int last_filled, union mm_context *mmu,
314 void (*do_ops)(int, struct host_vm_op *, int)) 271 void (*do_ops)(union mm_context *, struct host_vm_op *, int))
315{ 272{
316 struct host_vm_op *last; 273 struct host_vm_op *last;
317 274
@@ -325,7 +282,7 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
325 } 282 }
326 283
327 if(index == last_filled){ 284 if(index == last_filled){
328 (*do_ops)(data, ops, last_filled); 285 (*do_ops)(mmu, ops, last_filled);
329 index = -1; 286 index = -1;
330 } 287 }
331 288
@@ -337,8 +294,9 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
337} 294}
338 295
339int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, 296int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
340 struct host_vm_op *ops, int index, int last_filled, int data, 297 struct host_vm_op *ops, int index, int last_filled,
341 void (*do_ops)(int, struct host_vm_op *, int)) 298 union mm_context *mmu,
299 void (*do_ops)(union mm_context *, struct host_vm_op *, int))
342{ 300{
343 struct host_vm_op *last; 301 struct host_vm_op *last;
344 302
@@ -354,7 +312,7 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
354 } 312 }
355 313
356 if(index == last_filled){ 314 if(index == last_filled){
357 (*do_ops)(data, ops, last_filled); 315 (*do_ops)(mmu, ops, last_filled);
358 index = -1; 316 index = -1;
359 } 317 }
360 318
@@ -367,3 +325,49 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
367 .x = x } } }); 325 .x = x } } });
368 return(index); 326 return(index);
369} 327}
328
329void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
330{
331 address &= PAGE_MASK;
332 flush_tlb_range(vma, address, address + PAGE_SIZE);
333}
334
335void flush_tlb_all(void)
336{
337 flush_tlb_mm(current->mm);
338}
339
340void flush_tlb_kernel_range(unsigned long start, unsigned long end)
341{
342 CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
343 flush_tlb_kernel_range_common, start, end);
344}
345
346void flush_tlb_kernel_vm(void)
347{
348 CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
349 flush_tlb_kernel_range_common(start_vm, end_vm));
350}
351
352void __flush_tlb_one(unsigned long addr)
353{
354 CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
355}
356
357void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
358 unsigned long end)
359{
360 CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
361 end);
362}
363
364void flush_tlb_mm(struct mm_struct *mm)
365{
366 CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
367}
368
369void force_flush_all(void)
370{
371 CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
372}
373
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
index 203216ad86f1..2eefb43bc9c2 100644
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -17,7 +17,7 @@
17#include "os.h" 17#include "os.h"
18#include "tlb.h" 18#include "tlb.h"
19 19
20static void do_ops(int unused, struct host_vm_op *ops, int last) 20static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
21{ 21{
22 struct host_vm_op *op; 22 struct host_vm_op *op;
23 int i; 23 int i;
@@ -55,7 +55,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr,
55 panic("fix_range fixing wrong address space, current = 0x%p", 55 panic("fix_range fixing wrong address space, current = 0x%p",
56 current); 56 current);
57 57
58 fix_range_common(mm, start_addr, end_addr, force, 0, do_ops); 58 fix_range_common(mm, start_addr, end_addr, force, do_ops);
59} 59}
60 60
61atomic_t vmchange_seq = ATOMIC_INIT(1); 61atomic_t vmchange_seq = ATOMIC_INIT(1);
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index 61dfd4fef752..163476a8cb1b 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -30,6 +30,7 @@ SECTIONS
30 _einittext = .; 30 _einittext = .;
31 } 31 }
32 . = ALIGN(4096); 32 . = ALIGN(4096);
33
33 .text : 34 .text :
34 { 35 {
35 *(.text) 36 *(.text)
@@ -39,6 +40,12 @@ SECTIONS
39 /* .gnu.warning sections are handled specially by elf32.em. */ 40 /* .gnu.warning sections are handled specially by elf32.em. */
40 *(.gnu.warning) 41 *(.gnu.warning)
41 *(.gnu.linkonce.t*) 42 *(.gnu.linkonce.t*)
43
44 . = ALIGN(4096);
45 __syscall_stub_start = .;
46 *(.__syscall_stub*)
47 __syscall_stub_end = .;
48 . = ALIGN(4096);
42 } 49 }
43 50
44 #include "asm/common.lds.S" 51 #include "asm/common.lds.S"