/* $Id: bs3-cpu-basic-2-pf.c32 64752 2016-11-25 09:20:25Z vboxsync $ */ /** @file * BS3Kit - bs3-cpu-basic-2, 32-bit C code. */ /* * Copyright (C) 2007-2016 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the * VirtualBox OSE distribution, in which case the provisions of the * CDDL are applicable instead of those of the GPL. * * You may elect to license modified versions of this file under the * terms and conditions of either the GPL or the CDDL or both. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ typedef void BS3_CALL FNBS3CPUBASIC2PFSNIPPET(void); typedef struct FNBS3CPUBASIC2PFTSTCODE { FNBS3CPUBASIC2PFSNIPPET *pfn; uint8_t offUd2; uint8_t cbTmpl; } FNBS3CPUBASIC2PFTSTCODE; typedef struct BS3CPUBASIC2PFTTSTCMNMODE { uint8_t bMode; FNBS3CPUBASIC2PFTSTCODE ExecTmpl; FNBS3CPUBASIC2PFTSTCODE MovLoad; FNBS3CPUBASIC2PFTSTCODE MovStore; FNBS3CPUBASIC2PFTSTCODE Xchg; FNBS3CPUBASIC2PFTSTCODE CmpXchg; } BS3CPUBASIC2PFTTSTCMNMODE; typedef BS3CPUBASIC2PFTTSTCMNMODE const *PCBS3CPUBASIC2PFTTSTCMNMODE; typedef struct BS3CPUBASIC2PFSTATE { /** The mode we're currently testing. */ uint8_t bMode; /** The common mode functions. */ PCBS3CPUBASIC2PFTTSTCMNMODE pCmnMode; /** Pointer to the test area (alias). */ uint8_t *pbTest; /** Pointer to the orignal test area mapping. */ uint8_t *pbOrgTest; /** The size of the test area (at least two pages). */ uint32_t cbTest; /** 16-bit data selector for pbTest. */ uint16_t uSel16TestData; /** 16-bit code selector for pbTest. */ uint16_t uSel16TestCode; /** Test paging information for pbTest. */ BS3PAGINGINFO4ADDR PgInfo; /** Set if we can use the INVLPG instruction. */ bool fUseInvlPg; /** Trap context frame. */ BS3TRAPFRAME TrapCtx; } BS3CPUBASIC2PFSTATE; /** Pointer to state for the \#PF test. */ typedef BS3CPUBASIC2PFSTATE *PBS3CPUBASIC2PFSTATE; /********************************************************************************************************************************* * Internal Functions * *********************************************************************************************************************************/ FNBS3TESTDOMODE bs3CpuBasic2_RaiseXcpt0e_c32; /* bs3-cpu-basic-2-asm.asm: */ void BS3_CALL bs3CpuBasic2_Store_mov_c32(void *pvDst, uint32_t uValue, uint32_t uOld); void BS3_CALL bs3CpuBasic2_Store_xchg_c32(void *pvDst, uint32_t uValue, uint32_t uOld); void BS3_CALL bs3CpuBasic2_Store_cmpxchg_c32(void *pvDst, uint32_t uValue, uint32_t uOld); /* bs3-cpu-basic-2-template.mac: */ FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_RaisePF_ExecTmpl_c16; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c16; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c16; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_RaisePF_ExecTmpl_c32; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c32; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c32; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c32; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_RaisePF_ExecTmpl_c64; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c64; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c64; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c64; FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c64; /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** Page table access functions. */ static const struct { const char *pszStore; void (BS3_CALL *pfnStore)(void *pvDst, uint32_t uValue, uint32_t uOld); } g_aStoreMethods[] = { { "mov", bs3CpuBasic2_Store_mov_c32 }, { "xchg", bs3CpuBasic2_Store_xchg_c32 }, { "cmpxchg", bs3CpuBasic2_Store_cmpxchg_c32 }, }; static const BS3CPUBASIC2PFTTSTCMNMODE g_aCmnModes[] = { { BS3_MODE_CODE_16, { bs3CpuBasic2_RaisePF_ExecTmpl_c16, 0, 3 }, { bs3CpuBasic2_mov_ax_ds_bx__ud2_c16, 2 }, { bs3CpuBasic2_mov_ds_bx_ax__ud2_c16, 2 }, { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16, 2 }, { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16, 3 }, }, { BS3_MODE_CODE_32, { bs3CpuBasic2_RaisePF_ExecTmpl_c32, 0, 3 }, { bs3CpuBasic2_mov_ax_ds_bx__ud2_c32, 2 }, { bs3CpuBasic2_mov_ds_bx_ax__ud2_c32, 2 }, { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c32, 2 }, { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32, 3 }, }, { BS3_MODE_CODE_64, { bs3CpuBasic2_RaisePF_ExecTmpl_c64, 0, 3 }, { bs3CpuBasic2_mov_ax_ds_bx__ud2_c64, 2 + 1 }, { bs3CpuBasic2_mov_ds_bx_ax__ud2_c64, 2 + 1 }, { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c64, 2 + 1 }, { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c64, 3 + 1 }, }, { BS3_MODE_CODE_V86, { bs3CpuBasic2_RaisePF_ExecTmpl_c16, 0, 3 }, { bs3CpuBasic2_mov_ax_ds_bx__ud2_c16, 2 }, { bs3CpuBasic2_mov_ds_bx_ax__ud2_c16, 2 }, { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16, 2 }, { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16, 3 }, }, }; static void bs3CpuBasic2Pf_DoExecSubTest(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t uXcpt, uint8_t uPfErrCd, unsigned iRing) { uint8_t *pbOrgTest = pThis->pbOrgTest; unsigned off; for (off = X86_PAGE_SIZE - 2; off < X86_PAGE_SIZE + 2; off++) { pbOrgTest[off + 0] = X86_OP_PRF_SIZE_ADDR; pbOrgTest[off + 1] = X86_OP_PRF_SIZE_OP; pbOrgTest[off + 2] = 0x90; /* NOP */ pbOrgTest[off + 3] = 0x0f; /* UD2 */ pbOrgTest[off + 4] = 0x0b; pbOrgTest[off + 5] = 0xeb; /* JMP $-4 */ pbOrgTest[off + 6] = 0xfc; switch (pThis->bMode & BS3_MODE_CODE_MASK) { default: pCtx->rip.u = (uintptr_t)&pThis->pbTest[off]; break; case BS3_MODE_CODE_16: Bs3SelSetup16BitCode(&Bs3GdteSpare01, (uintptr_t)pThis->pbTest, iRing); pCtx->rip.u = off; pCtx->cs = BS3_SEL_SPARE_01; break; case BS3_MODE_CODE_V86: /** @todo fix me. */ return; } Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx); //bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); } } /** * Worker for bs3CpuBasic2_RaiseXcpt0e_c32 that does the actual testing. * * Caller does all the cleaning up. * * @returns Error count. * @param pThis Test state data. */ static uint8_t bs3CpuBasic2_RaiseXcpt0eWorker(PBS3CPUBASIC2PFSTATE register pThis) { unsigned iRing; BS3REGCTX aCtxts[4]; /* paranoia: Touch the various big stack structures to ensure the compiler has allocated stack for them. */ for (iRing = 0; iRing < RT_ELEMENTS(aCtxts); iRing++) Bs3MemZero(&aCtxts[iRing], sizeof(aCtxts[iRing])); /* * Set up a few contexts for testing this stuff. */ Bs3RegCtxSaveEx(&aCtxts[0], pThis->bMode, 2048); for (iRing = 1; iRing < 4; iRing++) { aCtxts[iRing] = aCtxts[0]; Bs3RegCtxConvertToRingX(&aCtxts[iRing], iRing); } if (!BS3_MODE_IS_16BIT_CODE(pThis->bMode)) { for (iRing = 0; iRing < 4; iRing++) aCtxts[iRing].rbx.u = (uintptr_t)pThis->pbTest; } else { for (iRing = 0; iRing < 4; iRing++) { aCtxts[iRing].ds = pThis->uSel16TestData; aCtxts[iRing].rbx.u = 0; } } /* * Check basic operation. */ for (iRing = 0; iRing < 4; iRing++) { /* we can execute the test page. */ bs3CpuBasic2Pf_DoExecSubTest(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, iRing); } return 0; } BS3_DECL_CALLBACK(uint8_t) bs3CpuBasic2_RaiseXcpt0e_c32(uint8_t bMode) { void *pvTestUnaligned; uint32_t cbTestUnaligned = _8M; uint8_t bRet = 1; int rc; BS3CPUBASIC2PFSTATE State; /* * Initalize the state data. */ Bs3MemZero(&State, sizeof(State)); State.bMode = bMode; State.pCmnMode = &g_aCmnModes[0]; while (State.pCmnMode->bMode != (bMode & BS3_MODE_CODE_MASK)) State.pCmnMode++; State.fUseInvlPg = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486; /* * Allocate a some memory we can play around with, then carve a size aligned * chunk out of it so we might be able to maybe play with 2/4MB pages too. */ cbTestUnaligned = _8M * 2; while ((pvTestUnaligned = Bs3MemAlloc(BS3MEMKIND_FLAT32, cbTestUnaligned)) == NULL) { cbTestUnaligned >>= 1; if (cbTestUnaligned <= _8K) { Bs3TestFailed("Failed to allocate memory to play around with\n"); return 1; } } if ((uintptr_t)pvTestUnaligned & (cbTestUnaligned - 1)) { State.cbTest = cbTestUnaligned >> 1; State.pbOrgTest = (uint8_t *)(((uintptr_t)pvTestUnaligned + State.cbTest - 1) & ~(State.cbTest - 1)); } else { State.pbOrgTest = pvTestUnaligned; State.cbTest = cbTestUnaligned; } /* * Alias this memory far away from where our code and data lives. */ State.pbTest = (uint8_t *)UINT32_C(0x80000000); rc = Bs3PagingAlias((uintptr_t)State.pbTest, (uintptr_t)State.pbOrgTest, State.cbTest, X86_PTE_P | X86_PTE_RW | X86_PTE_US); if (RT_SUCCESS(rc)) { rc = Bs3PagingQueryAddressInfo((uintptr_t)State.pbTest, &State.PgInfo); if (RT_SUCCESS(rc)) { /* * Setup a 16-bit selector for accessing the alias. */ Bs3SelSetup16BitData(&Bs3GdteSpare00, (uintptr_t)State.pbTest); State.uSel16TestData = BS3_SEL_SPARE_00 | 3; //Bs3TestPrintf("RaiseXcpt0e_c32: bMode=%#x/%#x cbTest=%#x pbTest=%p pbAlias=%p\n", // bMode, g_bBs3CurrentMode, cbTest, pbTest, pbAlias); bRet = bs3CpuBasic2_RaiseXcpt0eWorker(&State); } else Bs3TestFailedF("Bs3PagingQueryAddressInfo failed: %d\n", rc); Bs3PagingUnalias((uintptr_t)State.pbTest, State.cbTest); } else Bs3TestFailedF("Bs3PagingAlias failed! rc=%d\n", rc); Bs3MemFree(pvTestUnaligned, cbTestUnaligned); return bRet; }