/** * Reads a key by name from the host SMC. * * @returns success indicator. * @param pszName The key name, must be exactly 4 chars long. * @param pbBuf The output buffer. * @param cbBuf The buffer size. Max 32 bytes. */ static bool devR0SmcQueryHostKey(const char *pszName, uint8_t *pbBuf, size_t cbBuf) { Assert(strlen(pszName) == 4); Assert(cbBuf <= 32); Assert(cbBuf > 0); /* * Issue the READ command. */ uint32_t cMsSleep = 1; for (;;) { ASMOutU32(SMC_PORT_CMD, SMC_CMD_GET_KEY_VALUE); RTThreadSleep(cMsSleep); uint8_t bCurState = ASMInU8(SMC_PORT_CMD); if ((bCurState & 0xf) == 0xc) break; cMsSleep <<= 1; if (cMsSleep > 64) { LogRel(("devR0Smc: %s: bCurState=%#x, wanted %#x.\n", "cmd", bCurState, 0xc)); return false; } } /* * Send it the key. */ for (unsigned off = 0; off < 4; off++) { ASMOutU8(SMC_PORT_DATA, pszName[off]); if (!devR0SmcWaitHostState(4, "key")) return false; } /* * The desired amount of output. */ ASMOutU8(SMC_PORT_DATA, (uint8_t)cbBuf); /* * Read the output. */ for (size_t off = 0; off < cbBuf; off++) { if (!devR0SmcWaitHostState(5, off ? "data" : "len")) return false; pbBuf[off] = ASMInU8(SMC_PORT_DATA); } LogRel(("SMC: pbBuf=%.*s\n", cbBuf, pbBuf)); return true; }
static UINT32 VBoxReadNVRAM(UINT8 *pu8Buffer, UINT32 cbBuffer) { UINT32 idxBuffer = 0; for (idxBuffer = 0; idxBuffer < cbBuffer; ++idxBuffer) pu8Buffer[idxBuffer] = ASMInU8(EFI_VARIABLE_OP); return idxBuffer; }
/** * R0 mode function to ready byte value from the parallel port * status register. * @returns VBox status code. * @param pDrvIns Driver instance. * @param u64Arg Not used. */ static int drvR0HostParallelReqReadStatus(PPDMDRVINS pDrvIns, uint64_t u64Arg) { uint8_t u8Data; PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL); u8Data = ASMInU8(pThis->u32LptAddrStatus); LogFlowFunc(("read from status port=%#x val=%#x\n", pThis->u32LptAddr, u8Data)); pThis->u8ReadInStatus = u8Data; return VINF_SUCCESS; }
/** * RTOnce callback that initializes g_fHaveOsk and g_abOsk0And1. * * @returns VINF_SUCCESS. * @param pvUserIgnored Ignored. */ static DECLCALLBACK(int) devR0SmcInitOnce(void *pvUserIgnored) { g_fHaveOsk = devR0SmcQueryHostKey("OSK0", &g_abOsk0And1[0], 32) && devR0SmcQueryHostKey("OSK1", &g_abOsk0And1[32], 32); #if 0 /* * Dump the device registers. */ for (uint16_t uPort = 0x300; uPort < 0x320; uPort ++) LogRel(("SMC: %#06x=%#010x w={%#06x, %#06x}, b={%#04x %#04x %#04x %#04x}\n", uPort, ASMInU32(uPort), ASMInU16(uPort), ASMInU16(uPort + 2), ASMInU8(uPort), ASMInU8(uPort + 1), ASMInU8(uPort +2), ASMInU8(uPort + 3) )); #endif NOREF(pvUserIgnored); return VINF_SUCCESS; }
/** * Try undo the harm done by the init function. * * This may leave the system in an unstable state since we might have been * hijacking memory below 1MB that is in use by the kernel. */ void vmmR0TripleFaultHackTerm(void) { /* * Restore overwritten memory. */ if ( g_pvSavedLowCore && g_pbLowCore) memcpy(g_pbLowCore, g_pvSavedLowCore, PAGE_SIZE); if (g_pbPage0) { g_pbPage0[0x467+0] = RT_BYTE1(g_u32SavedVector); g_pbPage0[0x467+1] = RT_BYTE2(g_u32SavedVector); g_pbPage0[0x467+2] = RT_BYTE3(g_u32SavedVector); g_pbPage0[0x467+3] = RT_BYTE4(g_u32SavedVector); g_pbPage0[0x472+0] = RT_BYTE1(g_u16SavedCadIndicator); g_pbPage0[0x472+1] = RT_BYTE2(g_u16SavedCadIndicator); } /* * Fix the CMOS. */ if (g_pvSavedLowCore) { uint32_t fSaved = ASMIntDisableFlags(); ASMOutU8(0x70, 0x0f); ASMOutU8(0x71, 0x0a); ASMOutU8(0x70, 0x00); ASMInU8(0x71); ASMReloadCR3(); ASMWriteBackAndInvalidateCaches(); ASMSetFlags(fSaved); } /* * Release resources. */ RTMemFree(g_pvSavedLowCore); g_pvSavedLowCore = NULL; RTR0MemObjFree(g_hMemLowCore, true /*fFreeMappings*/); g_hMemLowCore = NIL_RTR0MEMOBJ; g_hMapLowCore = NIL_RTR0MEMOBJ; g_pbLowCore = NULL; g_HCPhysLowCore = NIL_RTHCPHYS; RTR0MemObjFree(g_hMemPage0, true /*fFreeMappings*/); g_hMemPage0 = NIL_RTR0MEMOBJ; g_hMapPage0 = NIL_RTR0MEMOBJ; g_pbPage0 = NULL; }
/** * R0 mode function to set the direction of parallel port - * operate in bidirectional mode or single direction. * @returns VBox status code. * @param pDrvIns Driver instance. * @param u64Arg Mode. */ static int drvR0HostParallelReqSetPortDir(PPDMDRVINS pDrvIns, uint64_t u64Arg) { PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL); uint8_t u8ReadControlVal; uint8_t u8WriteControlVal; if (u64Arg) { u8ReadControlVal = ASMInU8(pThis->u32LptAddrControl); u8WriteControlVal = u8ReadControlVal | LPT_CONTROL_ENABLE_BIDIRECT; /* enable input direction */ ASMOutU8(pThis->u32LptAddrControl, u8WriteControlVal); } else { u8ReadControlVal = ASMInU8(pThis->u32LptAddrControl); u8WriteControlVal = u8ReadControlVal & ~LPT_CONTROL_ENABLE_BIDIRECT; /* disable input direction */ ASMOutU8(pThis->u32LptAddrControl, u8WriteControlVal); } return VINF_SUCCESS; }
/** * Waits for the specified state on the host SMC. * * @returns success indicator. * @param bState The desired state. * @param pszWhat What we're currently doing. For the log. */ static bool devR0SmcWaitHostState(uint8_t bState, const char *pszWhat) { uint8_t bCurState; for (uint32_t cMsSleep = 1; cMsSleep <= 64; cMsSleep <<= 1) { RTThreadSleep(cMsSleep); bCurState = ASMInU16(SMC_PORT_CMD); if ((bCurState & 0xf) == bState) return true; } LogRel(("devR0Smc: %s: bCurState=%#x, wanted %#x.\n", pszWhat, bCurState, bState)); #if 0 uint8_t bCurStatus2 = ASMInU8(SMC_PORT_STATUS_CODE); uint8_t bCurStatus3 = ASMInU8(SMC_PORT_STATUS_CODE); uint16_t wCurStatus3 = ASMInU16(SMC_PORT_STATUS_CODE); uint32_t dwCurStatus3 = ASMInU32(SMC_PORT_STATUS_CODE); LogRel(("SMC: status2=%#x status3=%#x w=%#x dw=%#x\n", bCurStatus2, bCurStatus3, wCurStatus3, dwCurStatus3)); #endif return false; }
/** * Waits for the specified status on the host SMC. * * @returns success indicator. * @param bStatus The desired status. * @param pszWhat What we're currently doing. For the log. */ static bool devR0SmcWaitHostStatus(uint8_t bStatus, const char *pszWhat) { uint8_t bCurStatus; for (uint32_t cMsSleep = 1; cMsSleep <= 64; cMsSleep <<= 1) { RTThreadSleep(cMsSleep); bCurStatus = ASMInU8(APPLESMC_CMD_PORT); if ((bCurStatus & 0xf) == bStatus) return true; } LogRel(("devR0Smc: %s: bCurStatus=%#x, wanted %#x.\n", pszWhat, bCurStatus, bStatus)); return false; }
/* * Internal Functions * */ static UINT32 GetVmVariable(UINT32 Variable, CHAR8* Buffer, UINT32 Size ) { UINT32 VarLen, i; ASMOutU32(EFI_INFO_PORT, Variable); VarLen = ASMInU32(EFI_INFO_PORT); for (i=0; i < VarLen && i < Size; i++) { Buffer[i] = ASMInU8(EFI_INFO_PORT); } return VarLen; }
/** * Initalizes the triple fault / boot hack. * * Always call vmmR0TripleFaultHackTerm to clean up, even when this call fails. * * @returns VBox status code. */ int vmmR0TripleFaultHackInit(void) { /* * Map the first page. */ int rc = RTR0MemObjEnterPhys(&g_hMemPage0, 0, PAGE_SIZE, RTMEM_CACHE_POLICY_DONT_CARE); AssertRCReturn(rc, rc); rc = RTR0MemObjMapKernel(&g_hMapPage0, g_hMemPage0, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE); AssertRCReturn(rc, rc); g_pbPage0 = (uint8_t *)RTR0MemObjAddress(g_hMapPage0); LogRel(("0040:0067 = %04x:%04x\n", RT_MAKE_U16(g_pbPage0[0x467+2], g_pbPage0[0x467+3]), RT_MAKE_U16(g_pbPage0[0x467+0], g_pbPage0[0x467+1]) )); /* * Allocate some "low core" memory. If that fails, just grab some memory. */ //rc = RTR0MemObjAllocPhys(&g_hMemLowCore, PAGE_SIZE, _1M - 1); //__debugbreak(); rc = RTR0MemObjEnterPhys(&g_hMemLowCore, 0x7000, PAGE_SIZE, RTMEM_CACHE_POLICY_DONT_CARE); AssertRCReturn(rc, rc); rc = RTR0MemObjMapKernel(&g_hMapLowCore, g_hMemLowCore, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE); AssertRCReturn(rc, rc); g_pbLowCore = (uint8_t *)RTR0MemObjAddress(g_hMapLowCore); g_HCPhysLowCore = RTR0MemObjGetPagePhysAddr(g_hMapLowCore, 0); LogRel(("Low core at %RHp mapped at %p\n", g_HCPhysLowCore, g_pbLowCore)); /* * Save memory we'll be overwriting. */ g_pvSavedLowCore = RTMemAlloc(PAGE_SIZE); AssertReturn(g_pvSavedLowCore, VERR_NO_MEMORY); memcpy(g_pvSavedLowCore, g_pbLowCore, PAGE_SIZE); g_u32SavedVector = RT_MAKE_U32_FROM_U8(g_pbPage0[0x467], g_pbPage0[0x467+1], g_pbPage0[0x467+2], g_pbPage0[0x467+3]); g_u16SavedCadIndicator = RT_MAKE_U16(g_pbPage0[0x472], g_pbPage0[0x472+1]); /* * Install the code. */ size_t cbCode = (uintptr_t)&vmmR0TripleFaultHackEnd - (uintptr_t)&vmmR0TripleFaultHackStart; AssertLogRelReturn(cbCode <= PAGE_SIZE, VERR_OUT_OF_RANGE); memcpy(g_pbLowCore, &vmmR0TripleFaultHackStart, cbCode); g_pbPage0[0x467+0] = 0x00; g_pbPage0[0x467+1] = 0x70; g_pbPage0[0x467+2] = 0x00; g_pbPage0[0x467+3] = 0x00; g_pbPage0[0x472+0] = 0x34; g_pbPage0[0x472+1] = 0x12; /* * Configure the status port and cmos shutdown command. */ uint32_t fSaved = ASMIntDisableFlags(); ASMOutU8(0x70, 0x0f); ASMOutU8(0x71, 0x0a); ASMOutU8(0x70, 0x05); ASMInU8(0x71); ASMReloadCR3(); ASMWriteBackAndInvalidateCaches(); ASMSetFlags(fSaved); #if 1 /* For testing & debugging. */ vmmR0TripleFaultHackTripleFault(); #endif return VINF_SUCCESS; }