vserver 1.9.3
[linux-2.6.git] / arch / um / kernel / skas / process_kern.c
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 "frame.h"
23 #include "kern.h"
24 #include "mode.h"
25 #include "proc_mm.h"
26
27 static atomic_t using_sysemu;
28 int sysemu_supported;
29
30 void set_using_sysemu(int value)
31 {
32         atomic_set(&using_sysemu, sysemu_supported && value);
33 }
34
35 int get_using_sysemu(void)
36 {
37         return atomic_read(&using_sysemu);
38 }
39
40 int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
41 {
42         if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/
43                 *eof = 1;
44
45         return strlen(buf);
46 }
47
48 int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data)
49 {
50         char tmp[2];
51
52         if (copy_from_user(tmp, buf, 1))
53                 return -EFAULT;
54
55         if (tmp[0] == '0' || tmp[0] == '1')
56                 set_using_sysemu(tmp[0] - '0');
57         return count; /*We use the first char, but pretend to write everything*/
58 }
59
60 int __init make_proc_sysemu(void)
61 {
62         struct proc_dir_entry *ent;
63         if (mode_tt || !sysemu_supported)
64                 return 0;
65
66         ent = create_proc_entry("sysemu", 0600, &proc_root);
67
68         if (ent == NULL)
69         {
70                 printk("Failed to register /proc/sysemu\n");
71                 return(0);
72         }
73
74         ent->read_proc  = proc_read_sysemu;
75         ent->write_proc = proc_write_sysemu;
76
77         return 0;
78 }
79
80 late_initcall(make_proc_sysemu);
81
82 int singlestepping_skas(void)
83 {
84         int ret = current->ptrace & PT_DTRACE;
85
86         current->ptrace &= ~PT_DTRACE;
87         return(ret);
88 }
89
90 void *switch_to_skas(void *prev, void *next)
91 {
92         struct task_struct *from, *to;
93
94         from = prev;
95         to = next;
96
97         /* XXX need to check runqueues[cpu].idle */
98         if(current->pid == 0)
99                 switch_timers(0);
100
101         to->thread.prev_sched = from;
102         set_current(to);
103
104         switch_threads(&from->thread.mode.skas.switch_buf, 
105                        to->thread.mode.skas.switch_buf);
106
107         if(current->pid == 0)
108                 switch_timers(1);
109
110         return(current->thread.prev_sched);
111 }
112
113 extern void schedule_tail(struct task_struct *prev);
114
115 void new_thread_handler(int sig)
116 {
117         int (*fn)(void *), n;
118         void *arg;
119
120         fn = current->thread.request.u.thread.proc;
121         arg = current->thread.request.u.thread.arg;
122         change_sig(SIGUSR1, 1);
123         thread_wait(&current->thread.mode.skas.switch_buf, 
124                     current->thread.mode.skas.fork_buf);
125
126         if(current->thread.prev_sched != NULL)
127                 schedule_tail(current->thread.prev_sched);
128         current->thread.prev_sched = NULL;
129
130         /* The return value is 1 if the kernel thread execs a process,
131          * 0 if it just exits
132          */
133         n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
134         if(n == 1)
135                 userspace(&current->thread.regs.regs);
136         else do_exit(0);
137 }
138
139 void new_thread_proc(void *stack, void (*handler)(int sig))
140 {
141         init_new_thread_stack(stack, handler);
142         os_usr1_process(os_getpid());
143 }
144
145 void release_thread_skas(struct task_struct *task)
146 {
147 }
148
149 void exit_thread_skas(void)
150 {
151 }
152
153 void fork_handler(int sig)
154 {
155         change_sig(SIGUSR1, 1);
156         thread_wait(&current->thread.mode.skas.switch_buf, 
157                     current->thread.mode.skas.fork_buf);
158         
159         force_flush_all();
160         if(current->thread.prev_sched == NULL)
161                 panic("blech");
162
163         schedule_tail(current->thread.prev_sched);
164         current->thread.prev_sched = NULL;
165
166         userspace(&current->thread.regs.regs);
167 }
168
169 int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
170                      unsigned long stack_top, struct task_struct * p, 
171                      struct pt_regs *regs)
172 {
173         void (*handler)(int);
174
175         if(current->thread.forking){
176                 memcpy(&p->thread.regs.regs.skas, 
177                        &current->thread.regs.regs.skas, 
178                        sizeof(p->thread.regs.regs.skas));
179                 REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
180                 if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
181
182                 handler = fork_handler;
183         }
184         else {
185                 memcpy(p->thread.regs.regs.skas.regs, exec_regs, 
186                        sizeof(p->thread.regs.regs.skas.regs));
187                 memcpy(p->thread.regs.regs.skas.fp, exec_fp_regs, 
188                        sizeof(p->thread.regs.regs.skas.fp));
189                 memcpy(p->thread.regs.regs.skas.xfp, exec_fpx_regs, 
190                        sizeof(p->thread.regs.regs.skas.xfp));
191                 p->thread.request.u.thread = current->thread.request.u.thread;
192                 handler = new_thread_handler;
193         }
194
195         new_thread(p->thread_info, &p->thread.mode.skas.switch_buf,
196                    &p->thread.mode.skas.fork_buf, handler);
197         return(0);
198 }
199
200 int new_mm(int from)
201 {
202         struct proc_mm_op copy;
203         int n, fd;
204
205         fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
206         if(fd < 0)
207                 return(fd);
208
209         if(from != -1){
210                 copy = ((struct proc_mm_op) { .op       = MM_COPY_SEGMENTS,
211                                               .u        =
212                                               { .copy_segments  = from } } );
213                 n = os_write_file(fd, &copy, sizeof(copy));
214                 if(n != sizeof(copy))
215                         printk("new_mm : /proc/mm copy_segments failed, "
216                                "err = %d\n", -n);
217         }
218
219         return(fd);
220 }
221
222 void init_idle_skas(void)
223 {
224         cpu_tasks[current_thread->cpu].pid = os_getpid();
225         default_idle();
226 }
227
228 extern void start_kernel(void);
229
230 static int start_kernel_proc(void *unused)
231 {
232         int pid;
233
234         block_signals();
235         pid = os_getpid();
236
237         cpu_tasks[0].pid = pid;
238         cpu_tasks[0].task = current;
239 #ifdef CONFIG_SMP
240         cpu_online_map = cpumask_of_cpu(0);
241 #endif
242         start_kernel();
243         return(0);
244 }
245
246 int start_uml_skas(void)
247 {
248         start_userspace(0);
249         capture_signal_stack();
250
251         init_new_thread_signals(1);
252         uml_idle_timer();
253
254         init_task.thread.request.u.thread.proc = start_kernel_proc;
255         init_task.thread.request.u.thread.arg = NULL;
256         return(start_idle_thread(init_task.thread_info,
257                                  &init_task.thread.mode.skas.switch_buf,
258                                  &init_task.thread.mode.skas.fork_buf));
259 }
260
261 int external_pid_skas(struct task_struct *task)
262 {
263 #warning Need to look up userspace_pid by cpu
264         return(userspace_pid[0]);
265 }
266
267 int thread_pid_skas(struct task_struct *task)
268 {
269 #warning Need to look up userspace_pid by cpu
270         return(userspace_pid[0]);
271 }
272
273 /*
274  * Overrides for Emacs so that we follow Linus's tabbing style.
275  * Emacs will notice this stuff at the end of the file and automatically
276  * adjust the settings for this buffer only.  This must remain at the end
277  * of the file.
278  * ---------------------------------------------------------------------------
279  * Local variables:
280  * c-file-style: "linux"
281  * End:
282  */