/** * \#BP (Breakpoint) handler. * * @returns VBox status code. * VINF_SUCCESS means we completely handled this trap, * other codes are passed execution to host context. * * @param pTrpmCpu Pointer to TRPMCPU data (within VM). * @param pRegFrame Pointer to the register frame for the trap. * @internal */ DECLASM(int) TRPMGCTrap03Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame) { LogFlow(("TRPMGC03: %04x:%08x\n", pRegFrame->cs.Sel, pRegFrame->eip)); PVM pVM = TRPMCPU_2_VM(pTrpmCpu); PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu); int rc; PGMRZDynMapStartAutoSet(pVCpu); /* * PATM is using INT3s, let them have a go first. */ if ( (pRegFrame->ss.Sel & X86_SEL_RPL) == 1 && !pRegFrame->eflags.Bits.u1VM) { rc = PATMRCHandleInt3PatchTrap(pVM, pRegFrame); if ( rc == VINF_SUCCESS || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_PATM_PATCH_INT3 || rc == VINF_PATM_DUPLICATE_FUNCTION) { rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame); Log6(("TRPMGC03: %Rrc (%04x:%08x) (PATM)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip)); return rc; } } rc = DBGFRZTrap03Handler(pVM, pVCpu, pRegFrame); /* anything we should do with this? Schedule it in GC? */ rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame); Log6(("TRPMGC03: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip)); return rc; }
/** * Prepares the host FPU/SSE/AVX stuff for IEM action. * * This will make sure the FPU/SSE/AVX guest state is _not_ loaded in the CPU. * This will make sure the FPU/SSE/AVX host state is saved. * Finally, it will make sure the FPU/SSE/AVX host features can be safely * accessed. * * @param pVCpu The cross context virtual CPU structure. */ VMMRZ_INT_DECL(void) CPUMRZFpuStatePrepareHostCpuForUse(PVMCPU pVCpu) { pVCpu->cpum.s.fChanged |= CPUM_CHANGED_FPU_REM; switch (pVCpu->cpum.s.fUseFlags & (CPUM_USED_FPU_GUEST | CPUM_USED_FPU_HOST)) { case 0: #ifdef IN_RC cpumRZSaveHostFPUState(&pVCpu->cpum.s); VMCPU_FF_SET(pVCpu, VMCPU_FF_CPUM); /* Must recalc CR0 before executing more code! */ #else if (cpumRZSaveHostFPUState(&pVCpu->cpum.s) == VINF_CPUM_HOST_CR0_MODIFIED) HMR0NotifyCpumModifiedHostCr0(pVCpu); #endif Log6(("CPUMRZFpuStatePrepareHostCpuForUse: #0 - %#x\n", ASMGetCR0())); break; case CPUM_USED_FPU_HOST: #ifdef IN_RC VMCPU_FF_SET(pVCpu, VMCPU_FF_CPUM); /* (should be set already) */ #elif defined(IN_RING0) && ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS) if (pVCpu->cpum.s.fUseFlags | CPUM_SYNC_FPU_STATE) { pVCpu->cpum.s.fUseFlags &= ~CPUM_SYNC_FPU_STATE; HMR0NotifyCpumUnloadedGuestFpuState(pVCpu); } #endif Log6(("CPUMRZFpuStatePrepareHostCpuForUse: #1 - %#x\n", ASMGetCR0())); break; case CPUM_USED_FPU_GUEST | CPUM_USED_FPU_HOST: #if defined(IN_RING0) && ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS) Assert(!(pVCpu->cpum.s.fUseFlags & CPUM_SYNC_FPU_STATE)); if (CPUMIsGuestInLongModeEx(&pVCpu->cpum.s.Guest)) HMR0SaveFPUState(pVCpu->CTX_SUFF(pVM), pVCpu, &pVCpu->cpum.s.Guest); else #endif cpumRZSaveGuestFpuState(&pVCpu->cpum.s, true /*fLeaveFpuAccessible*/); #ifdef IN_RING0 HMR0NotifyCpumUnloadedGuestFpuState(pVCpu); #else VMCPU_FF_SET(pVCpu, VMCPU_FF_CPUM); /* Must recalc CR0 before executing more code! */ #endif Log6(("CPUMRZFpuStatePrepareHostCpuForUse: #2 - %#x\n", ASMGetCR0())); break; default: AssertFailed(); } }
/** * \#DB (Debug event) handler for the hypervisor code. * * This is mostly the same as TRPMGCTrap01Handler, but we skip the PGM auto * mapping set as well as the default trap exit path since they are both really * bad ideas in this context. * * @returns VBox status code. * VINF_SUCCESS means we completely handled this trap, * other codes are passed execution to host context. * * @param pTrpmCpu Pointer to TRPMCPU data (within VM). * @param pRegFrame Pointer to the register frame for the trap. * @internal */ DECLASM(int) TRPMGCHyperTrap01Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame) { RTGCUINTREG uDr6 = ASMGetAndClearDR6(); PVM pVM = TRPMCPU_2_VM(pTrpmCpu); PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu); LogFlow(("TRPMGCHyper01: cs:eip=%04x:%08x uDr6=%RTreg\n", pRegFrame->cs.Sel, pRegFrame->eip, uDr6)); /* * We currently don't make use of the X86_DR7_GD bit, but * there might come a time when we do. */ AssertReleaseMsgReturn((uDr6 & X86_DR6_BD) != X86_DR6_BD, ("X86_DR6_BD isn't used, but it's set! dr7=%RTreg(%RTreg) dr6=%RTreg\n", ASMGetDR7(), CPUMGetHyperDR7(pVCpu), uDr6), VERR_NOT_IMPLEMENTED); AssertReleaseMsg(!(uDr6 & X86_DR6_BT), ("X86_DR6_BT is impossible!\n")); /* * Now leave the rest to the DBGF. */ int rc = DBGFRZTrap01Handler(pVM, pVCpu, pRegFrame, uDr6); AssertStmt(rc != VINF_EM_RAW_GUEST_TRAP, rc = VERR_TRPM_IPE_1); Log6(("TRPMGCHyper01: %Rrc (%04x:%08x %RTreg)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip, uDr6)); return rc; }
/** * \#PF (Page Fault) handler. * * Calls PGM which does the actual handling. * * * @returns VBox status code. * VINF_SUCCESS means we completely handled this trap, * other codes are passed execution to host context. * * @param pTrpmCpu Pointer to TRPMCPU data (within VM). * @param pRegFrame Pointer to the register frame for the trap. * @internal */ DECLASM(int) TRPMGCTrap0eHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame) { PVM pVM = TRPMCPU_2_VM(pTrpmCpu); PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu); LogFlow(("TRPMGC0e: %04x:%08x err=%x cr2=%08x\n", pRegFrame->cs.Sel, pRegFrame->eip, (uint32_t)pVCpu->trpm.s.uActiveErrorCode, (uint32_t)pVCpu->trpm.s.uActiveCR2)); /* * This is all PGM stuff. */ PGMRZDynMapStartAutoSet(pVCpu); int rc = PGMTrap0eHandler(pVCpu, pVCpu->trpm.s.uActiveErrorCode, pRegFrame, (RTGCPTR)pVCpu->trpm.s.uActiveCR2); switch (rc) { case VINF_EM_RAW_EMULATE_INSTR: case VINF_EM_RAW_EMULATE_INSTR_PD_FAULT: case VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT: case VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT: case VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT: case VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT: if (PATMIsPatchGCAddr(pVM, pRegFrame->eip)) rc = VINF_PATCH_EMULATE_INSTR; break; case VINF_EM_RAW_GUEST_TRAP: if (PATMIsPatchGCAddr(pVM, pRegFrame->eip)) { PGMRZDynMapReleaseAutoSet(pVCpu); return VINF_PATM_PATCH_TRAP_PF; } rc = TRPMForwardTrap(pVCpu, pRegFrame, 0xE, 0, TRPM_TRAP_HAS_ERRORCODE, TRPM_TRAP, 0xe); Assert(rc == VINF_EM_RAW_GUEST_TRAP); break; case VINF_EM_RAW_INTERRUPT_PENDING: Assert(TRPMHasTrap(pVCpu)); /* no break; */ case VINF_IOM_R3_MMIO_READ: case VINF_IOM_R3_MMIO_WRITE: case VINF_IOM_R3_MMIO_READ_WRITE: case VINF_PATM_HC_MMIO_PATCH_READ: case VINF_PATM_HC_MMIO_PATCH_WRITE: case VINF_SUCCESS: case VINF_EM_RAW_TO_R3: case VINF_EM_PENDING_REQUEST: case VINF_EM_RAW_TIMER_PENDING: case VINF_EM_NO_MEMORY: case VINF_CSAM_PENDING_ACTION: case VINF_PGM_SYNC_CR3: /** @todo Check this with Sander. */ break; default: AssertMsg(PATMIsPatchGCAddr(pVM, pRegFrame->eip) == false, ("Patch address for return code %d. eip=%08x\n", rc, pRegFrame->eip)); break; } rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame); Log6(("TRPMGC0e: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip)); return rc; }
/** * Trap handler for device not present fault (\#NM). * * Device not available, FP or (F)WAIT instruction. * * @returns VBox status code. * VINF_SUCCESS means we completely handled this trap, * other codes are passed execution to host context. * * @param pTrpmCpu Pointer to TRPMCPU data (within VM). * @param pRegFrame Pointer to the register frame for the trap. * @internal */ DECLASM(int) TRPMGCTrap07Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame) { LogFlow(("TRPMGC07: %04x:%08x\n", pRegFrame->cs.Sel, pRegFrame->eip)); PVM pVM = TRPMCPU_2_VM(pTrpmCpu); PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu); PGMRZDynMapStartAutoSet(pVCpu); int rc = CPUMHandleLazyFPU(pVCpu); rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame); Log6(("TRPMGC07: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip)); return rc; }
/** * \#BP (Breakpoint) handler. * * This is similar to TRPMGCTrap03Handler but we bits which are potentially * harmful to us (common trap exit and the auto mapping set). * * @returns VBox status code. * VINF_SUCCESS means we completely handled this trap, * other codes are passed execution to host context. * * @param pTrpmCpu Pointer to TRPMCPU data (within VM). * @param pRegFrame Pointer to the register frame for the trap. * @internal */ DECLASM(int) TRPMGCHyperTrap03Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame) { LogFlow(("TRPMGCHyper03: %04x:%08x\n", pRegFrame->cs.Sel, pRegFrame->eip)); PVM pVM = TRPMCPU_2_VM(pTrpmCpu); PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu); /* * Hand it over to DBGF. */ int rc = DBGFRZTrap03Handler(pVM, pVCpu, pRegFrame); AssertStmt(rc != VINF_EM_RAW_GUEST_TRAP, rc = VERR_TRPM_IPE_2); Log6(("TRPMGCHyper03: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip)); return rc; }
/** * \#GP (General Protection Fault) handler. * * @returns VBox status code. * VINF_SUCCESS means we completely handled this trap, * other codes are passed execution to host context. * * @param pTrpmCpu Pointer to TRPMCPU data (within VM). * @param pRegFrame Pointer to the register frame for the trap. * @internal */ DECLASM(int) TRPMGCTrap0dHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame) { PVM pVM = TRPMCPU_2_VM(pTrpmCpu); PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu); LogFlow(("TRPMGC0d: %04x:%08x err=%x\n", pRegFrame->cs.Sel, pRegFrame->eip, (uint32_t)pVCpu->trpm.s.uActiveErrorCode)); PGMRZDynMapStartAutoSet(pVCpu); int rc = trpmGCTrap0dHandler(pVM, pTrpmCpu, pRegFrame); switch (rc) { case VINF_EM_RAW_GUEST_TRAP: case VINF_EM_RAW_EXCEPTION_PRIVILEGED: if (PATMIsPatchGCAddr(pVM, pRegFrame->eip)) rc = VINF_PATM_PATCH_TRAP_GP; break; case VINF_EM_RAW_INTERRUPT_PENDING: Assert(TRPMHasTrap(pVCpu)); /* no break; */ case VINF_PGM_SYNC_CR3: /** @todo Check this with Sander. */ case VINF_EM_RAW_EMULATE_INSTR: case VINF_IOM_R3_IOPORT_READ: case VINF_IOM_R3_IOPORT_WRITE: case VINF_IOM_R3_MMIO_WRITE: case VINF_IOM_R3_MMIO_READ: case VINF_IOM_R3_MMIO_READ_WRITE: case VINF_PATM_PATCH_INT3: case VINF_EM_NO_MEMORY: case VINF_EM_RAW_TO_R3: case VINF_EM_RAW_TIMER_PENDING: case VINF_EM_PENDING_REQUEST: case VINF_EM_HALT: case VINF_SUCCESS: break; default: AssertMsg(PATMIsPatchGCAddr(pVM, pRegFrame->eip) == false, ("return code %d\n", rc)); break; } Log6(("TRPMGC0d: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip)); return rc; }
static int vboxguestLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg) #endif { PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFilp->private_data; uint32_t cbData = _IOC_SIZE(uCmd); void *pvBufFree; void *pvBuf; int rc; uint64_t au64Buf[32/sizeof(uint64_t)]; Log6(("vboxguestLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid)); /* * Buffer the request. */ if (cbData <= sizeof(au64Buf)) { pvBufFree = NULL; pvBuf = &au64Buf[0]; } else { pvBufFree = pvBuf = RTMemTmpAlloc(cbData); if (RT_UNLIKELY(!pvBuf)) { LogRel((DEVICE_NAME "::IOCtl: RTMemTmpAlloc failed to alloc %u bytes.\n", cbData)); return -ENOMEM; } } if (RT_LIKELY(copy_from_user(pvBuf, (void *)ulArg, cbData) == 0)) { /* * Process the IOCtl. */ size_t cbDataReturned; rc = VbgdCommonIoCtl(uCmd, &g_DevExt, pSession, pvBuf, cbData, &cbDataReturned); /* * Copy ioctl data and output buffer back to user space. */ if (RT_SUCCESS(rc)) { rc = 0; if (RT_UNLIKELY(cbDataReturned > cbData)) { LogRel((DEVICE_NAME "::IOCtl: too much output data %u expected %u\n", cbDataReturned, cbData)); cbDataReturned = cbData; } if (cbDataReturned > 0) { if (RT_UNLIKELY(copy_to_user((void *)ulArg, pvBuf, cbDataReturned) != 0)) { LogRel((DEVICE_NAME "::IOCtl: copy_to_user failed; pvBuf=%p ulArg=%p cbDataReturned=%u uCmd=%d\n", pvBuf, (void *)ulArg, cbDataReturned, uCmd, rc)); rc = -EFAULT; } } } else { Log(("vboxguestLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc)); rc = -rc; Assert(rc > 0); /* Positive returns == negated VBox error status codes. */ } } else { Log((DEVICE_NAME "::IOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x.\n", ulArg, cbData, uCmd)); rc = -EFAULT; } if (pvBufFree) RTMemFree(pvBufFree); Log6(("vboxguestLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid)); return rc; }
/** * \#NP ((segment) Not Present) handler. * * @returns VBox status code. * VINF_SUCCESS means we completely handled this trap, * other codes are passed execution to host context. * * @param pTrpmCpu Pointer to TRPMCPU data (within VM). * @param pRegFrame Pointer to the register frame for the trap. * @internal */ DECLASM(int) TRPMGCTrap0bHandler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame) { LogFlow(("TRPMGC0b: %04x:%08x\n", pRegFrame->cs.Sel, pRegFrame->eip)); PVM pVM = TRPMCPU_2_VM(pTrpmCpu); PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu); PGMRZDynMapStartAutoSet(pVCpu); /* * Try to detect instruction by opcode which caused trap. * XXX note: this code may cause \#PF (trap e) or \#GP (trap d) while * accessing user code. need to handle it somehow in future! */ RTGCPTR GCPtr; if ( SELMValidateAndConvertCSAddr(pVCpu, pRegFrame->eflags, pRegFrame->ss.Sel, pRegFrame->cs.Sel, &pRegFrame->cs, (RTGCPTR)pRegFrame->eip, &GCPtr) == VINF_SUCCESS) { uint8_t *pu8Code = (uint8_t *)(uintptr_t)GCPtr; /* * First skip possible instruction prefixes, such as: * OS, AS * CS:, DS:, ES:, SS:, FS:, GS: * REPE, REPNE * * note: Currently we supports only up to 4 prefixes per opcode, more * prefixes (normally not used anyway) will cause trap d in guest. * note: Instruction length in IA-32 may be up to 15 bytes, we dont * check this issue, its too hard. */ for (unsigned i = 0; i < 4; i++) { if ( pu8Code[0] != 0xf2 /* REPNE/REPNZ */ && pu8Code[0] != 0xf3 /* REP/REPE/REPZ */ && pu8Code[0] != 0x2e /* CS: */ && pu8Code[0] != 0x36 /* SS: */ && pu8Code[0] != 0x3e /* DS: */ && pu8Code[0] != 0x26 /* ES: */ && pu8Code[0] != 0x64 /* FS: */ && pu8Code[0] != 0x65 /* GS: */ && pu8Code[0] != 0x66 /* OS */ && pu8Code[0] != 0x67 /* AS */ ) break; pu8Code++; } /* * Detect right switch using a callgate. * * We recognize the following causes for the trap 0b: * CALL FAR, CALL FAR [] * JMP FAR, JMP FAR [] * IRET (may cause a task switch) * * Note: we can't detect whether the trap was caused by a call to a * callgate descriptor or it is a real trap 0b due to a bad selector. * In both situations we'll pass execution to our recompiler so we don't * have to worry. * If we wanted to do better detection, we have set GDT entries to callgate * descriptors pointing to our own handlers. */ /** @todo not sure about IRET, may generate Trap 0d (\#GP), NEED TO CHECK! */ if ( pu8Code[0] == 0x9a /* CALL FAR */ || ( pu8Code[0] == 0xff /* CALL FAR [] */ && (pu8Code[1] & X86_OPCODE_MODRM_REG_MASK) == 0x18) || pu8Code[0] == 0xea /* JMP FAR */ || ( pu8Code[0] == 0xff /* JMP FAR [] */ && (pu8Code[1] & X86_OPCODE_MODRM_REG_MASK) == 0x28) || pu8Code[0] == 0xcf /* IRET */ ) { /* * Got potential call to callgate. * We simply return execution to the recompiler to do emulation * starting from the instruction which caused the trap. */ pTrpmCpu->uActiveVector = UINT32_MAX; Log6(("TRPMGC0b: %Rrc (%04x:%08x) (CG)\n", VINF_EM_RAW_RING_SWITCH, pRegFrame->cs.Sel, pRegFrame->eip)); PGMRZDynMapReleaseAutoSet(pVCpu); return VINF_EM_RAW_RING_SWITCH; } } /* * Pass trap 0b as is to the recompiler in all other cases. */ Log6(("TRPMGC0b: %Rrc (%04x:%08x)\n", VINF_EM_RAW_GUEST_TRAP, pRegFrame->cs.Sel, pRegFrame->eip)); PGMRZDynMapReleaseAutoSet(pVCpu); return VINF_EM_RAW_GUEST_TRAP; }
/** * Trap handler for illegal opcode fault (\#UD). * * @returns VBox status code. * VINF_SUCCESS means we completely handled this trap, * other codes are passed execution to host context. * * @param pTrpmCpu Pointer to TRPMCPU data (within VM). * @param pRegFrame Pointer to the register frame for the trap. * @internal */ DECLASM(int) TRPMGCTrap06Handler(PTRPMCPU pTrpmCpu, PCPUMCTXCORE pRegFrame) { LogFlow(("TRPMGC06: %04x:%08x efl=%x\n", pRegFrame->cs.Sel, pRegFrame->eip, pRegFrame->eflags.u32)); PVM pVM = TRPMCPU_2_VM(pTrpmCpu); PVMCPU pVCpu = TRPMCPU_2_VMCPU(pTrpmCpu); int rc; PGMRZDynMapStartAutoSet(pVCpu); if (CPUMGetGuestCPL(pVCpu) == 0) { /* * Decode the instruction. */ RTGCPTR PC; rc = SELMValidateAndConvertCSAddr(pVCpu, pRegFrame->eflags, pRegFrame->ss.Sel, pRegFrame->cs.Sel, &pRegFrame->cs, pRegFrame->rip, &PC); if (RT_FAILURE(rc)) { Log(("TRPMGCTrap06Handler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Rrc !!\n", pRegFrame->cs.Sel, pRegFrame->eip, pRegFrame->ss.Sel & X86_SEL_RPL, rc)); rc = trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_GUEST_TRAP, pRegFrame); Log6(("TRPMGC06: %Rrc (%04x:%08x) (SELM)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip)); return rc; } DISCPUSTATE Cpu; uint32_t cbOp; rc = EMInterpretDisasOneEx(pVM, pVCpu, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp); if (RT_FAILURE(rc)) { rc = trpmGCExitTrap(pVM, pVCpu, VINF_EM_RAW_EMULATE_INSTR, pRegFrame); Log6(("TRPMGC06: %Rrc (%04x:%08x) (EM)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip)); return rc; } /* * UD2 in a patch? * Note! PATMGCHandleIllegalInstrTrap doesn't always return. */ if ( Cpu.pCurInstr->uOpcode == OP_ILLUD2 && PATMIsPatchGCAddr(pVM, pRegFrame->eip)) { LogFlow(("TRPMGCTrap06Handler: -> PATMRCHandleIllegalInstrTrap\n")); rc = PATMRCHandleIllegalInstrTrap(pVM, pRegFrame); /** @todo These tests are completely unnecessary, should just follow the * flow and return at the end of the function. */ if ( rc == VINF_SUCCESS || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_PATM_DUPLICATE_FUNCTION || rc == VINF_PATM_PENDING_IRQ_AFTER_IRET || rc == VINF_EM_RESCHEDULE) { rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame); Log6(("TRPMGC06: %Rrc (%04x:%08x) (PATM)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip)); return rc; } } /* * Speed up dtrace and don't entrust invalid lock sequences to the recompiler. */ else if (Cpu.fPrefix & DISPREFIX_LOCK) { Log(("TRPMGCTrap06Handler: pc=%08x op=%d\n", pRegFrame->eip, Cpu.pCurInstr->uOpcode)); #ifdef DTRACE_EXPERIMENT /** @todo fix/remove/permanent-enable this when DIS/PATM handles invalid lock sequences. */ Assert(!PATMIsPatchGCAddr(pVM, pRegFrame->eip)); rc = TRPMForwardTrap(pVCpu, pRegFrame, 0x6, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, 0x6); Assert(rc == VINF_EM_RAW_GUEST_TRAP); #else rc = VINF_EM_RAW_EMULATE_INSTR; #endif } /* * Handle MONITOR - it causes an #UD exception instead of #GP when not executed in ring 0. */ else if (Cpu.pCurInstr->uOpcode == OP_MONITOR) { LogFlow(("TRPMGCTrap06Handler: -> EMInterpretInstructionCPU\n")); rc = EMInterpretInstructionDisasState(pVCpu, &Cpu, pRegFrame, PC, EMCODETYPE_SUPERVISOR); } /* Never generate a raw trap here; it might be an instruction, that requires emulation. */ else { LogFlow(("TRPMGCTrap06Handler: -> VINF_EM_RAW_EMULATE_INSTR\n")); rc = VINF_EM_RAW_EMULATE_INSTR; } } else { LogFlow(("TRPMGCTrap06Handler: -> TRPMForwardTrap\n")); rc = TRPMForwardTrap(pVCpu, pRegFrame, 0x6, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, 0x6); Assert(rc == VINF_EM_RAW_GUEST_TRAP); } rc = trpmGCExitTrap(pVM, pVCpu, rc, pRegFrame); Log6(("TRPMGC06: %Rrc (%04x:%08x)\n", rc, pRegFrame->cs.Sel, pRegFrame->eip)); return rc; }
/** * Device I/O Control entry point. * * @param pFilp Associated file pointer. * @param uCmd The function specified to ioctl(). * @param ulArg The argument specified to ioctl(). * @param pSession The session instance. */ static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession) { int rc; SUPREQHDR Hdr; PSUPREQHDR pHdr; uint32_t cbBuf; Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid)); /* * Read the header. */ if (RT_UNLIKELY(copy_from_user(&Hdr, (void *)ulArg, sizeof(Hdr)))) { Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x\n", ulArg, uCmd)); return -EFAULT; } if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC)) { Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd)); return -EINVAL; } /* * Buffer the request. */ cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut); if (RT_UNLIKELY(cbBuf > _1M*16)) { Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd)); return -E2BIG; } if (RT_UNLIKELY(_IOC_SIZE(uCmd) ? cbBuf != _IOC_SIZE(uCmd) : Hdr.cbIn < sizeof(Hdr))) { Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x\n", cbBuf, _IOC_SIZE(uCmd), uCmd)); return -EINVAL; } pHdr = RTMemAlloc(cbBuf); if (RT_UNLIKELY(!pHdr)) { OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x\n", cbBuf, uCmd)); return -ENOMEM; } if (RT_UNLIKELY(copy_from_user(pHdr, (void *)ulArg, Hdr.cbIn))) { Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x\n", ulArg, Hdr.cbIn, uCmd)); RTMemFree(pHdr); return -EFAULT; } if (Hdr.cbIn < cbBuf) RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbBuf - Hdr.cbIn); /* * Process the IOCtl. */ stac(); rc = supdrvIOCtl(uCmd, &g_DevExt, pSession, pHdr, cbBuf); clac(); /* * Copy ioctl data and output buffer back to user space. */ if (RT_LIKELY(!rc)) { uint32_t cbOut = pHdr->cbOut; if (RT_UNLIKELY(cbOut > cbBuf)) { OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd)); cbOut = cbBuf; } if (RT_UNLIKELY(copy_to_user((void *)ulArg, pHdr, cbOut))) { /* this is really bad! */ OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd)); rc = -EFAULT; } } else { Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc)); rc = -EINVAL; } RTMemFree(pHdr); Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid)); return rc; }