int
__unaligned_fixup(struct utrapframe *uf)
{
	u_char *addr;
	u_long val;
	u_int insn;
	int sig;

	sig = 0;
	addr = (u_char *)uf->uf_sfar;
	insn = *(u_int *)uf->uf_pc;
	flushw();
	switch (IF_OP(insn)) {
	case IOP_LDST:
		switch (IF_F3_OP3(insn)) {
		case INS3_LDUH:
			val = __unaligned_load(addr, 2);
			__emul_store_reg(uf, IF_F3_RD(insn), val);
			break;
		case INS3_LDUW:
			val = __unaligned_load(addr, 4);
			__emul_store_reg(uf, IF_F3_RD(insn), val);
			break;
		case INS3_LDX:
			val = __unaligned_load(addr, 8);
			__emul_store_reg(uf, IF_F3_RD(insn), val);
			break;
		case INS3_LDSH:
			val = __unaligned_load(addr, 2);
			__emul_store_reg(uf, IF_F3_RD(insn),
			    IF_SEXT(val, 16));
			break;
		case INS3_LDSW:
			val = __unaligned_load(addr, 4);
			__emul_store_reg(uf, IF_F3_RD(insn),
			    IF_SEXT(val, 32));
			break;
		case INS3_STH:
			val = __emul_fetch_reg(uf, IF_F3_RD(insn));
			__unaligned_store(addr, val, 2);
			break;
		case INS3_STW:
			val = __emul_fetch_reg(uf, IF_F3_RD(insn));
			__unaligned_store(addr, val, 4);
			break;
		case INS3_STX:
			val = __emul_fetch_reg(uf, IF_F3_RD(insn));
			__unaligned_store(addr, val, 8);
			break;
		default:
			sig = SIGILL;
			break;
		}
		break;
	default:
		sig = SIGILL;
		break;
	}
	return (sig);
}
int
cpu_set_user_tls(struct thread *td, void *tls_base)
{

	if (td == curthread)
		flushw();
	td->td_frame->tf_global[7] = (uint64_t) tls_base;
	return (0);
}
int
__emul_insn(struct utrapframe *uf)
{
	u_long reg, res;
	u_long *addr;
	u_int insn;
	int sig;
	int rd;
	int i;

	sig = 0;
	insn = *(u_int *)uf->uf_pc;
	flushw();
	switch (IF_OP(insn)) {
	case IOP_MISC:
		switch (IF_F3_OP3(insn)) {
		case INS2_POPC:
			if (IF_F3_RS1(insn) != 0) {
				sig = SIGILL;
				break;
			}
			reg = __emul_f3_op2(uf, insn);
			for (i = 0; i < 64; i++)
				res += (reg >> i) & 1;
			__emul_store_reg(uf, IF_F3_RD(insn), res);
			break;
		default:
			sig = SIGILL;
			break;
		}
		break;
	case IOP_LDST:
		switch (IF_F3_OP3(insn)) {
		case INS3_LDQF:
			rd = INSFPdq_RN(IF_F3_RD(insn));
			addr = (u_long *)__emul_f3_memop_addr(uf, insn);
			__fpu_setreg64(rd, addr[0]);
			__fpu_setreg64(rd + 2, addr[1]);
			break;
		case INS3_STQF:
			rd = INSFPdq_RN(IF_F3_RD(insn));
			addr = (u_long *)__emul_f3_memop_addr(uf, insn);
			addr[0] = __fpu_getreg64(rd);
			addr[1] = __fpu_getreg64(rd + 2);
			break;
		default:
			sig = SIGILL;
			break;
		}
		break;
	default:
		sig = SIGILL;
		break;
	}
	return (sig);
}
void
cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
	stack_t *stack)
{
	struct trapframe *tf;
	uint64_t sp;

	if (td == curthread)
		flushw();
	tf = td->td_frame;
	sp = (uint64_t)stack->ss_sp + stack->ss_size;
	tf->tf_out[0] = (uint64_t)arg;
	tf->tf_out[6] = sp - SPOFF - sizeof(struct frame);
	tf->tf_tpc = (uint64_t)entry;
	tf->tf_tnpc = tf->tf_tpc + 4;

	td->td_retval[0] = tf->tf_out[0];
	td->td_retval[1] = tf->tf_out[1];
}
Exemple #5
0
int
rwindow_save(struct thread *td)
{
	struct rwindow *rw;
	struct pcb *pcb;
	u_long *ausp;
	u_long usp;
	int error;
	int i;

	pcb = td->td_pcb;
	CTR3(KTR_TRAP, "rwindow_save: td=%p (%s) nsaved=%d", td,
	    td->td_proc->p_comm, pcb->pcb_nsaved);

	flushw();
	KASSERT(pcb->pcb_nsaved < MAXWIN,
	    ("rwindow_save: pcb_nsaved > MAXWIN"));
	if ((i = pcb->pcb_nsaved) == 0)
		return (0);
	ausp = pcb->pcb_rwsp;
	rw = pcb->pcb_rw;
	error = 0;
	do {
		usp = *ausp;
		CTR1(KTR_TRAP, "rwindow_save: usp=%#lx", usp);
		usp += SPOFF;
		if ((error = (usp & 0x7)) != 0)
			break;
		error = copyout(rw, (void *)usp, sizeof *rw);
		if (error)
			break;
		ausp++;
		rw++;
	} while (--i > 0);
	CTR1(KTR_TRAP, "rwindow_save: error=%d", error);
	if (error == 0)
		pcb->pcb_nsaved = 0;
	return (error == 0 ? 0 : SIGILL);
}
/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb, set up the stack so that the child
 * ready to run and return to user mode.
 */
