Ejemplo n.º 1
0
static int
segmf_fault_gref_range(struct seg *seg, caddr_t addr, size_t cnt)
{
	gnttab_map_grant_ref_t mapop[SEGMF_MAX_GREFS];
	struct segmf_data *data;
	segmf_map_t *map;
	uint_t idx;
	int e;
	int i;


	if (cnt > SEGMF_MAX_GREFS) {
		return (-1);
	}

	data = seg->s_data;
	idx = seg_page(seg, addr);
	map = &data->map[idx];

	bzero(mapop, sizeof (gnttab_map_grant_ref_t) * cnt);

	ASSERT(map->t_type == SEGMF_MAP_GREF);

	/*
	 * map in each page passed in into the user apps AS. We do this by
	 * passing the MA of the actual pte of the mapping to the hypervisor.
	 */
	for (i = 0; i < cnt; i++) {
		mapop[i].host_addr = map[i].u.g.g_ptep;
		mapop[i].dom = data->domid;
		mapop[i].ref = map[i].u.g.g_gref;
		mapop[i].flags = GNTMAP_host_map | GNTMAP_application_map |
		    GNTMAP_contains_pte;
		if (!(map[i].u.g.g_flags & SEGMF_GFLAGS_WR)) {
			mapop[i].flags |= GNTMAP_readonly;
		}
	}
	e = xen_map_gref(GNTTABOP_map_grant_ref, mapop, cnt, B_TRUE);
	if ((e != 0) || (mapop[0].status != GNTST_okay)) {
		return (FC_MAKE_ERR(EFAULT));
	}

	/* save handle for segmf_release_grefs() and mark it as mapped */
	for (i = 0; i < cnt; i++) {
		ASSERT(mapop[i].status == GNTST_okay);
		map[i].u.g.g_handle = mapop[i].handle;
		map[i].u.g.g_flags |= SEGMF_GFLAGS_MAPPED;
	}

	return (0);
}
Ejemplo n.º 2
0
void
maphandler(int sig, int code, struct sigcontext *scp, char *addr)
{
	switch (sig) {
		case SIGBUS:
		case SIGSEGV:
			switch (FC_CODE(code)) {
			case 3:		/* 5.x value for FC_OBJERR */
				code = FC_MAKE_ERR(FC_ERRNO(code));
				break;
			case 5:		/* 5.x value for FC_NOMAP */
				code = FC_NOMAP;
				break;
			}
			break;
	}
	__sendsig(maptooldsig(sig), code, scp, addr, handlers[sig]);
}
Ejemplo n.º 3
0
static void
ucbsigvechandler(int sig, siginfo_t *sip, ucontext_t *ucp)
{
	struct sigcontext sc;
	int code;
	char *addr;
	int i, j;
	int gwinswitch = 0;

	sc.sc_onstack = ((ucp->uc_stack.ss_flags & SS_ONSTACK) != 0);
	sc.sc_mask = set2mask(&ucp->uc_sigmask);

#if defined(__amd64)
	sc.sc_sp = (long)ucp->uc_mcontext.gregs[REG_RSP];
	sc.sc_pc = (long)ucp->uc_mcontext.gregs[REG_RIP];
	sc.sc_ps = (long)ucp->uc_mcontext.gregs[REG_RFL];
	sc.sc_r0 = (long)ucp->uc_mcontext.gregs[REG_RAX];
	sc.sc_r1 = (long)ucp->uc_mcontext.gregs[REG_RDX];
#else
	sc.sc_sp = (int)ucp->uc_mcontext.gregs[UESP];
	sc.sc_pc = (int)ucp->uc_mcontext.gregs[EIP];
	sc.sc_ps = (int)ucp->uc_mcontext.gregs[EFL];
	sc.sc_r0 = (int)ucp->uc_mcontext.gregs[EAX];
	sc.sc_r1 = (int)ucp->uc_mcontext.gregs[EDX];
#endif

	/*
	 * Translate signal codes from new to old.
	 * /usr/include/sys/siginfo.h contains new codes.
	 * /usr/ucbinclude/sys/signal.h contains old codes.
	 */
	code = 0;
	addr = SIG_NOADDR;
	if (sip != NULL && SI_FROMKERNEL(sip)) {
		addr = sip->si_addr;

		switch (sig) {
		case SIGILL:
		case SIGFPE:
			code = ILL_ILLINSTR_FAULT;
			break;

		case SIGBUS:
			switch (sip->si_code) {
			case BUS_ADRALN:
				code = BUS_ALIGN;
				break;
			case BUS_ADRERR:
				code = BUS_HWERR;
				break;
			default:	/* BUS_OBJERR */
				code = FC_MAKE_ERR(sip->si_errno);
				break;
			}
			break;

		case SIGSEGV:
			switch (sip->si_code) {
			case SEGV_MAPERR:
				code = SEGV_NOMAP;
				break;
			case SEGV_ACCERR:
				code = SEGV_PROT;
				break;
			default:
				code = FC_MAKE_ERR(sip->si_errno);
				break;
			}
			break;

		default:
			addr = SIG_NOADDR;
			break;
		}
	}

	(*_siguhandler[sig])(sig, code, &sc, addr);

	if (sc.sc_onstack)
		ucp->uc_stack.ss_flags |= SS_ONSTACK;
	else
		ucp->uc_stack.ss_flags &= ~SS_ONSTACK;
	mask2set(sc.sc_mask, &ucp->uc_sigmask);

#if defined(__amd64)
	ucp->uc_mcontext.gregs[REG_RSP] = (long)sc.sc_sp;
	ucp->uc_mcontext.gregs[REG_RIP] = (long)sc.sc_pc;
	ucp->uc_mcontext.gregs[REG_RFL] = (long)sc.sc_ps;
	ucp->uc_mcontext.gregs[REG_RAX] = (long)sc.sc_r0;
	ucp->uc_mcontext.gregs[REG_RDX] = (long)sc.sc_r1;
#else
	ucp->uc_mcontext.gregs[UESP] = (int)sc.sc_sp;
	ucp->uc_mcontext.gregs[EIP] = (int)sc.sc_pc;
	ucp->uc_mcontext.gregs[EFL] = (int)sc.sc_ps;
	ucp->uc_mcontext.gregs[EAX] = (int)sc.sc_r0;
	ucp->uc_mcontext.gregs[EDX] = (int)sc.sc_r1;
#endif

	setcontext(ucp);
}
Ejemplo n.º 4
0
/*ARGSUSED*/
static int
segmf_fault(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
    enum fault_type type, enum seg_rw rw)
{
	return (FC_MAKE_ERR(EFAULT));
}
Ejemplo n.º 5
0
/*ARGSUSED*/
static int
segmf_faultpage(struct hat *hat, struct seg *seg, caddr_t addr,
    enum fault_type type, uint_t prot)
{
	struct segmf_data *data = seg->s_data;
	uint_t hat_flags = HAT_LOAD_NOCONSIST;
	mfn_t mfn;
	x86pte_t pte;
	segmf_map_t *map;
	uint_t idx;


