5bb40a3f752328f950fbaa82b57e7c7b06922066
[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
26 #ifdef PTRACE_SYSEMU
27 static atomic_t using_sysemu;
28 #endif
29
30 void set_using_sysemu(int value)
31 {
32         atomic_set(&using_sysemu, 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
64         ent = create_proc_entry("sysemu", 00600, &proc_root);
65         ent->read_proc  = proc_read_sysemu;
66         ent->write_proc = proc_write_sysemu;
67
68         if (ent == NULL)
69         {
70                 printk("Failed to register /proc/sysemu\n");
71                 return(0);
72         }
73
74         return 0;
75 }
76
77 late_initcall(make_proc_sysemu);
78
79 int singlestepping_skas(void)
80 {
81         int ret = current->ptrace & PT_DTRACE;
82
83         current->ptrace &= ~PT_DTRACE;
84         return(ret);
85 }
86
87 void *switch_to_skas(void *prev, void *next)
88 {
89         struct task_struct *from, *to;
90
91         from = prev;
92         to = next;
93
94         /* XXX need to check runqueues[cpu].idle */
95         if(current->pid == 0)
96                 switch_timers(0);
97
98         to->thread.prev_sched = from;
99         set_current(to);
100
101         switch_threads(&from->thread.mode.skas.switch_buf, 
102                        to->thread.mode.skas.switch_buf);
103
104         if(current->pid == 0)
105                 switch_timers(1);
106
107         return(current->thread.prev_sched);
108 }
109
110 extern void schedule_tail(struct task_struct *prev);
111
112 void new_thread_handler(int sig)
113 {
114         int (*fn)(void *), n;
115         void *arg;
116
117         fn = current->thread.request.u.thread.proc;
118         arg = current->thread.request.u.thread.arg;
119         change_sig(SIGUSR1, 1);
120         thread_wait(&current->thread.mode.skas.switch_buf, 
121                     current->thread.mode.skas.fork_buf);
122
123         if(current->thread.prev_sched != NULL)
124                 schedule_tail(current->thread.prev_sched);
125         current->thread.prev_sched = NULL;
126
127         /* The return value is 1 if the kernel thread execs a process,
128          * 0 if it just exits
129          */
130         n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
131         if(n == 1)
132                 userspace(&current->thread.regs.regs);
133         else do_exit(0);
134 }
135
136 void new_thread_proc(void *stack, void (*handler)(int sig))
137 {
138         init_new_thread_stack(stack, handler);
139         os_usr1_process(os_getpid());
140 }
141
142 void release_thread_skas(struct task_struct *task)
143 {
144 }
145
146 void exit_thread_skas(void)
147 {
148 }
149
150 void fork_handler(int sig)
151 {
152         change_sig(SIGUSR1, 1);
153         thread_wait(&current->thread.mode.skas.switch_buf, 
154                     current->thread.mode.skas.fork_buf);
155         
156         force_flush_all();
157         if(current->thread.prev_sched == NULL)
158                 panic("blech");
159         
160         schedule_tail(current->thread.prev_sched);
161         current->thread.prev_sched = NULL;
162
163         userspace(&current->thread.regs.regs);
164 }
165
166 int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
167                      unsigned long stack_top, struct task_struct * p, 
168                      struct pt_regs *regs)
169 {
170         void (*handler)(int);
171
172         if(current->thread.forking){
173                 memcpy(&p->thread.regs.regs.skas, 
174                        &current->thread.regs.regs.skas, 
175                        sizeof(p->thread.regs.regs.skas));
176                 REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
177                 if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
178
179                 handler = fork_handler;
180         }
181         else {
182                 memcpy(p->thread.regs.regs.skas.regs, exec_regs, 
183                        sizeof(p->thread.regs.regs.skas.regs));
184                 memcpy(p->thread.regs.regs.skas.fp, exec_fp_regs, 
185                        sizeof(p->thread.regs.regs.skas.fp));
186                 memcpy(p->thread.regs.regs.skas.xfp, exec_fpx_regs, 
187                        sizeof(p->thread.regs.regs.skas.xfp));
188                 p->thread.request.u.thread = current->thread.request.u.thread;
189                 handler = new_thread_handler;
190         }
191
192         new_thread((void *) p->thread.kernel_stack, 
193                    &p->thread.mode.skas.switch_buf, 
194                    &p->thread.mode.skas.fork_buf, handler);
195         return(0);
196 }
197
198 void init_idle_skas(void)
199 {
200         cpu_tasks[current_thread->cpu].pid = os_getpid();
201         default_idle();
202 }
203
204 extern void start_kernel(void);
205
206 static int start_kernel_proc(void *unused)
207 {
208         int pid;
209
210         block_signals();
211         pid = os_getpid();
212
213         cpu_tasks[0].pid = pid;
214         cpu_tasks[0].task = current;
215 #ifdef CONFIG_SMP
216         cpu_online_map = cpumask_of_cpu(0);
217 #endif
218         start_kernel();
219         return(0);
220 }
221
222 int start_uml_skas(void)
223 {
224         start_userspace(0);
225         capture_signal_stack();
226         uml_idle_timer();
227
228         init_new_thread_signals(1);
229
230         init_task.thread.request.u.thread.proc = start_kernel_proc;
231         init_task.thread.request.u.thread.arg = NULL;
232         return(start_idle_thread((void *) init_task.thread.kernel_stack,
233                                  &init_task.thread.mode.skas.switch_buf,
234                                  &init_task.thread.mode.skas.fork_buf));
235 }
236
237 int external_pid_skas(struct task_struct *task)
238 {
239 #warning Need to look up userspace_pid by cpu   
240         return(userspace_pid[0]);
241 }
242
243 int thread_pid_skas(struct task_struct *task)
244 {
245 #warning Need to look up userspace_pid by cpu   
246         return(userspace_pid[0]);
247 }
248
249 /*
250  * Overrides for Emacs so that we follow Linus's tabbing style.
251  * Emacs will notice this stuff at the end of the file and automatically
252  * adjust the settings for this buffer only.  This must remain at the end
253  * of the file.
254  * ---------------------------------------------------------------------------
255  * Local variables:
256  * c-file-style: "linux"
257  * End:
258  */