SELM.cpp revision ff88d4153cd65650577e8c2d1a5a3fdfa0404a80
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * SELM - The Selector Manager.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * available from http://www.virtualbox.org. This file is free software;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * you can redistribute it and/or modify it under the terms of the GNU
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * General Public License (GPL) as published by the Free Software
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * additional information or have any questions.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/** @page pg_selm SELM - The Selector Manager
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * SELM takes care of GDT, LDT and TSS shadowing in raw-mode, and the injection
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * of a few hyper selector for the raw-mode context. In the hardware assisted
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * virtualization mode its only task is to decode entries in the guest GDT or
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * LDT once in a while.
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync * @see grp_selm
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @section seg_selm_shadowing Shadowing
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * SELMR3UpdateFromCPUM() and SELMR3SyncTSS() does the bulk synchronization
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync * work. The three structures (GDT, LDT, TSS) are all shadowed wholesale atm.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * The idea is to do it in a more on-demand fashion when we get time. There
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * also a whole bunch of issues with the current synchronization of all three
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * tables, see notes and todos in the code.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * When the guest makes changes to the GDT we will try update the shadow copy
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * without involving SELMR3UpdateFromCPUM(), see selmGCSyncGDTEntry().
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * When the guest make LDT changes we'll trigger a full resync of the LDT
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * (SELMR3UpdateFromCPUM()), which, needless to say, isn't optimal.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * The TSS shadowing is limited to the fields we need to care about, namely SS0
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * and ESP0. The Patch Manager makes use of these. We monitor updates to the
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * guest TSS and will try keep our SS0 and ESP0 copies up to date this way
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * rather than go the SELMR3SyncTSS() route.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * When in raw-mode SELM also injects a few extra GDT selectors which are used
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * by the raw-mode (hyper) context. These start their life at the high end of
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * the table and will be relocated when the guest tries to make use of them...
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * Well, that was that idea at least, only the code isn't quite there yet which
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * is why we have trouble with guests which actually have a full sized GDT.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * So, the summary of the current GDT, LDT and TSS shadowing is that there is a
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * lot of relatively simple and enjoyable work to be done, see @bugref{3267}.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/*******************************************************************************
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync* Header Files *
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync*******************************************************************************/
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync * Enable or disable tracking of Guest's GDT/LDT/TSS.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Enable or disable tracking of Shadow GDT/LDT/TSS.
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync/** SELM saved state version. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync/*******************************************************************************
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync* Internal Functions *
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync*******************************************************************************/
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic DECLCALLBACK(int) selmR3Save(PVM pVM, PSSMHANDLE pSSM);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic DECLCALLBACK(int) selmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic DECLCALLBACK(int) selmR3LoadDone(PVM pVM, PSSMHANDLE pSSM);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic DECLCALLBACK(int) selmR3GuestGDTWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic DECLCALLBACK(int) selmR3GuestLDTWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic DECLCALLBACK(int) selmR3GuestTSSWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic DECLCALLBACK(void) selmR3InfoGdt(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic DECLCALLBACK(void) selmR3InfoGdtGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(void) selmR3InfoLdt(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(void) selmR3InfoLdtGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync//static DECLCALLBACK(void) selmR3InfoTss(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync//static DECLCALLBACK(void) selmR3InfoTssGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Initializes the SELM.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @returns VBox status code.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @param pVM The VM to operate on.
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync * Assert alignment and sizes.
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync * (The TSS block requires contiguous back.)
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync AssertCompile(sizeof(pVM->selm.s) <= sizeof(pVM->selm.padding)); AssertRelease(sizeof(pVM->selm.s) <= sizeof(pVM->selm.padding));
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync AssertCompileMemberAlignment(VM, selm.s, 32); AssertRelease(!(RT_OFFSETOF(VM, selm.s) & 31));
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync#if 0 /* doesn't work */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync AssertCompile((RT_OFFSETOF(VM, selm.s.Tss) & PAGE_OFFSET_MASK) <= PAGE_SIZE - sizeof(pVM->selm.s.Tss));
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync AssertCompile((RT_OFFSETOF(VM, selm.s.TssTrap08) & PAGE_OFFSET_MASK) <= PAGE_SIZE - sizeof(pVM->selm.s.TssTrap08));
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync AssertRelease((RT_OFFSETOF(VM, selm.s.Tss) & PAGE_OFFSET_MASK) <= PAGE_SIZE - sizeof(pVM->selm.s.Tss));
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync AssertRelease((RT_OFFSETOF(VM, selm.s.TssTrap08) & PAGE_OFFSET_MASK) <= PAGE_SIZE - sizeof(pVM->selm.s.TssTrap08));
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync AssertRelease(sizeof(pVM->selm.s.Tss.IntRedirBitmap) == 0x20);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Init the structure.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS] = (SELM_GDT_ELEMENTS - 0x1) << 3;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS] = (SELM_GDT_ELEMENTS - 0x2) << 3;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS64] = (SELM_GDT_ELEMENTS - 0x3) << 3;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS] = (SELM_GDT_ELEMENTS - 0x4) << 3;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] = (SELM_GDT_ELEMENTS - 0x5) << 3;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Allocate GDT table.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync int rc = MMR3HyperAllocOnceNoRel(pVM, sizeof(pVM->selm.s.paGdtR3[0]) * SELM_GDT_ELEMENTS,
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync PAGE_SIZE, MM_TAG_SELM, (void **)&pVM->selm.s.paGdtR3);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Allocate LDT area.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = MMR3HyperAllocOnceNoRel(pVM, _64K + PAGE_SIZE, PAGE_SIZE, MM_TAG_SELM, &pVM->selm.s.pvLdtR3);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * Init Guest's and Shadow GDT, LDT, TSS changes control variables.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pVM->selm.s.paGdtRC = NIL_RTRCPTR; /* Must be set in SELMR3Relocate because of monitoring. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* The I/O bitmap starts right after the virtual interrupt redirection bitmap. Outside the TSS on purpose; the CPU will not check it
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * for I/O operations. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* bit set to 1 means no redirection */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync memset(pVM->selm.s.Tss.IntRedirBitmap, 0xff, sizeof(pVM->selm.s.Tss.IntRedirBitmap));
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Register the saved state data unit.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync rc = SSMR3RegisterInternal(pVM, "selm", 1, SELM_SAVED_STATE_VERSION, sizeof(SELM),
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Statistics.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync STAM_REG(pVM, &pVM->selm.s.StatRCWriteGuestGDTHandled, STAMTYPE_COUNTER, "/SELM/GC/Write/Guest/GDTInt", STAMUNIT_OCCURENCES, "The number of handled writes to the Guest GDT.");
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync STAM_REG(pVM, &pVM->selm.s.StatRCWriteGuestGDTUnhandled, STAMTYPE_COUNTER, "/SELM/GC/Write/Guest/GDTEmu", STAMUNIT_OCCURENCES, "The number of unhandled writes to the Guest GDT.");
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync STAM_REG(pVM, &pVM->selm.s.StatRCWriteGuestLDT, STAMTYPE_COUNTER, "/SELM/GC/Write/Guest/LDT", STAMUNIT_OCCURENCES, "The number of writes to the Guest LDT was detected.");
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync STAM_REG(pVM, &pVM->selm.s.StatRCWriteGuestTSSHandled, STAMTYPE_COUNTER, "/SELM/GC/Write/Guest/TSSInt", STAMUNIT_OCCURENCES, "The number of handled writes to the Guest TSS.");
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync STAM_REG(pVM, &pVM->selm.s.StatRCWriteGuestTSSRedir, STAMTYPE_COUNTER, "/SELM/GC/Write/Guest/TSSRedir",STAMUNIT_OCCURENCES, "The number of handled redir bitmap writes to the Guest TSS.");
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync STAM_REG(pVM, &pVM->selm.s.StatRCWriteGuestTSSHandledChanged,STAMTYPE_COUNTER, "/SELM/GC/Write/Guest/TSSIntChg", STAMUNIT_OCCURENCES, "The number of handled writes to the Guest TSS where the R0 stack changed.");
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync STAM_REG(pVM, &pVM->selm.s.StatRCWriteGuestTSSUnhandled, STAMTYPE_COUNTER, "/SELM/GC/Write/Guest/TSSEmu", STAMUNIT_OCCURENCES, "The number of unhandled writes to the Guest TSS.");
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync STAM_REG(pVM, &pVM->selm.s.StatTSSSync, STAMTYPE_PROFILE, "/PROF/SELM/TSSSync", STAMUNIT_TICKS_PER_CALL, "Profiling of the SELMR3SyncTSS() body.");
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync STAM_REG(pVM, &pVM->selm.s.StatUpdateFromCPUM, STAMTYPE_PROFILE, "/PROF/SELM/UpdateFromCPUM", STAMUNIT_TICKS_PER_CALL, "Profiling of the SELMR3UpdateFromCPUM() body.");
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync STAM_REG(pVM, &pVM->selm.s.StatHyperSelsChanged, STAMTYPE_COUNTER, "/SELM/HyperSels/Changed", STAMUNIT_OCCURENCES, "The number of times we had to relocate our hypervisor selectors.");
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync STAM_REG(pVM, &pVM->selm.s.StatScanForHyperSels, STAMTYPE_COUNTER, "/SELM/HyperSels/Scan", STAMUNIT_OCCURENCES, "The number of times we had find free hypervisor selectors.");
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * Default action when entering raw mode for the first time
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * Register info handlers.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync DBGFR3InfoRegisterInternal(pVM, "gdt", "Displays the shadow GDT. No arguments.", &selmR3InfoGdt);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync DBGFR3InfoRegisterInternal(pVM, "gdtguest", "Displays the guest GDT. No arguments.", &selmR3InfoGdtGuest);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync DBGFR3InfoRegisterInternal(pVM, "ldt", "Displays the shadow LDT. No arguments.", &selmR3InfoLdt);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync DBGFR3InfoRegisterInternal(pVM, "ldtguest", "Displays the guest LDT. No arguments.", &selmR3InfoLdtGuest);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync //DBGFR3InfoRegisterInternal(pVM, "tss", "Displays the shadow TSS. No arguments.", &selmR3InfoTss);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync //DBGFR3InfoRegisterInternal(pVM, "tssguest", "Displays the guest TSS. No arguments.", &selmR3InfoTssGuest);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * Finalizes HMA page attributes.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * @returns VBox status code.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * @param pVM The VM handle.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync /** @cfgm{/DoubleFault,bool,false}
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * Enables catching of double faults in the raw-mode context VMM code. This can
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * be used when the tripple faults or hangs occure and one suspect an unhandled
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * double fault. This is not enabled by default because it means making the
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * hyper selectors writeable for all supervisor code, including the guest's.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * The double fault is a task switch and thus requires write access to the GDT
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * of the TSS (to set it busy), to the old TSS (to store state), and to the Trap
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * 8 TSS for the back link.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync int rc = CFGMR3QueryBoolDef(CFGMR3GetRoot(pVM), "DoubleFault", &f, true);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync int rc = CFGMR3QueryBoolDef(CFGMR3GetRoot(pVM), "DoubleFault", &f, false);
6114ff5789db75ff28460a056ed422ee03d8f0ebvboxsync rc = PGMMapSetPage(pVM, MMHyperR3ToRC(pVM, &paGdt[pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] >> 3]), sizeof(paGdt[0]),
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync rc = PGMMapSetPage(pVM, MMHyperR3ToRC(pVM, &paGdt[pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS] >> 3]), sizeof(paGdt[0]),
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync rc = PGMMapSetPage(pVM, VM_RC_ADDR(pVM, &pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS]), sizeof(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS]),
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync rc = PGMMapSetPage(pVM, VM_RC_ADDR(pVM, &pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08]), sizeof(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08]),
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Setup the hypervisor GDT selectors in our shadow table
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @param pVM The VM handle.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Set up global code and data descriptors for use in the guest context.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Both are wide open (base 0, limit 4GB)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PX86DESC pDesc = &paGdt[pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS] >> 3];
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync pDesc->Gen.u1DescType = 1; /* not system, but code/data */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pDesc = &paGdt[pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS] >> 3];
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pDesc->Gen.u1DescType = 1; /* not system, but code/data */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* 64-bit mode code (& data?) */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pDesc = &paGdt[pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS64] >> 3];
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync pDesc->Gen.u1DescType = 1; /* not system, but code/data */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync pDesc->Gen.u1Long = 1; /* The Long (L) attribute bit. */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync pDesc->Gen.u1DefBig = 0; /* With L=1 this must be 0. */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync * TSS descriptor
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync pDesc = &paGdt[pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS] >> 3];
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync RTRCPTR RCPtrTSS = VM_RC_ADDR(pVM, &pVM->selm.s.Tss);
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync pDesc->Gen.u4Type = X86_SEL_TYPE_SYS_386_TSS_AVAIL;
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * TSS descriptor for trap 08
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pDesc = &paGdt[pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] >> 3];
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync RCPtrTSS = VM_RC_ADDR(pVM, &pVM->selm.s.TssTrap08);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pDesc->Gen.u4Type = X86_SEL_TYPE_SYS_386_TSS_AVAIL;
6114ff5789db75ff28460a056ed422ee03d8f0ebvboxsync * Applies relocations to data and code managed by this
6114ff5789db75ff28460a056ed422ee03d8f0ebvboxsync * component. This function will be called at init and
6114ff5789db75ff28460a056ed422ee03d8f0ebvboxsync * whenever the VMM need to relocate it self inside the GC.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param pVM The VM.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Update GDTR and selector.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync CPUMSetHyperGDTR(pVM, MMHyperR3ToRC(pVM, paGdt), SELM_GDT_ELEMENTS * sizeof(paGdt[0]) - 1);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** @todo selector relocations should be a seperate operation? */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync CPUMSetHyperCS(pVM, pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS]);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync CPUMSetHyperDS(pVM, pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS]);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync CPUMSetHyperES(pVM, pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS]);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync CPUMSetHyperSS(pVM, pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS]);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync CPUMSetHyperTR(pVM, pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS]);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/** @todo SELM must be called when any of the CR3s changes during a cpu mode change. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/** @todo PGM knows the proper CR3 values these days, not CPUM. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Update the TSSes.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* Current TSS */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.Tss.ss0 = pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS];
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.Tss.cs = pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS];
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.Tss.ds = pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS];
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.Tss.es = pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS];
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* trap 08 */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.TssTrap08.cr3 = PGMGetInterRCCR3(pVM); /* this should give use better survival chances. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.TssTrap08.ss0 = pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS];
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.TssTrap08.ss = pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS];
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.TssTrap08.esp0 = VMMGetStackRC(pVM) - PAGE_SIZE / 2; /* upper half can be analysed this way. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.TssTrap08.esp = pVM->selm.s.TssTrap08.esp0;
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync pVM->selm.s.TssTrap08.ebp = pVM->selm.s.TssTrap08.esp0;
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.TssTrap08.cs = pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS];
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.TssTrap08.ds = pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS];
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.TssTrap08.es = pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS];
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pVM->selm.s.TssTrap08.eflags = 0x2; /* all cleared */
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync pVM->selm.s.TssTrap08.ecx = VM_RC_ADDR(pVM, &pVM->selm.s.Tss); /* setup ecx to normal Hypervisor TSS address. */
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync pVM->selm.s.TssTrap08.edi = pVM->selm.s.TssTrap08.ecx;
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync pVM->selm.s.TssTrap08.eax = pVM->selm.s.TssTrap08.ecx;
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync pVM->selm.s.TssTrap08.edx = VM_RC_ADDR(pVM, pVM); /* setup edx VM address. */
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync pVM->selm.s.TssTrap08.edi = pVM->selm.s.TssTrap08.edx;
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync pVM->selm.s.TssTrap08.ebx = pVM->selm.s.TssTrap08.edx;
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync pVM->selm.s.TssTrap08.offIoBitmap = sizeof(VBOXTSS);
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync /* TRPM will be updating the eip */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Update shadow GDT/LDT/TSS write access handlers.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.paGdtRC);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_HYPERVISOR, pVM->selm.s.paGdtRC,
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync pVM->selm.s.paGdtRC + SELM_GDT_ELEMENTS * sizeof(paGdt[0]) - 1,
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync 0, 0, "selmRCShadowGDTWriteHandler", 0, "Shadow GDT write access handler");
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.pvMonShwTssRC);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync pVM->selm.s.pvMonShwTssRC = VM_RC_ADDR(pVM, &pVM->selm.s.Tss);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_HYPERVISOR, pVM->selm.s.pvMonShwTssRC,
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync pVM->selm.s.pvMonShwTssRC + sizeof(pVM->selm.s.Tss) - 1,
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync 0, 0, "selmRCShadowTSSWriteHandler", 0, "Shadow TSS write access handler");
7de81a482cdfc1bbf53600a4f6cdd4c892ee460cvboxsync * Update the GC LDT region handler and address.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.pvLdtRC);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync pVM->selm.s.pvLdtRC = MMHyperR3ToRC(pVM, pVM->selm.s.pvLdtR3);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_HYPERVISOR, pVM->selm.s.pvLdtRC,
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync 0, 0, "selmRCShadowLDTWriteHandler", 0, "Shadow LDT write access handler");
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Notification callback which is called whenever there is a chance that a CR3
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * value might have changed.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * This is called by PGM.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @param pVM The VM handle
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Terminates the SELM.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Termination means cleaning up and freeing all resources,
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * the VM it self is at this point powered off or suspended.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @returns VBox status code.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @param pVM The VM to operate on.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * The VM is being reset.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * For the SELM component this means that any GDT/LDT/TSS monitors
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * needs to be removed.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @param pVM VM handle.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Uninstall guest GDT/LDT/TSS write access handlers.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync if (pVM->selm.s.GuestGdtr.pGdt != RTRCPTR_MAX && pVM->selm.s.fGDTRangeRegistered)
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GuestGdtr.pGdt);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestLdt);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestTss);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Re-initialize other members.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Default action when entering raw mode for the first time
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Disable GDT/LDT/TSS monitoring and syncing
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param pVM The VM to operate on.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Uninstall guest GDT/LDT/TSS write access handlers.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync if (pVM->selm.s.GuestGdtr.pGdt != RTRCPTR_MAX && pVM->selm.s.fGDTRangeRegistered)
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GuestGdtr.pGdt);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestLdt);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestTss);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Unregister shadow GDT/LDT/TSS write access handlers.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.paGdtRC);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.pvMonShwTssRC);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.pvLdtRC);
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * Execute state save operation.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * @returns VBox status code.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * @param pVM VM Handle.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * @param pSSM SSM operation handle.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsyncstatic DECLCALLBACK(int) selmR3Save(PVM pVM, PSSMHANDLE pSSM)
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * Save the basic bits - fortunately all the other things can be resynced on load.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync SSMR3PutSel(pSSM, pSelm->aHyperSel[SELM_HYPER_SEL_CS]);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync SSMR3PutSel(pSSM, pSelm->aHyperSel[SELM_HYPER_SEL_DS]);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync SSMR3PutSel(pSSM, pSelm->aHyperSel[SELM_HYPER_SEL_CS64]);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync SSMR3PutSel(pSSM, pSelm->aHyperSel[SELM_HYPER_SEL_CS64]); /* reserved for DS64. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync SSMR3PutSel(pSSM, pSelm->aHyperSel[SELM_HYPER_SEL_TSS]);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return SSMR3PutSel(pSSM, pSelm->aHyperSel[SELM_HYPER_SEL_TSS_TRAP08]);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Execute state load operation.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @returns VBox status code.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @param pVM VM Handle.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @param pSSM SSM operation handle.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @param u32Version Data layout version.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(int) selmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Validate version.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync AssertMsgFailed(("selmR3Load: Invalid version u32Version=%d!\n", u32Version));
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Do a reset.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* Get the monitoring flag. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync SSMR3GetBool(pSSM, &pVM->selm.s.fDisableMonitoring);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* Get the TSS state flag. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync SSMR3GetBool(pSSM, &pVM->selm.s.fSyncTSSRing0Stack);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Get the selectors.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* Copy the selectors; they will be checked during relocation. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pSelm->aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] = SelTSSTrap08;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Sync the GDT, LDT and TSS after loading the state.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Just to play save, we set the FFs to force syncing before
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * executing GC code.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * @returns VBox status code.
f687f34bd232be13744edbc0cc5155fa5d4540edvboxsync * @param pVM VM Handle.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * @param pSSM SSM operation handle.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsyncstatic DECLCALLBACK(int) selmR3LoadDone(PVM pVM, PSSMHANDLE pSSM)
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Don't do anything if it's a load failure.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Do the syncing if we're in protected mode.
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync * Flag everything for resync on next raw mode entry.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Updates the Guest GDT & LDT virtualization based on current CPU state.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @returns VBox status code.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @param pVM The VM to operate on.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync STAM_PROFILE_START(&pVM->selm.s.StatUpdateFromCPUM, a);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Always assume the best
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* If the GDT was changed, then make sure the LDT is checked too */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /** @todo only do this if the actual ldtr selector was changed; this is a bit excessive */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* Same goes for the TSS selector */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Get the GDTR and check if there is anything to do (there usually is).
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync STAM_PROFILE_STOP(&pVM->selm.s.StatUpdateFromCPUM, a);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * Read the Guest GDT.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * ASSUMES that the entire GDT is in memory.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync rc = PGMPhysSimpleReadGCPtr(pVM, pGDTE, GDTR.pGdt + sizeof(X86DESC), cbEffLimit + 1 - sizeof(X86DESC));
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Read it page by page.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Keep track of the last valid page and delay memsets and
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * adjust cbEffLimit to reflect the effective size. The latter
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * is something we do in the belief that the guest will probably
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * never actually commit the last page, thus allowing us to keep
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * our selectors in the high end of the GDT.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync RTGCPTR GCPtrSrc = (RTGCPTR)GDTR.pGdt + sizeof(X86DESC);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync uint8_t *pu8Dst = (uint8_t *)&pVM->selm.s.paGdtR3[1];
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync RTUINT cb = PAGE_SIZE - (GCPtrSrc & PAGE_OFFSET_MASK);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = PGMPhysSimpleReadGCPtr(pVM, pu8Dst, GCPtrSrc, cb);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync AssertReleaseMsgFailed(("Couldn't read GDT at %016RX64, rc=%Rrc!\n", GDTR.pGdt, rc));
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync STAM_PROFILE_STOP(&pVM->selm.s.StatUpdateFromCPUM, a);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* any invalid pages at the end? */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync cbEffLimit = pu8DstInvalid - (uint8_t *)pVM->selm.s.paGdtR3 - 1;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* If any GDTEs was invalidated, zero them. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync memset(pu8DstInvalid + cbEffLimit + 1, 0, pVM->selm.s.cbEffGuestGdtLimit - cbEffLimit);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* keep track of the effective limit. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync Log(("SELMR3UpdateFromCPUM: cbEffGuestGdtLimit=%#x -> %#x (actual %#x)\n",
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pVM->selm.s.cbEffGuestGdtLimit, cbEffLimit, GDTR.cbGdt));
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Check if the Guest GDT intrudes on our GDT entries.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** @todo we should try to minimize relocations by making sure our current selectors can be reused. */
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync PX86DESC pGDTE = (PX86DESC)((char *)pGDTEStart + GDTR.cbGdt + 1 - sizeof(X86DESC));
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync Log(("Internal SELM GDT conflict: use non-present entries\n"));
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync STAM_COUNTER_INC(&pVM->selm.s.StatScanForHyperSels);
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync /* We can reuse non-present entries */
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync aHyperSel[iGDT] = ((uintptr_t)pGDTE - (uintptr_t)pVM->selm.s.paGdtR3) / sizeof(X86DESC);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync aHyperSel[iGDT] = aHyperSel[iGDT] << X86_SEL_SHIFT;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync Log(("SELM: Found unused GDT %04X\n", aHyperSel[iGDT]));
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync AssertReleaseMsgFailed(("Internal SELM GDT conflict.\n"));
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync STAM_PROFILE_STOP(&pVM->selm.s.StatUpdateFromCPUM, a);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync aHyperSel[SELM_HYPER_SEL_CS] = SELM_HYPER_DEFAULT_SEL_CS;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync aHyperSel[SELM_HYPER_SEL_DS] = SELM_HYPER_DEFAULT_SEL_DS;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync aHyperSel[SELM_HYPER_SEL_CS64] = SELM_HYPER_DEFAULT_SEL_CS64;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync aHyperSel[SELM_HYPER_SEL_TSS] = SELM_HYPER_DEFAULT_SEL_TSS;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] = SELM_HYPER_DEFAULT_SEL_TSS_TRAP08;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Work thru the copied GDT entries adjusting them for correct virtualization.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync PX86DESC pGDTEEnd = (PX86DESC)((char *)pGDTE + cbEffLimit + 1 - sizeof(X86DESC));
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Code and data selectors are generally 1:1, with the
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * 'little' adjustment we do for DPL 0 selectors.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Hack for A-bit against Trap E on read-only GDT.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /** @todo Fix this by loading ds and cs before turning off WP. */
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * All DPL 0 code and data segments are squeezed into DPL 1.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * We're skipping conforming segments here because those
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * cannot give us any trouble.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync && (pGDTE->Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * System type selectors are marked not present.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Recompiler or special handling is required for these.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /** @todo what about interrupt gates and rawr0? */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* Next GDT entry. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Check if our hypervisor selectors were changed.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync if ( aHyperSel[SELM_HYPER_SEL_CS] != pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS]
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync || aHyperSel[SELM_HYPER_SEL_DS] != pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS]
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync || aHyperSel[SELM_HYPER_SEL_CS64] != pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS64]
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync || aHyperSel[SELM_HYPER_SEL_TSS] != pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS]
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync || aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] != pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08])
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* Reinitialize our hypervisor GDTs */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS] = aHyperSel[SELM_HYPER_SEL_CS];
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS] = aHyperSel[SELM_HYPER_SEL_DS];
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS64] = aHyperSel[SELM_HYPER_SEL_CS64];
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS] = aHyperSel[SELM_HYPER_SEL_TSS];
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] = aHyperSel[SELM_HYPER_SEL_TSS_TRAP08];
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync STAM_COUNTER_INC(&pVM->selm.s.StatHyperSelsChanged);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Do the relocation callbacks to let everyone update their hyper selector dependencies.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * (SELMR3Relocate will call selmR3SetupHyperGDTSelectors() for us.)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* We overwrote all entries above, so we have to save them again. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Adjust the cached GDT limit.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Any GDT entries which have been removed must be cleared.
#ifndef SELM_TRACK_GUEST_GDT_CHANGES
#ifdef SELM_TRACK_GUEST_GDT_CHANGES
Log(("SELMR3UpdateFromCPUM: Guest's GDT is changed to pGdt=%016RX64 cbGdt=%08X\n", GDTR.pGdt, GDTR.cbGdt));
rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GDTR.pGdt, GDTR.pGdt + GDTR.cbGdt /* already inclusive */,
return rc;
#ifdef SELM_TRACK_GUEST_LDT_CHANGES
return VINF_SUCCESS;
if ( !cbLdt
#ifdef SELM_TRACK_GUEST_LDT_CHANGES
return VINF_SUCCESS;
AssertMsg(RT_ALIGN(cbLdt + 1, sizeof(X86DESC)) == cbLdt + 1 && cbLdt <= 0xffff, ("cbLdt=%d\n", cbLdt));
#ifdef SELM_TRACK_GUEST_LDT_CHANGES
Log(("SELMR3UpdateFromCPUM: Guest LDT changed to from %RGv:%04x to %RGv:%04x. (GDTR=%016RX64:%04x)\n",
pVM->selm.s.GCPtrGuestLdt, pVM->selm.s.cbLdtLimit, GCPtrLdt, cbLdt, pVM->selm.s.GuestGdtr.pGdt, pVM->selm.s.GuestGdtr.cbGdt));
#ifdef DEBUG
rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtrLdt, GCPtrLdt + cbLdt /* already inclusive */,
/** @todo investigate the various cases where conflicts happen and try avoid them by enh. the instruction emulation. */
Log(("WARNING: Guest LDT (%RGv:%04x) conflicted with existing access range!! Assumes LDT is begin updated. (GDTR=%016RX64:%04x)\n",
return rc;
unsigned off;
while (cbLeft)
rc = PGMMapSetPage(pVM, GCPtrShadowLDT & PAGE_BASE_GC_MASK, PAGE_SIZE, X86_PTE_P | X86_PTE_A | X86_PTE_D);
pLDTE++;
return VINF_SUCCESS;
static DECLCALLBACK(int) selmR3GuestGDTWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
return VINF_PGM_HANDLER_DO_DEFAULT;
static DECLCALLBACK(int) selmR3GuestLDTWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
return VINF_PGM_HANDLER_DO_DEFAULT;
static DECLCALLBACK(int) selmR3GuestTSSWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
return VINF_PGM_HANDLER_DO_DEFAULT;
int rc;
return VINF_SUCCESS;
cbTss++;
/* Note: We should monitor the whole TSS to catch accesses to the virtual interrupt redirection bitmap, but
* that causes some problems and with Windows guests some overhead as the entire TSS is rather big (3 pages).
Log(("SELMR3UpdateFromCPUM: Guest's TSS is changed to pTss=%08X cbTss=%08X cbGuestTss\n", GCPtrTss, cbTss, pVM->selm.s.cbGuestTss));
|| !cbTss
return rc;
rc = PGMPhysSimpleReadGCPtr(pVM, &tss, GCPtrTss, RT_OFFSETOF(VBOXTSS, offIoBitmap) + sizeof(tss.offIoBitmap));
#ifdef LOG_ENABLED
rc = PGMPhysSimpleReadGCPtr(pVM, &pVM->selm.s.Tss.IntRedirBitmap, GCPtrTss + offRedirBitmap, sizeof(tss.IntRedirBitmap));
return VINF_SUCCESS;
#ifdef VBOX_STRICT
return VINF_SUCCESS;
Log(("SELMR3DebugCheck: limits have changed! new=%d old=%d\n", GDTR.cbGdt, pVM->selm.s.GuestGdtr.cbGdt));
pGDTE++;
return VINF_SUCCESS;
return VERR_INTERNAL_ERROR;
int rc = PGMPhysSimpleReadGCPtr(pVM, &LDTDesc, GDTR.pGdt + (SelLdt & X86_SEL_MASK), sizeof(LDTDesc));
return rc;
if (!cbLdt)
return VINF_SUCCESS;
AssertMsg(RT_ALIGN(cbLdt + 1, sizeof(X86DESC)) == cbLdt + 1 && cbLdt <= 0xffff, ("cbLdt=%d\n", cbLdt));
return VERR_INTERNAL_ERROR;
pLDTE++;
return VINF_SUCCESS;
#ifdef VBOX_STRICT
AssertMsg((SelTss & X86_SEL_MASK) == (pVM->selm.s.GCSelTss & X86_SEL_MASK), ("New TSS selector = %04X, old TSS selector = %04X\n", SelTss, pVM->selm.s.GCSelTss));
cbTss++;
int rc = PGMPhysSimpleReadGCPtr(pVM, &ESPR0, GCPtrGuestTSS + RT_OFFSETOF(VBOXTSS, esp0), sizeof(ESPR0));
rc = PGMPhysSimpleReadGCPtr(pVM, &SelSS0, GCPtrGuestTSS + RT_OFFSETOF(VBOXTSS, ss0), sizeof(SelSS0));
Assert(rc == VINF_SUCCESS || ((rc == VERR_PAGE_TABLE_NOT_PRESENT || rc == VERR_PAGE_NOT_PRESENT) && !(CPUMGetGuestEFlags(pVM) & X86_EFL_IF)));
return VERR_INVALID_SELECTOR;
int rc = PGMPhysSimpleReadGCPtr(pVM, (void *)&Desc, (RTGCPTR)(GDTR.pGdt + (SelLdt & X86_SEL_MASK)), sizeof(Desc));
return VERR_SELECTOR_NOT_PRESENT;
return VERR_SELECTOR_NOT_PRESENT;
return VERR_INVALID_SELECTOR;
if (ppvLdt)
return VINF_SUCCESS;
return VERR_INVALID_SELECTOR;
if ( (unsigned)(SelLdt & X86_SEL_MASK) < sizeof(X86DESC) /* the first selector is invalid, right? */
return VERR_INVALID_SELECTOR;
return rc;
return VERR_SELECTOR_NOT_PRESENT;
return VERR_INVALID_SELECTOR;
return VERR_INVALID_SELECTOR;
return rc;
return VINF_SUCCESS;
return VERR_INVALID_SELECTOR;
if ( (unsigned)(SelLdt & X86_SEL_MASK) < sizeof(X86DESC) /* the first selector is invalid, right? */
return VERR_INVALID_SELECTOR;
return rc;
return VERR_SELECTOR_NOT_PRESENT;
return VERR_INVALID_SELECTOR;
return VERR_INVALID_SELECTOR;
return rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
unsigned cch;
const char *psz;
selmR3FormatDescriptor(pVM->selm.s.paGdtR3[iGDT], iGDT << X86_SEL_SHIFT, &szOutput[0], sizeof(szOutput));
pHlp->pfnPrintf(pHlp, "%04x - read error rc=%Rrc GCAddr=%RGv\n", iGDT << X86_SEL_SHIFT, rc, GCPtrGDT);
pHlp->pfnPrintf(pHlp, "Shadow LDT (GCAddr=%RRv limit=%#x):\n", pVM->selm.s.pvLdtRC + pVM->selm.s.offLdtHyper, pVM->selm.s.cbLdtLimit);
selmR3FormatDescriptor(paLDT[iLDT], (iLDT << X86_SEL_SHIFT) | X86_SEL_LDT, &szOutput[0], sizeof(szOutput));
unsigned cbLdt;
selmR3FormatDescriptor(LdtE, (iLdt << X86_SEL_SHIFT) | X86_SEL_LDT, &szOutput[0], sizeof(szOutput));
pHlp->pfnPrintf(pHlp, "%04x - page not present (GCAddr=%RGv)\n", (iLdt << X86_SEL_SHIFT) | X86_SEL_LDT, GCPtrLdt);
pHlp->pfnPrintf(pHlp, "%04x - read error rc=%Rrc GCAddr=%RGv\n", (iLdt << X86_SEL_SHIFT) | X86_SEL_LDT, rc, GCPtrLdt);