	idx = seg_page(seg, addr);
	map = &data->map[idx];
	ASSERT(map->t_type == SEGMF_MAP_MFN);

	mfn = map->u.m.m_mfn;

	if (type == F_SOFTLOCK) {
		mutex_enter(&freemem_lock);
		data->softlockcnt++;
		mutex_exit(&freemem_lock);
		hat_flags |= HAT_LOAD_LOCK;
	} else
		hat_flags |= HAT_LOAD;

	if (segmf_faultpage_debug > 0) {
		uprintf("segmf_faultpage: addr %p domid %x mfn %lx prot %x\n",
		    (void *)addr, data->domid, mfn, prot);
		segmf_faultpage_debug--;
	}

	/*
	 * Ask the HAT to load a throwaway mapping to page zero, then
	 * overwrite it with our foreign domain mapping. It gets removed
	 * later via hat_unload()
	 */
	hat_devload(hat, addr, MMU_PAGESIZE, (pfn_t)0,
	    PROT_READ | HAT_UNORDERED_OK, hat_flags);

	pte = mmu_ptob((x86pte_t)mfn) | PT_VALID | PT_USER | PT_FOREIGN;
	if (prot & PROT_WRITE)
		pte |= PT_WRITABLE;

	if (HYPERVISOR_update_va_mapping_otherdomain((uintptr_t)addr, pte,
	    UVMF_INVLPG | UVMF_ALL, data->domid) != 0) {
		hat_flags = HAT_UNLOAD_UNMAP;

		if (type == F_SOFTLOCK) {
			hat_flags |= HAT_UNLOAD_UNLOCK;
			mutex_enter(&freemem_lock);
			data->softlockcnt--;
			mutex_exit(&freemem_lock);
		}

		hat_unload(hat, addr, MMU_PAGESIZE, hat_flags);
		return (FC_MAKE_ERR(EFAULT));
	}

