tstOhciRegisterAccess.cpp revision f94dcbf4d4de095572e91b9475d65a68c18ab92a
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * tstOhciRegisterAccess - OHCI Register Access Tests / Experiments.
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * Copyright (C) 2011 Oracle Corporation
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * available from http://www.virtualbox.org. This file is free software;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * General Public License (GPL) as published by the Free Software
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync/*******************************************************************************
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync* Header Files *
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync*******************************************************************************/
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync/*******************************************************************************
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync* Global Variables *
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync*******************************************************************************/
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync/** Register names. */
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsyncstatic const char * const g_apszRegNms[] =
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRevision",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcControl",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcCommandStatus",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcInterruptStatus",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcInterruptEnable",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcInterruptDisable",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcPeriodCurrentED",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcControlHeadED",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcControlCurrentED",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcBulkHeadED",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcBulkCurrentED",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcDoneHead",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcFmInterval",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcFmRemaining",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcFmNumber",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcPeriodicStart",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcLSThreshold",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhDescriptorA",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhDescriptorB",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhStatus",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync /* Variable number of root hub ports: */
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhPortStatus[0]",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhPortStatus[1]",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhPortStatus[2]",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhPortStatus[3]",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhPortStatus[4]",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhPortStatus[5]",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhPortStatus[6]",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "HcRhPortStatus[7]"
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync static struct
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync bool fSuccess = true;
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync for (unsigned i = 0; i < RT_ELEMENTS(s_aRegs); i++)
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync LogRel(("TestOhciWrites: %p iReg=%2d %20s = %08RX32\n", uPtrReg.pv, iReg, g_apszRegNms[iReg], uInitialValue));
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync bool fDone = true;
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync * DWORD writes.
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync uint32_t const uChangedValue = s_aRegs[i].uVal1 != uInitialValue ? s_aRegs[i].uVal1 : s_aRegs[i].uVal2;
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync /* Change the value. */
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync * Write byte changes.
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync * Complain on failure.
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync LogRel(("TestOhciWrites: Warning! Register %s was never stable enough for testing! %08RX32 %08RX32 %08RX32\n",
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync g_apszRegNms[iReg], uInitialValue, u32A, uChangedValue, uInitialValue));
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync LogRel(("TestOhciWrites: Error! Register %s failed: %s; uInitialValue=%08RX32 uChangedValue=%08RX32 u32A=%08RX32\n",
f94dcbf4d4de095572e91b9475d65a68c18ab92avboxsync g_apszRegNms[iReg], pszError, uInitialValue, uChangedValue, u32A));
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * We can read just about any register we like since read shouldn't have
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * any side effects. However, some registers are volatile and makes for
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * difficult targets, thus the ugly code.
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync bool fSuccess = true;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync for (uint32_t iReg = 0; iReg < cMaxReg; iReg++, uPtr.pu32++)
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync bool fDone = false;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync LogRel(("TestOhciReads: %p iReg=%2d %20s = %08RX32\n", uPtr.pv, iReg, g_apszRegNms[iReg], uInitialValue));
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync for (uint32_t iTry = 0; !fDone && iTry < 1024; iTry++)
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync /* Test byte access. */
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync if (u32A != uInitialValue || u32C != uInitialValue)
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync UINT32_C(0xffffff00), UINT32_C(0xffff00ff), UINT32_C(0xff00ffff), UINT32_C(0x00ffffff)
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync static const char * const s_apsz[] = { "byte 0", "byte 1", "byte 2", "byte 3" };
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync /* Test aligned word access. */
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync if (u32A != uInitialValue || u32C != uInitialValue)
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync u32B |= uInitialValue & (iWord == 0 ? UINT32_C(0xffff0000) : UINT32_C(0x0000ffff));
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync pszError = iWord == 0 ? "aligned word 0 access" : "aligned word 1 access";
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync /* Test unaligned word access. */
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync for (int iWord = ((uintptr_t)uPtr.pv & PAGE_OFFSET_MASK) == 0; iWord < 3; iWord++)
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync u32B = *(volatile uint16_t *)&uPtr.pu8[iWord * 2 - 1];
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync if (u32A != uInitialValue || u32C != uInitialValue)
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync case 0: u32B = (u32B >> 8) | (u32A & UINT32_C(0xffffff00)); break;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync case 1: u32B = (u32B << 8) | (u32A & UINT32_C(0xff0000ff)); break;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync case 2: u32B = (u32B << 24) | (u32A & UINT32_C(0x00ffffff)); break;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync static const char * const s_apsz[] = { "unaligned word 0", "unaligned word 1", "unaligned word 2" };
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync /* Test unaligned dword access. */
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync for (int iByte = ((uintptr_t)uPtr.pv & PAGE_OFFSET_MASK) == 0 ? 0 : -3; iByte < 4; iByte++)
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync if (u32A != uInitialValue || u32C != uInitialValue)
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync case -3: u32B = (u32B >> 24) | (uInitialValue & UINT32_C(0xffffff00)); break;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync case -2: u32B = (u32B >> 16) | (uInitialValue & UINT32_C(0xffff0000)); break;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync case -1: u32B = (u32B >> 8) | (uInitialValue & UINT32_C(0xff000000)); break;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync case 0: break;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync case 1: u32B = (u32B << 8) | (uInitialValue & UINT32_C(0x000000ff)); break;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync case 2: u32B = (u32B << 16) | (uInitialValue & UINT32_C(0x0000ffff)); break;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync case 3: u32B = (u32B << 24) | (uInitialValue & UINT32_C(0x00ffffff)); break;
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync static const char * const s_apsz[] =
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "unaligned dword -3", "unaligned dword -2", "unaligned dword -1",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync "unaligned dword 0", "unaligned dword 1", "unaligned dword 2", "unaligned dword 3"
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync } /* try loop */
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * Complain on failure.
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync LogRel(("TestOhciReads: Warning! Register %s was never stable enough for testing! %08RX32 %08RX32 %08RX32\n",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync LogRel(("TestOhciReads: Error! Register %s failed: %s; uInitialValue=%08RX32 u32B=%08RX32\n",
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync g_apszRegNms[iReg], pszError, uInitialValue, u32B));
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync LogRel(("tstOhciRegisterAccess: HCPhysOHCI=%RHp\n", HCPhysOHCI));
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * Map the OHCI registers so we can access them.
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync int rc = RTR0MemObjEnterPhys(&hMemObj, HCPhysOHCI, PAGE_SIZE, RTMEM_CACHE_POLICY_MMIO);
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync LogRel(("tstOhciRegisterAccess: Failed to enter OHCI memory at %RHp: %Rrc\n", HCPhysOHCI, rc));
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync rc = RTR0MemObjMapKernel(&hMapObj, hMemObj, (void *)-1, 0 /*uAlignment*/, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync uPtr.pv = (void volatile *)RTR0MemObjAddress(hMapObj);
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync LogRel(("tstOhciRegisterAccess: mapping address %p\n", uPtr.pv));
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync LogRel(("tstOhciRegisterAccess: HcRevision=%#x\n", *uPtr.pu32));
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * Do the access tests.
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync * Clean up.
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync LogRel(("tstOhciRegisterAccess: Failed to map OHCI memory at %RHp: %Rrc\n", HCPhysOHCI, rc));
cde46304e0c614aad7fd63abacb0180e4e83f24cvboxsync LogRel(("tstOhciRegisterAccess: returns %Rrc\n", rc));