process.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
  3. * Licensed under the GPL
  4. */
  5. #include <stdlib.h>
  6. #include <string.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. #include "process.h"
  31. int is_skas_winch(int pid, int fd, void *data)
  32. {
  33. if(pid != os_getpgrp())
  34. return(0);
  35. register_winch_irq(-1, fd, -1, data);
  36. return(1);
  37. }
  38. void get_skas_faultinfo(int pid, struct faultinfo * fi)
  39. {
  40. int err;
  41. err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
  42. if(err)
  43. panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
  44. "errno = %d\n", errno);
  45. /* Special handling for i386, which has different structs */
  46. if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
  47. memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
  48. sizeof(struct faultinfo) -
  49. sizeof(struct ptrace_faultinfo));
  50. }
  51. static void handle_segv(int pid, union uml_pt_regs * regs)
  52. {
  53. get_skas_faultinfo(pid, &regs->skas.faultinfo);
  54. segv(regs->skas.faultinfo, 0, 1, NULL);
  55. }
  56. /*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
  57. static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu)
  58. {
  59. int err, status;
  60. /* Mark this as a syscall */
  61. UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs);
  62. if (!local_using_sysemu)
  63. {
  64. err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
  65. if(err < 0)
  66. panic("handle_trap - nullifying syscall failed errno = %d\n",
  67. errno);
  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. CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
  73. if((err < 0) || !WIFSTOPPED(status) ||
  74. (WSTOPSIG(status) != SIGTRAP + 0x80))
  75. panic("handle_trap - failed to wait at end of syscall, "
  76. "errno = %d, status = %d\n", errno, status);
  77. }
  78. handle_syscall(regs);
  79. }
  80. static int userspace_tramp(void *arg)
  81. {
  82. init_new_thread_signals(0);
  83. enable_timer();
  84. ptrace(PTRACE_TRACEME, 0, 0, 0);
  85. os_stop_process(os_getpid());
  86. return(0);
  87. }
  88. /* Each element set once, and only accessed by a single processor anyway */
  89. #undef NR_CPUS
  90. #define NR_CPUS 1
  91. int userspace_pid[NR_CPUS];
  92. void start_userspace(int cpu)
  93. {
  94. void *stack;
  95. unsigned long sp;
  96. int pid, status, n;
  97. stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
  98. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  99. if(stack == MAP_FAILED)
  100. panic("start_userspace : mmap failed, errno = %d", errno);
  101. sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
  102. pid = clone(userspace_tramp, (void *) sp,
  103. CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
  104. if(pid < 0)
  105. panic("start_userspace : clone failed, errno = %d", errno);
  106. do {
  107. CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  108. if(n < 0)
  109. panic("start_userspace : wait failed, errno = %d",
  110. errno);
  111. } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
  112. if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
  113. panic("start_userspace : expected SIGSTOP, got status = %d",
  114. status);
  115. if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, (void *)PTRACE_O_TRACESYSGOOD) < 0)
  116. panic("start_userspace : PTRACE_SETOPTIONS failed, errno=%d\n",
  117. errno);
  118. if(munmap(stack, PAGE_SIZE) < 0)
  119. panic("start_userspace : munmap failed, errno = %d\n", errno);
  120. userspace_pid[cpu] = pid;
  121. }
  122. void userspace(union uml_pt_regs *regs)
  123. {
  124. int err, status, op, pid = userspace_pid[0];
  125. int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
  126. while(1){
  127. restore_registers(pid, regs);
  128. /* Now we set local_using_sysemu to be used for one loop */
  129. local_using_sysemu = get_using_sysemu();
  130. op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
  131. err = ptrace(op, pid, 0, 0);
  132. if(err)
  133. panic("userspace - could not resume userspace process, "
  134. "pid=%d, ptrace operation = %d, errno = %d\n",
  135. op, errno);
  136. CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
  137. if(err < 0)
  138. panic("userspace - waitpid failed, errno = %d\n",
  139. errno);
  140. regs->skas.is_user = 1;
  141. save_registers(pid, regs);
  142. UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
  143. if(WIFSTOPPED(status)){
  144. switch(WSTOPSIG(status)){
  145. case SIGSEGV:
  146. handle_segv(pid, regs);
  147. break;
  148. case SIGTRAP + 0x80:
  149. handle_trap(pid, regs, local_using_sysemu);
  150. break;
  151. case SIGTRAP:
  152. relay_signal(SIGTRAP, regs);
  153. break;
  154. case SIGIO:
  155. case SIGVTALRM:
  156. case SIGILL:
  157. case SIGBUS:
  158. case SIGFPE:
  159. case SIGWINCH:
  160. user_signal(WSTOPSIG(status), regs, pid);
  161. break;
  162. default:
  163. printk("userspace - child stopped with signal "
  164. "%d\n", WSTOPSIG(status));
  165. }
  166. interrupt_end();
  167. /* Avoid -ERESTARTSYS handling in host */
  168. PT_SYSCALL_NR(regs->skas.regs) = -1;
  169. }
  170. }
  171. }
  172. #define INIT_JMP_NEW_THREAD 0
  173. #define INIT_JMP_REMOVE_SIGSTACK 1
  174. #define INIT_JMP_CALLBACK 2
  175. #define INIT_JMP_HALT 3
  176. #define INIT_JMP_REBOOT 4
  177. void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
  178. void (*handler)(int))
  179. {
  180. unsigned long flags;
  181. sigjmp_buf switch_buf, fork_buf;
  182. *switch_buf_ptr = &switch_buf;
  183. *fork_buf_ptr = &fork_buf;
  184. /* Somewhat subtle - siglongjmp restores the signal mask before doing
  185. * the longjmp. This means that when jumping from one stack to another
  186. * when the target stack has interrupts enabled, an interrupt may occur
  187. * on the source stack. This is bad when starting up a process because
  188. * it's not supposed to get timer ticks until it has been scheduled.
  189. * So, we disable interrupts around the sigsetjmp to ensure that
  190. * they can't happen until we get back here where they are safe.
  191. */
  192. flags = get_signals();
  193. block_signals();
  194. if(sigsetjmp(fork_buf, 1) == 0)
  195. new_thread_proc(stack, handler);
  196. remove_sigstack();
  197. set_signals(flags);
  198. }
  199. void thread_wait(void *sw, void *fb)
  200. {
  201. sigjmp_buf buf, **switch_buf = sw, *fork_buf;
  202. *switch_buf = &buf;
  203. fork_buf = fb;
  204. if(sigsetjmp(buf, 1) == 0)
  205. siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK);
  206. }
  207. void switch_threads(void *me, void *next)
  208. {
  209. sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
  210. *me_ptr = &my_buf;
  211. if(sigsetjmp(my_buf, 1) == 0)
  212. siglongjmp(*next_buf, 1);
  213. }
  214. static sigjmp_buf initial_jmpbuf;
  215. /* XXX Make these percpu */
  216. static void (*cb_proc)(void *arg);
  217. static void *cb_arg;
  218. static sigjmp_buf *cb_back;
  219. int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
  220. {
  221. sigjmp_buf **switch_buf = switch_buf_ptr;
  222. int n;
  223. set_handler(SIGWINCH, (__sighandler_t) sig_handler,
  224. SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
  225. SIGVTALRM, -1);
  226. *fork_buf_ptr = &initial_jmpbuf;
  227. n = sigsetjmp(initial_jmpbuf, 1);
  228. switch(n){
  229. case INIT_JMP_NEW_THREAD:
  230. new_thread_proc((void *) stack, new_thread_handler);
  231. break;
  232. case INIT_JMP_REMOVE_SIGSTACK:
  233. remove_sigstack();
  234. break;
  235. case INIT_JMP_CALLBACK:
  236. (*cb_proc)(cb_arg);
  237. siglongjmp(*cb_back, 1);
  238. break;
  239. case INIT_JMP_HALT:
  240. kmalloc_ok = 0;
  241. return(0);
  242. case INIT_JMP_REBOOT:
  243. kmalloc_ok = 0;
  244. return(1);
  245. default:
  246. panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
  247. }
  248. siglongjmp(**switch_buf, 1);
  249. }
  250. void remove_sigstack(void)
  251. {
  252. stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
  253. .ss_sp = NULL,
  254. .ss_size = 0 });
  255. if(sigaltstack(&stack, NULL) != 0)
  256. panic("disabling signal stack failed, errno = %d\n", errno);
  257. }
  258. void initial_thread_cb_skas(void (*proc)(void *), void *arg)
  259. {
  260. sigjmp_buf here;
  261. cb_proc = proc;
  262. cb_arg = arg;
  263. cb_back = &here;
  264. block_signals();
  265. if(sigsetjmp(here, 1) == 0)
  266. siglongjmp(initial_jmpbuf, INIT_JMP_CALLBACK);
  267. unblock_signals();
  268. cb_proc = NULL;
  269. cb_arg = NULL;
  270. cb_back = NULL;
  271. }
  272. void halt_skas(void)
  273. {
  274. block_signals();
  275. siglongjmp(initial_jmpbuf, INIT_JMP_HALT);
  276. }
  277. void reboot_skas(void)
  278. {
  279. block_signals();
  280. siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
  281. }
  282. void switch_mm_skas(int mm_fd)
  283. {
  284. int err;
  285. #warning need cpu pid in switch_mm_skas
  286. err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
  287. if(err)
  288. panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
  289. errno);
  290. }
  291. void kill_off_processes_skas(void)
  292. {
  293. #warning need to loop over userspace_pids in kill_off_processes_skas
  294. os_kill_ptraced_process(userspace_pid[0], 1);
  295. }
  296. /*
  297. * Overrides for Emacs so that we follow Linus's tabbing style.
  298. * Emacs will notice this stuff at the end of the file and automatically
  299. * adjust the settings for this buffer only. This must remain at the end
  300. * of the file.
  301. * ---------------------------------------------------------------------------
  302. * Local variables:
  303. * c-file-style: "linux"
  304. * End:
  305. */