void userspace()

in os-Linux/skas/process.c [382:508]


void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
{
	int err, status, op, pid = userspace_pid[0];
	/* To prevent races if using_sysemu changes under us.*/
	int local_using_sysemu;
	siginfo_t si;

	/* Handle any immediate reschedules or signals */
	interrupt_end();

	while (1) {
		if (kill_userspace_mm[0])
			fatal_sigsegv();

		/*
		 * This can legitimately fail if the process loads a
		 * bogus value into a segment register.  It will
		 * segfault and PTRACE_GETREGS will read that value
		 * out of the process.  However, PTRACE_SETREGS will
		 * fail.  In this case, there is nothing to do but
		 * just kill the process.
		 */
		if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) {
			printk(UM_KERN_ERR "userspace - ptrace set regs "
			       "failed, errno = %d\n", errno);
			fatal_sigsegv();
		}

		if (put_fp_registers(pid, regs->fp)) {
			printk(UM_KERN_ERR "userspace - ptrace set fp regs "
			       "failed, errno = %d\n", errno);
			fatal_sigsegv();
		}

		/* Now we set local_using_sysemu to be used for one loop */
		local_using_sysemu = get_using_sysemu();

		op = SELECT_PTRACE_OPERATION(local_using_sysemu,
					     singlestepping(NULL));

		if (ptrace(op, pid, 0, 0)) {
			printk(UM_KERN_ERR "userspace - ptrace continue "
			       "failed, op = %d, errno = %d\n", op, errno);
			fatal_sigsegv();
		}

		CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
		if (err < 0) {
			printk(UM_KERN_ERR "userspace - wait failed, "
			       "errno = %d\n", errno);
			fatal_sigsegv();
		}

		regs->is_user = 1;
		if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) {
			printk(UM_KERN_ERR "userspace - PTRACE_GETREGS failed, "
			       "errno = %d\n", errno);
			fatal_sigsegv();
		}

		if (get_fp_registers(pid, regs->fp)) {
			printk(UM_KERN_ERR "userspace -  get_fp_registers failed, "
			       "errno = %d\n", errno);
			fatal_sigsegv();
		}

		UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */

		if (WIFSTOPPED(status)) {
			int sig = WSTOPSIG(status);

			/* These signal handlers need the si argument.
			 * The SIGIO and SIGALARM handlers which constitute the
			 * majority of invocations, do not use it.
			 */
			switch (sig) {
			case SIGSEGV:
			case SIGTRAP:
			case SIGILL:
			case SIGBUS:
			case SIGFPE:
			case SIGWINCH:
				ptrace(PTRACE_GETSIGINFO, pid, 0, (struct siginfo *)&si);
				break;
			}

			switch (sig) {
			case SIGSEGV:
				if (PTRACE_FULL_FAULTINFO) {
					get_skas_faultinfo(pid,
							   &regs->faultinfo, aux_fp_regs);
					(*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si,
							     regs);
				}
				else handle_segv(pid, regs, aux_fp_regs);
				break;
			case SIGTRAP + 0x80:
			        handle_trap(pid, regs, local_using_sysemu);
				break;
			case SIGTRAP:
				relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
				break;
			case SIGALRM:
				break;
			case SIGIO:
			case SIGILL:
			case SIGBUS:
			case SIGFPE:
			case SIGWINCH:
				block_signals_trace();
				(*sig_info[sig])(sig, (struct siginfo *)&si, regs);
				unblock_signals_trace();
				break;
			default:
				printk(UM_KERN_ERR "userspace - child stopped "
				       "with signal %d\n", sig);
				fatal_sigsegv();
			}
			pid = userspace_pid[0];
			interrupt_end();

			/* Avoid -ERESTARTSYS handling in host */
			if (PT_SYSCALL_NR_OFFSET != PT_SYSCALL_RET_OFFSET)
				PT_SYSCALL_NR(regs->gp) = -1;
		}
	}
}