VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/SELM.cpp@ 80191

Last change on this file since 80191 was 80191, checked in by vboxsync, 5 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 22.9 KB
Line 
1/* $Id: SELM.cpp 80191 2019-08-08 00:36:57Z vboxsync $ */
2/** @file
3 * SELM - The Selector Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
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
18/** @page pg_selm SELM - The Selector Manager
19 *
20 * SELM takes care of GDT, LDT and TSS shadowing in raw-mode, and the injection
21 * of a few hyper selector for the raw-mode context. In the hardware assisted
22 * virtualization mode its only task is to decode entries in the guest GDT or
23 * LDT once in a while.
24 *
25 * @see grp_selm
26 *
27 *
28 * @section seg_selm_shadowing Shadowing
29 *
30 * SELMR3UpdateFromCPUM() and SELMR3SyncTSS() does the bulk synchronization
31 * work. The three structures (GDT, LDT, TSS) are all shadowed wholesale atm.
32 * The idea is to do it in a more on-demand fashion when we get time. There
33 * also a whole bunch of issues with the current synchronization of all three
34 * tables, see notes and todos in the code.
35 *
36 * When the guest makes changes to the GDT we will try update the shadow copy
37 * without involving SELMR3UpdateFromCPUM(), see selmGCSyncGDTEntry().
38 *
39 * When the guest make LDT changes we'll trigger a full resync of the LDT
40 * (SELMR3UpdateFromCPUM()), which, needless to say, isn't optimal.
41 *
42 * The TSS shadowing is limited to the fields we need to care about, namely SS0
43 * and ESP0. The Patch Manager makes use of these. We monitor updates to the
44 * guest TSS and will try keep our SS0 and ESP0 copies up to date this way
45 * rather than go the SELMR3SyncTSS() route.
46 *
47 * When in raw-mode SELM also injects a few extra GDT selectors which are used
48 * by the raw-mode (hyper) context. These start their life at the high end of
49 * the table and will be relocated when the guest tries to make use of them...
50 * Well, that was that idea at least, only the code isn't quite there yet which
51 * is why we have trouble with guests which actually have a full sized GDT.
52 *
53 * So, the summary of the current GDT, LDT and TSS shadowing is that there is a
54 * lot of relatively simple and enjoyable work to be done, see @bugref{3267}.
55 *
56 */
57
58
59/*********************************************************************************************************************************
60* Header Files *
61*********************************************************************************************************************************/
62#define VBOX_BUGREF_9217_PART_I
63#define LOG_GROUP LOG_GROUP_SELM
64#include <VBox/vmm/selm.h>
65#include <VBox/vmm/cpum.h>
66#include <VBox/vmm/stam.h>
67#include <VBox/vmm/em.h>
68#include <VBox/vmm/hm.h>
69#include <VBox/vmm/mm.h>
70#include <VBox/vmm/ssm.h>
71#include <VBox/vmm/pgm.h>
72#include <VBox/vmm/trpm.h>
73#include <VBox/vmm/dbgf.h>
74#include "SELMInternal.h"
75#include <VBox/vmm/vm.h>
76#include <VBox/err.h>
77#include <VBox/param.h>
78
79#include <iprt/assert.h>
80#include <VBox/log.h>
81#include <iprt/asm.h>
82#include <iprt/string.h>
83#include <iprt/thread.h>
84#include <iprt/string.h>
85
86
87/*********************************************************************************************************************************
88* Internal Functions *
89*********************************************************************************************************************************/
90static DECLCALLBACK(void) selmR3InfoGdtGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
91static DECLCALLBACK(void) selmR3InfoLdtGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
92//static DECLCALLBACK(void) selmR3InfoTssGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
93
94
95
96/**
97 * Initializes the SELM.
98 *
99 * @returns VBox status code.
100 * @param pVM The cross context VM structure.
101 */
102VMMR3DECL(int) SELMR3Init(PVM pVM)
103{
104 int rc;
105 LogFlow(("SELMR3Init\n"));
106
107 /*
108 * Assert alignment and sizes.
109 * (The TSS block requires contiguous back.)
110 */
111 AssertCompile(sizeof(pVM->selm.s) <= sizeof(pVM->selm.padding)); AssertRelease(sizeof(pVM->selm.s) <= sizeof(pVM->selm.padding));
112 AssertCompileMemberAlignment(VM, selm.s, 32); AssertRelease(!(RT_UOFFSETOF(VM, selm.s) & 31));
113
114 /*
115 * Register the saved state data unit.
116 */
117 rc = SSMR3RegisterStub(pVM, "selm", 1);
118 if (RT_FAILURE(rc))
119 return rc;
120
121 /*
122 * Statistics.
123 */
124 STAM_REG( pVM, &pVM->selm.s.StatLoadHidSelGst, STAMTYPE_COUNTER, "/SELM/LoadHidSel/LoadedGuest", STAMUNIT_OCCURENCES, "SELMLoadHiddenSelectorReg: Loaded from guest tables.");
125 STAM_REG( pVM, &pVM->selm.s.StatLoadHidSelShw, STAMTYPE_COUNTER, "/SELM/LoadHidSel/LoadedShadow", STAMUNIT_OCCURENCES, "SELMLoadHiddenSelectorReg: Loaded from shadow tables.");
126 STAM_REL_REG(pVM, &pVM->selm.s.StatLoadHidSelReadErrors, STAMTYPE_COUNTER, "/SELM/LoadHidSel/GstReadErrors", STAMUNIT_OCCURENCES, "SELMLoadHiddenSelectorReg: Guest table read errors.");
127 STAM_REL_REG(pVM, &pVM->selm.s.StatLoadHidSelGstNoGood, STAMTYPE_COUNTER, "/SELM/LoadHidSel/NoGoodGuest", STAMUNIT_OCCURENCES, "SELMLoadHiddenSelectorReg: No good guest table entry.");
128
129 /*
130 * Register info handlers.
131 */
132 DBGFR3InfoRegisterInternalEx(pVM, "gdt", "Displays the guest GDT. No arguments.", &selmR3InfoGdtGuest, DBGFINFO_FLAGS_RUN_ON_EMT);
133 DBGFR3InfoRegisterInternalEx(pVM, "ldt", "Displays the guest LDT. No arguments.", &selmR3InfoLdtGuest, DBGFINFO_FLAGS_RUN_ON_EMT);
134 //DBGFR3InfoRegisterInternal(pVM, "tss", "Displays the guest TSS. No arguments.", &selmR3InfoTssGuest, DBGFINFO_FLAGS_RUN_ON_EMT);
135
136 return rc;
137}
138
139
140/**
141 * Applies relocations to data and code managed by this
142 * component. This function will be called at init and
143 * whenever the VMM need to relocate it self inside the GC.
144 *
145 * @param pVM The cross context VM structure.
146 */
147VMMR3DECL(void) SELMR3Relocate(PVM pVM)
148{
149 LogFlow(("SELMR3Relocate\n"));
150 RT_NOREF(pVM);
151}
152
153
154/**
155 * Terminates the SELM.
156 *
157 * Termination means cleaning up and freeing all resources,
158 * the VM it self is at this point powered off or suspended.
159 *
160 * @returns VBox status code.
161 * @param pVM The cross context VM structure.
162 */
163VMMR3DECL(int) SELMR3Term(PVM pVM)
164{
165 NOREF(pVM);
166 return VINF_SUCCESS;
167}
168
169
170/**
171 * The VM is being reset.
172 *
173 * For the SELM component this means that any GDT/LDT/TSS monitors
174 * needs to be removed.
175 *
176 * @param pVM The cross context VM structure.
177 */
178VMMR3DECL(void) SELMR3Reset(PVM pVM)
179{
180 LogFlow(("SELMR3Reset:\n"));
181 VM_ASSERT_EMT(pVM);
182 RT_NOREF(pVM);
183}
184
185
186/**
187 * Gets information about a 64-bit selector, SELMR3GetSelectorInfo helper.
188 *
189 * See SELMR3GetSelectorInfo for details.
190 *
191 * @returns VBox status code, see SELMR3GetSelectorInfo for details.
192 *
193 * @param pVCpu The cross context virtual CPU structure.
194 * @param Sel The selector to get info about.
195 * @param pSelInfo Where to store the information.
196 */
197static int selmR3GetSelectorInfo64(PVMCPU pVCpu, RTSEL Sel, PDBGFSELINFO pSelInfo)
198{
199 /*
200 * Read it from the guest descriptor table.
201 */
202/** @todo this is bogus wrt the LDT/GDT limit on long selectors. */
203 X86DESC64 Desc;
204 RTGCPTR GCPtrDesc;
205 if (!(Sel & X86_SEL_LDT))
206 {
207 /* GDT */
208 VBOXGDTR Gdtr;
209 CPUMGetGuestGDTR(pVCpu, &Gdtr);
210 if ((Sel | X86_SEL_RPL_LDT) > Gdtr.cbGdt)
211 return VERR_INVALID_SELECTOR;
212 GCPtrDesc = Gdtr.pGdt + (Sel & X86_SEL_MASK);
213 }
214 else
215 {
216 /* LDT */
217 uint64_t GCPtrBase;
218 uint32_t cbLimit;
219 CPUMGetGuestLdtrEx(pVCpu, &GCPtrBase, &cbLimit);
220 if ((Sel | X86_SEL_RPL_LDT) > cbLimit)
221 return VERR_INVALID_SELECTOR;
222
223 /* calc the descriptor location. */
224 GCPtrDesc = GCPtrBase + (Sel & X86_SEL_MASK);
225 }
226
227 /* read the descriptor. */
228 int rc = PGMPhysSimpleReadGCPtr(pVCpu, &Desc, GCPtrDesc, sizeof(Desc));
229 if (RT_FAILURE(rc))
230 {
231 rc = PGMPhysSimpleReadGCPtr(pVCpu, &Desc, GCPtrDesc, sizeof(X86DESC));
232 if (RT_FAILURE(rc))
233 return rc;
234 Desc.au64[1] = 0;
235 }
236
237 /*
238 * Extract the base and limit
239 * (We ignore the present bit here, which is probably a bit silly...)
240 */
241 pSelInfo->Sel = Sel;
242 pSelInfo->fFlags = DBGFSELINFO_FLAGS_LONG_MODE;
243 pSelInfo->u.Raw64 = Desc;
244 if (Desc.Gen.u1DescType)
245 {
246 /*
247 * 64-bit code selectors are wide open, it's not possible to detect
248 * 64-bit data or stack selectors without also dragging in assumptions
249 * about current CS (i.e. that's we're executing in 64-bit mode). So,
250 * the selinfo user needs to deal with this in the context the info is
251 * used unfortunately.
252 */
253 if ( Desc.Gen.u1Long
254 && !Desc.Gen.u1DefBig
255 && (Desc.Gen.u4Type & X86_SEL_TYPE_CODE))
256 {
257 /* Note! We ignore the segment limit hacks that was added by AMD. */
258 pSelInfo->GCPtrBase = 0;
259 pSelInfo->cbLimit = ~(RTGCUINTPTR)0;
260 }
261 else
262 {
263 pSelInfo->cbLimit = X86DESC_LIMIT_G(&Desc);
264 pSelInfo->GCPtrBase = X86DESC_BASE(&Desc);
265 }
266 pSelInfo->SelGate = 0;
267 }
268 else if ( Desc.Gen.u4Type == AMD64_SEL_TYPE_SYS_LDT
269 || Desc.Gen.u4Type == AMD64_SEL_TYPE_SYS_TSS_AVAIL
270 || Desc.Gen.u4Type == AMD64_SEL_TYPE_SYS_TSS_BUSY)
271 {
272 /* Note. LDT descriptors are weird in long mode, we ignore the footnote
273 in the AMD manual here as a simplification. */
274 pSelInfo->GCPtrBase = X86DESC64_BASE(&Desc);
275 pSelInfo->cbLimit = X86DESC_LIMIT_G(&Desc);
276 pSelInfo->SelGate = 0;
277 }
278 else if ( Desc.Gen.u4Type == AMD64_SEL_TYPE_SYS_CALL_GATE
279 || Desc.Gen.u4Type == AMD64_SEL_TYPE_SYS_TRAP_GATE
280 || Desc.Gen.u4Type == AMD64_SEL_TYPE_SYS_INT_GATE)
281 {
282 pSelInfo->cbLimit = X86DESC64_BASE(&Desc);
283 pSelInfo->GCPtrBase = Desc.Gate.u16OffsetLow
284 | ((uint32_t)Desc.Gate.u16OffsetHigh << 16)
285 | ((uint64_t)Desc.Gate.u32OffsetTop << 32);
286 pSelInfo->SelGate = Desc.Gate.u16Sel;
287 pSelInfo->fFlags |= DBGFSELINFO_FLAGS_GATE;
288 }
289 else
290 {
291 pSelInfo->cbLimit = 0;
292 pSelInfo->GCPtrBase = 0;
293 pSelInfo->SelGate = 0;
294 pSelInfo->fFlags |= DBGFSELINFO_FLAGS_INVALID;
295 }
296 if (!Desc.Gen.u1Present)
297 pSelInfo->fFlags |= DBGFSELINFO_FLAGS_NOT_PRESENT;
298
299 return VINF_SUCCESS;
300}
301
302
303/**
304 * Worker for selmR3GetSelectorInfo32 and SELMR3GetShadowSelectorInfo that
305 * interprets a legacy descriptor table entry and fills in the selector info
306 * structure from it.
307 *
308 * @param pSelInfo Where to store the selector info. Only the fFlags and
309 * Sel members have been initialized.
310 * @param pDesc The legacy descriptor to parse.
311 */
312DECLINLINE(void) selmR3SelInfoFromDesc32(PDBGFSELINFO pSelInfo, PCX86DESC pDesc)
313{
314 pSelInfo->u.Raw64.au64[1] = 0;
315 pSelInfo->u.Raw = *pDesc;
316 if ( pDesc->Gen.u1DescType
317 || !(pDesc->Gen.u4Type & 4))
318 {
319 pSelInfo->cbLimit = X86DESC_LIMIT_G(pDesc);
320 pSelInfo->GCPtrBase = X86DESC_BASE(pDesc);
321 pSelInfo->SelGate = 0;
322 }
323 else if (pDesc->Gen.u4Type != X86_SEL_TYPE_SYS_UNDEFINED4)
324 {
325 pSelInfo->cbLimit = 0;
326 if (pDesc->Gen.u4Type == X86_SEL_TYPE_SYS_TASK_GATE)
327 pSelInfo->GCPtrBase = 0;
328 else
329 pSelInfo->GCPtrBase = pDesc->Gate.u16OffsetLow
330 | (uint32_t)pDesc->Gate.u16OffsetHigh << 16;
331 pSelInfo->SelGate = pDesc->Gate.u16Sel;
332 pSelInfo->fFlags |= DBGFSELINFO_FLAGS_GATE;
333 }
334 else
335 {
336 pSelInfo->cbLimit = 0;
337 pSelInfo->GCPtrBase = 0;
338 pSelInfo->SelGate = 0;
339 pSelInfo->fFlags |= DBGFSELINFO_FLAGS_INVALID;
340 }
341 if (!pDesc->Gen.u1Present)
342 pSelInfo->fFlags |= DBGFSELINFO_FLAGS_NOT_PRESENT;
343}
344
345
346/**
347 * Gets information about a 64-bit selector, SELMR3GetSelectorInfo helper.
348 *
349 * See SELMR3GetSelectorInfo for details.
350 *
351 * @returns VBox status code, see SELMR3GetSelectorInfo for details.
352 *
353 * @param pVCpu The cross context virtual CPU structure.
354 * @param Sel The selector to get info about.
355 * @param pSelInfo Where to store the information.
356 */
357static int selmR3GetSelectorInfo32(PVMCPU pVCpu, RTSEL Sel, PDBGFSELINFO pSelInfo)
358{
359 /*
360 * Read the descriptor entry
361 */
362 pSelInfo->fFlags = 0;
363 if (CPUMIsGuestInProtectedMode(pVCpu))
364 {
365 /*
366 * Read it from the guest descriptor table.
367 */
368 pSelInfo->fFlags = DBGFSELINFO_FLAGS_PROT_MODE;
369
370 RTGCPTR GCPtrDesc;
371 if (!(Sel & X86_SEL_LDT))
372 {
373 /* GDT */
374 VBOXGDTR Gdtr;
375 CPUMGetGuestGDTR(pVCpu, &Gdtr);
376 if ((Sel | X86_SEL_RPL_LDT) > Gdtr.cbGdt)
377 return VERR_INVALID_SELECTOR;
378 GCPtrDesc = Gdtr.pGdt + (Sel & X86_SEL_MASK);
379 }
380 else
381 {
382 /* LDT */
383 uint64_t GCPtrBase;
384 uint32_t cbLimit;
385 CPUMGetGuestLdtrEx(pVCpu, &GCPtrBase, &cbLimit);
386 if ((Sel | X86_SEL_RPL_LDT) > cbLimit)
387 return VERR_INVALID_SELECTOR;
388
389 /* calc the descriptor location. */
390 GCPtrDesc = GCPtrBase + (Sel & X86_SEL_MASK);
391 }
392
393 /* read the descriptor. */
394 X86DESC Desc;
395 int rc = PGMPhysSimpleReadGCPtr(pVCpu, &Desc, GCPtrDesc, sizeof(Desc));
396 if (RT_SUCCESS(rc))
397 {
398 /*
399 * Extract the base and limit or sel:offset for gates.
400 */
401 pSelInfo->Sel = Sel;
402 selmR3SelInfoFromDesc32(pSelInfo, &Desc);
403
404 return VINF_SUCCESS;
405 }
406 return rc;
407 }
408
409 /*
410 * We're in real mode.
411 */
412 pSelInfo->Sel = Sel;
413 pSelInfo->GCPtrBase = Sel << 4;
414 pSelInfo->cbLimit = 0xffff;
415 pSelInfo->fFlags = DBGFSELINFO_FLAGS_REAL_MODE;
416 pSelInfo->u.Raw64.au64[0] = 0;
417 pSelInfo->u.Raw64.au64[1] = 0;
418 pSelInfo->SelGate = 0;
419 return VINF_SUCCESS;
420}
421
422
423/**
424 * Gets information about a selector.
425 *
426 * Intended for the debugger mostly and will prefer the guest descriptor tables
427 * over the shadow ones.
428 *
429 * @retval VINF_SUCCESS on success.
430 * @retval VERR_INVALID_SELECTOR if the selector isn't fully inside the
431 * descriptor table.
432 * @retval VERR_SELECTOR_NOT_PRESENT if the LDT is invalid or not present. This
433 * is not returned if the selector itself isn't present, you have to
434 * check that for yourself (see DBGFSELINFO::fFlags).
435 * @retval VERR_PAGE_TABLE_NOT_PRESENT or VERR_PAGE_NOT_PRESENT if the
436 * pagetable or page backing the selector table wasn't present.
437 * @returns Other VBox status code on other errors.
438 *
439 * @param pVCpu The cross context virtual CPU structure.
440 * @param Sel The selector to get info about.
441 * @param pSelInfo Where to store the information.
442 */
443VMMR3DECL(int) SELMR3GetSelectorInfo(PVMCPU pVCpu, RTSEL Sel, PDBGFSELINFO pSelInfo)
444{
445 AssertPtr(pSelInfo);
446 if (CPUMIsGuestInLongMode(pVCpu))
447 return selmR3GetSelectorInfo64(pVCpu, Sel, pSelInfo);
448 return selmR3GetSelectorInfo32(pVCpu, Sel, pSelInfo);
449}
450
451
452/**
453 * Formats a descriptor.
454 *
455 * @param Desc Descriptor to format.
456 * @param Sel Selector number.
457 * @param pszOutput Output buffer.
458 * @param cchOutput Size of output buffer.
459 */
460static void selmR3FormatDescriptor(X86DESC Desc, RTSEL Sel, char *pszOutput, size_t cchOutput)
461{
462 /*
463 * Make variable description string.
464 */
465 static struct
466 {
467 unsigned cch;
468 const char *psz;
469 } const aTypes[32] =
470 {
471#define STRENTRY(str) { sizeof(str) - 1, str }
472 /* system */
473 STRENTRY("Reserved0 "), /* 0x00 */
474 STRENTRY("TSS16Avail "), /* 0x01 */
475 STRENTRY("LDT "), /* 0x02 */
476 STRENTRY("TSS16Busy "), /* 0x03 */
477 STRENTRY("Call16 "), /* 0x04 */
478 STRENTRY("Task "), /* 0x05 */
479 STRENTRY("Int16 "), /* 0x06 */
480 STRENTRY("Trap16 "), /* 0x07 */
481 STRENTRY("Reserved8 "), /* 0x08 */
482 STRENTRY("TSS32Avail "), /* 0x09 */
483 STRENTRY("ReservedA "), /* 0x0a */
484 STRENTRY("TSS32Busy "), /* 0x0b */
485 STRENTRY("Call32 "), /* 0x0c */
486 STRENTRY("ReservedD "), /* 0x0d */
487 STRENTRY("Int32 "), /* 0x0e */
488 STRENTRY("Trap32 "), /* 0x0f */
489 /* non system */
490 STRENTRY("DataRO "), /* 0x10 */
491 STRENTRY("DataRO Accessed "), /* 0x11 */
492 STRENTRY("DataRW "), /* 0x12 */
493 STRENTRY("DataRW Accessed "), /* 0x13 */
494 STRENTRY("DataDownRO "), /* 0x14 */
495 STRENTRY("DataDownRO Accessed "), /* 0x15 */
496 STRENTRY("DataDownRW "), /* 0x16 */
497 STRENTRY("DataDownRW Accessed "), /* 0x17 */
498 STRENTRY("CodeEO "), /* 0x18 */
499 STRENTRY("CodeEO Accessed "), /* 0x19 */
500 STRENTRY("CodeER "), /* 0x1a */
501 STRENTRY("CodeER Accessed "), /* 0x1b */
502 STRENTRY("CodeConfEO "), /* 0x1c */
503 STRENTRY("CodeConfEO Accessed "), /* 0x1d */
504 STRENTRY("CodeConfER "), /* 0x1e */
505 STRENTRY("CodeConfER Accessed ") /* 0x1f */
506#undef SYSENTRY
507 };
508#define ADD_STR(psz, pszAdd) do { strcpy(psz, pszAdd); psz += strlen(pszAdd); } while (0)
509 char szMsg[128];
510 char *psz = &szMsg[0];
511 unsigned i = Desc.Gen.u1DescType << 4 | Desc.Gen.u4Type;
512 memcpy(psz, aTypes[i].psz, aTypes[i].cch);
513 psz += aTypes[i].cch;
514
515 if (Desc.Gen.u1Present)
516 ADD_STR(psz, "Present ");
517 else
518 ADD_STR(psz, "Not-Present ");
519 if (Desc.Gen.u1Granularity)
520 ADD_STR(psz, "Page ");
521 if (Desc.Gen.u1DefBig)
522 ADD_STR(psz, "32-bit ");
523 else
524 ADD_STR(psz, "16-bit ");
525#undef ADD_STR
526 *psz = '\0';
527
528 /*
529 * Limit and Base and format the output.
530 */
531 uint32_t u32Limit = X86DESC_LIMIT_G(&Desc);
532 uint32_t u32Base = X86DESC_BASE(&Desc);
533
534 RTStrPrintf(pszOutput, cchOutput, "%04x - %08x %08x - base=%08x limit=%08x dpl=%d %s",
535 Sel, Desc.au32[0], Desc.au32[1], u32Base, u32Limit, Desc.Gen.u2Dpl, szMsg);
536}
537
538
539/**
540 * Dumps a descriptor.
541 *
542 * @param Desc Descriptor to dump.
543 * @param Sel Selector number.
544 * @param pszMsg Message to prepend the log entry with.
545 */
546VMMR3DECL(void) SELMR3DumpDescriptor(X86DESC Desc, RTSEL Sel, const char *pszMsg)
547{
548#ifdef LOG_ENABLED
549 if (LogIsEnabled())
550 {
551 char szOutput[128];
552 selmR3FormatDescriptor(Desc, Sel, &szOutput[0], sizeof(szOutput));
553 Log(("%s: %s\n", pszMsg, szOutput));
554 }
555#else
556 RT_NOREF3(Desc, Sel, pszMsg);
557#endif
558}
559
560
561/**
562 * Display the guest gdt.
563 *
564 * @param pVM The cross context VM structure.
565 * @param pHlp The info helpers.
566 * @param pszArgs Arguments, ignored.
567 */
568static DECLCALLBACK(void) selmR3InfoGdtGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
569{
570 /** @todo SMP support! */
571 PVMCPU pVCpu = pVM->apCpusR3[0];
572
573 VBOXGDTR GDTR;
574 CPUMGetGuestGDTR(pVCpu, &GDTR);
575 RTGCPTR GCPtrGDT = GDTR.pGdt;
576 unsigned cGDTs = ((unsigned)GDTR.cbGdt + 1) / sizeof(X86DESC);
577
578 pHlp->pfnPrintf(pHlp, "Guest GDT (GCAddr=%RGv limit=%x):\n", GCPtrGDT, GDTR.cbGdt);
579 for (unsigned iGDT = 0; iGDT < cGDTs; iGDT++, GCPtrGDT += sizeof(X86DESC))
580 {
581 X86DESC GDTE;
582 int rc = PGMPhysSimpleReadGCPtr(pVCpu, &GDTE, GCPtrGDT, sizeof(GDTE));
583 if (RT_SUCCESS(rc))
584 {
585 if (GDTE.Gen.u1Present)
586 {
587 char szOutput[128];
588 selmR3FormatDescriptor(GDTE, iGDT << X86_SEL_SHIFT, &szOutput[0], sizeof(szOutput));
589 pHlp->pfnPrintf(pHlp, "%s\n", szOutput);
590 }
591 }
592 else if (rc == VERR_PAGE_NOT_PRESENT)
593 {
594 if ((GCPtrGDT & PAGE_OFFSET_MASK) + sizeof(X86DESC) - 1 < sizeof(X86DESC))
595 pHlp->pfnPrintf(pHlp, "%04x - page not present (GCAddr=%RGv)\n", iGDT << X86_SEL_SHIFT, GCPtrGDT);
596 }
597 else
598 pHlp->pfnPrintf(pHlp, "%04x - read error rc=%Rrc GCAddr=%RGv\n", iGDT << X86_SEL_SHIFT, rc, GCPtrGDT);
599 }
600 NOREF(pszArgs);
601}
602
603
604/**
605 * Display the guest ldt.
606 *
607 * @param pVM The cross context VM structure.
608 * @param pHlp The info helpers.
609 * @param pszArgs Arguments, ignored.
610 */
611static DECLCALLBACK(void) selmR3InfoLdtGuest(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
612{
613 /** @todo SMP support! */
614 PVMCPU pVCpu = pVM->apCpusR3[0];
615
616 uint64_t GCPtrLdt;
617 uint32_t cbLdt;
618 RTSEL SelLdt = CPUMGetGuestLdtrEx(pVCpu, &GCPtrLdt, &cbLdt);
619 if (!(SelLdt & X86_SEL_MASK_OFF_RPL))
620 {
621 pHlp->pfnPrintf(pHlp, "Guest LDT (Sel=%x): Null-Selector\n", SelLdt);
622 return;
623 }
624
625 pHlp->pfnPrintf(pHlp, "Guest LDT (Sel=%x GCAddr=%RX64 limit=%x):\n", SelLdt, GCPtrLdt, cbLdt);
626 unsigned cLdts = (cbLdt + 1) >> X86_SEL_SHIFT;
627 for (unsigned iLdt = 0; iLdt < cLdts; iLdt++, GCPtrLdt += sizeof(X86DESC))
628 {
629 X86DESC LdtE;
630 int rc = PGMPhysSimpleReadGCPtr(pVCpu, &LdtE, GCPtrLdt, sizeof(LdtE));
631 if (RT_SUCCESS(rc))
632 {
633 if (LdtE.Gen.u1Present)
634 {
635 char szOutput[128];
636 selmR3FormatDescriptor(LdtE, (iLdt << X86_SEL_SHIFT) | X86_SEL_LDT, &szOutput[0], sizeof(szOutput));
637 pHlp->pfnPrintf(pHlp, "%s\n", szOutput);
638 }
639 }
640 else if (rc == VERR_PAGE_NOT_PRESENT)
641 {
642 if ((GCPtrLdt & PAGE_OFFSET_MASK) + sizeof(X86DESC) - 1 < sizeof(X86DESC))
643 pHlp->pfnPrintf(pHlp, "%04x - page not present (GCAddr=%RGv)\n", (iLdt << X86_SEL_SHIFT) | X86_SEL_LDT, GCPtrLdt);
644 }
645 else
646 pHlp->pfnPrintf(pHlp, "%04x - read error rc=%Rrc GCAddr=%RGv\n", (iLdt << X86_SEL_SHIFT) | X86_SEL_LDT, rc, GCPtrLdt);
647 }
648 NOREF(pszArgs);
649}
650
651
652/**
653 * Dumps the guest GDT
654 *
655 * @param pVM The cross context VM structure.
656 */
657VMMR3DECL(void) SELMR3DumpGuestGDT(PVM pVM)
658{
659 DBGFR3Info(pVM->pUVM, "gdt", NULL, NULL);
660}
661
662
663/**
664 * Dumps the guest LDT
665 *
666 * @param pVM The cross context VM structure.
667 */
668VMMR3DECL(void) SELMR3DumpGuestLDT(PVM pVM)
669{
670 DBGFR3Info(pVM->pUVM, "ldt", NULL, NULL);
671}
672
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use