Blame view
arch/um/kernel/process.c
9.49 KB
995473aec [PATCH] uml: file... |
1 |
/* |
ba180fd43 uml: style fixes ... |
2 |
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
1da177e4c Linux-2.6.12-rc2 |
3 4 5 |
* Copyright 2003 PathScale, Inc. * Licensed under the GPL */ |
c5d4bb171 uml: style fixes ... |
6 7 8 |
#include <linux/stddef.h> #include <linux/err.h> #include <linux/hardirq.h> |
c5d4bb171 uml: style fixes ... |
9 |
#include <linux/mm.h> |
6613c5e86 uml: convert to s... |
10 |
#include <linux/module.h> |
c5d4bb171 uml: style fixes ... |
11 12 13 14 |
#include <linux/personality.h> #include <linux/proc_fs.h> #include <linux/ptrace.h> #include <linux/random.h> |
5a0e3ad6a include cleanup: ... |
15 |
#include <linux/slab.h> |
c5d4bb171 uml: style fixes ... |
16 |
#include <linux/sched.h> |
6613c5e86 uml: convert to s... |
17 |
#include <linux/seq_file.h> |
c5d4bb171 uml: style fixes ... |
18 19 20 21 |
#include <linux/tick.h> #include <linux/threads.h> #include <asm/current.h> #include <asm/pgtable.h> |
445c5786c um: kill shared/t... |
22 |
#include <asm/mmu_context.h> |
c5d4bb171 uml: style fixes ... |
23 |
#include <asm/uaccess.h> |
4ff83ce11 uml: create as-la... |
24 |
#include "as-layout.h" |
ba180fd43 uml: style fixes ... |
25 |
#include "kern_util.h" |
1da177e4c Linux-2.6.12-rc2 |
26 |
#include "os.h" |
77bf44003 uml: remove code ... |
27 |
#include "skas.h" |
1da177e4c Linux-2.6.12-rc2 |
28 |
|
ba180fd43 uml: style fixes ... |
29 30 |
/* * This is a per-cpu array. A processor only modifies its entry and it only |
1da177e4c Linux-2.6.12-rc2 |
31 32 33 34 |
* cares about its entry, so it's OK if another processor is modifying its * entry. */ struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; |
2dc5802a2 uml: remove dupli... |
35 |
static inline int external_pid(void) |
1da177e4c Linux-2.6.12-rc2 |
36 |
{ |
77bf44003 uml: remove code ... |
37 |
/* FIXME: Need to look up userspace_pid by cpu */ |
ba180fd43 uml: style fixes ... |
38 |
return userspace_pid[0]; |
1da177e4c Linux-2.6.12-rc2 |
39 40 41 42 43 |
} int pid_to_processor_id(int pid) { int i; |
c5d4bb171 uml: style fixes ... |
44 |
for (i = 0; i < ncpus; i++) { |
ba180fd43 uml: style fixes ... |
45 |
if (cpu_tasks[i].pid == pid) |
6e21aec3f uml: tidy process.c |
46 |
return i; |
1da177e4c Linux-2.6.12-rc2 |
47 |
} |
6e21aec3f uml: tidy process.c |
48 |
return -1; |
1da177e4c Linux-2.6.12-rc2 |
49 50 51 52 53 54 55 56 57 58 |
} void free_stack(unsigned long stack, int order) { free_pages(stack, order); } unsigned long alloc_stack(int order, int atomic) { unsigned long page; |
53f9fc93f [PATCH] gfp_t: re... |
59 |
gfp_t flags = GFP_KERNEL; |
1da177e4c Linux-2.6.12-rc2 |
60 |
|
46db4a42d [PATCH] uml: Fix ... |
61 62 |
if (atomic) flags = GFP_ATOMIC; |
1da177e4c Linux-2.6.12-rc2 |
63 |
page = __get_free_pages(flags, order); |
5c8aaceab uml: stop special... |
64 |
|
6e21aec3f uml: tidy process.c |
65 |
return page; |
1da177e4c Linux-2.6.12-rc2 |
66 67 68 69 70 71 72 73 |
} int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { int pid; current->thread.request.u.thread.proc = fn; current->thread.request.u.thread.arg = arg; |
e0877f07e [PATCH] uml: fork... |
74 75 |
pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, ¤t->thread.regs, 0, NULL, NULL); |
6e21aec3f uml: tidy process.c |
76 |
return pid; |
1da177e4c Linux-2.6.12-rc2 |
77 |
} |
73395a000 um: distribute ex... |
78 |
EXPORT_SYMBOL(kernel_thread); |
1da177e4c Linux-2.6.12-rc2 |
79 |
|
6e21aec3f uml: tidy process.c |
80 |
static inline void set_current(struct task_struct *task) |
1da177e4c Linux-2.6.12-rc2 |
81 |
{ |
ca9bc0bb2 [PATCH] uml: task... |
82 |
cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) |
2dc5802a2 uml: remove dupli... |
83 |
{ external_pid(), task }); |
1da177e4c Linux-2.6.12-rc2 |
84 |
} |
291248fd6 uml: remove unuse... |
85 |
extern void arch_switch_to(struct task_struct *to); |
77bf44003 uml: remove code ... |
86 |
|
1da177e4c Linux-2.6.12-rc2 |
87 88 |
void *_switch_to(void *prev, void *next, void *last) { |
995473aec [PATCH] uml: file... |
89 |
struct task_struct *from = prev; |
291248fd6 uml: remove unuse... |
90 |
struct task_struct *to = next; |
f6e34c6af [PATCH] uml: _swi... |
91 |
|
995473aec [PATCH] uml: file... |
92 93 |
to->thread.prev_sched = from; set_current(to); |
f6e34c6af [PATCH] uml: _swi... |
94 |
|
3eddddcf2 [PATCH] uml: brea... |
95 |
do { |
6aa802ce6 uml: throw out CH... |
96 |
current->thread.saved_task = NULL; |
77bf44003 uml: remove code ... |
97 |
|
c5d4bb171 uml: style fixes ... |
98 99 |
switch_threads(&from->thread.switch_buf, &to->thread.switch_buf); |
77bf44003 uml: remove code ... |
100 |
|
291248fd6 uml: remove unuse... |
101 |
arch_switch_to(current); |
77bf44003 uml: remove code ... |
102 |
|
ba180fd43 uml: style fixes ... |
103 |
if (current->thread.saved_task) |
3eddddcf2 [PATCH] uml: brea... |
104 |
show_regs(&(current->thread.regs)); |
c5d4bb171 uml: style fixes ... |
105 106 |
to = current->thread.saved_task; from = current; |
291248fd6 uml: remove unuse... |
107 |
} while (current->thread.saved_task); |
f6e34c6af [PATCH] uml: _swi... |
108 |
|
6e21aec3f uml: tidy process.c |
109 |
return current->thread.prev_sched; |
f6e34c6af [PATCH] uml: _swi... |
110 |
|
1da177e4c Linux-2.6.12-rc2 |
111 112 113 114 |
} void interrupt_end(void) { |
ba180fd43 uml: style fixes ... |
115 |
if (need_resched()) |
6e21aec3f uml: tidy process.c |
116 |
schedule(); |
ba180fd43 uml: style fixes ... |
117 |
if (test_tsk_thread_flag(current, TIF_SIGPENDING)) |
6e21aec3f uml: tidy process.c |
118 |
do_signal(); |
1da177e4c Linux-2.6.12-rc2 |
119 |
} |
1da177e4c Linux-2.6.12-rc2 |
120 121 |
void exit_thread(void) { |
1da177e4c Linux-2.6.12-rc2 |
122 |
} |
995473aec [PATCH] uml: file... |
123 |
|
1da177e4c Linux-2.6.12-rc2 |
124 125 |
void *get_current(void) { |
6e21aec3f uml: tidy process.c |
126 |
return current; |
1da177e4c Linux-2.6.12-rc2 |
127 |
} |
ba180fd43 uml: style fixes ... |
128 129 |
/* * This is called magically, by its address being stuffed in a jmp_buf |
77bf44003 uml: remove code ... |
130 131 132 133 134 135 |
* and being longjmp-d to. */ void new_thread_handler(void) { int (*fn)(void *), n; void *arg; |
ba180fd43 uml: style fixes ... |
136 |
if (current->thread.prev_sched != NULL) |
77bf44003 uml: remove code ... |
137 138 139 140 141 |
schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; fn = current->thread.request.u.thread.proc; arg = current->thread.request.u.thread.arg; |
ba180fd43 uml: style fixes ... |
142 143 |
/* * The return value is 1 if the kernel thread execs a process, |
77bf44003 uml: remove code ... |
144 145 146 |
* 0 if it just exits */ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); |
ba180fd43 uml: style fixes ... |
147 |
if (n == 1) { |
77bf44003 uml: remove code ... |
148 149 150 151 152 153 154 155 156 157 158 |
/* Handle any immediate reschedules or signals */ interrupt_end(); userspace(¤t->thread.regs.regs); } else do_exit(0); } /* Called magically, see new_thread_handler above */ void fork_handler(void) { force_flush_all(); |
77bf44003 uml: remove code ... |
159 160 |
schedule_tail(current->thread.prev_sched); |
ba180fd43 uml: style fixes ... |
161 162 |
/* * XXX: if interrupt_end() calls schedule, this call to |
77bf44003 uml: remove code ... |
163 |
* arch_switch_to isn't needed. We could want to apply this to |
ba180fd43 uml: style fixes ... |
164 165 |
* improve performance. -bb */ |
291248fd6 uml: remove unuse... |
166 |
arch_switch_to(current); |
77bf44003 uml: remove code ... |
167 168 169 170 171 172 173 174 |
current->thread.prev_sched = NULL; /* Handle any immediate reschedules or signals */ interrupt_end(); userspace(¤t->thread.regs.regs); } |
6f2c55b84 Simplify copy_thr... |
175 |
int copy_thread(unsigned long clone_flags, unsigned long sp, |
995473aec [PATCH] uml: file... |
176 |
unsigned long stack_top, struct task_struct * p, |
1da177e4c Linux-2.6.12-rc2 |
177 178 |
struct pt_regs *regs) { |
77bf44003 uml: remove code ... |
179 180 |
void (*handler)(void); int ret = 0; |
aa6758d48 [PATCH] uml: impl... |
181 |
|
1da177e4c Linux-2.6.12-rc2 |
182 |
p->thread = (struct thread_struct) INIT_THREAD; |
aa6758d48 [PATCH] uml: impl... |
183 |
|
ba180fd43 uml: style fixes ... |
184 |
if (current->thread.forking) { |
77bf44003 uml: remove code ... |
185 186 |
memcpy(&p->thread.regs.regs, ®s->regs, sizeof(p->thread.regs.regs)); |
18badddaa uml: rename pt_re... |
187 |
REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.gp, 0); |
ba180fd43 uml: style fixes ... |
188 |
if (sp != 0) |
18badddaa uml: rename pt_re... |
189 |
REGS_SP(p->thread.regs.regs.gp) = sp; |
aa6758d48 [PATCH] uml: impl... |
190 |
|
77bf44003 uml: remove code ... |
191 |
handler = fork_handler; |
aa6758d48 [PATCH] uml: impl... |
192 |
|
77bf44003 uml: remove code ... |
193 194 195 |
arch_copy_thread(¤t->thread.arch, &p->thread.arch); } else { |
fbfe9c847 um: Save FPU regi... |
196 |
get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp); |
77bf44003 uml: remove code ... |
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
p->thread.request.u.thread = current->thread.request.u.thread; handler = new_thread_handler; } new_thread(task_stack_page(p), &p->thread.switch_buf, handler); if (current->thread.forking) { clear_flushed_tls(p); /* * Set a new TLS for the child thread? */ if (clone_flags & CLONE_SETTLS) ret = arch_copy_tls(p); } |
aa6758d48 [PATCH] uml: impl... |
212 |
|
aa6758d48 [PATCH] uml: impl... |
213 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
214 215 216 217 218 219 220 |
} void initial_thread_cb(void (*proc)(void *), void *arg) { int save_kmalloc_ok = kmalloc_ok; kmalloc_ok = 0; |
6aa802ce6 uml: throw out CH... |
221 |
initial_thread_cb_skas(proc, arg); |
1da177e4c Linux-2.6.12-rc2 |
222 223 |
kmalloc_ok = save_kmalloc_ok; } |
995473aec [PATCH] uml: file... |
224 |
|
1da177e4c Linux-2.6.12-rc2 |
225 226 |
void default_idle(void) { |
b160fb630 uml: eliminate in... |
227 |
unsigned long long nsecs; |
c5d4bb171 uml: style fixes ... |
228 |
while (1) { |
1da177e4c Linux-2.6.12-rc2 |
229 |
/* endless idle loop with no priority at all */ |
1da177e4c Linux-2.6.12-rc2 |
230 231 232 233 234 |
/* * although we are an idle CPU, we do not want to * get into the scheduler unnecessarily. */ |
ba180fd43 uml: style fixes ... |
235 |
if (need_resched()) |
1da177e4c Linux-2.6.12-rc2 |
236 |
schedule(); |
995473aec [PATCH] uml: file... |
237 |
|
1268fbc74 nohz: Remove tick... |
238 239 |
tick_nohz_idle_enter(); rcu_idle_enter(); |
b160fb630 uml: eliminate in... |
240 241 |
nsecs = disable_timer(); idle_sleep(nsecs); |
1268fbc74 nohz: Remove tick... |
242 243 |
rcu_idle_exit(); tick_nohz_idle_exit(); |
1da177e4c Linux-2.6.12-rc2 |
244 245 246 247 248 |
} } void cpu_idle(void) { |
a5a678c80 uml: current.h cl... |
249 |
cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); |
77bf44003 uml: remove code ... |
250 |
default_idle(); |
1da177e4c Linux-2.6.12-rc2 |
251 |
} |
b63162939 [PATCH] uml: avoi... |
252 253 254 |
int __cant_sleep(void) { return in_atomic() || irqs_disabled() || in_interrupt(); /* Is in_interrupt() really needed? */ |
1da177e4c Linux-2.6.12-rc2 |
255 |
} |
1da177e4c Linux-2.6.12-rc2 |
256 257 258 259 260 |
int user_context(unsigned long sp) { unsigned long stack; stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER); |
a5a678c80 uml: current.h cl... |
261 |
return stack != (unsigned long) current_thread_info(); |
1da177e4c Linux-2.6.12-rc2 |
262 |
} |
1da177e4c Linux-2.6.12-rc2 |
263 264 265 266 267 268 269 270 271 272 |
extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; void do_uml_exitcalls(void) { exitcall_t *call; call = &__uml_exitcall_end; while (--call >= &__uml_exitcall_begin) (*call)(); } |
c0a9290ec uml: const and ot... |
273 |
char *uml_strdup(const char *string) |
1da177e4c Linux-2.6.12-rc2 |
274 |
{ |
dfe52244e [PATCH] kstrdup: ... |
275 |
return kstrdup(string, GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
276 |
} |
73395a000 um: distribute ex... |
277 |
EXPORT_SYMBOL(uml_strdup); |
1da177e4c Linux-2.6.12-rc2 |
278 |
|
1da177e4c Linux-2.6.12-rc2 |
279 280 |
int copy_to_user_proc(void __user *to, void *from, int size) { |
6e21aec3f uml: tidy process.c |
281 |
return copy_to_user(to, from, size); |
1da177e4c Linux-2.6.12-rc2 |
282 283 284 285 |
} int copy_from_user_proc(void *to, void __user *from, int size) { |
6e21aec3f uml: tidy process.c |
286 |
return copy_from_user(to, from, size); |
1da177e4c Linux-2.6.12-rc2 |
287 288 289 290 |
} int clear_user_proc(void __user *buf, int size) { |
6e21aec3f uml: tidy process.c |
291 |
return clear_user(buf, size); |
1da177e4c Linux-2.6.12-rc2 |
292 293 294 295 |
} int strlen_user_proc(char __user *str) { |
6e21aec3f uml: tidy process.c |
296 |
return strlen_user(str); |
1da177e4c Linux-2.6.12-rc2 |
297 298 299 300 301 |
} int smp_sigio_handler(void) { #ifdef CONFIG_SMP |
a5a678c80 uml: current.h cl... |
302 |
int cpu = current_thread_info()->cpu; |
1da177e4c Linux-2.6.12-rc2 |
303 |
IPI_handler(cpu); |
ba180fd43 uml: style fixes ... |
304 |
if (cpu != 0) |
6e21aec3f uml: tidy process.c |
305 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
306 |
#endif |
6e21aec3f uml: tidy process.c |
307 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
308 |
} |
1da177e4c Linux-2.6.12-rc2 |
309 310 |
int cpu(void) { |
a5a678c80 uml: current.h cl... |
311 |
return current_thread_info()->cpu; |
1da177e4c Linux-2.6.12-rc2 |
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
} static atomic_t using_sysemu = ATOMIC_INIT(0); int sysemu_supported; void set_using_sysemu(int value) { if (value > sysemu_supported) return; atomic_set(&using_sysemu, value); } int get_using_sysemu(void) { return atomic_read(&using_sysemu); } |
6613c5e86 uml: convert to s... |
328 |
static int sysemu_proc_show(struct seq_file *m, void *v) |
1da177e4c Linux-2.6.12-rc2 |
329 |
{ |
6613c5e86 uml: convert to s... |
330 331 332 333 |
seq_printf(m, "%d ", get_using_sysemu()); return 0; } |
1da177e4c Linux-2.6.12-rc2 |
334 |
|
6613c5e86 uml: convert to s... |
335 336 337 |
static int sysemu_proc_open(struct inode *inode, struct file *file) { return single_open(file, sysemu_proc_show, NULL); |
1da177e4c Linux-2.6.12-rc2 |
338 |
} |
6613c5e86 uml: convert to s... |
339 340 |
static ssize_t sysemu_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) |
1da177e4c Linux-2.6.12-rc2 |
341 342 343 344 345 346 347 348 |
{ char tmp[2]; if (copy_from_user(tmp, buf, 1)) return -EFAULT; if (tmp[0] >= '0' && tmp[0] <= '2') set_using_sysemu(tmp[0] - '0'); |
ba180fd43 uml: style fixes ... |
349 350 |
/* We use the first char, but pretend to write everything */ return count; |
1da177e4c Linux-2.6.12-rc2 |
351 |
} |
6613c5e86 uml: convert to s... |
352 353 354 355 356 357 358 359 |
static const struct file_operations sysemu_proc_fops = { .owner = THIS_MODULE, .open = sysemu_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .write = sysemu_proc_write, }; |
1da177e4c Linux-2.6.12-rc2 |
360 361 362 363 364 |
int __init make_proc_sysemu(void) { struct proc_dir_entry *ent; if (!sysemu_supported) return 0; |
6613c5e86 uml: convert to s... |
365 |
ent = proc_create("sysemu", 0600, NULL, &sysemu_proc_fops); |
1da177e4c Linux-2.6.12-rc2 |
366 367 368 |
if (ent == NULL) { |
30f417c65 [PATCH] uml: Clea... |
369 370 |
printk(KERN_WARNING "Failed to register /proc/sysemu "); |
6e21aec3f uml: tidy process.c |
371 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
372 |
} |
1da177e4c Linux-2.6.12-rc2 |
373 374 375 376 377 378 379 380 |
return 0; } late_initcall(make_proc_sysemu); int singlestepping(void * t) { struct task_struct *task = t ? t : current; |
c5d4bb171 uml: style fixes ... |
381 |
if (!(task->ptrace & PT_DTRACE)) |
ba180fd43 uml: style fixes ... |
382 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
383 384 |
if (task->thread.singlestep_syscall) |
ba180fd43 uml: style fixes ... |
385 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
386 387 388 |
return 2; } |
b8bd0220c [PATCH] uml: S390... |
389 390 391 392 393 394 395 396 |
/* * Only x86 and x86_64 have an arch_align_stack(). * All other arches have "#define arch_align_stack(x) (x)" * in their asm/system.h * As this is included in UML from asm-um/system-generic.h, * we can use it to behave as the subarch does. */ #ifndef arch_align_stack |
1da177e4c Linux-2.6.12-rc2 |
397 398 |
unsigned long arch_align_stack(unsigned long sp) { |
8f80e9466 [PATCH] uml: Fix ... |
399 |
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) |
1da177e4c Linux-2.6.12-rc2 |
400 401 402 |
sp -= get_random_int() % 8192; return sp & ~0xf; } |
b8bd0220c [PATCH] uml: S390... |
403 |
#endif |
c11274655 uml: implement ge... |
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
unsigned long get_wchan(struct task_struct *p) { unsigned long stack_page, sp, ip; bool seen_sched = 0; if ((p == NULL) || (p == current) || (p->state == TASK_RUNNING)) return 0; stack_page = (unsigned long) task_stack_page(p); /* Bail if the process has no kernel stack for some reason */ if (stack_page == 0) return 0; sp = p->thread.switch_buf->JB_SP; /* * Bail if the stack pointer is below the bottom of the kernel * stack for some reason */ if (sp < stack_page) return 0; while (sp < stack_page + THREAD_SIZE) { ip = *((unsigned long *) sp); if (in_sched_functions(ip)) /* Ignore everything until we're above the scheduler */ seen_sched = 1; else if (kernel_text_address(ip) && seen_sched) return ip; sp += sizeof(unsigned long); } return 0; } |
8192ab42b uml: header untan... |
439 440 441 442 443 444 445 |
int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu) { int cpu = current_thread_info()->cpu; return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu); } |