void
cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
{
	struct trapframe *tf;
	struct frame *fp;
	struct pcb *pcb1;
	struct pcb *pcb2, *pcb2orig;
	vm_offset_t sp;
	int error;
	int i;

	KASSERT(td1 == curthread || td1 == &thread0,
	    ("cpu_fork: p1 not curproc and not proc0"));

	if ((flags & RFPROC) == 0)
		return;

	p2->p_md.md_sigtramp = td1->td_proc->p_md.md_sigtramp;
	p2->p_md.md_utrap = utrap_hold(td1->td_proc->p_md.md_utrap);

	/* The pcb must be aligned on a 64-byte boundary. */
	pcb1 = td1->td_pcb;

	pcb2orig = (struct pcb *)((td2->td_kstack + td2->td_kstack_pages *
	    PAGE_SIZE - sizeof(struct pcb)) & ~0x3fUL);
	pcb2 = (struct pcb *)TLB_PHYS_TO_DIRECT(vtophys((vm_offset_t)pcb2orig));

	td2->td_pcb = pcb2;

	/*
	 * Ensure that p1's pcb is up to date.
	 */
	critical_enter();
	if ((td1->td_frame->tf_fprs & FPRS_FEF) != 0)
		savefpctx(pcb1->pcb_ufp);
	critical_exit();
	/* Make sure the copied windows are spilled. */
	flushw();
	/* Copy the pcb (this will copy the windows saved in the pcb, too). */
	bcopy(pcb1, pcb2, sizeof(*pcb1));

	/*
	 * If we're creating a new user process and we're sharing the address
	 * space, the parent's top most frame must be saved in the pcb.  The
	 * child will pop the frame when it returns to user mode, and may
	 * overwrite it with its own data causing much suffering for the
	 * parent.  We check if its already in the pcb, and if not copy it
	 * in.  Its unlikely that the copyin will fail, but if so there's not
	 * much we can do.  The parent will likely crash soon anyway in that
	 * case.
	 */
	if ((flags & RFMEM) != 0 && td1 != &thread0) {
		sp = td1->td_frame->tf_sp;
		for (i = 0; i < pcb1->pcb_nsaved; i++) {
			if (pcb1->pcb_rwsp[i] == sp)
				break;
		}
		if (i == pcb1->pcb_nsaved) {
			error = copyin((caddr_t)sp + SPOFF, &pcb1->pcb_rw[i],
			    sizeof(struct rwindow));
			if (error == 0) {
				pcb1->pcb_rwsp[i] = sp;
				pcb1->pcb_nsaved++;
			}
		}
	}

	/*
	 * Create a new fresh stack for the new process.
	 * Copy the trap frame for the return to user mode as if from a
	 * syscall.  This copies most of the user mode register values.
	 */
	tf = (struct trapframe *)pcb2orig - 1;
	bcopy(td1->td_frame, tf, sizeof(*tf));

	tf->tf_out[0] = 0;			/* Child returns zero */
	tf->tf_out[1] = 0;
	tf->tf_tstate &= ~TSTATE_XCC_C;		/* success */
	tf->tf_fprs = 0;
	tf->tf_wstate = WSTATE_U64;


	td2->td_frame = tf;
	fp = (struct frame *)tf - 1;
	fp->fr_local[0] = (u_long)fork_return;
	fp->fr_local[1] = (u_long)td2;
	fp->fr_local[2] = (u_long)tf;
	/* Terminate stack traces at this frame. */
	fp->fr_pc = fp->fr_fp = 0;
	pcb2->pcb_sp = (u_long)fp - SPOFF;
	pcb2->pcb_pc = (u_long)fork_trampoline - 8;
	pcb2->pcb_kstack = (uint64_t)(((char *)pcb2orig) - (CCFSZ + SPOFF));

	/* Setup to release spin count in fork_exit(). */
	td2->td_md.md_spinlock_count = 1;
	td2->td_md.md_saved_pil = 0;

	/*
	 * Now, cpu_switch() can schedule the new process.
	 */
}