	return (0);
}
Ejemplo n.º 6
0
static void
ucbsigvechandler(int sig, siginfo_t *sip, ucontext_t *ucp)
{
	struct sigcontext sc;
	int code;
	char *addr;
#ifdef NEVER
	int gwinswitch = 0;
#endif

	sc.sc_onstack = ((ucp->uc_stack.ss_flags & SS_ONSTACK) != 0);
	sc.sc_mask = set2mask(&ucp->uc_sigmask);

#if defined(__sparc)
	if (sig == SIGFPE && sip != NULL && SI_FROMKERNEL(sip) &&
	    (sip->si_code == FPE_INTDIV || sip->si_code == FPE_INTOVF)) {
		/*
		 * Hack to emulate the 4.x kernel behavior of incrementing
		 * the PC on integer divide by zero and integer overflow
		 * on sparc machines.  (5.x does not increment the PC.)
		 */
		ucp->uc_mcontext.gregs[REG_PC] =
		    ucp->uc_mcontext.gregs[REG_nPC];
		ucp->uc_mcontext.gregs[REG_nPC] += 4;
	}
	sc.sc_sp = ucp->uc_mcontext.gregs[REG_SP];
	sc.sc_pc = ucp->uc_mcontext.gregs[REG_PC];
	sc.sc_npc = ucp->uc_mcontext.gregs[REG_nPC];

	/* XX64 There is no REG_PSR for sparcv9, we map in REG_CCR for now */
#if defined(__sparcv9)
	sc.sc_psr = ucp->uc_mcontext.gregs[REG_CCR];
#else
	sc.sc_psr = ucp->uc_mcontext.gregs[REG_PSR];
#endif

	sc.sc_g1 = ucp->uc_mcontext.gregs[REG_G1];
	sc.sc_o0 = ucp->uc_mcontext.gregs[REG_O0];

	/*
	 * XXX - What a kludge!
	 * Store a pointer to the original ucontext_t in the sigcontext
	 * so that it's available to the sigcleanup call that needs to
	 * return from the signal handler.  Otherwise, vital information
	 * (e.g., the "out" registers) that's only saved in the
	 * ucontext_t isn't available to sigcleanup.
	 */
	sc.sc_wbcnt = (int)(sizeof (*ucp));
	sc.sc_spbuf[0] = (char *)(uintptr_t)sig;
	sc.sc_spbuf[1] = (char *)ucp;
#ifdef NEVER
	/*
	 * XXX - Sorry, we can never pass the saved register windows
	 * on in the sigcontext because we use that space to save the
	 * ucontext_t.
	 */
	if (ucp->uc_mcontext.gwins != (gwindows_t *)0) {
		int i, j;

		gwinswitch = 1;
		sc.sc_wbcnt = ucp->uc_mcontext.gwins->wbcnt;
		/* XXX - should use bcopy to move this in bulk */
		for (i = 0; i < ucp->uc_mcontext.gwins; i++) {
			sc.sc_spbuf[i] = ucp->uc_mcontext.gwins->spbuf[i];
			for (j = 0; j < 8; j++)
				sc.sc_wbuf[i][j] =
				    ucp->uc_mcontext.gwins->wbuf[i].rw_local[j];
			for (j = 0; j < 8; j++)
				sc.sc_wbuf[i][j+8] =
				    ucp->uc_mcontext.gwins->wbuf[i].rw_in[j];
		}
	}
#endif
#endif

	/*
	 * Translate signal codes from new to old.
	 * /usr/include/sys/siginfo.h contains new codes.
	 * /usr/ucbinclude/sys/signal.h contains old codes.
	 */
	code = 0;
	addr = SIG_NOADDR;
	if (sip != NULL && SI_FROMKERNEL(sip)) {
		addr = sip->si_addr;

		switch (sig) {
		case SIGILL:
			switch (sip->si_code) {
			case ILL_PRVOPC:
				code = ILL_PRIVINSTR_FAULT;
				break;
			case ILL_BADSTK:
				code = ILL_STACK;
				break;
			case ILL_ILLTRP:
				code = ILL_TRAP_FAULT(sip->si_trapno);
				break;
			default:
				code = ILL_ILLINSTR_FAULT;
				break;
			}
			break;

		case SIGEMT:
			code = EMT_TAG;
			break;

		case SIGFPE:
			switch (sip->si_code) {
			case FPE_INTDIV:
				code = FPE_INTDIV_TRAP;
				break;
			case FPE_INTOVF:
				code = FPE_INTOVF_TRAP;
				break;
			case FPE_FLTDIV:
				code = FPE_FLTDIV_TRAP;
				break;
			case FPE_FLTOVF:
				code = FPE_FLTOVF_TRAP;
				break;
			case FPE_FLTUND:
				code = FPE_FLTUND_TRAP;
				break;
			case FPE_FLTRES:
				code = FPE_FLTINEX_TRAP;
				break;
			default:
				code = FPE_FLTOPERR_TRAP;
				break;
			}
			break;

		case SIGBUS:
			switch (sip->si_code) {
			case BUS_ADRALN:
				code = BUS_ALIGN;
				break;
			case BUS_ADRERR:
				code = BUS_HWERR;
				break;
			default:	/* BUS_OBJERR */
				code = FC_MAKE_ERR(sip->si_errno);
				break;
			}
			break;

		case SIGSEGV:
			switch (sip->si_code) {
			case SEGV_MAPERR:
				code = SEGV_NOMAP;
				break;
			case SEGV_ACCERR:
				code = SEGV_PROT;
				break;
			default:
				code = FC_MAKE_ERR(sip->si_errno);
				break;
			}
			break;

		default:
			addr = SIG_NOADDR;
			break;
		}
	}

	(*_siguhandler[sig])(sig, code, &sc, addr);

	if (sc.sc_onstack)
		ucp->uc_stack.ss_flags |= SS_ONSTACK;
	else
		ucp->uc_stack.ss_flags &= ~SS_ONSTACK;
	mask2set(sc.sc_mask, &ucp->uc_sigmask);

#if defined(__sparc)
	ucp->uc_mcontext.gregs[REG_SP] = sc.sc_sp;
	ucp->uc_mcontext.gregs[REG_PC] = sc.sc_pc;
	ucp->uc_mcontext.gregs[REG_nPC] = sc.sc_npc;
#if defined(__sparcv9)
	ucp->uc_mcontext.gregs[REG_CCR] = sc.sc_psr;
#else
	ucp->uc_mcontext.gregs[REG_PSR] = sc.sc_psr;
#endif
	ucp->uc_mcontext.gregs[REG_G1] = sc.sc_g1;
	ucp->uc_mcontext.gregs[REG_O0] = sc.sc_o0;
#ifdef NEVER
	if (gwinswitch == 1) {
		int i, j;

		ucp->uc_mcontext.gwins->wbcnt = sc.sc_wbcnt;
		/* XXX - should use bcopy to move this in bulk */
		for (i = 0; i < sc.sc_wbcnt; i++) {
			ucp->uc_mcontext.gwins->spbuf[i] = sc.sc_spbuf[i];
			for (j = 0; j < 8; j++)
				ucp->uc_mcontext.gwins->wbuf[i].rw_local[j] =
				    sc.sc_wbuf[i][j];
			for (j = 0; j < 8; j++)
				ucp->uc_mcontext.gwins->wbuf[i].rw_in[j] =
				    sc.sc_wbuf[i][j+8];
		}
	}
#endif

	if (sig == SIGFPE) {
		if (ucp->uc_mcontext.fpregs.fpu_qcnt > 0) {
			ucp->uc_mcontext.fpregs.fpu_qcnt--;
			ucp->uc_mcontext.fpregs.fpu_q++;
		}
	}
#endif

	(void) setcontext(ucp);
}