VirtualBox

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

Last change on this file since 13813 was 13577, checked in by vboxsync, 16 years ago

#1865: SELM.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 19.0 KB
Line 
1/* $Id: SELMGC.cpp 13577 2008-10-27 13:53:04Z 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/pgm.h>
33
34#include <VBox/param.h>
35#include <VBox/err.h>
36#include <VBox/log.h>
37#include <iprt/assert.h>
38#include <iprt/asm.h>
39
40
41/**
42 * Synchronizes one GDT entry (guest -> shadow).
43 *
44 * @returns VBox status code (appropriate for trap handling and GC return).
45 * @param pVM VM Handle.
46 * @param pRegFrame Trap register frame.
47 * @param iGDTEntry The GDT entry to sync.
48 */
49static int selmGCSyncGDTEntry(PVM pVM, PCPUMCTXCORE pRegFrame, unsigned iGDTEntry)
50{
51 Log2(("GDT %04X LDTR=%04X\n", iGDTEntry, CPUMGetGuestLDTR(pVM)));
52
53 /*
54 * Validate the offset.
55 */
56 VBOXGDTR GdtrGuest;
57 CPUMGetGuestGDTR(pVM, &GdtrGuest);
58 unsigned offEntry = iGDTEntry * sizeof(X86DESC);
59 if ( iGDTEntry >= SELM_GDT_ELEMENTS
60 || offEntry > GdtrGuest.cbGdt)
61 return VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT;
62
63 /*
64 * Read the guest descriptor.
65 */
66 X86DESC Desc;
67 int rc = MMGCRamRead(pVM, &Desc, (uint8_t *)GdtrGuest.pGdt + offEntry, sizeof(X86DESC));
68 if (VBOX_FAILURE(rc))
69 return VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT;
70
71 /*
72 * Check for conflicts.
73 */
74 RTSEL Sel = iGDTEntry << X86_SEL_SHIFT;
75 Assert( !(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS] & ~X86_SEL_MASK)
76 && !(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS] & ~X86_SEL_MASK)
77 && !(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS64] & ~X86_SEL_MASK)
78 && !(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS] & ~X86_SEL_MASK)
79 && !(pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] & ~X86_SEL_MASK));
80 if ( pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS] == Sel
81 || pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS] == Sel
82 || pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS64] == Sel
83 || pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS] == Sel
84 || pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08] == Sel)
85 {
86 if (Desc.Gen.u1Present)
87 {
88 Log(("selmGCSyncGDTEntry: Sel=%d Desc=%.8Vhxs: detected conflict!!\n", Sel, &Desc));
89 return VINF_SELM_SYNC_GDT;
90 }
91 Log(("selmGCSyncGDTEntry: Sel=%d Desc=%.8Vhxs: potential conflict (still not present)!\n", Sel, &Desc));
92
93 /* Note: we can't continue below or else we'll change the shadow descriptor!! */
94 /* When the guest makes the selector present, then we'll do a GDT sync. */
95 return VINF_SUCCESS;
96 }
97
98 /*
99 * Code and data selectors are generally 1:1, with the
100 * 'little' adjustment we do for DPL 0 selectors.
101 */
102 PX86DESC pShadowDescr = &pVM->selm.s.paGdtRC[iGDTEntry];
103 if (Desc.Gen.u1DescType)
104 {
105 /*
106 * Hack for A-bit against Trap E on read-only GDT.
107 */
108 /** @todo Fix this by loading ds and cs before turning off WP. */
109 Desc.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
110
111 /*
112 * All DPL 0 code and data segments are squeezed into DPL 1.
113 *
114 * We're skipping conforming segments here because those
115 * cannot give us any trouble.
116 */
117 if ( Desc.Gen.u2Dpl == 0
118 && (Desc.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
119 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF) )
120 Desc.Gen.u2Dpl = 1;
121 }
122 else
123 {
124 /*
125 * System type selectors are marked not present.
126 * Recompiler or special handling is required for these.
127 */
128 /** @todo what about interrupt gates and rawr0? */
129 Desc.Gen.u1Present = 0;
130 }
131 //Log(("O: base=%08X limit=%08X attr=%04X\n", X86DESC_BASE(*pShadowDescr)), X86DESC_LIMIT(*pShadowDescr), (pShadowDescr->au32[1] >> 8) & 0xFFFF ));
132 //Log(("N: base=%08X limit=%08X attr=%04X\n", X86DESC_BASE(Desc)), X86DESC_LIMIT(Desc), (Desc.au32[1] >> 8) & 0xFFFF ));
133 *pShadowDescr = Desc;
134
135 /* Check if we change the LDT selector */
136 if (Sel == CPUMGetGuestLDTR(pVM))
137 {
138 VM_FF_SET(pVM, VM_FF_SELM_SYNC_LDT);
139 return VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT;
140 }
141
142 /* Or the TR selector */
143 if (Sel == CPUMGetGuestTR(pVM))
144 {
145 VM_FF_SET(pVM, VM_FF_SELM_SYNC_TSS);
146 return VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT;
147 }
148
149#ifdef VBOX_STRICT
150 if (Sel == (pRegFrame->cs & X86_SEL_MASK))
151 Log(("GDT write to selector in CS register %04X\n", pRegFrame->cs));
152 else if (Sel == (pRegFrame->ds & X86_SEL_MASK))
153 Log(("GDT write to selector in DS register %04X\n", pRegFrame->ds));
154 else if (Sel == (pRegFrame->es & X86_SEL_MASK))
155 Log(("GDT write to selector in ES register %04X\n", pRegFrame->es));
156 else if (Sel == (pRegFrame->fs & X86_SEL_MASK))
157 Log(("GDT write to selector in FS register %04X\n", pRegFrame->fs));
158 else if (Sel == (pRegFrame->gs & X86_SEL_MASK))
159 Log(("GDT write to selector in GS register %04X\n", pRegFrame->gs));
160 else if (Sel == (pRegFrame->ss & X86_SEL_MASK))
161 Log(("GDT write to selector in SS register %04X\n", pRegFrame->ss));
162#endif
163 return VINF_SUCCESS;
164}
165
166
167/**
168 * \#PF Virtual Handler callback for Guest write access to the Guest's own GDT.
169 *
170 * @returns VBox status code (appropriate for trap handling and GC return).
171 * @param pVM VM Handle.
172 * @param uErrorCode CPU Error code.
173 * @param pRegFrame Trap register frame.
174 * @param pvFault The fault address (cr2).
175 * @param pvRange The base address of the handled virtual range.
176 * @param offRange The offset of the access into this range.
177 * (If it's a EIP range this's the EIP, if not it's pvFault.)
178 */
179VMMRCDECL(int) selmRCGuestGDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
180{
181 LogFlow(("selmRCGuestGDTWriteHandler errcode=%x fault=%VGv offRange=%08x\n", (uint32_t)uErrorCode, pvFault, offRange));
182
183 /*
184 * First check if this is the LDT entry.
185 * LDT updates are problemous since an invalid LDT entry will cause trouble during worldswitch.
186 */
187 int rc;
188 if (CPUMGetGuestLDTR(pVM) / sizeof(X86DESC) == offRange / sizeof(X86DESC))
189 {
190 Log(("LDTR selector change -> fall back to HC!!\n"));
191 rc = VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT;
192 /** @todo We're not handling changed to the selectors in LDTR and TR correctly at all.
193 * We should ignore any changes to those and sync them only when they are loaded by the guest! */
194 }
195 else
196 {
197 /*
198 * Attempt to emulate the instruction and sync the affected entries.
199 */
200 /** @todo should check if any affected selectors are loaded. */
201 uint32_t cb;
202 rc = EMInterpretInstruction(pVM, pRegFrame, (RTGCPTR)(RTRCUINTPTR)pvFault, &cb);
203 if (VBOX_SUCCESS(rc) && cb)
204 {
205 unsigned iGDTE1 = offRange / sizeof(X86DESC);
206 int rc2 = selmGCSyncGDTEntry(pVM, pRegFrame, iGDTE1);
207 if (rc2 == VINF_SUCCESS)
208 {
209 Assert(cb);
210 unsigned iGDTE2 = (offRange + cb - 1) / sizeof(X86DESC);
211 if (iGDTE1 != iGDTE2)
212 rc2 = selmGCSyncGDTEntry(pVM, pRegFrame, iGDTE2);
213 if (rc2 == VINF_SUCCESS)
214 {
215 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestGDTHandled);
216 return rc;
217 }
218 }
219 if (rc == VINF_SUCCESS || VBOX_FAILURE(rc2))
220 rc = rc2;
221 }
222 else
223 {
224 Assert(VBOX_FAILURE(rc));
225 if (rc == VERR_EM_INTERPRETER)
226 rc = VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT;
227 }
228 }
229 if ( rc != VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT
230 && rc != VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT)
231 {
232 /* Not necessary when we need to go back to the host context to sync the LDT or TSS. */
233 VM_FF_SET(pVM, VM_FF_SELM_SYNC_GDT);
234 }
235 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestGDTUnhandled);
236 return rc;
237}
238
239
240/**
241 * \#PF Virtual Handler callback for Guest write access to the Guest's own LDT.
242 *
243 * @returns VBox status code (appropriate for trap handling and GC return).
244 * @param pVM VM Handle.
245 * @param uErrorCode CPU Error code.
246 * @param pRegFrame Trap register frame.
247 * @param pvFault The fault address (cr2).
248 * @param pvRange The base address of the handled virtual range.
249 * @param offRange The offset of the access into this range.
250 * (If it's a EIP range this's the EIP, if not it's pvFault.)
251 */
252VMMRCDECL(int) selmRCGuestLDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
253{
254 /** @todo To be implemented. */
255 ////LogCom(("selmRCGuestLDTWriteHandler: eip=%08X pvFault=%VGv pvRange=%VGv\r\n", pRegFrame->eip, pvFault, pvRange));
256
257 VM_FF_SET(pVM, VM_FF_SELM_SYNC_LDT);
258 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestLDT);
259 return VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT;
260}
261
262
263/**
264 * \#PF Virtual Handler callback for Guest write access to the Guest's own current TSS.
265 *
266 * @returns VBox status code (appropriate for trap handling and GC return).
267 * @param pVM VM Handle.
268 * @param uErrorCode CPU Error code.
269 * @param pRegFrame Trap register frame.
270 * @param pvFault The fault address (cr2).
271 * @param pvRange The base address of the handled virtual range.
272 * @param offRange The offset of the access into this range.
273 * (If it's a EIP range this's the EIP, if not it's pvFault.)
274 */
275VMMRCDECL(int) selmRCGuestTSSWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
276{
277 LogFlow(("selmRCGuestTSSWriteHandler errcode=%x fault=%VGv offRange=%08x\n", (uint32_t)uErrorCode, pvFault, offRange));
278
279 /*
280 * Try emulate the access and compare the R0 ss:esp with the shadow tss values.
281 *
282 * Note, that it's safe to access the TSS after a successfull instruction emulation,
283 * even if the stuff that was changed wasn't the ss0 or esp0 bits. The CPU insists
284 * on the TSS being all one physical page, so ASSUMING that we're not trapping
285 * I/O map accesses this is safe.
286 */
287 uint32_t cb;
288 int rc = EMInterpretInstruction(pVM, pRegFrame, (RTGCPTR)(RTRCUINTPTR)pvFault, &cb);
289 if (VBOX_SUCCESS(rc) && cb)
290 {
291 PCVBOXTSS pGuestTSS = (PVBOXTSS)pVM->selm.s.GCPtrGuestTss;
292 if ( pGuestTSS->esp0 != pVM->selm.s.Tss.esp1
293 || pGuestTSS->ss0 != (pVM->selm.s.Tss.ss1 & ~1)) /* undo raw-r0 */
294 {
295 Log(("selmRCGuestTSSWriteHandler: R0 stack: %RTsel:%VGv -> %RTsel:%VGv\n",
296 (RTSEL)(pVM->selm.s.Tss.ss1 & ~1), pVM->selm.s.Tss.esp1, (RTSEL)pGuestTSS->ss0, pGuestTSS->esp0));
297 pVM->selm.s.Tss.esp1 = pGuestTSS->esp0;
298 pVM->selm.s.Tss.ss1 = pGuestTSS->ss0 | 1;
299 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSHandledChanged);
300 }
301 if (CPUMGetGuestCR4(pVM) & X86_CR4_VME)
302 {
303 uint32_t offIntRedirBitmap = pGuestTSS->offIoBitmap - sizeof(pVM->selm.s.Tss.IntRedirBitmap);
304
305 /** @todo not sure how the partial case is handled; probably not allowed */
306 if ( offIntRedirBitmap <= offRange
307 && offIntRedirBitmap + sizeof(pVM->selm.s.Tss.IntRedirBitmap) >= offRange + cb
308 && offIntRedirBitmap + sizeof(pVM->selm.s.Tss.IntRedirBitmap) <= pVM->selm.s.cbGuestTss)
309 {
310 Log(("offIoBitmap=%x offIntRedirBitmap=%x cbTSS=%x\n", pGuestTSS->offIoBitmap, offIntRedirBitmap, pVM->selm.s.cbGuestTss));
311 /** @todo only update the changed part. */
312 for (uint32_t i = 0; i < sizeof(pVM->selm.s.Tss.IntRedirBitmap) / 8;i++)
313 {
314 rc = MMGCRamRead(pVM, &pVM->selm.s.Tss.IntRedirBitmap[i * 8], (uint8_t *)pGuestTSS + offIntRedirBitmap + i * 8, 8);
315 if (VBOX_FAILURE(rc))
316 {
317 /* Shadow page table might be out of sync */
318 rc = PGMPrefetchPage(pVM, (RTGCPTR)(RTRCUINTPTR)((uint8_t *)pGuestTSS + offIntRedirBitmap + i*8));
319 if (VBOX_FAILURE(rc))
320 {
321 AssertMsg(rc == VINF_SUCCESS, ("PGMPrefetchPage %VGv failed with %Vrc\n", (uint8_t *)pGuestTSS + offIntRedirBitmap + i*8, rc));
322 break;
323 }
324 rc = MMGCRamRead(pVM, &pVM->selm.s.Tss.IntRedirBitmap[i * 8], (uint8_t *)pGuestTSS + offIntRedirBitmap + i * 8, 8);
325 }
326 AssertMsg(rc == VINF_SUCCESS, ("MMGCRamRead %VGv failed with %Vrc\n", (uint8_t *)pGuestTSS + offIntRedirBitmap + i * 8, rc));
327 }
328 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSRedir);
329 }
330 }
331 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSHandled);
332 }
333 else
334 {
335 Assert(VBOX_FAILURE(rc));
336 VM_FF_SET(pVM, VM_FF_SELM_SYNC_TSS);
337 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSUnhandled);
338 if (rc == VERR_EM_INTERPRETER)
339 rc = VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT;
340 }
341 return rc;
342}
343
344
345/**
346 * \#PF Virtual Handler callback for Guest write access to the VBox shadow GDT.
347 *
348 * @returns VBox status code (appropriate for trap handling and GC return).
349 * @param pVM VM Handle.
350 * @param uErrorCode CPU Error code.
351 * @param pRegFrame Trap register frame.
352 * @param pvFault The fault address (cr2).
353 * @param pvRange The base address of the handled virtual range.
354 * @param offRange The offset of the access into this range.
355 * (If it's a EIP range this's the EIP, if not it's pvFault.)
356 */
357VMMRCDECL(int) selmRCShadowGDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
358{
359 LogRel(("FATAL ERROR: selmRCShadowGDTWriteHandler: eip=%08X pvFault=%VGv pvRange=%VGv\r\n", pRegFrame->eip, pvFault, pvRange));
360 return VERR_SELM_SHADOW_GDT_WRITE;
361}
362
363
364/**
365 * \#PF Virtual Handler callback for Guest write access to the VBox shadow LDT.
366 *
367 * @returns VBox status code (appropriate for trap handling and GC return).
368 * @param pVM VM Handle.
369 * @param uErrorCode CPU Error code.
370 * @param pRegFrame Trap register frame.
371 * @param pvFault The fault address (cr2).
372 * @param pvRange The base address of the handled virtual range.
373 * @param offRange The offset of the access into this range.
374 * (If it's a EIP range this's the EIP, if not it's pvFault.)
375 */
376VMMRCDECL(int) selmRCShadowLDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
377{
378 LogRel(("FATAL ERROR: selmRCShadowLDTWriteHandler: eip=%08X pvFault=%VGv pvRange=%VGv\r\n", pRegFrame->eip, pvFault, pvRange));
379 Assert((RTRCPTR)pvFault >= pVM->selm.s.pvLdtRC && (RTRCUINTPTR)pvFault < (RTRCUINTPTR)pVM->selm.s.pvLdtRC + 65536 + PAGE_SIZE);
380 return VERR_SELM_SHADOW_LDT_WRITE;
381}
382
383
384/**
385 * \#PF Virtual Handler callback for Guest write access to the VBox shadow TSS.
386 *
387 * @returns VBox status code (appropriate for trap handling and GC return).
388 * @param pVM VM Handle.
389 * @param uErrorCode CPU Error code.
390 * @param pRegFrame Trap register frame.
391 * @param pvFault The fault address (cr2).
392 * @param pvRange The base address of the handled virtual range.
393 * @param offRange The offset of the access into this range.
394 * (If it's a EIP range this's the EIP, if not it's pvFault.)
395 */
396VMMRCDECL(int) selmRCShadowTSSWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
397{
398 LogRel(("FATAL ERROR: selmRCShadowTSSWriteHandler: eip=%08X pvFault=%VGv pvRange=%VGv\r\n", pRegFrame->eip, pvFault, pvRange));
399 return VERR_SELM_SHADOW_TSS_WRITE;
400}
401
402
403/**
404 * Gets ss:esp for ring1 in main Hypervisor's TSS.
405 *
406 * @returns VBox status code.
407 * @param pVM VM Handle.
408 * @param pSS Ring1 SS register value.
409 * @param pEsp Ring1 ESP register value.
410 */
411VMMRCDECL(int) SELMGCGetRing1Stack(PVM pVM, uint32_t *pSS, uint32_t *pEsp)
412{
413 if (pVM->selm.s.fSyncTSSRing0Stack)
414 {
415 uint8_t * GCPtrGuestTss = (uint8_t *)(uintptr_t)pVM->selm.s.GCPtrGuestTss;
416 bool fTriedAlready = false;
417 int rc;
418 VBOXTSS tss;
419
420 Assert(pVM->selm.s.GCPtrGuestTss && pVM->selm.s.cbMonitoredGuestTss);
421
422l_tryagain:
423 rc = MMGCRamRead(pVM, &tss.ss0, GCPtrGuestTss + RT_OFFSETOF(VBOXTSS, ss0), sizeof(tss.ss0));
424 rc |= MMGCRamRead(pVM, &tss.esp0, GCPtrGuestTss + RT_OFFSETOF(VBOXTSS, esp0), sizeof(tss.esp0));
425#ifdef DEBUG
426 rc |= MMGCRamRead(pVM, &tss.offIoBitmap, GCPtrGuestTss + RT_OFFSETOF(VBOXTSS, offIoBitmap), sizeof(tss.offIoBitmap));
427#endif
428
429 if (VBOX_FAILURE(rc))
430 {
431 if (!fTriedAlready)
432 {
433 /* Shadow page might be out of sync. Sync and try again */
434 /** @todo might cross page boundary */
435 fTriedAlready = true;
436 rc = PGMPrefetchPage(pVM, (RTGCPTR)(uintptr_t)GCPtrGuestTss);
437 if (rc != VINF_SUCCESS)
438 return rc;
439 goto l_tryagain;
440 }
441 AssertMsgFailed(("Unable to read TSS structure at %RRv\n", GCPtrGuestTss));
442 return rc;
443 }
444
445#ifdef LOG_ENABLED
446 uint32_t ssr0 = pVM->selm.s.Tss.ss1;
447 uint32_t espr0 = pVM->selm.s.Tss.esp1;
448 ssr0 &= ~1;
449
450 if (ssr0 != tss.ss0 || espr0 != tss.esp0)
451 Log(("SELMGetRing1Stack: Updating TSS ring 0 stack to %04X:%08X\n", tss.ss0, tss.esp0));
452
453 Log(("offIoBitmap=%#x\n", tss.offIoBitmap));
454#endif
455 /* Update our TSS structure for the guest's ring 1 stack */
456 SELMSetRing1Stack(pVM, tss.ss0 | 1, (RTGCPTR32)tss.esp0);
457 pVM->selm.s.fSyncTSSRing0Stack = false;
458 }
459
460 *pSS = pVM->selm.s.Tss.ss1;
461 *pEsp = pVM->selm.s.Tss.esp1;
462
463 return VINF_SUCCESS;
464}
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