aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/skas
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/um/kernel/skas
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/um/kernel/skas')
-rw-r--r--arch/um/kernel/skas/Makefile13
-rw-r--r--arch/um/kernel/skas/exec_kern.c41
-rw-r--r--arch/um/kernel/skas/include/mmu-skas.h24
-rw-r--r--arch/um/kernel/skas/include/mode-skas.h34
-rw-r--r--arch/um/kernel/skas/include/mode_kern-skas.h53
-rw-r--r--arch/um/kernel/skas/include/proc_mm.h55
-rw-r--r--arch/um/kernel/skas/include/skas.h46
-rw-r--r--arch/um/kernel/skas/include/uaccess-skas.h45
-rw-r--r--arch/um/kernel/skas/mem.c35
-rw-r--r--arch/um/kernel/skas/mem_user.c102
-rw-r--r--arch/um/kernel/skas/mmu.c48
-rw-r--r--arch/um/kernel/skas/process.c339
-rw-r--r--arch/um/kernel/skas/process_kern.c213
-rw-r--r--arch/um/kernel/skas/syscall_kern.c43
-rw-r--r--arch/um/kernel/skas/syscall_user.c44
-rw-r--r--arch/um/kernel/skas/time.c30
-rw-r--r--arch/um/kernel/skas/tlb.c85
-rw-r--r--arch/um/kernel/skas/trap_user.c71
-rw-r--r--arch/um/kernel/skas/uaccess.c259
-rw-r--r--arch/um/kernel/skas/util/Makefile4
-rw-r--r--arch/um/kernel/skas/util/mk_ptregs-i386.c51
-rw-r--r--arch/um/kernel/skas/util/mk_ptregs-x86_64.c68
22 files changed, 1703 insertions, 0 deletions
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
new file mode 100644
index 000000000000..d37d1bfcd6f7
--- /dev/null
+++ b/arch/um/kernel/skas/Makefile
@@ -0,0 +1,13 @@
1#
2# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
3# Licensed under the GPL
4#
5
6obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
7 syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o \
8
9subdir- := util
10
11USER_OBJS := process.o time.o
12
13include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
new file mode 100644
index 000000000000..c6b4d5dba789
--- /dev/null
+++ b/arch/um/kernel/skas/exec_kern.c
@@ -0,0 +1,41 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "asm/current.h"
8#include "asm/page.h"
9#include "asm/signal.h"
10#include "asm/ptrace.h"
11#include "asm/uaccess.h"
12#include "asm/mmu_context.h"
13#include "tlb.h"
14#include "skas.h"
15#include "um_mmu.h"
16#include "os.h"
17
18void flush_thread_skas(void)
19{
20 force_flush_all();
21 switch_mm_skas(current->mm->context.skas.mm_fd);
22}
23
24void start_thread_skas(struct pt_regs *regs, unsigned long eip,
25 unsigned long esp)
26{
27 set_fs(USER_DS);
28 PT_REGS_IP(regs) = eip;
29 PT_REGS_SP(regs) = esp;
30}
31
32/*
33 * Overrides for Emacs so that we follow Linus's tabbing style.
34 * Emacs will notice this stuff at the end of the file and automatically
35 * adjust the settings for this buffer only. This must remain at the end
36 * of the file.
37 * ---------------------------------------------------------------------------
38 * Local variables:
39 * c-file-style: "linux"
40 * End:
41 */
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
new file mode 100644
index 000000000000..4cd60d7213f3
--- /dev/null
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -0,0 +1,24 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_MMU_H
7#define __SKAS_MMU_H
8
9struct mmu_context_skas {
10 int mm_fd;
11};
12
13#endif
14
15/*
16 * Overrides for Emacs so that we follow Linus's tabbing style.
17 * Emacs will notice this stuff at the end of the file and automatically
18 * adjust the settings for this buffer only. This must remain at the end
19 * of the file.
20 * ---------------------------------------------------------------------------
21 * Local variables:
22 * c-file-style: "linux"
23 * End:
24 */
diff --git a/arch/um/kernel/skas/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h
new file mode 100644
index 000000000000..c1e33bd788db
--- /dev/null
+++ b/arch/um/kernel/skas/include/mode-skas.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MODE_SKAS_H__
7#define __MODE_SKAS_H__
8
9#include <sysdep/ptrace.h>
10
11extern unsigned long exec_regs[];
12extern unsigned long exec_fp_regs[];
13extern unsigned long exec_fpx_regs[];
14extern int have_fpx_regs;
15
16extern void user_time_init_skas(void);
17extern void sig_handler_common_skas(int sig, void *sc_ptr);
18extern void halt_skas(void);
19extern void reboot_skas(void);
20extern void kill_off_processes_skas(void);
21extern int is_skas_winch(int pid, int fd, void *data);
22
23#endif
24
25/*
26 * Overrides for Emacs so that we follow Linus's tabbing style.
27 * Emacs will notice this stuff at the end of the file and automatically
28 * adjust the settings for this buffer only. This must remain at the end
29 * of the file.
30 * ---------------------------------------------------------------------------
31 * Local variables:
32 * c-file-style: "linux"
33 * End:
34 */
diff --git a/arch/um/kernel/skas/include/mode_kern-skas.h b/arch/um/kernel/skas/include/mode_kern-skas.h
new file mode 100644
index 000000000000..94c564962378
--- /dev/null
+++ b/arch/um/kernel/skas/include/mode_kern-skas.h
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_MODE_KERN_H__
7#define __SKAS_MODE_KERN_H__
8
9#include "linux/sched.h"
10#include "asm/page.h"
11#include "asm/ptrace.h"
12
13extern void flush_thread_skas(void);
14extern void *switch_to_skas(void *prev, void *next);
15extern void start_thread_skas(struct pt_regs *regs, unsigned long eip,
16 unsigned long esp);
17extern int copy_thread_skas(int nr, unsigned long clone_flags,
18 unsigned long sp, unsigned long stack_top,
19 struct task_struct *p, struct pt_regs *regs);
20extern void release_thread_skas(struct task_struct *task);
21extern void exit_thread_skas(void);
22extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
23extern void init_idle_skas(void);
24extern void flush_tlb_kernel_range_skas(unsigned long start,
25 unsigned long end);
26extern void flush_tlb_kernel_vm_skas(void);
27extern void __flush_tlb_one_skas(unsigned long addr);
28extern void flush_tlb_range_skas(struct vm_area_struct *vma,
29 unsigned long start, unsigned long end);
30extern void flush_tlb_mm_skas(struct mm_struct *mm);
31extern void force_flush_all_skas(void);
32extern long execute_syscall_skas(void *r);
33extern void before_mem_skas(unsigned long unused);
34extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
35 unsigned long *task_size_out);
36extern int start_uml_skas(void);
37extern int external_pid_skas(struct task_struct *task);
38extern int thread_pid_skas(struct task_struct *task);
39
40#define kmem_end_skas (host_task_size - 1024 * 1024)
41
42#endif
43
44/*
45 * Overrides for Emacs so that we follow Linus's tabbing style.
46 * Emacs will notice this stuff at the end of the file and automatically
47 * adjust the settings for this buffer only. This must remain at the end
48 * of the file.
49 * ---------------------------------------------------------------------------
50 * Local variables:
51 * c-file-style: "linux"
52 * End:
53 */
diff --git a/arch/um/kernel/skas/include/proc_mm.h b/arch/um/kernel/skas/include/proc_mm.h
new file mode 100644
index 000000000000..cce61a679052
--- /dev/null
+++ b/arch/um/kernel/skas/include/proc_mm.h
@@ -0,0 +1,55 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_PROC_MM_H
7#define __SKAS_PROC_MM_H
8
9#define MM_MMAP 54
10#define MM_MUNMAP 55
11#define MM_MPROTECT 56
12#define MM_COPY_SEGMENTS 57
13
14struct mm_mmap {
15 unsigned long addr;
16 unsigned long len;
17 unsigned long prot;
18 unsigned long flags;
19 unsigned long fd;
20 unsigned long offset;
21};
22
23struct mm_munmap {
24 unsigned long addr;
25 unsigned long len;
26};
27
28struct mm_mprotect {
29 unsigned long addr;
30 unsigned long len;
31 unsigned int prot;
32};
33
34struct proc_mm_op {
35 int op;
36 union {
37 struct mm_mmap mmap;
38 struct mm_munmap munmap;
39 struct mm_mprotect mprotect;
40 int copy_segments;
41 } u;
42};
43
44#endif
45
46/*
47 * Overrides for Emacs so that we follow Linus's tabbing style.
48 * Emacs will notice this stuff at the end of the file and automatically
49 * adjust the settings for this buffer only. This must remain at the end
50 * of the file.
51 * ---------------------------------------------------------------------------
52 * Local variables:
53 * c-file-style: "linux"
54 * End:
55 */
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
new file mode 100644
index 000000000000..f0702c2c7204
--- /dev/null
+++ b/arch/um/kernel/skas/include/skas.h
@@ -0,0 +1,46 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_H
7#define __SKAS_H
8
9#include "sysdep/ptrace.h"
10
11extern int userspace_pid[];
12
13extern void switch_threads(void *me, void *next);
14extern void thread_wait(void *sw, void *fb);
15extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
16 void (*handler)(int));
17extern int start_idle_thread(void *stack, void *switch_buf_ptr,
18 void **fork_buf_ptr);
19extern int user_thread(unsigned long stack, int flags);
20extern void userspace(union uml_pt_regs *regs);
21extern void new_thread_proc(void *stack, void (*handler)(int sig));
22extern void remove_sigstack(void);
23extern void new_thread_handler(int sig);
24extern void handle_syscall(union uml_pt_regs *regs);
25extern void map(int fd, unsigned long virt, unsigned long len, int r, int w,
26 int x, int phys_fd, unsigned long long offset);
27extern int unmap(int fd, void *addr, unsigned long len);
28extern int protect(int fd, unsigned long addr, unsigned long len,
29 int r, int w, int x);
30extern void user_signal(int sig, union uml_pt_regs *regs);
31extern int new_mm(int from);
32extern void start_userspace(int cpu);
33extern long execute_syscall_skas(void *r);
34
35#endif
36
37/*
38 * Overrides for Emacs so that we follow Linus's tabbing style.
39 * Emacs will notice this stuff at the end of the file and automatically
40 * adjust the settings for this buffer only. This must remain at the end
41 * of the file.
42 * ---------------------------------------------------------------------------
43 * Local variables:
44 * c-file-style: "linux"
45 * End:
46 */
diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h
new file mode 100644
index 000000000000..11986c9b9ddf
--- /dev/null
+++ b/arch/um/kernel/skas/include/uaccess-skas.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SKAS_UACCESS_H
7#define __SKAS_UACCESS_H
8
9#include "asm/errno.h"
10#include "asm/fixmap.h"
11
12#define access_ok_skas(type, addr, size) \
13 ((segment_eq(get_fs(), KERNEL_DS)) || \
14 (((unsigned long) (addr) < TASK_SIZE) && \
15 ((unsigned long) (addr) + (size) <= TASK_SIZE)) || \
16 ((type == VERIFY_READ ) && \
17 ((unsigned long) (addr) >= FIXADDR_USER_START) && \
18 ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
19 ((unsigned long) (addr) + (size) >= (unsigned long)(addr))))
20
21static inline int verify_area_skas(int type, const void * addr,
22 unsigned long size)
23{
24 return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
25}
26
27extern int copy_from_user_skas(void *to, const void *from, int n);
28extern int copy_to_user_skas(void *to, const void *from, int n);
29extern int strncpy_from_user_skas(char *dst, const char *src, int count);
30extern int __clear_user_skas(void *mem, int len);
31extern int clear_user_skas(void *mem, int len);
32extern int strnlen_user_skas(const void *str, int len);
33
34#endif
35
36/*
37 * Overrides for Emacs so that we follow Linus's tabbing style.
38 * Emacs will notice this stuff at the end of the file and automatically
39 * adjust the settings for this buffer only. This must remain at the end
40 * of the file.
41 * ---------------------------------------------------------------------------
42 * Local variables:
43 * c-file-style: "linux"
44 * End:
45 */
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
new file mode 100644
index 000000000000..438db2f43456
--- /dev/null
+++ b/arch/um/kernel/skas/mem.c
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/mm.h"
8#include "mem_user.h"
9
10unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
11 unsigned long *task_size_out)
12{
13 /* Round up to the nearest 4M */
14 unsigned long top = ROUND_4M((unsigned long) &arg);
15
16#ifdef CONFIG_HOST_TASK_SIZE
17 *host_size_out = CONFIG_HOST_TASK_SIZE;
18 *task_size_out = CONFIG_HOST_TASK_SIZE;
19#else
20 *host_size_out = top;
21 *task_size_out = top;
22#endif
23 return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
24}
25
26/*
27 * Overrides for Emacs so that we follow Linus's tabbing style.
28 * Emacs will notice this stuff at the end of the file and automatically
29 * adjust the settings for this buffer only. This must remain at the end
30 * of the file.
31 * ---------------------------------------------------------------------------
32 * Local variables:
33 * c-file-style: "linux"
34 * End:
35 */
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
new file mode 100644
index 000000000000..1310bf1e88d1
--- /dev/null
+++ b/arch/um/kernel/skas/mem_user.c
@@ -0,0 +1,102 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <errno.h>
7#include <sys/mman.h>
8#include "mem_user.h"
9#include "mem.h"
10#include "user.h"
11#include "os.h"
12#include "proc_mm.h"
13
14void map(int fd, unsigned long virt, unsigned long len, int r, int w,
15 int x, int phys_fd, unsigned long long offset)
16{
17 struct proc_mm_op map;
18 int prot, n;
19
20 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
21 (x ? PROT_EXEC : 0);
22
23 map = ((struct proc_mm_op) { .op = MM_MMAP,
24 .u =
25 { .mmap =
26 { .addr = virt,
27 .len = len,
28 .prot = prot,
29 .flags = MAP_SHARED |
30 MAP_FIXED,
31 .fd = phys_fd,
32 .offset = offset
33 } } } );
34 n = os_write_file(fd, &map, sizeof(map));
35 if(n != sizeof(map))
36 printk("map : /proc/mm map failed, err = %d\n", -n);
37}
38
39int unmap(int fd, void *addr, unsigned long len)
40{
41 struct proc_mm_op unmap;
42 int n;
43
44 unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
45 .u =
46 { .munmap =
47 { .addr = (unsigned long) addr,
48 .len = len } } } );
49 n = os_write_file(fd, &unmap, sizeof(unmap));
50 if(n != sizeof(unmap)) {
51 if(n < 0)
52 return(n);
53 else if(n > 0)
54 return(-EIO);
55 }
56
57 return(0);
58}
59
60int protect(int fd, unsigned long addr, unsigned long len, int r, int w,
61 int x, int must_succeed)
62{
63 struct proc_mm_op protect;
64 int prot, n;
65
66 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
67 (x ? PROT_EXEC : 0);
68
69 protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
70 .u =
71 { .mprotect =
72 { .addr = (unsigned long) addr,
73 .len = len,
74 .prot = prot } } } );
75
76 n = os_write_file(fd, &protect, sizeof(protect));
77 if(n != sizeof(protect)) {
78 if(n == 0) return(0);
79
80 if(must_succeed)
81 panic("protect failed, err = %d", -n);
82
83 return(-EIO);
84 }
85
86 return(0);
87}
88
89void before_mem_skas(unsigned long unused)
90{
91}
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
new file mode 100644
index 000000000000..6cb9a6d028a9
--- /dev/null
+++ b/arch/um/kernel/skas/mmu.c
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/list.h"
8#include "linux/spinlock.h"
9#include "linux/slab.h"
10#include "asm/current.h"
11#include "asm/segment.h"
12#include "asm/mmu.h"
13#include "os.h"
14#include "skas.h"
15
16int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
17{
18 int from;
19
20 if((current->mm != NULL) && (current->mm != &init_mm))
21 from = current->mm->context.skas.mm_fd;
22 else from = -1;
23
24 mm->context.skas.mm_fd = new_mm(from);
25 if(mm->context.skas.mm_fd < 0){
26 printk("init_new_context_skas - new_mm failed, errno = %d\n",
27 mm->context.skas.mm_fd);
28 return(mm->context.skas.mm_fd);
29 }
30
31 return(0);
32}
33
34void destroy_context_skas(struct mm_struct *mm)
35{
36 os_close_file(mm->context.skas.mm_fd);
37}
38
39/*
40 * Overrides for Emacs so that we follow Linus's tabbing style.
41 * Emacs will notice this stuff at the end of the file and automatically
42 * adjust the settings for this buffer only. This must remain at the end
43 * of the file.
44 * ---------------------------------------------------------------------------
45 * Local variables:
46 * c-file-style: "linux"
47 * End:
48 */
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
new file mode 100644
index 000000000000..b4ffaaa81241
--- /dev/null
+++ b/arch/um/kernel/skas/process.c
@@ -0,0 +1,339 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <unistd.h>
8#include <errno.h>
9#include <signal.h>
10#include <setjmp.h>
11#include <sched.h>
12#include <sys/wait.h>
13#include <sys/mman.h>
14#include <sys/user.h>
15#include <asm/unistd.h>
16#include "user.h"
17#include "ptrace_user.h"
18#include "time_user.h"
19#include "sysdep/ptrace.h"
20#include "user_util.h"
21#include "kern_util.h"
22#include "skas.h"
23#include "sysdep/sigcontext.h"
24#include "os.h"
25#include "proc_mm.h"
26#include "skas_ptrace.h"
27#include "chan_user.h"
28#include "signal_user.h"
29#include "registers.h"
30
31int is_skas_winch(int pid, int fd, void *data)
32{
33 if(pid != os_getpid())
34 return(0);
35
36 register_winch_irq(-1, fd, -1, data);
37 return(1);
38}
39
40static void handle_segv(int pid)
41{
42 struct ptrace_faultinfo fault;
43 int err;
44
45 err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault);
46 if(err)
47 panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n",
48 errno);
49
50 segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
51}
52
53/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
54static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu)
55{
56 int err, status;
57
58 /* Mark this as a syscall */
59 UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs);
60
61 if (!local_using_sysemu)
62 {
63 err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
64 if(err < 0)
65 panic("handle_trap - nullifying syscall failed errno = %d\n",
66 errno);
67
68 err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
69 if(err < 0)
70 panic("handle_trap - continuing to end of syscall failed, "
71 "errno = %d\n", errno);
72
73 CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
74 if((err < 0) || !WIFSTOPPED(status) ||
75 (WSTOPSIG(status) != SIGTRAP + 0x80))
76 panic("handle_trap - failed to wait at end of syscall, "
77 "errno = %d, status = %d\n", errno, status);
78 }
79
80 handle_syscall(regs);
81}
82
83static int userspace_tramp(void *arg)
84{
85 init_new_thread_signals(0);
86 enable_timer();
87 ptrace(PTRACE_TRACEME, 0, 0, 0);
88 os_stop_process(os_getpid());
89 return(0);
90}
91
92/* Each element set once, and only accessed by a single processor anyway */
93#undef NR_CPUS
94#define NR_CPUS 1
95int userspace_pid[NR_CPUS];
96
97void start_userspace(int cpu)
98{
99 void *stack;
100 unsigned long sp;
101 int pid, status, n;
102
103 stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
104 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
105 if(stack == MAP_FAILED)
106 panic("start_userspace : mmap failed, errno = %d", errno);
107 sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
108
109 pid = clone(userspace_tramp, (void *) sp,
110 CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
111 if(pid < 0)
112 panic("start_userspace : clone failed, errno = %d", errno);
113
114 do {
115 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
116 if(n < 0)
117 panic("start_userspace : wait failed, errno = %d",
118 errno);
119 } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
120
121 if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
122 panic("start_userspace : expected SIGSTOP, got status = %d",
123 status);
124
125 if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, (void *)PTRACE_O_TRACESYSGOOD) < 0)
126 panic("start_userspace : PTRACE_SETOPTIONS failed, errno=%d\n",
127 errno);
128
129 if(munmap(stack, PAGE_SIZE) < 0)
130 panic("start_userspace : munmap failed, errno = %d\n", errno);
131
132 userspace_pid[cpu] = pid;
133}
134
135void userspace(union uml_pt_regs *regs)
136{
137 int err, status, op, pid = userspace_pid[0];
138 int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
139
140 while(1){
141 restore_registers(pid, regs);
142
143 /* Now we set local_using_sysemu to be used for one loop */
144 local_using_sysemu = get_using_sysemu();
145
146 op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
147
148 err = ptrace(op, pid, 0, 0);
149 if(err)
150 panic("userspace - could not resume userspace process, "
151 "pid=%d, ptrace operation = %d, errno = %d\n",
152 op, errno);
153
154 CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
155 if(err < 0)
156 panic("userspace - waitpid failed, errno = %d\n",
157 errno);
158
159 regs->skas.is_user = 1;
160 save_registers(pid, regs);
161 UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
162
163 if(WIFSTOPPED(status)){
164 switch(WSTOPSIG(status)){
165 case SIGSEGV:
166 handle_segv(pid);
167 break;
168 case SIGTRAP + 0x80:
169 handle_trap(pid, regs, local_using_sysemu);
170 break;
171 case SIGTRAP:
172 relay_signal(SIGTRAP, regs);
173 break;
174 case SIGIO:
175 case SIGVTALRM:
176 case SIGILL:
177 case SIGBUS:
178 case SIGFPE:
179 case SIGWINCH:
180 user_signal(WSTOPSIG(status), regs);
181 break;
182 default:
183 printk("userspace - child stopped with signal "
184 "%d\n", WSTOPSIG(status));
185 }
186 interrupt_end();
187
188 /* Avoid -ERESTARTSYS handling in host */
189 PT_SYSCALL_NR(regs->skas.regs) = -1;
190 }
191 }
192}
193
194void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
195 void (*handler)(int))
196{
197 unsigned long flags;
198 sigjmp_buf switch_buf, fork_buf;
199
200 *switch_buf_ptr = &switch_buf;
201 *fork_buf_ptr = &fork_buf;
202
203 /* Somewhat subtle - siglongjmp restores the signal mask before doing
204 * the longjmp. This means that when jumping from one stack to another
205 * when the target stack has interrupts enabled, an interrupt may occur
206 * on the source stack. This is bad when starting up a process because
207 * it's not supposed to get timer ticks until it has been scheduled.
208 * So, we disable interrupts around the sigsetjmp to ensure that
209 * they can't happen until we get back here where they are safe.
210 */
211 flags = get_signals();
212 block_signals();
213 if(sigsetjmp(fork_buf, 1) == 0)
214 new_thread_proc(stack, handler);
215
216 remove_sigstack();
217
218 set_signals(flags);
219}
220
221void thread_wait(void *sw, void *fb)
222{
223 sigjmp_buf buf, **switch_buf = sw, *fork_buf;
224
225 *switch_buf = &buf;
226 fork_buf = fb;
227 if(sigsetjmp(buf, 1) == 0)
228 siglongjmp(*fork_buf, 1);
229}
230
231void switch_threads(void *me, void *next)
232{
233 sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
234
235 *me_ptr = &my_buf;
236 if(sigsetjmp(my_buf, 1) == 0)
237 siglongjmp(*next_buf, 1);
238}
239
240static sigjmp_buf initial_jmpbuf;
241
242/* XXX Make these percpu */
243static void (*cb_proc)(void *arg);
244static void *cb_arg;
245static sigjmp_buf *cb_back;
246
247int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
248{
249 sigjmp_buf **switch_buf = switch_buf_ptr;
250 int n;
251
252 *fork_buf_ptr = &initial_jmpbuf;
253 n = sigsetjmp(initial_jmpbuf, 1);
254 if(n == 0)
255 new_thread_proc((void *) stack, new_thread_handler);
256 else if(n == 1)
257 remove_sigstack();
258 else if(n == 2){
259 (*cb_proc)(cb_arg);
260 siglongjmp(*cb_back, 1);
261 }
262 else if(n == 3){
263 kmalloc_ok = 0;
264 return(0);
265 }
266 else if(n == 4){
267 kmalloc_ok = 0;
268 return(1);
269 }
270 siglongjmp(**switch_buf, 1);
271}
272
273void remove_sigstack(void)
274{
275 stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
276 .ss_sp = NULL,
277 .ss_size = 0 });
278
279 if(sigaltstack(&stack, NULL) != 0)
280 panic("disabling signal stack failed, errno = %d\n", errno);
281}
282
283void initial_thread_cb_skas(void (*proc)(void *), void *arg)
284{
285 sigjmp_buf here;
286
287 cb_proc = proc;
288 cb_arg = arg;
289 cb_back = &here;
290
291 block_signals();
292 if(sigsetjmp(here, 1) == 0)
293 siglongjmp(initial_jmpbuf, 2);
294 unblock_signals();
295
296 cb_proc = NULL;
297 cb_arg = NULL;
298 cb_back = NULL;
299}
300
301void halt_skas(void)
302{
303 block_signals();
304 siglongjmp(initial_jmpbuf, 3);
305}
306
307void reboot_skas(void)
308{
309 block_signals();
310 siglongjmp(initial_jmpbuf, 4);
311}
312
313void switch_mm_skas(int mm_fd)
314{
315 int err;
316
317#warning need cpu pid in switch_mm_skas
318 err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
319 if(err)
320 panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
321 errno);
322}
323
324void kill_off_processes_skas(void)
325{
326#warning need to loop over userspace_pids in kill_off_processes_skas
327 os_kill_ptraced_process(userspace_pid[0], 1);
328}
329
330/*
331 * Overrides for Emacs so that we follow Linus's tabbing style.
332 * Emacs will notice this stuff at the end of the file and automatically
333 * adjust the settings for this buffer only. This must remain at the end
334 * of the file.
335 * ---------------------------------------------------------------------------
336 * Local variables:
337 * c-file-style: "linux"
338 * End:
339 */
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
new file mode 100644
index 000000000000..5d096ea63b97
--- /dev/null
+++ b/arch/um/kernel/skas/process_kern.c
@@ -0,0 +1,213 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/slab.h"
8#include "linux/ptrace.h"
9#include "linux/proc_fs.h"
10#include "linux/file.h"
11#include "linux/errno.h"
12#include "linux/init.h"
13#include "asm/uaccess.h"
14#include "asm/atomic.h"
15#include "kern_util.h"
16#include "time_user.h"
17#include "signal_user.h"
18#include "skas.h"
19#include "os.h"
20#include "user_util.h"
21#include "tlb.h"
22#include "kern.h"
23#include "mode.h"
24#include "proc_mm.h"
25#include "registers.h"
26
27void *switch_to_skas(void *prev, void *next)
28{
29 struct task_struct *from, *to;
30
31 from = prev;
32 to = next;
33
34 /* XXX need to check runqueues[cpu].idle */
35 if(current->pid == 0)
36 switch_timers(0);
37
38 to->thread.prev_sched = from;
39 set_current(to);
40
41 switch_threads(&from->thread.mode.skas.switch_buf,
42 to->thread.mode.skas.switch_buf);
43
44 if(current->pid == 0)
45 switch_timers(1);
46
47 return(current->thread.prev_sched);
48}
49
50extern void schedule_tail(struct task_struct *prev);
51
52void new_thread_handler(int sig)
53{
54 int (*fn)(void *), n;
55 void *arg;
56
57 fn = current->thread.request.u.thread.proc;
58 arg = current->thread.request.u.thread.arg;
59 change_sig(SIGUSR1, 1);
60 thread_wait(&current->thread.mode.skas.switch_buf,
61 current->thread.mode.skas.fork_buf);
62
63 if(current->thread.prev_sched != NULL)
64 schedule_tail(current->thread.prev_sched);
65 current->thread.prev_sched = NULL;
66
67 /* The return value is 1 if the kernel thread execs a process,
68 * 0 if it just exits
69 */
70 n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
71 if(n == 1)
72 userspace(&current->thread.regs.regs);
73 else do_exit(0);
74}
75
76void new_thread_proc(void *stack, void (*handler)(int sig))
77{
78 init_new_thread_stack(stack, handler);
79 os_usr1_process(os_getpid());
80}
81
82void release_thread_skas(struct task_struct *task)
83{
84}
85
86void exit_thread_skas(void)
87{
88}
89
90void fork_handler(int sig)
91{
92 change_sig(SIGUSR1, 1);
93 thread_wait(&current->thread.mode.skas.switch_buf,
94 current->thread.mode.skas.fork_buf);
95
96 force_flush_all();
97 if(current->thread.prev_sched == NULL)
98 panic("blech");
99
100 schedule_tail(current->thread.prev_sched);
101 current->thread.prev_sched = NULL;
102
103 userspace(&current->thread.regs.regs);
104}
105
106int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
107 unsigned long stack_top, struct task_struct * p,
108 struct pt_regs *regs)
109{
110 void (*handler)(int);
111
112 if(current->thread.forking){
113 memcpy(&p->thread.regs.regs.skas,
114 &current->thread.regs.regs.skas,
115 sizeof(p->thread.regs.regs.skas));
116 REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
117 if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
118
119 handler = fork_handler;
120 }
121 else {
122 init_thread_registers(&p->thread.regs.regs);
123 p->thread.request.u.thread = current->thread.request.u.thread;
124 handler = new_thread_handler;
125 }
126
127 new_thread(p->thread_info, &p->thread.mode.skas.switch_buf,
128 &p->thread.mode.skas.fork_buf, handler);
129 return(0);
130}
131
132int new_mm(int from)
133{
134 struct proc_mm_op copy;
135 int n, fd;
136
137 fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
138 if(fd < 0)
139 return(fd);
140
141 if(from != -1){
142 copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS,
143 .u =
144 { .copy_segments = from } } );
145 n = os_write_file(fd, &copy, sizeof(copy));
146 if(n != sizeof(copy))
147 printk("new_mm : /proc/mm copy_segments failed, "
148 "err = %d\n", -n);
149 }
150
151 return(fd);
152}
153
154void init_idle_skas(void)
155{
156 cpu_tasks[current_thread->cpu].pid = os_getpid();
157 default_idle();
158}
159
160extern void start_kernel(void);
161
162static int start_kernel_proc(void *unused)
163{
164 int pid;
165
166 block_signals();
167 pid = os_getpid();
168
169 cpu_tasks[0].pid = pid;
170 cpu_tasks[0].task = current;
171#ifdef CONFIG_SMP
172 cpu_online_map = cpumask_of_cpu(0);
173#endif
174 start_kernel();
175 return(0);
176}
177
178int start_uml_skas(void)
179{
180 start_userspace(0);
181
182 init_new_thread_signals(1);
183 uml_idle_timer();
184
185 init_task.thread.request.u.thread.proc = start_kernel_proc;
186 init_task.thread.request.u.thread.arg = NULL;
187 return(start_idle_thread(init_task.thread_info,
188 &init_task.thread.mode.skas.switch_buf,
189 &init_task.thread.mode.skas.fork_buf));
190}
191
192int external_pid_skas(struct task_struct *task)
193{
194#warning Need to look up userspace_pid by cpu
195 return(userspace_pid[0]);
196}
197
198int thread_pid_skas(struct task_struct *task)
199{
200#warning Need to look up userspace_pid by cpu
201 return(userspace_pid[0]);
202}
203
204/*
205 * Overrides for Emacs so that we follow Linus's tabbing style.
206 * Emacs will notice this stuff at the end of the file and automatically
207 * adjust the settings for this buffer only. This must remain at the end
208 * of the file.
209 * ---------------------------------------------------------------------------
210 * Local variables:
211 * c-file-style: "linux"
212 * End:
213 */
diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c
new file mode 100644
index 000000000000..bdf040ce5b8e
--- /dev/null
+++ b/arch/um/kernel/skas/syscall_kern.c
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sys.h"
7#include "linux/ptrace.h"
8#include "asm/errno.h"
9#include "asm/unistd.h"
10#include "asm/ptrace.h"
11#include "asm/current.h"
12#include "sysdep/syscalls.h"
13#include "kern_util.h"
14
15extern syscall_handler_t *sys_call_table[];
16
17long execute_syscall_skas(void *r)
18{
19 struct pt_regs *regs = r;
20 long res;
21 int syscall;
22
23 current->thread.nsyscalls++;
24 nsyscalls++;
25 syscall = UPT_SYSCALL_NR(&regs->regs);
26
27 if((syscall >= NR_syscalls) || (syscall < 0))
28 res = -ENOSYS;
29 else res = EXECUTE_SYSCALL(syscall, regs);
30
31 return(res);
32}
33
34/*
35 * Overrides for Emacs so that we follow Linus's tabbing style.
36 * Emacs will notice this stuff at the end of the file and automatically
37 * adjust the settings for this buffer only. This must remain at the end
38 * of the file.
39 * ---------------------------------------------------------------------------
40 * Local variables:
41 * c-file-style: "linux"
42 * End:
43 */
diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c
new file mode 100644
index 000000000000..2828e6e37721
--- /dev/null
+++ b/arch/um/kernel/skas/syscall_user.c
@@ -0,0 +1,44 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <signal.h>
8#include "kern_util.h"
9#include "uml-config.h"
10#include "syscall_user.h"
11#include "sysdep/ptrace.h"
12#include "sysdep/sigcontext.h"
13#include "skas.h"
14
15void handle_syscall(union uml_pt_regs *regs)
16{
17 long result;
18#if UML_CONFIG_SYSCALL_DEBUG
19 int index;
20
21 index = record_syscall_start(UPT_SYSCALL_NR(regs));
22#endif
23
24 syscall_trace(regs, 0);
25 result = execute_syscall_skas(regs);
26
27 REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
28
29 syscall_trace(regs, 1);
30#if UML_CONFIG_SYSCALL_DEBUG
31 record_syscall_end(index, result);
32#endif
33}
34
35/*
36 * Overrides for Emacs so that we follow Linus's tabbing style.
37 * Emacs will notice this stuff at the end of the file and automatically
38 * adjust the settings for this buffer only. This must remain at the end
39 * of the file.
40 * ---------------------------------------------------------------------------
41 * Local variables:
42 * c-file-style: "linux"
43 * End:
44 */
diff --git a/arch/um/kernel/skas/time.c b/arch/um/kernel/skas/time.c
new file mode 100644
index 000000000000..98091494b897
--- /dev/null
+++ b/arch/um/kernel/skas/time.c
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <sys/signal.h>
7#include <sys/time.h>
8#include "time_user.h"
9#include "process.h"
10#include "user.h"
11
12void user_time_init_skas(void)
13{
14 if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
15 panic("Couldn't set SIGALRM handler");
16 if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
17 panic("Couldn't set SIGVTALRM handler");
18 set_interval(ITIMER_VIRTUAL);
19}
20
21/*
22 * Overrides for Emacs so that we follow Linus's tabbing style.
23 * Emacs will notice this stuff at the end of the file and automatically
24 * adjust the settings for this buffer only. This must remain at the end
25 * of the file.
26 * ---------------------------------------------------------------------------
27 * Local variables:
28 * c-file-style: "linux"
29 * End:
30 */
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
new file mode 100644
index 000000000000..b8c5e71763d1
--- /dev/null
+++ b/arch/um/kernel/skas/tlb.c
@@ -0,0 +1,85 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Copyright 2003 PathScale, Inc.
4 * Licensed under the GPL
5 */
6
7#include "linux/stddef.h"
8#include "linux/sched.h"
9#include "linux/mm.h"
10#include "asm/page.h"
11#include "asm/pgtable.h"
12#include "asm/mmu.h"
13#include "user_util.h"
14#include "mem_user.h"
15#include "mem.h"
16#include "skas.h"
17#include "os.h"
18#include "tlb.h"
19
20static void do_ops(int fd, struct host_vm_op *ops, int last)
21{
22 struct host_vm_op *op;
23 int i;
24
25 for(i = 0; i <= last; i++){
26 op = &ops[i];
27 switch(op->type){
28 case MMAP:
29 map(fd, 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.fd, op->u.mmap.offset);
32 break;
33 case MUNMAP:
34 unmap(fd, (void *) op->u.munmap.addr,
35 op->u.munmap.len);
36 break;
37 case MPROTECT:
38 protect(fd, op->u.mprotect.addr, op->u.mprotect.len,
39 op->u.mprotect.r, op->u.mprotect.w,
40 op->u.mprotect.x);
41 break;
42 default:
43 printk("Unknown op type %d in do_ops\n", op->type);
44 break;
45 }
46 }
47}
48
49static void fix_range(struct mm_struct *mm, unsigned long start_addr,
50 unsigned long end_addr, int force)
51{
52 int fd = mm->context.skas.mm_fd;
53
54 fix_range_common(mm, start_addr, end_addr, force, fd, do_ops);
55}
56
57void __flush_tlb_one_skas(unsigned long addr)
58{
59 flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE);
60}
61
62void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start,
63 unsigned long end)
64{
65 if(vma->vm_mm == NULL)
66 flush_tlb_kernel_range_common(start, end);
67 else fix_range(vma->vm_mm, start, end, 0);
68}
69
70void flush_tlb_mm_skas(struct mm_struct *mm)
71{
72 /* Don't bother flushing if this address space is about to be
73 * destroyed.
74 */
75 if(atomic_read(&mm->mm_users) == 0)
76 return;
77
78 fix_range(mm, 0, host_task_size, 0);
79 flush_tlb_kernel_range_common(start_vm, end_vm);
80}
81
82void force_flush_all_skas(void)
83{
84 fix_range(current->mm, 0, host_task_size, 1);
85}
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c
new file mode 100644
index 000000000000..8e9b46d4702e
--- /dev/null
+++ b/arch/um/kernel/skas/trap_user.c
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <signal.h>
7#include <errno.h>
8#include "sysdep/ptrace.h"
9#include "signal_user.h"
10#include "user_util.h"
11#include "kern_util.h"
12#include "task.h"
13#include "sigcontext.h"
14
15void sig_handler_common_skas(int sig, void *sc_ptr)
16{
17 struct sigcontext *sc = sc_ptr;
18 struct skas_regs *r;
19 struct signal_info *info;
20 int save_errno = errno;
21 int save_user;
22
23 /* This is done because to allow SIGSEGV to be delivered inside a SEGV
24 * handler. This can happen in copy_user, and if SEGV is disabled,
25 * the process will die.
26 * XXX Figure out why this is better than SA_NODEFER
27 */
28 if(sig == SIGSEGV)
29 change_sig(SIGSEGV, 1);
30
31 r = &TASK_REGS(get_current())->skas;
32 save_user = r->is_user;
33 r->is_user = 0;
34 r->fault_addr = SC_FAULT_ADDR(sc);
35 r->fault_type = SC_FAULT_TYPE(sc);
36 r->trap_type = SC_TRAP_TYPE(sc);
37
38 change_sig(SIGUSR1, 1);
39 info = &sig_info[sig];
40 if(!info->is_irq) unblock_signals();
41
42 (*info->handler)(sig, (union uml_pt_regs *) r);
43
44 errno = save_errno;
45 r->is_user = save_user;
46}
47
48void user_signal(int sig, union uml_pt_regs *regs)
49{
50 struct signal_info *info;
51
52 regs->skas.is_user = 1;
53 regs->skas.fault_addr = 0;
54 regs->skas.fault_type = 0;
55 regs->skas.trap_type = 0;
56 info = &sig_info[sig];
57 (*info->handler)(sig, regs);
58
59 unblock_signals();
60}
61
62/*
63 * Overrides for Emacs so that we follow Linus's tabbing style.
64 * Emacs will notice this stuff at the end of the file and automatically
65 * adjust the settings for this buffer only. This must remain at the end
66 * of the file.
67 * ---------------------------------------------------------------------------
68 * Local variables:
69 * c-file-style: "linux"
70 * End:
71 */
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
new file mode 100644
index 000000000000..7575ec489b63
--- /dev/null
+++ b/arch/um/kernel/skas/uaccess.c
@@ -0,0 +1,259 @@
1/*
2 * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/stddef.h"
7#include "linux/kernel.h"
8#include "linux/string.h"
9#include "linux/fs.h"
10#include "linux/highmem.h"
11#include "asm/page.h"
12#include "asm/pgtable.h"
13#include "asm/uaccess.h"
14#include "kern_util.h"
15#include "user_util.h"
16
17extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
18 pte_t *pte_out);
19
20static unsigned long maybe_map(unsigned long virt, int is_write)
21{
22 pte_t pte;
23 int err;
24
25 void *phys = um_virt_to_phys(current, virt, &pte);
26 int dummy_code;
27
28 if(IS_ERR(phys) || (is_write && !pte_write(pte))){
29 err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
30 if(err)
31 return(0);
32 phys = um_virt_to_phys(current, virt, NULL);
33 }
34 return((unsigned long) phys);
35}
36
37static int do_op(unsigned long addr, int len, int is_write,
38 int (*op)(unsigned long addr, int len, void *arg), void *arg)
39{
40 struct page *page;
41 int n;
42
43 addr = maybe_map(addr, is_write);
44 if(addr == -1)
45 return(-1);
46
47 page = phys_to_page(addr);
48 addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK);
49 n = (*op)(addr, len, arg);
50 kunmap(page);
51
52 return(n);
53}
54
55static void do_buffer_op(void *jmpbuf, void *arg_ptr)
56{
57 va_list args;
58 unsigned long addr;
59 int len, is_write, size, remain, n;
60 int (*op)(unsigned long, int, void *);
61 void *arg;
62 int *res;
63
64 /* Some old gccs recognize __va_copy, but not va_copy */
65 __va_copy(args, *(va_list *)arg_ptr);
66 addr = va_arg(args, unsigned long);
67 len = va_arg(args, int);
68 is_write = va_arg(args, int);
69 op = va_arg(args, void *);
70 arg = va_arg(args, void *);
71 res = va_arg(args, int *);
72 va_end(args);
73 size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
74 remain = len;
75
76 current->thread.fault_catcher = jmpbuf;
77 n = do_op(addr, size, is_write, op, arg);
78 if(n != 0){
79 *res = (n < 0 ? remain : 0);
80 goto out;
81 }
82
83 addr += size;
84 remain -= size;
85 if(remain == 0){
86 *res = 0;
87 goto out;
88 }
89
90 while(addr < ((addr + remain) & PAGE_MASK)){
91 n = do_op(addr, PAGE_SIZE, is_write, op, arg);
92 if(n != 0){
93 *res = (n < 0 ? remain : 0);
94 goto out;
95 }
96
97 addr += PAGE_SIZE;
98 remain -= PAGE_SIZE;
99 }
100 if(remain == 0){
101 *res = 0;
102 goto out;
103 }
104
105 n = do_op(addr, remain, is_write, op, arg);
106 if(n != 0)
107 *res = (n < 0 ? remain : 0);
108 else *res = 0;
109 out:
110 current->thread.fault_catcher = NULL;
111}
112
113static int buffer_op(unsigned long addr, int len, int is_write,
114 int (*op)(unsigned long addr, int len, void *arg),
115 void *arg)
116{
117 int faulted, res;
118
119 faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg,
120 &res);
121 if(!faulted)
122 return(res);
123
124 return(addr + len - (unsigned long) current->thread.fault_addr);
125}
126
127static int copy_chunk_from_user(unsigned long from, int len, void *arg)
128{
129 unsigned long *to_ptr = arg, to = *to_ptr;
130
131 memcpy((void *) to, (void *) from, len);
132 *to_ptr += len;
133 return(0);
134}
135
136int copy_from_user_skas(void *to, const void __user *from, int n)
137{
138 if(segment_eq(get_fs(), KERNEL_DS)){
139 memcpy(to, (__force void*)from, n);
140 return(0);
141 }
142
143 return(access_ok_skas(VERIFY_READ, from, n) ?
144 buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
145 n);
146}
147
148static int copy_chunk_to_user(unsigned long to, int len, void *arg)
149{
150 unsigned long *from_ptr = arg, from = *from_ptr;
151
152 memcpy((void *) to, (void *) from, len);
153 *from_ptr += len;
154 return(0);
155}
156
157int copy_to_user_skas(void __user *to, const void *from, int n)
158{
159 if(segment_eq(get_fs(), KERNEL_DS)){
160 memcpy((__force void*)to, from, n);
161 return(0);
162 }
163
164 return(access_ok_skas(VERIFY_WRITE, to, n) ?
165 buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
166 n);
167}
168
169static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
170{
171 char **to_ptr = arg, *to = *to_ptr;
172 int n;
173
174 strncpy(to, (void *) from, len);
175 n = strnlen(to, len);
176 *to_ptr += n;
177
178 if(n < len)
179 return(1);
180 return(0);
181}
182
183int strncpy_from_user_skas(char *dst, const char __user *src, int count)
184{
185 int n;
186 char *ptr = dst;
187
188 if(segment_eq(get_fs(), KERNEL_DS)){
189 strncpy(dst, (__force void*)src, count);
190 return(strnlen(dst, count));
191 }
192
193 if(!access_ok_skas(VERIFY_READ, src, 1))
194 return(-EFAULT);
195
196 n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
197 &ptr);
198 if(n != 0)
199 return(-EFAULT);
200 return(strnlen(dst, count));
201}
202
203static int clear_chunk(unsigned long addr, int len, void *unused)
204{
205 memset((void *) addr, 0, len);
206 return(0);
207}
208
209int __clear_user_skas(void __user *mem, int len)
210{
211 return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL));
212}
213
214int clear_user_skas(void __user *mem, int len)
215{
216 if(segment_eq(get_fs(), KERNEL_DS)){
217 memset((__force void*)mem, 0, len);
218 return(0);
219 }
220
221 return(access_ok_skas(VERIFY_WRITE, mem, len) ?
222 buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
223}
224
225static int strnlen_chunk(unsigned long str, int len, void *arg)
226{
227 int *len_ptr = arg, n;
228
229 n = strnlen((void *) str, len);
230 *len_ptr += n;
231
232 if(n < len)
233 return(1);
234 return(0);
235}
236
237int strnlen_user_skas(const void __user *str, int len)
238{
239 int count = 0, n;
240
241 if(segment_eq(get_fs(), KERNEL_DS))
242 return(strnlen((__force char*)str, len) + 1);
243
244 n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
245 if(n == 0)
246 return(count + 1);
247 return(-EFAULT);
248}
249
250/*
251 * Overrides for Emacs so that we follow Linus's tabbing style.
252 * Emacs will notice this stuff at the end of the file and automatically
253 * adjust the settings for this buffer only. This must remain at the end
254 * of the file.
255 * ---------------------------------------------------------------------------
256 * Local variables:
257 * c-file-style: "linux"
258 * End:
259 */
diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile
new file mode 100644
index 000000000000..17f5909d60f7
--- /dev/null
+++ b/arch/um/kernel/skas/util/Makefile
@@ -0,0 +1,4 @@
1hostprogs-y := mk_ptregs
2always := $(hostprogs-y)
3
4mk_ptregs-objs := mk_ptregs-$(SUBARCH).o
diff --git a/arch/um/kernel/skas/util/mk_ptregs-i386.c b/arch/um/kernel/skas/util/mk_ptregs-i386.c
new file mode 100644
index 000000000000..0788dd05bcac
--- /dev/null
+++ b/arch/um/kernel/skas/util/mk_ptregs-i386.c
@@ -0,0 +1,51 @@
1#include <stdio.h>
2#include <asm/ptrace.h>
3#include <asm/user.h>
4
5#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val))
6
7int main(int argc, char **argv)
8{
9 printf("/* Automatically generated by "
10 "arch/um/kernel/skas/util/mk_ptregs */\n");
11 printf("\n");
12 printf("#ifndef __SKAS_PT_REGS_\n");
13 printf("#define __SKAS_PT_REGS_\n");
14 printf("\n");
15 printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE);
16 printf("#define HOST_FP_SIZE %d\n",
17 sizeof(struct user_i387_struct) / sizeof(unsigned long));
18 printf("#define HOST_XFP_SIZE %d\n",
19 sizeof(struct user_fxsr_struct) / sizeof(unsigned long));
20
21 PRINT_REG("IP", EIP);
22 PRINT_REG("SP", UESP);
23 PRINT_REG("EFLAGS", EFL);
24 PRINT_REG("EAX", EAX);
25 PRINT_REG("EBX", EBX);
26 PRINT_REG("ECX", ECX);
27 PRINT_REG("EDX", EDX);
28 PRINT_REG("ESI", ESI);
29 PRINT_REG("EDI", EDI);
30 PRINT_REG("EBP", EBP);
31 PRINT_REG("CS", CS);
32 PRINT_REG("SS", SS);
33 PRINT_REG("DS", DS);
34 PRINT_REG("FS", FS);
35 PRINT_REG("ES", ES);
36 PRINT_REG("GS", GS);
37 printf("\n");
38 printf("#endif\n");
39 return(0);
40}
41
42/*
43 * Overrides for Emacs so that we follow Linus's tabbing style.
44 * Emacs will notice this stuff at the end of the file and automatically
45 * adjust the settings for this buffer only. This must remain at the end
46 * of the file.
47 * ---------------------------------------------------------------------------
48 * Local variables:
49 * c-file-style: "linux"
50 * End:
51 */
diff --git a/arch/um/kernel/skas/util/mk_ptregs-x86_64.c b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
new file mode 100644
index 000000000000..67aee92a70ef
--- /dev/null
+++ b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c
@@ -0,0 +1,68 @@
1/*
2 * Copyright 2003 PathScale, Inc.
3 *
4 * Licensed under the GPL
5 */
6
7#include <stdio.h>
8#define __FRAME_OFFSETS
9#include <asm/ptrace.h>
10
11#define PRINT_REG(name, val) \
12 printf("#define HOST_%s (%d / sizeof(unsigned long))\n", (name), (val))
13
14int main(int argc, char **argv)
15{
16 printf("/* Automatically generated by "
17 "arch/um/kernel/skas/util/mk_ptregs */\n");
18 printf("\n");
19 printf("#ifndef __SKAS_PT_REGS_\n");
20 printf("#define __SKAS_PT_REGS_\n");
21 printf("#define HOST_FRAME_SIZE (%d / sizeof(unsigned long))\n",
22 FRAME_SIZE);
23 PRINT_REG("RBX", RBX);
24 PRINT_REG("RCX", RCX);
25 PRINT_REG("RDI", RDI);
26 PRINT_REG("RSI", RSI);
27 PRINT_REG("RDX", RDX);
28 PRINT_REG("RBP", RBP);
29 PRINT_REG("RAX", RAX);
30 PRINT_REG("R8", R8);
31 PRINT_REG("R9", R9);
32 PRINT_REG("R10", R10);
33 PRINT_REG("R11", R11);
34 PRINT_REG("R12", R12);
35 PRINT_REG("R13", R13);
36 PRINT_REG("R14", R14);
37 PRINT_REG("R15", R15);
38 PRINT_REG("ORIG_RAX", ORIG_RAX);
39 PRINT_REG("CS", CS);
40 PRINT_REG("SS", SS);
41 PRINT_REG("EFLAGS", EFLAGS);
42#if 0
43 PRINT_REG("FS", FS);
44 PRINT_REG("GS", GS);
45 PRINT_REG("DS", DS);
46 PRINT_REG("ES", ES);
47#endif
48
49 PRINT_REG("IP", RIP);
50 PRINT_REG("SP", RSP);
51 printf("#define HOST_FP_SIZE 0\n");
52 printf("#define HOST_XFP_SIZE 0\n");
53 printf("\n");
54 printf("\n");
55 printf("#endif\n");
56 return(0);
57}
58
59/*
60 * Overrides for Emacs so that we follow Linus's tabbing style.
61 * Emacs will notice this stuff at the end of the file and automatically
62 * adjust the settings for this buffer only. This must remain at the end
63 * of the file.
64 * ---------------------------------------------------------------------------
65 * Local variables:
66 * c-file-style: "linux"
67 * End:
68 */