aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel')
-rw-r--r--arch/um/kernel/Makefile2
-rw-r--r--arch/um/kernel/gmon_syms.c13
-rw-r--r--arch/um/kernel/ksyms.c3
-rw-r--r--arch/um/kernel/mem.c3
-rw-r--r--arch/um/kernel/process.c (renamed from arch/um/kernel/process_kern.c)33
-rw-r--r--arch/um/kernel/skas/Makefile3
-rw-r--r--arch/um/kernel/skas/exec.c30
-rw-r--r--arch/um/kernel/skas/exec_kern.c41
-rw-r--r--arch/um/kernel/skas/process.c217
-rw-r--r--arch/um/kernel/skas/process_kern.c533
-rw-r--r--arch/um/kernel/time.c2
-rw-r--r--arch/um/kernel/trap.c17
-rw-r--r--arch/um/kernel/um_arch.c2
13 files changed, 676 insertions, 223 deletions
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index a2d93065b2d0..6fa63a2a89e3 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -7,7 +7,7 @@ extra-y := vmlinux.lds
7clean-files := 7clean-files :=
8 8
9obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \ 9obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \
10 physmem.o process_kern.o ptrace.o reboot.o resource.o sigio.o \ 10 physmem.o process.o ptrace.o reboot.o resource.o sigio.o \
11 signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \ 11 signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \
12 um_arch.o umid.o 12 um_arch.o umid.o
13 13
diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c
index 2c86e7fdb014..13aa115cd1b4 100644
--- a/arch/um/kernel/gmon_syms.c
+++ b/arch/um/kernel/gmon_syms.c
@@ -5,7 +5,7 @@
5 5
6#include "linux/module.h" 6#include "linux/module.h"
7 7
8extern void __bb_init_func(void *); 8extern void __bb_init_func(void *) __attribute__((weak));
9EXPORT_SYMBOL(__bb_init_func); 9EXPORT_SYMBOL(__bb_init_func);
10 10
11/* This is defined (and referred to in profiling stub code) only by some GCC 11/* This is defined (and referred to in profiling stub code) only by some GCC
@@ -21,14 +21,3 @@ EXPORT_SYMBOL(__gcov_init);
21 21
22extern void __gcov_merge_add(void *) __attribute__((weak)); 22extern void __gcov_merge_add(void *) __attribute__((weak));
23EXPORT_SYMBOL(__gcov_merge_add); 23EXPORT_SYMBOL(__gcov_merge_add);
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/ksyms.c b/arch/um/kernel/ksyms.c
index c97045d6d89f..f030e44262ba 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -21,7 +21,6 @@
21#include "mem_user.h" 21#include "mem_user.h"
22#include "os.h" 22#include "os.h"
23 23
24EXPORT_SYMBOL(stop);
25EXPORT_SYMBOL(uml_physmem); 24EXPORT_SYMBOL(uml_physmem);
26EXPORT_SYMBOL(set_signals); 25EXPORT_SYMBOL(set_signals);
27EXPORT_SYMBOL(get_signals); 26EXPORT_SYMBOL(get_signals);
@@ -41,12 +40,14 @@ EXPORT_SYMBOL(handle_page_fault);
41EXPORT_SYMBOL(find_iomem); 40EXPORT_SYMBOL(find_iomem);
42 41
43#ifdef CONFIG_MODE_TT 42#ifdef CONFIG_MODE_TT
43EXPORT_SYMBOL(stop);
44EXPORT_SYMBOL(strncpy_from_user_tt); 44EXPORT_SYMBOL(strncpy_from_user_tt);
45EXPORT_SYMBOL(copy_from_user_tt); 45EXPORT_SYMBOL(copy_from_user_tt);
46EXPORT_SYMBOL(copy_to_user_tt); 46EXPORT_SYMBOL(copy_to_user_tt);
47#endif 47#endif
48 48
49#ifdef CONFIG_MODE_SKAS 49#ifdef CONFIG_MODE_SKAS
50EXPORT_SYMBOL(strnlen_user_skas);
50EXPORT_SYMBOL(strncpy_from_user_skas); 51EXPORT_SYMBOL(strncpy_from_user_skas);
51EXPORT_SYMBOL(copy_to_user_skas); 52EXPORT_SYMBOL(copy_to_user_skas);
52EXPORT_SYMBOL(copy_from_user_skas); 53EXPORT_SYMBOL(copy_from_user_skas);
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 93121c6d26e5..c95855ba6ab5 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -226,7 +226,8 @@ void paging_init(void)
226 for(i = 0; i < ARRAY_SIZE(zones_size); i++) 226 for(i = 0; i < ARRAY_SIZE(zones_size); i++)
227 zones_size[i] = 0; 227 zones_size[i] = 0;
228 228
229 zones_size[ZONE_DMA] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); 229 zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) -
230 (uml_physmem >> PAGE_SHIFT);
230#ifdef CONFIG_HIGHMEM 231#ifdef CONFIG_HIGHMEM
231 zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT; 232 zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT;
232#endif 233#endif
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process.c
index 537895d68ad1..fe6c64abda5b 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process.c
@@ -1,10 +1,9 @@
1/* 1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) 2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Copyright 2003 PathScale, Inc. 3 * Copyright 2003 PathScale, Inc.
4 * Licensed under the GPL 4 * Licensed under the GPL
5 */ 5 */
6 6
7#include "linux/config.h"
8#include "linux/kernel.h" 7#include "linux/kernel.h"
9#include "linux/sched.h" 8#include "linux/sched.h"
10#include "linux/interrupt.h" 9#include "linux/interrupt.h"
@@ -113,11 +112,11 @@ void set_current(void *t)
113 112
114void *_switch_to(void *prev, void *next, void *last) 113void *_switch_to(void *prev, void *next, void *last)
115{ 114{
116 struct task_struct *from = prev; 115 struct task_struct *from = prev;
117 struct task_struct *to= next; 116 struct task_struct *to= next;
118 117
119 to->thread.prev_sched = from; 118 to->thread.prev_sched = from;
120 set_current(to); 119 set_current(to);
121 120
122 do { 121 do {
123 current->thread.saved_task = NULL ; 122 current->thread.saved_task = NULL ;
@@ -128,7 +127,7 @@ void *_switch_to(void *prev, void *next, void *last)
128 prev= current; 127 prev= current;
129 } while(current->thread.saved_task); 128 } while(current->thread.saved_task);
130 129
131 return(current->thread.prev_sched); 130 return(current->thread.prev_sched);
132 131
133} 132}
134 133
@@ -142,19 +141,19 @@ void release_thread(struct task_struct *task)
142{ 141{
143 CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task)); 142 CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
144} 143}
145 144
146void exit_thread(void) 145void exit_thread(void)
147{ 146{
148 unprotect_stack((unsigned long) current_thread); 147 unprotect_stack((unsigned long) current_thread);
149} 148}
150 149
151void *get_current(void) 150void *get_current(void)
152{ 151{
153 return(current); 152 return(current);
154} 153}
155 154
156int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, 155int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
157 unsigned long stack_top, struct task_struct * p, 156 unsigned long stack_top, struct task_struct * p,
158 struct pt_regs *regs) 157 struct pt_regs *regs)
159{ 158{
160 int ret; 159 int ret;
@@ -183,11 +182,11 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
183 int save_kmalloc_ok = kmalloc_ok; 182 int save_kmalloc_ok = kmalloc_ok;
184 183
185 kmalloc_ok = 0; 184 kmalloc_ok = 0;
186 CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, 185 CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc,
187 arg); 186 arg);
188 kmalloc_ok = save_kmalloc_ok; 187 kmalloc_ok = save_kmalloc_ok;
189} 188}
190 189
191unsigned long stack_sp(unsigned long page) 190unsigned long stack_sp(unsigned long page)
192{ 191{
193 return(page + PAGE_SIZE - sizeof(void *)); 192 return(page + PAGE_SIZE - sizeof(void *));
@@ -211,7 +210,7 @@ void default_idle(void)
211 */ 210 */
212 if(need_resched()) 211 if(need_resched())
213 schedule(); 212 schedule();
214 213
215 idle_sleep(10); 214 idle_sleep(10);
216 } 215 }
217} 216}
@@ -226,7 +225,7 @@ int page_size(void)
226 return(PAGE_SIZE); 225 return(PAGE_SIZE);
227} 226}
228 227
229void *um_virt_to_phys(struct task_struct *task, unsigned long addr, 228void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
230 pte_t *pte_out) 229 pte_t *pte_out)
231{ 230{
232 pgd_t *pgd; 231 pgd_t *pgd;
@@ -235,7 +234,7 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
235 pte_t *pte; 234 pte_t *pte;
236 pte_t ptent; 235 pte_t ptent;
237 236
238 if(task->mm == NULL) 237 if(task->mm == NULL)
239 return(ERR_PTR(-EINVAL)); 238 return(ERR_PTR(-EINVAL));
240 pgd = pgd_offset(task->mm, addr); 239 pgd = pgd_offset(task->mm, addr);
241 if(!pgd_present(*pgd)) 240 if(!pgd_present(*pgd))
@@ -246,7 +245,7 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
246 return(ERR_PTR(-EINVAL)); 245 return(ERR_PTR(-EINVAL));
247 246
248 pmd = pmd_offset(pud, addr); 247 pmd = pmd_offset(pud, addr);
249 if(!pmd_present(*pmd)) 248 if(!pmd_present(*pmd))
250 return(ERR_PTR(-EINVAL)); 249 return(ERR_PTR(-EINVAL));
251 250
252 pte = pte_offset_kernel(pmd, addr); 251 pte = pte_offset_kernel(pmd, addr);
@@ -271,7 +270,7 @@ char *current_cmd(void)
271 270
272void force_sigbus(void) 271void force_sigbus(void)
273{ 272{
274 printk(KERN_ERR "Killing pid %d because of a lack of memory\n", 273 printk(KERN_ERR "Killing pid %d because of a lack of memory\n",
275 current->pid); 274 current->pid);
276 lock_kernel(); 275 lock_kernel();
277 sigaddset(&current->pending.signal, SIGBUS); 276 sigaddset(&current->pending.signal, SIGBUS);
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index ea3a8e409a6e..3e3fa7e7e3cf 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -3,8 +3,7 @@
3# Licensed under the GPL 3# Licensed under the GPL
4# 4#
5 5
6obj-y := clone.o exec_kern.o mem.o mmu.o process_kern.o \ 6obj-y := clone.o exec.o mem.o mmu.o process.o syscall.o tlb.o uaccess.o
7 syscall.o tlb.o uaccess.o
8 7
9# clone.o is in the stub, so it can't be built with profiling 8# clone.o is in the stub, so it can't be built with profiling
10# GCC hardened also auto-enables -fpic, but we need %ebx so it can't work -> 9# GCC hardened also auto-enables -fpic, but we need %ebx so it can't work ->
diff --git a/arch/um/kernel/skas/exec.c b/arch/um/kernel/skas/exec.c
new file mode 100644
index 000000000000..54b795951372
--- /dev/null
+++ b/arch/um/kernel/skas/exec.c
@@ -0,0 +1,30 @@
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.id);
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}
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
deleted file mode 100644
index 77ed7bbab219..000000000000
--- a/arch/um/kernel/skas/exec_kern.c
+++ /dev/null
@@ -1,41 +0,0 @@
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.id);
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/process.c b/arch/um/kernel/skas/process.c
new file mode 100644
index 000000000000..ae4fa71d3b8b
--- /dev/null
+++ b/arch/um/kernel/skas/process.c
@@ -0,0 +1,217 @@
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 "skas.h"
17#include "os.h"
18#include "user_util.h"
19#include "tlb.h"
20#include "kern.h"
21#include "mode.h"
22#include "registers.h"
23
24void switch_to_skas(void *prev, void *next)
25{
26 struct task_struct *from, *to;
27
28 from = prev;
29 to = next;
30
31 /* XXX need to check runqueues[cpu].idle */
32 if(current->pid == 0)
33 switch_timers(0);
34
35 switch_threads(&from->thread.mode.skas.switch_buf,
36 &to->thread.mode.skas.switch_buf);
37
38 arch_switch_to_skas(current->thread.prev_sched, current);
39
40 if(current->pid == 0)
41 switch_timers(1);
42}
43
44extern void schedule_tail(struct task_struct *prev);
45
46/* This is called magically, by its address being stuffed in a jmp_buf
47 * and being longjmp-d to.
48 */
49void new_thread_handler(void)
50{
51 int (*fn)(void *), n;
52 void *arg;
53
54 if(current->thread.prev_sched != NULL)
55 schedule_tail(current->thread.prev_sched);
56 current->thread.prev_sched = NULL;
57
58 fn = current->thread.request.u.thread.proc;
59 arg = current->thread.request.u.thread.arg;
60
61 /* The return value is 1 if the kernel thread execs a process,
62 * 0 if it just exits
63 */
64 n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
65 if(n == 1){
66 /* Handle any immediate reschedules or signals */
67 interrupt_end();
68 userspace(&current->thread.regs.regs);
69 }
70 else do_exit(0);
71}
72
73void release_thread_skas(struct task_struct *task)
74{
75}
76
77/* Called magically, see new_thread_handler above */
78void fork_handler(void)
79{
80 force_flush_all();
81 if(current->thread.prev_sched == NULL)
82 panic("blech");
83
84 schedule_tail(current->thread.prev_sched);
85
86 /* XXX: if interrupt_end() calls schedule, this call to
87 * arch_switch_to_skas isn't needed. We could want to apply this to
88 * improve performance. -bb */
89 arch_switch_to_skas(current->thread.prev_sched, current);
90
91 current->thread.prev_sched = NULL;
92
93/* Handle any immediate reschedules or signals */
94 interrupt_end();
95
96 userspace(&current->thread.regs.regs);
97}
98
99int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
100 unsigned long stack_top, struct task_struct * p,
101 struct pt_regs *regs)
102{
103 void (*handler)(void);
104
105 if(current->thread.forking){
106 memcpy(&p->thread.regs.regs.skas, &regs->regs.skas,
107 sizeof(p->thread.regs.regs.skas));
108 REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
109 if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
110
111 handler = fork_handler;
112
113 arch_copy_thread(&current->thread.arch, &p->thread.arch);
114 }
115 else {
116 init_thread_registers(&p->thread.regs.regs);
117 p->thread.request.u.thread = current->thread.request.u.thread;
118 handler = new_thread_handler;
119 }
120
121 new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf,
122 handler);
123 return(0);
124}
125
126int new_mm(unsigned long stack)
127{
128 int fd;
129
130 fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
131 if(fd < 0)
132 return(fd);
133
134 if(skas_needs_stub)
135 map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack);
136
137 return(fd);
138}
139
140void init_idle_skas(void)
141{
142 cpu_tasks[current_thread->cpu].pid = os_getpid();
143 default_idle();
144}
145
146extern void start_kernel(void);
147
148static int start_kernel_proc(void *unused)
149{
150 int pid;
151
152 block_signals();
153 pid = os_getpid();
154
155 cpu_tasks[0].pid = pid;
156 cpu_tasks[0].task = current;
157#ifdef CONFIG_SMP
158 cpu_online_map = cpumask_of_cpu(0);
159#endif
160 start_kernel();
161 return(0);
162}
163
164extern int userspace_pid[];
165
166int start_uml_skas(void)
167{
168 if(proc_mm)
169 userspace_pid[0] = start_userspace(0);
170
171 init_new_thread_signals();
172
173 init_task.thread.request.u.thread.proc = start_kernel_proc;
174 init_task.thread.request.u.thread.arg = NULL;
175 return(start_idle_thread(task_stack_page(&init_task),
176 &init_task.thread.mode.skas.switch_buf));
177}
178
179int external_pid_skas(struct task_struct *task)
180{
181#warning Need to look up userspace_pid by cpu
182 return(userspace_pid[0]);
183}
184
185int thread_pid_skas(struct task_struct *task)
186{
187#warning Need to look up userspace_pid by cpu
188 return(userspace_pid[0]);
189}
190
191void kill_off_processes_skas(void)
192{
193 if(proc_mm)
194#warning need to loop over userspace_pids in kill_off_processes_skas
195 os_kill_ptraced_process(userspace_pid[0], 1);
196 else {
197 struct task_struct *p;
198 int pid, me;
199
200 me = os_getpid();
201 for_each_process(p){
202 if(p->mm == NULL)
203 continue;
204
205 pid = p->mm->context.skas.id.u.pid;
206 os_kill_ptraced_process(pid, 1);
207 }
208 }
209}
210
211unsigned long current_stub_stack(void)
212{
213 if(current->mm == NULL)
214 return(0);
215
216 return(current->mm->context.skas.id.stack);
217}
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index 55caeec8b257..0f3d5d084dc7 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -1,227 +1,484 @@
1/* 1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) 2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Copyright 2003 PathScale, Inc.
3 * Licensed under the GPL 4 * Licensed under the GPL
4 */ 5 */
5 6
7#include "linux/config.h"
8#include "linux/kernel.h"
6#include "linux/sched.h" 9#include "linux/sched.h"
10#include "linux/interrupt.h"
11#include "linux/string.h"
12#include "linux/mm.h"
7#include "linux/slab.h" 13#include "linux/slab.h"
8#include "linux/ptrace.h" 14#include "linux/utsname.h"
9#include "linux/proc_fs.h" 15#include "linux/fs.h"
10#include "linux/file.h" 16#include "linux/utime.h"
11#include "linux/errno.h" 17#include "linux/smp_lock.h"
18#include "linux/module.h"
12#include "linux/init.h" 19#include "linux/init.h"
20#include "linux/capability.h"
21#include "linux/vmalloc.h"
22#include "linux/spinlock.h"
23#include "linux/proc_fs.h"
24#include "linux/ptrace.h"
25#include "linux/random.h"
26#include "linux/personality.h"
27#include "asm/unistd.h"
28#include "asm/mman.h"
29#include "asm/segment.h"
30#include "asm/stat.h"
31#include "asm/pgtable.h"
32#include "asm/processor.h"
33#include "asm/tlbflush.h"
13#include "asm/uaccess.h" 34#include "asm/uaccess.h"
14#include "asm/atomic.h" 35#include "asm/user.h"
15#include "kern_util.h"
16#include "skas.h"
17#include "os.h"
18#include "user_util.h" 36#include "user_util.h"
19#include "tlb.h" 37#include "kern_util.h"
20#include "kern.h" 38#include "kern.h"
39#include "signal_kern.h"
40#include "init.h"
41#include "irq_user.h"
42#include "mem_user.h"
43#include "tlb.h"
44#include "frame_kern.h"
45#include "sigcontext.h"
46#include "os.h"
21#include "mode.h" 47#include "mode.h"
22#include "registers.h" 48#include "mode_kern.h"
49#include "choose-mode.h"
50
51/* This is a per-cpu array. A processor only modifies its entry and it only
52 * cares about its entry, so it's OK if another processor is modifying its
53 * entry.
54 */
55struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
56
57int external_pid(void *t)
58{
59 struct task_struct *task = t ? t : current;
60
61 return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
62}
63
64int pid_to_processor_id(int pid)
65{
66 int i;
67
68 for(i = 0; i < ncpus; i++){
69 if(cpu_tasks[i].pid == pid) return(i);
70 }
71 return(-1);
72}
73
74void free_stack(unsigned long stack, int order)
75{
76 free_pages(stack, order);
77}
78
79unsigned long alloc_stack(int order, int atomic)
80{
81 unsigned long page;
82 gfp_t flags = GFP_KERNEL;
83
84 if (atomic)
85 flags = GFP_ATOMIC;
86 page = __get_free_pages(flags, order);
87 if(page == 0)
88 return(0);
89 stack_protections(page);
90 return(page);
91}
92
93int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
94{
95 int pid;
96
97 current->thread.request.u.thread.proc = fn;
98 current->thread.request.u.thread.arg = arg;
99 pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0,
100 &current->thread.regs, 0, NULL, NULL);
101 if(pid < 0)
102 panic("do_fork failed in kernel_thread, errno = %d", pid);
103 return(pid);
104}
23 105
24void switch_to_skas(void *prev, void *next) 106void set_current(void *t)
25{ 107{
26 struct task_struct *from, *to; 108 struct task_struct *task = t;
27 109
28 from = prev; 110 cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
29 to = next; 111 { external_pid(task), task });
112}
30 113
31 /* XXX need to check runqueues[cpu].idle */ 114void *_switch_to(void *prev, void *next, void *last)
32 if(current->pid == 0) 115{
33 switch_timers(0); 116 struct task_struct *from = prev;
117 struct task_struct *to= next;
34 118
35 switch_threads(&from->thread.mode.skas.switch_buf, 119 to->thread.prev_sched = from;
36 to->thread.mode.skas.switch_buf); 120 set_current(to);
37 121
38 arch_switch_to_skas(current->thread.prev_sched, current); 122 do {
123 current->thread.saved_task = NULL ;
124 CHOOSE_MODE_PROC(switch_to_tt, switch_to_skas, prev, next);
125 if(current->thread.saved_task)
126 show_regs(&(current->thread.regs));
127 next= current->thread.saved_task;
128 prev= current;
129 } while(current->thread.saved_task);
130
131 return(current->thread.prev_sched);
39 132
40 if(current->pid == 0)
41 switch_timers(1);
42} 133}
43 134
44extern void schedule_tail(struct task_struct *prev); 135void interrupt_end(void)
136{
137 if(need_resched()) schedule();
138 if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal();
139}
45 140
46void new_thread_handler(int sig) 141void release_thread(struct task_struct *task)
47{ 142{
48 int (*fn)(void *), n; 143 CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
49 void *arg; 144}
50 145
51 fn = current->thread.request.u.thread.proc; 146void exit_thread(void)
52 arg = current->thread.request.u.thread.arg; 147{
53 os_usr1_signal(1); 148 unprotect_stack((unsigned long) current_thread);
54 thread_wait(&current->thread.mode.skas.switch_buf, 149}
55 current->thread.mode.skas.fork_buf);
56 150
57 if(current->thread.prev_sched != NULL) 151void *get_current(void)
58 schedule_tail(current->thread.prev_sched); 152{
59 current->thread.prev_sched = NULL; 153 return(current);
154}
155
156int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
157 unsigned long stack_top, struct task_struct * p,
158 struct pt_regs *regs)
159{
160 int ret;
60 161
61 /* The return value is 1 if the kernel thread execs a process, 162 p->thread = (struct thread_struct) INIT_THREAD;
62 * 0 if it just exits 163 ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
164 clone_flags, sp, stack_top, p, regs);
165
166 if (ret || !current->thread.forking)
167 goto out;
168
169 clear_flushed_tls(p);
170
171 /*
172 * Set a new TLS for the child thread?
63 */ 173 */
64 n = run_kernel_thread(fn, arg, &current->thread.exec_buf); 174 if (clone_flags & CLONE_SETTLS)
65 if(n == 1){ 175 ret = arch_copy_tls(p);
66 /* Handle any immediate reschedules or signals */ 176
67 interrupt_end(); 177out:
68 userspace(&current->thread.regs.regs); 178 return ret;
179}
180
181void initial_thread_cb(void (*proc)(void *), void *arg)
182{
183 int save_kmalloc_ok = kmalloc_ok;
184
185 kmalloc_ok = 0;
186 CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc,
187 arg);
188 kmalloc_ok = save_kmalloc_ok;
189}
190
191unsigned long stack_sp(unsigned long page)
192{
193 return(page + PAGE_SIZE - sizeof(void *));
194}
195
196int current_pid(void)
197{
198 return(current->pid);
199}
200
201void default_idle(void)
202{
203 CHOOSE_MODE(uml_idle_timer(), (void) 0);
204
205 while(1){
206 /* endless idle loop with no priority at all */
207
208 /*
209 * although we are an idle CPU, we do not want to
210 * get into the scheduler unnecessarily.
211 */
212 if(need_resched())
213 schedule();
214
215 idle_sleep(10);
69 } 216 }
70 else do_exit(0);
71} 217}
72 218
73void new_thread_proc(void *stack, void (*handler)(int sig)) 219void cpu_idle(void)
74{ 220{
75 init_new_thread_stack(stack, handler); 221 CHOOSE_MODE(init_idle_tt(), init_idle_skas());
76 os_usr1_process(os_getpid());
77} 222}
78 223
79void release_thread_skas(struct task_struct *task) 224int page_size(void)
80{ 225{
226 return(PAGE_SIZE);
81} 227}
82 228
83void fork_handler(int sig) 229void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
230 pte_t *pte_out)
84{ 231{
85 os_usr1_signal(1); 232 pgd_t *pgd;
86 thread_wait(&current->thread.mode.skas.switch_buf, 233 pud_t *pud;
87 current->thread.mode.skas.fork_buf); 234 pmd_t *pmd;
88 235 pte_t *pte;
89 force_flush_all(); 236 pte_t ptent;
90 if(current->thread.prev_sched == NULL) 237
91 panic("blech"); 238 if(task->mm == NULL)
239 return(ERR_PTR(-EINVAL));
240 pgd = pgd_offset(task->mm, addr);
241 if(!pgd_present(*pgd))
242 return(ERR_PTR(-EINVAL));
243
244 pud = pud_offset(pgd, addr);
245 if(!pud_present(*pud))
246 return(ERR_PTR(-EINVAL));
247
248 pmd = pmd_offset(pud, addr);
249 if(!pmd_present(*pmd))
250 return(ERR_PTR(-EINVAL));
251
252 pte = pte_offset_kernel(pmd, addr);
253 ptent = *pte;
254 if(!pte_present(ptent))
255 return(ERR_PTR(-EINVAL));
256
257 if(pte_out != NULL)
258 *pte_out = ptent;
259 return((void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK));
260}
92 261
93 schedule_tail(current->thread.prev_sched); 262char *current_cmd(void)
263{
264#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
265 return("(Unknown)");
266#else
267 void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
268 return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
269#endif
270}
94 271
95 /* XXX: if interrupt_end() calls schedule, this call to 272void force_sigbus(void)
96 * arch_switch_to_skas isn't needed. We could want to apply this to 273{
97 * improve performance. -bb */ 274 printk(KERN_ERR "Killing pid %d because of a lack of memory\n",
98 arch_switch_to_skas(current->thread.prev_sched, current); 275 current->pid);
276 lock_kernel();
277 sigaddset(&current->pending.signal, SIGBUS);
278 recalc_sigpending();
279 current->flags |= PF_SIGNALED;
280 do_exit(SIGBUS | 0x80);
281}
99 282
100 current->thread.prev_sched = NULL; 283void dump_thread(struct pt_regs *regs, struct user *u)
284{
285}
101 286
102/* Handle any immediate reschedules or signals */ 287void enable_hlt(void)
103 interrupt_end(); 288{
289 panic("enable_hlt");
290}
291
292EXPORT_SYMBOL(enable_hlt);
104 293
105 userspace(&current->thread.regs.regs); 294void disable_hlt(void)
295{
296 panic("disable_hlt");
106} 297}
107 298
108int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, 299EXPORT_SYMBOL(disable_hlt);
109 unsigned long stack_top, struct task_struct * p, 300
110 struct pt_regs *regs) 301void *um_kmalloc(int size)
111{ 302{
112 void (*handler)(int); 303 return kmalloc(size, GFP_KERNEL);
304}
113 305
114 if(current->thread.forking){ 306void *um_kmalloc_atomic(int size)
115 memcpy(&p->thread.regs.regs.skas, &regs->regs.skas, 307{
116 sizeof(p->thread.regs.regs.skas)); 308 return kmalloc(size, GFP_ATOMIC);
117 REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0); 309}
118 if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
119 310
120 handler = fork_handler; 311void *um_vmalloc(int size)
312{
313 return vmalloc(size);
314}
121 315
122 arch_copy_thread(&current->thread.arch, &p->thread.arch); 316void *um_vmalloc_atomic(int size)
123 } 317{
124 else { 318 return __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, PAGE_KERNEL);
125 init_thread_registers(&p->thread.regs.regs); 319}
126 p->thread.request.u.thread = current->thread.request.u.thread;
127 handler = new_thread_handler;
128 }
129 320
130 new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf, 321int __cant_sleep(void) {
131 &p->thread.mode.skas.fork_buf, handler); 322 return in_atomic() || irqs_disabled() || in_interrupt();
132 return(0); 323 /* Is in_interrupt() really needed? */
324}
325
326unsigned long get_fault_addr(void)
327{
328 return((unsigned long) current->thread.fault_addr);
133} 329}
134 330
135int new_mm(unsigned long stack) 331EXPORT_SYMBOL(get_fault_addr);
332
333void not_implemented(void)
136{ 334{
137 int fd; 335 printk(KERN_DEBUG "Something isn't implemented in here\n");
336}
138 337
139 fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); 338EXPORT_SYMBOL(not_implemented);
140 if(fd < 0)
141 return(fd);
142 339
143 if(skas_needs_stub) 340int user_context(unsigned long sp)
144 map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack); 341{
342 unsigned long stack;
145 343
146 return(fd); 344 stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
345 return(stack != (unsigned long) current_thread);
147} 346}
148 347
149void init_idle_skas(void) 348extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
349
350void do_uml_exitcalls(void)
150{ 351{
151 cpu_tasks[current_thread->cpu].pid = os_getpid(); 352 exitcall_t *call;
152 default_idle(); 353
354 call = &__uml_exitcall_end;
355 while (--call >= &__uml_exitcall_begin)
356 (*call)();
153} 357}
154 358
155extern void start_kernel(void); 359char *uml_strdup(char *string)
360{
361 return kstrdup(string, GFP_KERNEL);
362}
156 363
157static int start_kernel_proc(void *unused) 364int copy_to_user_proc(void __user *to, void *from, int size)
158{ 365{
159 int pid; 366 return(copy_to_user(to, from, size));
367}
368
369int copy_from_user_proc(void *to, void __user *from, int size)
370{
371 return(copy_from_user(to, from, size));
372}
373
374int clear_user_proc(void __user *buf, int size)
375{
376 return(clear_user(buf, size));
377}
160 378
161 block_signals(); 379int strlen_user_proc(char __user *str)
162 pid = os_getpid(); 380{
381 return(strlen_user(str));
382}
163 383
164 cpu_tasks[0].pid = pid; 384int smp_sigio_handler(void)
165 cpu_tasks[0].task = current; 385{
166#ifdef CONFIG_SMP 386#ifdef CONFIG_SMP
167 cpu_online_map = cpumask_of_cpu(0); 387 int cpu = current_thread->cpu;
388 IPI_handler(cpu);
389 if(cpu != 0)
390 return(1);
168#endif 391#endif
169 start_kernel();
170 return(0); 392 return(0);
171} 393}
172 394
173extern int userspace_pid[]; 395int cpu(void)
174
175int start_uml_skas(void)
176{ 396{
177 if(proc_mm) 397 return(current_thread->cpu);
178 userspace_pid[0] = start_userspace(0); 398}
399
400static atomic_t using_sysemu = ATOMIC_INIT(0);
401int sysemu_supported;
179 402
180 init_new_thread_signals(); 403void set_using_sysemu(int value)
404{
405 if (value > sysemu_supported)
406 return;
407 atomic_set(&using_sysemu, value);
408}
181 409
182 init_task.thread.request.u.thread.proc = start_kernel_proc; 410int get_using_sysemu(void)
183 init_task.thread.request.u.thread.arg = NULL; 411{
184 return(start_idle_thread(task_stack_page(&init_task), 412 return atomic_read(&using_sysemu);
185 &init_task.thread.mode.skas.switch_buf,
186 &init_task.thread.mode.skas.fork_buf));
187} 413}
188 414
189int external_pid_skas(struct task_struct *task) 415static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
190{ 416{
191#warning Need to look up userspace_pid by cpu 417 if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/
192 return(userspace_pid[0]); 418 *eof = 1;
419
420 return strlen(buf);
193} 421}
194 422
195int thread_pid_skas(struct task_struct *task) 423static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned long count,void *data)
196{ 424{
197#warning Need to look up userspace_pid by cpu 425 char tmp[2];
198 return(userspace_pid[0]); 426
427 if (copy_from_user(tmp, buf, 1))
428 return -EFAULT;
429
430 if (tmp[0] >= '0' && tmp[0] <= '2')
431 set_using_sysemu(tmp[0] - '0');
432 return count; /*We use the first char, but pretend to write everything*/
199} 433}
200 434
201void kill_off_processes_skas(void) 435int __init make_proc_sysemu(void)
202{ 436{
203 if(proc_mm) 437 struct proc_dir_entry *ent;
204#warning need to loop over userspace_pids in kill_off_processes_skas 438 if (!sysemu_supported)
205 os_kill_ptraced_process(userspace_pid[0], 1); 439 return 0;
206 else {
207 struct task_struct *p;
208 int pid, me;
209 440
210 me = os_getpid(); 441 ent = create_proc_entry("sysemu", 0600, &proc_root);
211 for_each_process(p){
212 if(p->mm == NULL)
213 continue;
214 442
215 pid = p->mm->context.skas.id.u.pid; 443 if (ent == NULL)
216 os_kill_ptraced_process(pid, 1); 444 {
217 } 445 printk(KERN_WARNING "Failed to register /proc/sysemu\n");
446 return(0);
218 } 447 }
448
449 ent->read_proc = proc_read_sysemu;
450 ent->write_proc = proc_write_sysemu;
451
452 return 0;
219} 453}
220 454
221unsigned long current_stub_stack(void) 455late_initcall(make_proc_sysemu);
456
457int singlestepping(void * t)
222{ 458{
223 if(current->mm == NULL) 459 struct task_struct *task = t ? t : current;
460
461 if ( ! (task->ptrace & PT_DTRACE) )
224 return(0); 462 return(0);
225 463
226 return(current->mm->context.skas.id.stack); 464 if (task->thread.singlestep_syscall)
465 return(1);
466
467 return 2;
468}
469
470/*
471 * Only x86 and x86_64 have an arch_align_stack().
472 * All other arches have "#define arch_align_stack(x) (x)"
473 * in their asm/system.h
474 * As this is included in UML from asm-um/system-generic.h,
475 * we can use it to behave as the subarch does.
476 */
477#ifndef arch_align_stack
478unsigned long arch_align_stack(unsigned long sp)
479{
480 if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
481 sp -= get_random_int() % 8192;
482 return sp & ~0xf;
227} 483}
484#endif
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 2454bbd9555d..820affbf3e16 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -95,7 +95,7 @@ irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
95 95
96 do_timer(regs); 96 do_timer(regs);
97 97
98 nsecs = get_time() + local_offset; 98 nsecs = get_time();
99 xtime.tv_sec = nsecs / NSEC_PER_SEC; 99 xtime.tv_sec = nsecs / NSEC_PER_SEC;
100 xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC; 100 xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC;
101 101
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index e5eeaf2b6af1..61a23fff4395 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -140,14 +140,6 @@ void segv_handler(int sig, union uml_pt_regs *regs)
140 segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); 140 segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
141} 141}
142 142
143struct kern_handlers handlinfo_kern = {
144 .relay_signal = relay_signal,
145 .winch = winch,
146 .bus_handler = relay_signal,
147 .page_fault = segv_handler,
148 .sigio_handler = sigio_handler,
149 .timer_handler = timer_handler
150};
151/* 143/*
152 * We give a *copy* of the faultinfo in the regs to segv. 144 * We give a *copy* of the faultinfo in the regs to segv.
153 * This must be done, since nesting SEGVs could overwrite 145 * This must be done, since nesting SEGVs could overwrite
@@ -253,6 +245,15 @@ void winch(int sig, union uml_pt_regs *regs)
253 do_IRQ(WINCH_IRQ, regs); 245 do_IRQ(WINCH_IRQ, regs);
254} 246}
255 247
248const struct kern_handlers handlinfo_kern = {
249 .relay_signal = relay_signal,
250 .winch = winch,
251 .bus_handler = bus_handler,
252 .page_fault = segv_handler,
253 .sigio_handler = sigio_handler,
254 .timer_handler = timer_handler
255};
256
256void trap_init(void) 257void trap_init(void)
257{ 258{
258} 259}
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 7896cf98232d..55005710dcbb 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -106,7 +106,7 @@ static void c_stop(struct seq_file *m, void *v)
106{ 106{
107} 107}
108 108
109struct seq_operations cpuinfo_op = { 109const struct seq_operations cpuinfo_op = {
110 .start = c_start, 110 .start = c_start,
111 .next = c_next, 111 .next = c_next,
112 .stop = c_stop, 112 .stop = c_stop,