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); }
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]); }
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); }
/*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)); }
/*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); }
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); }