int foo(int i, int iZero, int iMinusOne) { NOREF(iZero); /* allocate a buffer which we fill up to the end. */ size_t cb = (i % 1555) + 32; g_cbFoo = cb; char *pv = (char *)alloca(cb); RTStrPrintf(pv, cb, "i=%d%*s\n", i, cb, ""); #ifdef VMM_R0_SWITCH_STACK g_cbFooUsed = VMM_STACK_SIZE - ((uintptr_t)pv - (uintptr_t)g_Jmp.pvSavedStack); RTTESTI_CHECK_MSG_RET(g_cbFooUsed < (intptr_t)VMM_STACK_SIZE - 128, ("%#x - (%p - %p) -> %#x; cb=%#x i=%d\n", VMM_STACK_SIZE, pv, g_Jmp.pvSavedStack, g_cbFooUsed, cb, i), -15); #elif defined(RT_ARCH_AMD64) g_cbFooUsed = (uintptr_t)g_Jmp.rsp - (uintptr_t)pv; RTTESTI_CHECK_MSG_RET(g_cbFooUsed < VMM_STACK_SIZE - 128, ("%p - %p -> %#x; cb=%#x i=%d\n", g_Jmp.rsp, pv, g_cbFooUsed, cb, i), -15); #elif defined(RT_ARCH_X86) g_cbFooUsed = (uintptr_t)g_Jmp.esp - (uintptr_t)pv; RTTESTI_CHECK_MSG_RET(g_cbFooUsed < (intptr_t)VMM_STACK_SIZE - 128, ("%p - %p -> %#x; cb=%#x i=%d\n", g_Jmp.esp, pv, g_cbFooUsed, cb, i), -15); #endif /* Do long jmps every 7th time */ if ((i % 7) == 0) { g_cJmps++; int rc = vmmR0CallRing3LongJmp(&g_Jmp, 42); if (!rc) return i + 10000; return -1; } NOREF(iMinusOne); return i; }
/** * Calls the ring-3 host code. * * @returns VBox status code of the ring-3 call. * @retval VERR_VMM_RING3_CALL_DISABLED if called at the wrong time. This must * be passed up the stack, or if that isn't possible then VMMRZCallRing3 * needs to change it into an assertion. * * * @param pVM The cross context VM structure. * @param pVCpu The cross context virtual CPU structure of the calling EMT. * @param enmOperation The operation. * @param uArg The argument to the operation. */ VMMRZDECL(int) VMMRZCallRing3(PVM pVM, PVMCPU pVCpu, VMMCALLRING3 enmOperation, uint64_t uArg) { VMCPU_ASSERT_EMT(pVCpu); /* * Check if calling ring-3 has been disabled and only let let fatal calls thru. */ if (RT_UNLIKELY( pVCpu->vmm.s.cCallRing3Disabled != 0 && enmOperation != VMMCALLRING3_VM_R0_ASSERTION)) { #ifndef IN_RING0 /* * In most cases, it's sufficient to return a status code which * will then be propagated up the code usually encountering several * AssertRC invocations along the way. Hitting one of those is more * helpful than stopping here. * * However, some doesn't check the status code because they are called * from void functions, and for these we'll turn this into a ring-0 * assertion host call. */ if (enmOperation != VMMCALLRING3_REM_REPLAY_HANDLER_NOTIFICATIONS) return VERR_VMM_RING3_CALL_DISABLED; #endif #ifdef IN_RC RTStrPrintf(g_szRTAssertMsg1, sizeof(pVM->vmm.s.szRing0AssertMsg1), "VMMRZCallRing3: enmOperation=%d uArg=%#llx idCpu=%#x\n", enmOperation, uArg, pVCpu->idCpu); #endif RTStrPrintf(pVM->vmm.s.szRing0AssertMsg1, sizeof(pVM->vmm.s.szRing0AssertMsg1), "VMMRZCallRing3: enmOperation=%d uArg=%#llx idCpu=%#x\n", enmOperation, uArg, pVCpu->idCpu); enmOperation = VMMCALLRING3_VM_R0_ASSERTION; } /* * The normal path. */ /** @todo profile this! */ pVCpu->vmm.s.enmCallRing3Operation = enmOperation; pVCpu->vmm.s.u64CallRing3Arg = uArg; pVCpu->vmm.s.rcCallRing3 = VERR_VMM_RING3_CALL_NO_RC; #ifdef IN_RC pVM->vmm.s.pfnRCToHost(VINF_VMM_CALL_HOST); #else int rc; if (pVCpu->vmm.s.pfnCallRing3CallbackR0) { rc = pVCpu->vmm.s.pfnCallRing3CallbackR0(pVCpu, enmOperation, pVCpu->vmm.s.pvCallRing3CallbackUserR0); if (RT_FAILURE(rc)) return rc; } rc = vmmR0CallRing3LongJmp(&pVCpu->vmm.s.CallRing3JmpBufR0, VINF_VMM_CALL_HOST); if (RT_FAILURE(rc)) return rc; #endif return pVCpu->vmm.s.rcCallRing3; }