VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMGC/SELMGC.cpp@ 23911

Last change on this file since 23911 was 19141, checked in by vboxsync, 16 years ago

Action flags breakup.
Fixed PGM saved state loading of 2.2.2 images.
Reduced hacks in PATM state loading (fixups).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 19.8 KB
Line 
1/* $Id: SELMGC.cpp 19141 2009-04-23 13:52:18Z vboxsync $ */
2/** @file
3 * SELM - The Selector Manager, Guest Context.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_SELM
26#include <VBox/selm.h>
27#include <VBox/mm.h>
28#include <VBox/em.h>
29#include <VBox/trpm.h>
30#include "SELMInternal.h"
31#include <VBox/vm.h>
32#include <VBox/vmm.h>
33#include <VBox/pgm.h>
34
35#include <VBox/param.h>
36#include <VBox/err.h>
37#include <VBox/log.h>
38#include <iprt/assert.h>
39#include <iprt/asm.h>
40
41
42/**
43 * Synchronizes one GDT entry (guest -> shadow).
44 *
45 * @returns VBox status code (appropriate for trap handling and GC return).
46 * @param pVM VM Handle.
47 * @param pRegFrame Trap register frame.
48 * @param iGDTEntry The GDT entry to sync.
49 */
50static int selmGCSyncGDTEntry(PVM pVM, PCPUMCTXCORE pRegFrame, unsigned iGDTEntry)
51{
52 PVMCPU pVCpu = VMMGetCpu0(pVM);
53
54 Log2(("GDT %04X LDTR=%04X\n", iGDTEntry, CPUMGetGuestLDTR(pVCpu)));
55
56 /*
57 * Validate the offset.
58 */
59 VBOXGDTR GdtrGuest;
60 CPUMGetGuestGDTR(pVCpu, &GdtrGuest);
61 unsigned offEntry = iGDTEntry * sizeof(X86DESC);
62 if ( iGDTEntry >= SELM_GDT_ELEMENTS
63 || offEntry > GdtrGuest.cbGdt)
64 return VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT;
65
66 /*
67 * Read the guest descriptor.
68 */
69 X86DESC Desc;
70 int rc = MMGCRamRead(pVM, &Desc, (uint8_t *)GdtrGuest.pGdt + offEntry, sizeof(X86DESC));
71 if (RT_FAILURE(rc))
72 return VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT;
73
74 /*
75 * Check for conflicts.
76 */
77 RTSEL Sel = iGDTEntry << X86_SEL_SHIFT;
78 Assert( !(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS] & ~X86_SEL_MASK)
79 && !(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS] & ~X86_SEL_MASK)
80 && !(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS64] & ~X86_SEL_MASK)
81 && !(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS] & ~X86_SEL_MASK)
82 && !(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] & ~X86_SEL_MASK));
83 if ( pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS] == Sel
84 || pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS] == Sel
85 || pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS64] == Sel
86 || pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS] == Sel
87 || pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] == Sel)
88 {
89 if (Desc.Gen.u1Present)
90 {
91 Log(("selmGCSyncGDTEntry: Sel=%d Desc=%.8Rhxs: detected conflict!!\n", Sel, &Desc));
92 return VINF_SELM_SYNC_GDT;
93 }
94 Log(("selmGCSyncGDTEntry: Sel=%d Desc=%.8Rhxs: potential conflict (still not present)!\n", Sel, &Desc));
95
96 /* Note: we can't continue below or else we'll change the shadow descriptor!! */
97 /* When the guest makes the selector present, then we'll do a GDT sync. */
98 return VINF_SUCCESS;
99 }
100
101 /*
102 * Code and data selectors are generally 1:1, with the
103 * 'little' adjustment we do for DPL 0 selectors.
104 */
105 PX86DESC pShadowDescr = &pVM->selm.s.paGdtRC[iGDTEntry];
106 if (Desc.Gen.u1DescType)
107 {
108 /*
109 * Hack for A-bit against Trap E on read-only GDT.
110 */
111 /** @todo Fix this by loading ds and cs before turning off WP. */
112 Desc.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
113
114 /*
115 * All DPL 0 code and data segments are squeezed into DPL 1.
116 *
117 * We're skipping conforming segments here because those
118 * cannot give us any trouble.
119 */
120 if ( Desc.Gen.u2Dpl == 0
121 && (Desc.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
122 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF) )
123 Desc.Gen.u2Dpl = 1;
124 }
125 else
126 {
127 /*
128 * System type selectors are marked not present.
129 * Recompiler or special handling is required for these.
130 */
131 /** @todo what about interrupt gates and rawr0? */
132 Desc.Gen.u1Present = 0;
133 }
134 //Log(("O: base=%08X limit=%08X attr=%04X\n", X86DESC_BASE(*pShadowDescr)), X86DESC_LIMIT(*pShadowDescr), (pShadowDescr->au32[1] >> 8) & 0xFFFF ));
135 //Log(("N: base=%08X limit=%08X attr=%04X\n", X86DESC_BASE(Desc)), X86DESC_LIMIT(Desc), (Desc.au32[1] >> 8) & 0xFFFF ));
136 *pShadowDescr = Desc;
137
138 /* Check if we change the LDT selector */
139 if (Sel == CPUMGetGuestLDTR(pVCpu)) /** @todo this isn't correct in two(+) ways! 1. It shouldn't be done until the LDTR is reloaded. 2. It caused the next instruction to be emulated. */
140 {
141 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_LDT);
142 return VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT;
143 }
144
145#ifdef LOG_ENABLED
146 if (Sel == (pRegFrame->cs & X86_SEL_MASK))
147 Log(("GDT write to selector in CS register %04X\n", pRegFrame->cs));
148 else if (Sel == (pRegFrame->ds & X86_SEL_MASK))
149 Log(("GDT write to selector in DS register %04X\n", pRegFrame->ds));
150 else if (Sel == (pRegFrame->es & X86_SEL_MASK))
151 Log(("GDT write to selector in ES register %04X\n", pRegFrame->es));
152 else if (Sel == (pRegFrame->fs & X86_SEL_MASK))
153 Log(("GDT write to selector in FS register %04X\n", pRegFrame->fs));
154 else if (Sel == (pRegFrame->gs & X86_SEL_MASK))
155 Log(("GDT write to selector in GS register %04X\n", pRegFrame->gs));
156 else if (Sel == (pRegFrame->ss & X86_SEL_MASK))
157 Log(("GDT write to selector in SS register %04X\n", pRegFrame->ss));
158#endif
159 return VINF_SUCCESS;
160}
161
162
163/**
164 * \#PF Virtual Handler callback for Guest write access to the Guest's own GDT.
165 *
166 * @returns VBox status code (appropriate for trap handling and GC return).
167 * @param pVM VM Handle.
168 * @param uErrorCode CPU Error code.
169 * @param pRegFrame Trap register frame.
170 * @param pvFault The fault address (cr2).
171 * @param pvRange The base address of the handled virtual range.
172 * @param offRange The offset of the access into this range.
173 * (If it's a EIP range this's the EIP, if not it's pvFault.)
174 */
175VMMRCDECL(int) selmRCGuestGDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
176{
177 PVMCPU pVCpu = VMMGetCpu0(pVM);
178
179 LogFlow(("selmRCGuestGDTWriteHandler errcode=%x fault=%RGv offRange=%08x\n", (uint32_t)uErrorCode, pvFault, offRange));
180
181 /*
182 * First check if this is the LDT entry.
183 * LDT updates are problemous since an invalid LDT entry will cause trouble during worldswitch.
184 */
185 int rc;
186 if (CPUMGetGuestLDTR(pVCpu) / sizeof(X86DESC) == offRange / sizeof(X86DESC))
187 {
188 Log(("LDTR selector change -> fall back to HC!!\n"));
189 rc = VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT;
190 /** @todo We're not handling changed to the selectors in LDTR and TR correctly at all.
191 * We should ignore any changes to those and sync them only when they are loaded by the guest! */
192 }
193 else
194 {
195 /*
196 * Attempt to emulate the instruction and sync the affected entries.
197 */
198 /** @todo should check if any affected selectors are loaded. */
199 uint32_t cb;
200 rc = EMInterpretInstruction(pVM, pVCpu, pRegFrame, (RTGCPTR)(RTRCUINTPTR)pvFault, &cb);
201 if (RT_SUCCESS(rc) && cb)
202 {
203 unsigned iGDTE1 = offRange / sizeof(X86DESC);
204 int rc2 = selmGCSyncGDTEntry(pVM, pRegFrame, iGDTE1);
205 if (rc2 == VINF_SUCCESS)
206 {
207 Assert(cb);
208 unsigned iGDTE2 = (offRange + cb - 1) / sizeof(X86DESC);
209 if (iGDTE1 != iGDTE2)
210 rc2 = selmGCSyncGDTEntry(pVM, pRegFrame, iGDTE2);
211 if (rc2 == VINF_SUCCESS)
212 {
213 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestGDTHandled);
214 return rc;
215 }
216 }
217 if (rc == VINF_SUCCESS || RT_FAILURE(rc2))
218 rc = rc2;
219 }
220 else
221 {
222 Assert(RT_FAILURE(rc));
223 if (rc == VERR_EM_INTERPRETER)
224 rc = VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT;
225 }
226 }
227 if ( rc != VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT
228 && rc != VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT)
229 {
230 /* Not necessary when we need to go back to the host context to sync the LDT or TSS. */
231 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_GDT);
232 }
233 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestGDTUnhandled);
234 return rc;
235}
236
237
238/**
239 * \#PF Virtual Handler callback for Guest write access to the Guest's own LDT.
240 *
241 * @returns VBox status code (appropriate for trap handling and GC return).
242 * @param pVM VM Handle.
243 * @param uErrorCode CPU Error code.
244 * @param pRegFrame Trap register frame.
245 * @param pvFault The fault address (cr2).
246 * @param pvRange The base address of the handled virtual range.
247 * @param offRange The offset of the access into this range.
248 * (If it's a EIP range this's the EIP, if not it's pvFault.)
249 */
250VMMRCDECL(int) selmRCGuestLDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
251{
252 /** @todo To be implemented. */
253 ////LogCom(("selmRCGuestLDTWriteHandler: eip=%08X pvFault=%RGv pvRange=%RGv\r\n", pRegFrame->eip, pvFault, pvRange));
254
255 VMCPU_FF_SET(VMMGetCpu0(pVM), VMCPU_FF_SELM_SYNC_LDT);
256 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestLDT);
257 return VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT;
258}
259
260
261/**
262 * Read wrapper used by selmRCGuestTSSWriteHandler.
263 * @returns VBox status code (appropriate for trap handling and GC return).
264 * @param pVM The VM handle
265 * @param pvDst Where to put the bits we read.
266 * @param pvSrc Guest address to read from.
267 * @param cb The number of bytes to read.
268 */
269DECLINLINE(int) selmRCReadTssBits(PVM pVM, void *pvDst, void const *pvSrc, size_t cb)
270{
271 PVMCPU pVCpu = VMMGetCpu0(pVM);
272
273 int rc = MMGCRamRead(pVM, pvDst, (void *)pvSrc, cb);
274 if (RT_SUCCESS(rc))
275 return VINF_SUCCESS;
276
277 /** @todo use different fallback? */
278 rc = PGMPrefetchPage(pVCpu, (uintptr_t)pvSrc);
279 AssertMsg(rc == VINF_SUCCESS, ("PGMPrefetchPage %p failed with %Rrc\n", &pvSrc, rc));
280 if (rc == VINF_SUCCESS)
281 {
282 rc = MMGCRamRead(pVM, pvDst, (void *)pvSrc, cb);
283 AssertMsg(rc == VINF_SUCCESS, ("MMGCRamRead %p failed with %Rrc\n", &pvSrc, rc));
284 }
285 return rc;
286}
287
288/**
289 * \#PF Virtual Handler callback for Guest write access to the Guest's own current TSS.
290 *
291 * @returns VBox status code (appropriate for trap handling and GC return).
292 * @param pVM VM Handle.
293 * @param uErrorCode CPU Error code.
294 * @param pRegFrame Trap register frame.
295 * @param pvFault The fault address (cr2).
296 * @param pvRange The base address of the handled virtual range.
297 * @param offRange The offset of the access into this range.
298 * (If it's a EIP range this's the EIP, if not it's pvFault.)
299 */
300VMMRCDECL(int) selmRCGuestTSSWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
301{
302 PVMCPU pVCpu = VMMGetCpu0(pVM);
303
304 LogFlow(("selmRCGuestTSSWriteHandler errcode=%x fault=%RGv offRange=%08x\n", (uint32_t)uErrorCode, pvFault, offRange));
305
306 /*
307 * Try emulate the access.
308 */
309 uint32_t cb;
310 int rc = EMInterpretInstruction(pVM, pVCpu, pRegFrame, (RTGCPTR)(RTRCUINTPTR)pvFault, &cb);
311 if (RT_SUCCESS(rc) && cb)
312 {
313 rc = VINF_SUCCESS;
314
315 /*
316 * If it's on the same page as the esp0 and ss0 fields or actually one of them,
317 * then check if any of these has changed.
318 */
319 PCVBOXTSS pGuestTss = (PVBOXTSS)pVM->selm.s.GCPtrGuestTss;
320 if ( PAGE_ADDRESS(&pGuestTss->esp0) == PAGE_ADDRESS(&pGuestTss->padding_ss0)
321 && PAGE_ADDRESS(&pGuestTss->esp0) == PAGE_ADDRESS((uint8_t *)pGuestTss + offRange)
322 && ( pGuestTss->esp0 != pVM->selm.s.Tss.esp1
323 || pGuestTss->ss0 != (pVM->selm.s.Tss.ss1 & ~1)) /* undo raw-r0 */
324 )
325 {
326 Log(("selmRCGuestTSSWriteHandler: R0 stack: %RTsel:%RGv -> %RTsel:%RGv\n",
327 (RTSEL)(pVM->selm.s.Tss.ss1 & ~1), (RTGCPTR)pVM->selm.s.Tss.esp1, (RTSEL)pGuestTss->ss0, (RTGCPTR)pGuestTss->esp0));
328 pVM->selm.s.Tss.esp1 = pGuestTss->esp0;
329 pVM->selm.s.Tss.ss1 = pGuestTss->ss0 | 1;
330 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSHandledChanged);
331 }
332 /* Handle misaligned TSS in a safe manner (just in case). */
333 else if ( offRange >= RT_UOFFSETOF(VBOXTSS, esp0)
334 && offRange < RT_UOFFSETOF(VBOXTSS, padding_ss0))
335 {
336 struct
337 {
338 uint32_t esp0;
339 uint16_t ss0;
340 uint16_t padding_ss0;
341 } s;
342 AssertCompileSize(s, 8);
343 rc = selmRCReadTssBits(pVM, &s, &pGuestTss->esp0, sizeof(s));
344 if ( rc == VINF_SUCCESS
345 && ( s.esp0 != pVM->selm.s.Tss.esp1
346 || s.ss0 != (pVM->selm.s.Tss.ss1 & ~1)) /* undo raw-r0 */
347 )
348 {
349 Log(("selmRCGuestTSSWriteHandler: R0 stack: %RTsel:%RGv -> %RTsel:%RGv [x-page]\n",
350 (RTSEL)(pVM->selm.s.Tss.ss1 & ~1), (RTGCPTR)pVM->selm.s.Tss.esp1, (RTSEL)s.ss0, (RTGCPTR)s.esp0));
351 pVM->selm.s.Tss.esp1 = s.esp0;
352 pVM->selm.s.Tss.ss1 = s.ss0 | 1;
353 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSHandledChanged);
354 }
355 }
356
357 /*
358 * If VME is enabled we need to check if the interrupt redirection bitmap
359 * needs updating.
360 */
361 if ( offRange >= RT_UOFFSETOF(VBOXTSS, offIoBitmap)
362 && (CPUMGetGuestCR4(pVCpu) & X86_CR4_VME))
363 {
364 if (offRange - RT_UOFFSETOF(VBOXTSS, offIoBitmap) < sizeof(pGuestTss->offIoBitmap))
365 {
366 uint16_t offIoBitmap = pGuestTss->offIoBitmap;
367 if (offIoBitmap != pVM->selm.s.offGuestIoBitmap)
368 {
369 Log(("TSS offIoBitmap changed: old=%#x new=%#x -> resync in ring-3\n", pVM->selm.s.offGuestIoBitmap, offIoBitmap));
370 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
371 VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
372 }
373 else
374 Log(("TSS offIoBitmap: old=%#x new=%#x [unchanged]\n", pVM->selm.s.offGuestIoBitmap, offIoBitmap));
375 }
376 else
377 {
378 /** @todo not sure how the partial case is handled; probably not allowed */
379 uint32_t offIntRedirBitmap = pVM->selm.s.offGuestIoBitmap - sizeof(pVM->selm.s.Tss.IntRedirBitmap);
380 if ( offIntRedirBitmap <= offRange
381 && offIntRedirBitmap + sizeof(pVM->selm.s.Tss.IntRedirBitmap) >= offRange + cb
382 && offIntRedirBitmap + sizeof(pVM->selm.s.Tss.IntRedirBitmap) <= pVM->selm.s.cbGuestTss)
383 {
384 Log(("TSS IntRedirBitmap Changed: offIoBitmap=%x offIntRedirBitmap=%x cbTSS=%x offRange=%x cb=%x\n",
385 pVM->selm.s.offGuestIoBitmap, offIntRedirBitmap, pVM->selm.s.cbGuestTss, offRange, cb));
386
387 /** @todo only update the changed part. */
388 for (uint32_t i = 0; i < sizeof(pVM->selm.s.Tss.IntRedirBitmap) / 8; i++)
389 {
390 rc = selmRCReadTssBits(pVM, &pVM->selm.s.Tss.IntRedirBitmap[i * 8],
391 (uint8_t *)pGuestTss + offIntRedirBitmap + i * 8, 8);
392 if (rc != VINF_SUCCESS)
393 break;
394 }
395 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSRedir);
396 }
397 }
398 }
399
400 /* Return to ring-3 for a full resync if any of the above fails... (?) */
401 if (rc != VINF_SUCCESS)
402 {
403 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
404 VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
405 if (RT_SUCCESS(rc))
406 rc = VINF_SUCCESS;
407 }
408
409 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSHandled);
410 }
411 else
412 {
413 Assert(RT_FAILURE(rc));
414 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
415 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSUnhandled);
416 if (rc == VERR_EM_INTERPRETER)
417 rc = VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT;
418 }
419 return rc;
420}
421
422
423/**
424 * \#PF Virtual Handler callback for Guest write access to the VBox shadow GDT.
425 *
426 * @returns VBox status code (appropriate for trap handling and GC return).
427 * @param pVM VM Handle.
428 * @param uErrorCode CPU Error code.
429 * @param pRegFrame Trap register frame.
430 * @param pvFault The fault address (cr2).
431 * @param pvRange The base address of the handled virtual range.
432 * @param offRange The offset of the access into this range.
433 * (If it's a EIP range this's the EIP, if not it's pvFault.)
434 */
435VMMRCDECL(int) selmRCShadowGDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
436{
437 LogRel(("FATAL ERROR: selmRCShadowGDTWriteHandler: eip=%08X pvFault=%RGv pvRange=%RGv\r\n", pRegFrame->eip, pvFault, pvRange));
438 return VERR_SELM_SHADOW_GDT_WRITE;
439}
440
441
442/**
443 * \#PF Virtual Handler callback for Guest write access to the VBox shadow LDT.
444 *
445 * @returns VBox status code (appropriate for trap handling and GC return).
446 * @param pVM VM Handle.
447 * @param uErrorCode CPU Error code.
448 * @param pRegFrame Trap register frame.
449 * @param pvFault The fault address (cr2).
450 * @param pvRange The base address of the handled virtual range.
451 * @param offRange The offset of the access into this range.
452 * (If it's a EIP range this's the EIP, if not it's pvFault.)
453 */
454VMMRCDECL(int) selmRCShadowLDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
455{
456 LogRel(("FATAL ERROR: selmRCShadowLDTWriteHandler: eip=%08X pvFault=%RGv pvRange=%RGv\r\n", pRegFrame->eip, pvFault, pvRange));
457 Assert((RTRCPTR)pvFault >= pVM->selm.s.pvLdtRC && (RTRCUINTPTR)pvFault < (RTRCUINTPTR)pVM->selm.s.pvLdtRC + 65536 + PAGE_SIZE);
458 return VERR_SELM_SHADOW_LDT_WRITE;
459}
460
461
462/**
463 * \#PF Virtual Handler callback for Guest write access to the VBox shadow TSS.
464 *
465 * @returns VBox status code (appropriate for trap handling and GC return).
466 * @param pVM VM Handle.
467 * @param uErrorCode CPU Error code.
468 * @param pRegFrame Trap register frame.
469 * @param pvFault The fault address (cr2).
470 * @param pvRange The base address of the handled virtual range.
471 * @param offRange The offset of the access into this range.
472 * (If it's a EIP range this's the EIP, if not it's pvFault.)
473 */
474VMMRCDECL(int) selmRCShadowTSSWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
475{
476 LogRel(("FATAL ERROR: selmRCShadowTSSWriteHandler: eip=%08X pvFault=%RGv pvRange=%RGv\r\n", pRegFrame->eip, pvFault, pvRange));
477 return VERR_SELM_SHADOW_TSS_WRITE;
478}
479
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette