VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp@ 69111

Last change on this file since 69111 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 45.4 KB
Line 
1/* $Id: IOMAllMMIO.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * IOM - Input / Output Monitor - Any Context, MMIO & String I/O.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_IOM
23#include <VBox/vmm/iom.h>
24#include <VBox/vmm/cpum.h>
25#include <VBox/vmm/pgm.h>
26#include <VBox/vmm/selm.h>
27#include <VBox/vmm/mm.h>
28#include <VBox/vmm/em.h>
29#include <VBox/vmm/pgm.h>
30#include <VBox/vmm/trpm.h>
31#include <VBox/vmm/iem.h>
32#include "IOMInternal.h"
33#include <VBox/vmm/vm.h>
34#include <VBox/vmm/vmm.h>
35#include <VBox/vmm/hm.h>
36#include "IOMInline.h"
37
38#include <VBox/dis.h>
39#include <VBox/disopcode.h>
40#include <VBox/vmm/pdmdev.h>
41#include <VBox/param.h>
42#include <VBox/err.h>
43#include <iprt/assert.h>
44#include <VBox/log.h>
45#include <iprt/asm.h>
46#include <iprt/string.h>
47
48
49
50#ifndef IN_RING3
51/**
52 * Defers a pending MMIO write to ring-3.
53 *
54 * @returns VINF_IOM_R3_MMIO_COMMIT_WRITE
55 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
56 * @param GCPhys The write address.
57 * @param pvBuf The bytes being written.
58 * @param cbBuf How many bytes.
59 * @param pRange The range, if resolved.
60 */
61static VBOXSTRICTRC iomMmioRing3WritePending(PVMCPU pVCpu, RTGCPHYS GCPhys, void const *pvBuf, size_t cbBuf, PIOMMMIORANGE pRange)
62{
63 Log5(("iomMmioRing3WritePending: %RGp LB %#x\n", GCPhys, cbBuf));
64 AssertReturn(pVCpu->iom.s.PendingMmioWrite.cbValue == 0, VERR_IOM_MMIO_IPE_1);
65 pVCpu->iom.s.PendingMmioWrite.GCPhys = GCPhys;
66 AssertReturn(cbBuf <= sizeof(pVCpu->iom.s.PendingMmioWrite.abValue), VERR_IOM_MMIO_IPE_2);
67 pVCpu->iom.s.PendingMmioWrite.cbValue = (uint32_t)cbBuf;
68 memcpy(pVCpu->iom.s.PendingMmioWrite.abValue, pvBuf, cbBuf);
69 VMCPU_FF_SET(pVCpu, VMCPU_FF_IOM);
70 RT_NOREF_PV(pRange);
71 return VINF_IOM_R3_MMIO_COMMIT_WRITE;
72}
73#endif
74
75
76/**
77 * Deals with complicated MMIO writes.
78 *
79 * Complicated means unaligned or non-dword/qword sized accesses depending on
80 * the MMIO region's access mode flags.
81 *
82 * @returns Strict VBox status code. Any EM scheduling status code,
83 * VINF_IOM_R3_MMIO_WRITE, VINF_IOM_R3_MMIO_READ_WRITE or
84 * VINF_IOM_R3_MMIO_READ may be returned.
85 *
86 * @param pVM The cross context VM structure.
87 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
88 * @param pRange The range to write to.
89 * @param GCPhys The physical address to start writing.
90 * @param pvValue Where to store the value.
91 * @param cbValue The size of the value to write.
92 */
93static VBOXSTRICTRC iomMMIODoComplicatedWrite(PVM pVM, PVMCPU pVCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhys,
94 void const *pvValue, unsigned cbValue)
95{
96 RT_NOREF_PV(pVCpu);
97 AssertReturn( (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) != IOMMMIO_FLAGS_WRITE_PASSTHRU
98 && (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING,
99 VERR_IOM_MMIO_IPE_1);
100 AssertReturn(cbValue != 0 && cbValue <= 16, VERR_IOM_MMIO_IPE_2);
101 RTGCPHYS const GCPhysStart = GCPhys; NOREF(GCPhysStart);
102 bool const fReadMissing = (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_READ_MISSING
103 || (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING;
104
105 /*
106 * Do debug stop if requested.
107 */
108 int rc = VINF_SUCCESS; NOREF(pVM);
109#ifdef VBOX_STRICT
110 if (pRange->fFlags & IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_WRITE)
111 {
112# ifdef IN_RING3
113 LogRel(("IOM: Complicated write %#x byte at %RGp to %s, initiating debugger intervention\n", cbValue, GCPhys,
114 R3STRING(pRange->pszDesc)));
115 rc = DBGFR3EventSrc(pVM, DBGFEVENT_DEV_STOP, RT_SRC_POS,
116 "Complicated write %#x byte at %RGp to %s\n", cbValue, GCPhys, R3STRING(pRange->pszDesc));
117 if (rc == VERR_DBGF_NOT_ATTACHED)
118 rc = VINF_SUCCESS;
119# else
120 return VINF_IOM_R3_MMIO_WRITE;
121# endif
122 }
123#endif
124
125 /*
126 * Check if we should ignore the write.
127 */
128 if ((pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD)
129 {
130 Assert(cbValue != 4 || (GCPhys & 3));
131 return VINF_SUCCESS;
132 }
133 if ((pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD)
134 {
135 Assert((cbValue != 4 && cbValue != 8) || (GCPhys & (cbValue - 1)));
136 return VINF_SUCCESS;
137 }
138
139 /*
140 * Split and conquer.
141 */
142 for (;;)
143 {
144 unsigned const offAccess = GCPhys & 3;
145 unsigned cbThisPart = 4 - offAccess;
146 if (cbThisPart > cbValue)
147 cbThisPart = cbValue;
148
149 /*
150 * Get the missing bits (if any).
151 */
152 uint32_t u32MissingValue = 0;
153 if (fReadMissing && cbThisPart != 4)
154 {
155 int rc2 = pRange->CTX_SUFF(pfnReadCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
156 GCPhys & ~(RTGCPHYS)3, &u32MissingValue, sizeof(u32MissingValue));
157 switch (rc2)
158 {
159 case VINF_SUCCESS:
160 break;
161 case VINF_IOM_MMIO_UNUSED_FF:
162 u32MissingValue = UINT32_C(0xffffffff);
163 break;
164 case VINF_IOM_MMIO_UNUSED_00:
165 u32MissingValue = 0;
166 break;
167#ifndef IN_RING3
168 case VINF_IOM_R3_MMIO_READ:
169 case VINF_IOM_R3_MMIO_READ_WRITE:
170 case VINF_IOM_R3_MMIO_WRITE:
171 LogFlow(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [read]\n", GCPhys, GCPhysStart, cbValue, rc2));
172 rc2 = VBOXSTRICTRC_TODO(iomMmioRing3WritePending(pVCpu, GCPhys, pvValue, cbValue, pRange));
173 if (rc == VINF_SUCCESS || rc2 < rc)
174 rc = rc2;
175 return rc;
176#endif
177 default:
178 if (RT_FAILURE(rc2))
179 {
180 Log(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [read]\n", GCPhys, GCPhysStart, cbValue, rc2));
181 return rc2;
182 }
183 AssertMsgReturn(rc2 >= VINF_EM_FIRST && rc2 <= VINF_EM_LAST, ("%Rrc\n", rc2), VERR_IPE_UNEXPECTED_INFO_STATUS);
184 if (rc == VINF_SUCCESS || rc2 < rc)
185 rc = rc2;
186 break;
187 }
188 }
189
190 /*
191 * Merge missing and given bits.
192 */
193 uint32_t u32GivenMask;
194 uint32_t u32GivenValue;
195 switch (cbThisPart)
196 {
197 case 1:
198 u32GivenValue = *(uint8_t const *)pvValue;
199 u32GivenMask = UINT32_C(0x000000ff);
200 break;
201 case 2:
202 u32GivenValue = *(uint16_t const *)pvValue;
203 u32GivenMask = UINT32_C(0x0000ffff);
204 break;
205 case 3:
206 u32GivenValue = RT_MAKE_U32_FROM_U8(((uint8_t const *)pvValue)[0], ((uint8_t const *)pvValue)[1],
207 ((uint8_t const *)pvValue)[2], 0);
208 u32GivenMask = UINT32_C(0x00ffffff);
209 break;
210 case 4:
211 u32GivenValue = *(uint32_t const *)pvValue;
212 u32GivenMask = UINT32_C(0xffffffff);
213 break;
214 default:
215 AssertFailedReturn(VERR_IOM_MMIO_IPE_3);
216 }
217 if (offAccess)
218 {
219 u32GivenValue <<= offAccess * 8;
220 u32GivenMask <<= offAccess * 8;
221 }
222
223 uint32_t u32Value = (u32MissingValue & ~u32GivenMask)
224 | (u32GivenValue & u32GivenMask);
225
226 /*
227 * Do DWORD write to the device.
228 */
229 int rc2 = pRange->CTX_SUFF(pfnWriteCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
230 GCPhys & ~(RTGCPHYS)3, &u32Value, sizeof(u32Value));
231 switch (rc2)
232 {
233 case VINF_SUCCESS:
234 break;
235#ifndef IN_RING3
236 case VINF_IOM_R3_MMIO_READ:
237 case VINF_IOM_R3_MMIO_READ_WRITE:
238 case VINF_IOM_R3_MMIO_WRITE:
239 Log3(("iomMMIODoComplicatedWrite: deferring GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [write]\n", GCPhys, GCPhysStart, cbValue, rc2));
240 AssertReturn(pVCpu->iom.s.PendingMmioWrite.cbValue == 0, VERR_IOM_MMIO_IPE_1);
241 AssertReturn(cbValue + (GCPhys & 3) <= sizeof(pVCpu->iom.s.PendingMmioWrite.abValue), VERR_IOM_MMIO_IPE_2);
242 pVCpu->iom.s.PendingMmioWrite.GCPhys = GCPhys & ~(RTGCPHYS)3;
243 pVCpu->iom.s.PendingMmioWrite.cbValue = cbValue + (GCPhys & 3);
244 *(uint32_t *)pVCpu->iom.s.PendingMmioWrite.abValue = u32Value;
245 if (cbValue > cbThisPart)
246 memcpy(&pVCpu->iom.s.PendingMmioWrite.abValue[4],
247 (uint8_t const *)pvValue + cbThisPart, cbValue - cbThisPart);
248 VMCPU_FF_SET(pVCpu, VMCPU_FF_IOM);
249 if (rc == VINF_SUCCESS)
250 rc = VINF_IOM_R3_MMIO_COMMIT_WRITE;
251 return rc2;
252#endif
253 default:
254 if (RT_FAILURE(rc2))
255 {
256 Log(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [write]\n", GCPhys, GCPhysStart, cbValue, rc2));
257 return rc2;
258 }
259 AssertMsgReturn(rc2 >= VINF_EM_FIRST && rc2 <= VINF_EM_LAST, ("%Rrc\n", rc2), VERR_IPE_UNEXPECTED_INFO_STATUS);
260 if (rc == VINF_SUCCESS || rc2 < rc)
261 rc = rc2;
262 break;
263 }
264
265 /*
266 * Advance.
267 */
268 cbValue -= cbThisPart;
269 if (!cbValue)
270 break;
271 GCPhys += cbThisPart;
272 pvValue = (uint8_t const *)pvValue + cbThisPart;
273 }
274
275 return rc;
276}
277
278
279
280
281/**
282 * Wrapper which does the write and updates range statistics when such are enabled.
283 * @warning RT_SUCCESS(rc=VINF_IOM_R3_MMIO_WRITE) is TRUE!
284 */
285static VBOXSTRICTRC iomMMIODoWrite(PVM pVM, PVMCPU pVCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault,
286 const void *pvData, unsigned cb)
287{
288#ifdef VBOX_WITH_STATISTICS
289 int rcSem = IOM_LOCK_SHARED(pVM);
290 if (rcSem == VERR_SEM_BUSY)
291 return VINF_IOM_R3_MMIO_WRITE;
292 PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhysFault, pRange);
293 if (!pStats)
294# ifdef IN_RING3
295 return VERR_NO_MEMORY;
296# else
297 return VINF_IOM_R3_MMIO_WRITE;
298# endif
299 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfWrite), a);
300#else
301 NOREF(pVCpu);
302#endif
303
304 VBOXSTRICTRC rcStrict;
305 if (RT_LIKELY(pRange->CTX_SUFF(pfnWriteCallback)))
306 {
307 if ( (cb == 4 && !(GCPhysFault & 3))
308 || (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_PASSTHRU
309 || (cb == 8 && !(GCPhysFault & 7) && IOMMMIO_DOES_WRITE_MODE_ALLOW_QWORD(pRange->fFlags)) )
310 rcStrict = pRange->CTX_SUFF(pfnWriteCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
311 GCPhysFault, (void *)pvData, cb); /** @todo fix const!! */
312 else
313 rcStrict = iomMMIODoComplicatedWrite(pVM, pVCpu, pRange, GCPhysFault, pvData, cb);
314 }
315 else
316 rcStrict = VINF_SUCCESS;
317
318 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfWrite), a);
319 STAM_COUNTER_INC(&pStats->Accesses);
320 return rcStrict;
321}
322
323
324/**
325 * Deals with complicated MMIO reads.
326 *
327 * Complicated means unaligned or non-dword/qword sized accesses depending on
328 * the MMIO region's access mode flags.
329 *
330 * @returns Strict VBox status code. Any EM scheduling status code,
331 * VINF_IOM_R3_MMIO_READ, VINF_IOM_R3_MMIO_READ_WRITE or
332 * VINF_IOM_R3_MMIO_WRITE may be returned.
333 *
334 * @param pVM The cross context VM structure.
335 * @param pRange The range to read from.
336 * @param GCPhys The physical address to start reading.
337 * @param pvValue Where to store the value.
338 * @param cbValue The size of the value to read.
339 */
340static VBOXSTRICTRC iomMMIODoComplicatedRead(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhys, void *pvValue, unsigned cbValue)
341{
342 AssertReturn( (pRange->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_DWORD
343 || (pRange->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_DWORD_QWORD,
344 VERR_IOM_MMIO_IPE_1);
345 AssertReturn(cbValue != 0 && cbValue <= 16, VERR_IOM_MMIO_IPE_2);
346 RTGCPHYS const GCPhysStart = GCPhys; NOREF(GCPhysStart);
347
348 /*
349 * Do debug stop if requested.
350 */
351 int rc = VINF_SUCCESS; NOREF(pVM);
352#ifdef VBOX_STRICT
353 if (pRange->fFlags & IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_READ)
354 {
355# ifdef IN_RING3
356 rc = DBGFR3EventSrc(pVM, DBGFEVENT_DEV_STOP, RT_SRC_POS,
357 "Complicated read %#x byte at %RGp to %s\n", cbValue, GCPhys, R3STRING(pRange->pszDesc));
358 if (rc == VERR_DBGF_NOT_ATTACHED)
359 rc = VINF_SUCCESS;
360# else
361 return VINF_IOM_R3_MMIO_READ;
362# endif
363 }
364#endif
365
366 /*
367 * Split and conquer.
368 */
369 for (;;)
370 {
371 /*
372 * Do DWORD read from the device.
373 */
374 uint32_t u32Value;
375 int rc2 = pRange->CTX_SUFF(pfnReadCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
376 GCPhys & ~(RTGCPHYS)3, &u32Value, sizeof(u32Value));
377 switch (rc2)
378 {
379 case VINF_SUCCESS:
380 break;
381 case VINF_IOM_MMIO_UNUSED_FF:
382 u32Value = UINT32_C(0xffffffff);
383 break;
384 case VINF_IOM_MMIO_UNUSED_00:
385 u32Value = 0;
386 break;
387 case VINF_IOM_R3_MMIO_READ:
388 case VINF_IOM_R3_MMIO_READ_WRITE:
389 case VINF_IOM_R3_MMIO_WRITE:
390 /** @todo What if we've split a transfer and already read
391 * something? Since reads can have sideeffects we could be
392 * kind of screwed here... */
393 LogFlow(("iomMMIODoComplicatedRead: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc\n", GCPhys, GCPhysStart, cbValue, rc2));
394 return rc2;
395 default:
396 if (RT_FAILURE(rc2))
397 {
398 Log(("iomMMIODoComplicatedRead: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc\n", GCPhys, GCPhysStart, cbValue, rc2));
399 return rc2;
400 }
401 AssertMsgReturn(rc2 >= VINF_EM_FIRST && rc2 <= VINF_EM_LAST, ("%Rrc\n", rc2), VERR_IPE_UNEXPECTED_INFO_STATUS);
402 if (rc == VINF_SUCCESS || rc2 < rc)
403 rc = rc2;
404 break;
405 }
406 u32Value >>= (GCPhys & 3) * 8;
407
408 /*
409 * Write what we've read.
410 */
411 unsigned cbThisPart = 4 - (GCPhys & 3);
412 if (cbThisPart > cbValue)
413 cbThisPart = cbValue;
414
415 switch (cbThisPart)
416 {
417 case 1:
418 *(uint8_t *)pvValue = (uint8_t)u32Value;
419 break;
420 case 2:
421 *(uint16_t *)pvValue = (uint16_t)u32Value;
422 break;
423 case 3:
424 ((uint8_t *)pvValue)[0] = RT_BYTE1(u32Value);
425 ((uint8_t *)pvValue)[1] = RT_BYTE2(u32Value);
426 ((uint8_t *)pvValue)[2] = RT_BYTE3(u32Value);
427 break;
428 case 4:
429 *(uint32_t *)pvValue = u32Value;
430 break;
431 }
432
433 /*
434 * Advance.
435 */
436 cbValue -= cbThisPart;
437 if (!cbValue)
438 break;
439 GCPhys += cbThisPart;
440 pvValue = (uint8_t *)pvValue + cbThisPart;
441 }
442
443 return rc;
444}
445
446
447/**
448 * Implements VINF_IOM_MMIO_UNUSED_FF.
449 *
450 * @returns VINF_SUCCESS.
451 * @param pvValue Where to store the zeros.
452 * @param cbValue How many bytes to read.
453 */
454static int iomMMIODoReadFFs(void *pvValue, size_t cbValue)
455{
456 switch (cbValue)
457 {
458 case 1: *(uint8_t *)pvValue = UINT8_C(0xff); break;
459 case 2: *(uint16_t *)pvValue = UINT16_C(0xffff); break;
460 case 4: *(uint32_t *)pvValue = UINT32_C(0xffffffff); break;
461 case 8: *(uint64_t *)pvValue = UINT64_C(0xffffffffffffffff); break;
462 default:
463 {
464 uint8_t *pb = (uint8_t *)pvValue;
465 while (cbValue--)
466 *pb++ = UINT8_C(0xff);
467 break;
468 }
469 }
470 return VINF_SUCCESS;
471}
472
473
474/**
475 * Implements VINF_IOM_MMIO_UNUSED_00.
476 *
477 * @returns VINF_SUCCESS.
478 * @param pvValue Where to store the zeros.
479 * @param cbValue How many bytes to read.
480 */
481static int iomMMIODoRead00s(void *pvValue, size_t cbValue)
482{
483 switch (cbValue)
484 {
485 case 1: *(uint8_t *)pvValue = UINT8_C(0x00); break;
486 case 2: *(uint16_t *)pvValue = UINT16_C(0x0000); break;
487 case 4: *(uint32_t *)pvValue = UINT32_C(0x00000000); break;
488 case 8: *(uint64_t *)pvValue = UINT64_C(0x0000000000000000); break;
489 default:
490 {
491 uint8_t *pb = (uint8_t *)pvValue;
492 while (cbValue--)
493 *pb++ = UINT8_C(0x00);
494 break;
495 }
496 }
497 return VINF_SUCCESS;
498}
499
500
501/**
502 * Wrapper which does the read and updates range statistics when such are enabled.
503 */
504DECLINLINE(VBOXSTRICTRC) iomMMIODoRead(PVM pVM, PVMCPU pVCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhys,
505 void *pvValue, unsigned cbValue)
506{
507#ifdef VBOX_WITH_STATISTICS
508 int rcSem = IOM_LOCK_SHARED(pVM);
509 if (rcSem == VERR_SEM_BUSY)
510 return VINF_IOM_R3_MMIO_READ;
511 PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhys, pRange);
512 if (!pStats)
513# ifdef IN_RING3
514 return VERR_NO_MEMORY;
515# else
516 return VINF_IOM_R3_MMIO_READ;
517# endif
518 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfRead), a);
519#else
520 NOREF(pVCpu);
521#endif
522
523 VBOXSTRICTRC rcStrict;
524 if (RT_LIKELY(pRange->CTX_SUFF(pfnReadCallback)))
525 {
526 if ( ( cbValue == 4
527 && !(GCPhys & 3))
528 || (pRange->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_PASSTHRU
529 || ( cbValue == 8
530 && !(GCPhys & 7)
531 && (pRange->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_DWORD_QWORD ) )
532 rcStrict = pRange->CTX_SUFF(pfnReadCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser), GCPhys,
533 pvValue, cbValue);
534 else
535 rcStrict = iomMMIODoComplicatedRead(pVM, pRange, GCPhys, pvValue, cbValue);
536 }
537 else
538 rcStrict = VINF_IOM_MMIO_UNUSED_FF;
539 if (rcStrict != VINF_SUCCESS)
540 {
541 switch (VBOXSTRICTRC_VAL(rcStrict))
542 {
543 case VINF_IOM_MMIO_UNUSED_FF: rcStrict = iomMMIODoReadFFs(pvValue, cbValue); break;
544 case VINF_IOM_MMIO_UNUSED_00: rcStrict = iomMMIODoRead00s(pvValue, cbValue); break;
545 }
546 }
547
548 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfRead), a);
549 STAM_COUNTER_INC(&pStats->Accesses);
550 return rcStrict;
551}
552
553/**
554 * Common worker for the \#PF handler and IOMMMIOPhysHandler (APIC+VT-x).
555 *
556 * @returns VBox status code (appropriate for GC return).
557 * @param pVM The cross context VM structure.
558 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
559 * @param uErrorCode CPU Error code. This is UINT32_MAX when we don't have
560 * any error code (the EPT misconfig hack).
561 * @param pCtxCore Trap register frame.
562 * @param GCPhysFault The GC physical address corresponding to pvFault.
563 * @param pvUser Pointer to the MMIO ring-3 range entry.
564 */
565static VBOXSTRICTRC iomMmioCommonPfHandler(PVM pVM, PVMCPU pVCpu, uint32_t uErrorCode, PCPUMCTXCORE pCtxCore,
566 RTGCPHYS GCPhysFault, void *pvUser)
567{
568 RT_NOREF_PV(uErrorCode);
569 int rc = IOM_LOCK_SHARED(pVM);
570#ifndef IN_RING3
571 if (rc == VERR_SEM_BUSY)
572 return VINF_IOM_R3_MMIO_READ_WRITE;
573#endif
574 AssertRC(rc);
575
576 STAM_PROFILE_START(&pVM->iom.s.StatRZMMIOHandler, a);
577 Log(("iomMmioCommonPfHandler: GCPhys=%RGp uErr=%#x rip=%RGv\n", GCPhysFault, uErrorCode, (RTGCPTR)pCtxCore->rip));
578
579 PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
580 Assert(pRange);
581 Assert(pRange == iomMmioGetRange(pVM, pVCpu, GCPhysFault));
582 iomMmioRetainRange(pRange);
583#ifndef VBOX_WITH_STATISTICS
584 IOM_UNLOCK_SHARED(pVM);
585
586#else
587 /*
588 * Locate the statistics.
589 */
590 PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhysFault, pRange);
591 if (!pStats)
592 {
593 iomMmioReleaseRange(pVM, pRange);
594# ifdef IN_RING3
595 return VERR_NO_MEMORY;
596# else
597 STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
598 STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOFailures);
599 return VINF_IOM_R3_MMIO_READ_WRITE;
600# endif
601 }
602#endif
603
604#ifndef IN_RING3
605 /*
606 * Should we defer the request right away? This isn't usually the case, so
607 * do the simple test first and the try deal with uErrorCode being N/A.
608 */
609 if (RT_UNLIKELY( ( !pRange->CTX_SUFF(pfnWriteCallback)
610 || !pRange->CTX_SUFF(pfnReadCallback))
611 && ( uErrorCode == UINT32_MAX
612 ? pRange->pfnWriteCallbackR3 || pRange->pfnReadCallbackR3
613 : uErrorCode & X86_TRAP_PF_RW
614 ? !pRange->CTX_SUFF(pfnWriteCallback) && pRange->pfnWriteCallbackR3
615 : !pRange->CTX_SUFF(pfnReadCallback) && pRange->pfnReadCallbackR3
616 )
617 )
618 )
619 {
620 if (uErrorCode & X86_TRAP_PF_RW)
621 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Write,ToR3));
622 else
623 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Read,ToR3));
624
625 STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
626 STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOFailures);
627 iomMmioReleaseRange(pVM, pRange);
628 return VINF_IOM_R3_MMIO_READ_WRITE;
629 }
630#endif /* !IN_RING3 */
631
632 /*
633 * Retain the range and do locking.
634 */
635 PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
636 rc = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ_WRITE);
637 if (rc != VINF_SUCCESS)
638 {
639 iomMmioReleaseRange(pVM, pRange);
640 return rc;
641 }
642
643 /*
644 * Let IEM call us back via iomMmioHandler.
645 */
646 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
647
648 NOREF(pCtxCore); NOREF(GCPhysFault);
649 STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
650 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
651 iomMmioReleaseRange(pVM, pRange);
652 if (RT_SUCCESS(rcStrict))
653 return rcStrict;
654 if ( rcStrict == VERR_IEM_ASPECT_NOT_IMPLEMENTED
655 || rcStrict == VERR_IEM_INSTR_NOT_IMPLEMENTED)
656 {
657 Log(("IOM: Hit unsupported IEM feature!\n"));
658 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
659 }
660 return rcStrict;
661}
662
663
664/**
665 * @callback_method_impl{FNPGMRZPHYSPFHANDLER,
666 * \#PF access handler callback for MMIO pages.}
667 *
668 * @remarks The @a pvUser argument points to the IOMMMIORANGE.
669 */
670DECLEXPORT(VBOXSTRICTRC) iomMmioPfHandler(PVM pVM, PVMCPU pVCpu, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPTR pvFault,
671 RTGCPHYS GCPhysFault, void *pvUser)
672{
673 LogFlow(("iomMmioPfHandler: GCPhys=%RGp uErr=%#x pvFault=%RGv rip=%RGv\n",
674 GCPhysFault, (uint32_t)uErrorCode, pvFault, (RTGCPTR)pCtxCore->rip)); NOREF(pvFault);
675 return iomMmioCommonPfHandler(pVM, pVCpu, (uint32_t)uErrorCode, pCtxCore, GCPhysFault, pvUser);
676}
677
678
679/**
680 * Physical access handler for MMIO ranges.
681 *
682 * @returns VBox status code (appropriate for GC return).
683 * @param pVM The cross context VM structure.
684 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
685 * @param uErrorCode CPU Error code.
686 * @param pCtxCore Trap register frame.
687 * @param GCPhysFault The GC physical address.
688 */
689VMMDECL(VBOXSTRICTRC) IOMMMIOPhysHandler(PVM pVM, PVMCPU pVCpu, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPHYS GCPhysFault)
690{
691 /*
692 * We don't have a range here, so look it up before calling the common function.
693 */
694 int rc2 = IOM_LOCK_SHARED(pVM); NOREF(rc2);
695#ifndef IN_RING3
696 if (rc2 == VERR_SEM_BUSY)
697 return VINF_IOM_R3_MMIO_READ_WRITE;
698#endif
699 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhysFault);
700 if (RT_UNLIKELY(!pRange))
701 {
702 IOM_UNLOCK_SHARED(pVM);
703 return VERR_IOM_MMIO_RANGE_NOT_FOUND;
704 }
705 iomMmioRetainRange(pRange);
706 IOM_UNLOCK_SHARED(pVM);
707
708 VBOXSTRICTRC rcStrict = iomMmioCommonPfHandler(pVM, pVCpu, (uint32_t)uErrorCode, pCtxCore, GCPhysFault, pRange);
709
710 iomMmioReleaseRange(pVM, pRange);
711 return VBOXSTRICTRC_VAL(rcStrict);
712}
713
714
715/**
716 * @callback_method_impl{FNPGMPHYSHANDLER, MMIO page accesses}
717 *
718 * @remarks The @a pvUser argument points to the MMIO range entry.
719 */
720PGM_ALL_CB2_DECL(VBOXSTRICTRC) iomMmioHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhysFault, void *pvPhys, void *pvBuf,
721 size_t cbBuf, PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
722{
723 PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
724 STAM_COUNTER_INC(&pVM->iom.s.StatR3MMIOHandler);
725
726 NOREF(pvPhys); NOREF(enmOrigin);
727 AssertPtr(pRange);
728 AssertMsg(cbBuf >= 1, ("%zu\n", cbBuf));
729
730
731#ifndef IN_RING3
732 /*
733 * If someone is doing FXSAVE, FXRSTOR, XSAVE, XRSTOR or other stuff dealing with
734 * large amounts of data, just go to ring-3 where we don't need to deal with partial
735 * successes. No chance any of these will be problematic read-modify-write stuff.
736 */
737 if (cbBuf > sizeof(pVCpu->iom.s.PendingMmioWrite.abValue))
738 return enmAccessType == PGMACCESSTYPE_WRITE ? VINF_IOM_R3_MMIO_WRITE : VINF_IOM_R3_MMIO_READ;
739#endif
740
741 /*
742 * Validate the range.
743 */
744 int rc = IOM_LOCK_SHARED(pVM);
745#ifndef IN_RING3
746 if (rc == VERR_SEM_BUSY)
747 {
748 if (enmAccessType == PGMACCESSTYPE_READ)
749 return VINF_IOM_R3_MMIO_READ;
750 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
751 return iomMmioRing3WritePending(pVCpu, GCPhysFault, pvBuf, cbBuf, NULL /*pRange*/);
752 }
753#endif
754 AssertRC(rc);
755 Assert(pRange == iomMmioGetRange(pVM, pVCpu, GCPhysFault));
756
757 /*
758 * Perform locking.
759 */
760 iomMmioRetainRange(pRange);
761 PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
762 IOM_UNLOCK_SHARED(pVM);
763 VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ_WRITE);
764 if (rcStrict == VINF_SUCCESS)
765 {
766 /*
767 * Perform the access.
768 */
769 if (enmAccessType == PGMACCESSTYPE_READ)
770 rcStrict = iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, pvBuf, (unsigned)cbBuf);
771 else
772 {
773 rcStrict = iomMMIODoWrite(pVM, pVCpu, pRange, GCPhysFault, pvBuf, (unsigned)cbBuf);
774#ifndef IN_RING3
775 if (rcStrict == VINF_IOM_R3_MMIO_WRITE)
776 rcStrict = iomMmioRing3WritePending(pVCpu, GCPhysFault, pvBuf, cbBuf, pRange);
777#endif
778 }
779
780 /* Check the return code. */
781#ifdef IN_RING3
782 AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc - %RGp - %s\n", VBOXSTRICTRC_VAL(rcStrict), GCPhysFault, pRange->pszDesc));
783#else
784 AssertMsg( rcStrict == VINF_SUCCESS
785 || rcStrict == (enmAccessType == PGMACCESSTYPE_READ ? VINF_IOM_R3_MMIO_READ : VINF_IOM_R3_MMIO_WRITE)
786 || (rcStrict == VINF_IOM_R3_MMIO_COMMIT_WRITE && enmAccessType == PGMACCESSTYPE_WRITE)
787 || rcStrict == VINF_IOM_R3_MMIO_READ_WRITE
788 || rcStrict == VINF_EM_DBG_STOP
789 || rcStrict == VINF_EM_DBG_EVENT
790 || rcStrict == VINF_EM_DBG_BREAKPOINT
791 || rcStrict == VINF_EM_OFF
792 || rcStrict == VINF_EM_SUSPEND
793 || rcStrict == VINF_EM_RESET
794 || rcStrict == VINF_EM_RAW_EMULATE_IO_BLOCK
795 //|| rcStrict == VINF_EM_HALT /* ?? */
796 //|| rcStrict == VINF_EM_NO_MEMORY /* ?? */
797 , ("%Rrc - %RGp - %p\n", VBOXSTRICTRC_VAL(rcStrict), GCPhysFault, pDevIns));
798#endif
799
800 iomMmioReleaseRange(pVM, pRange);
801 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
802 }
803#ifdef IN_RING3
804 else
805 iomMmioReleaseRange(pVM, pRange);
806#else
807 else
808 {
809 if (rcStrict == VINF_IOM_R3_MMIO_READ_WRITE)
810 {
811 if (enmAccessType == PGMACCESSTYPE_READ)
812 rcStrict = VINF_IOM_R3_MMIO_READ;
813 else
814 {
815 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
816 rcStrict = iomMmioRing3WritePending(pVCpu, GCPhysFault, pvBuf, cbBuf, pRange);
817 }
818 }
819 iomMmioReleaseRange(pVM, pRange);
820 }
821#endif
822 return rcStrict;
823}
824
825
826#ifdef IN_RING3 /* Only used by REM. */
827
828/**
829 * Reads a MMIO register.
830 *
831 * @returns VBox status code.
832 *
833 * @param pVM The cross context VM structure.
834 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
835 * @param GCPhys The physical address to read.
836 * @param pu32Value Where to store the value read.
837 * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
838 */
839VMMDECL(VBOXSTRICTRC) IOMMMIORead(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, uint32_t *pu32Value, size_t cbValue)
840{
841 Assert(pVCpu->iom.s.PendingMmioWrite.cbValue == 0);
842 /* Take the IOM lock before performing any MMIO. */
843 VBOXSTRICTRC rc = IOM_LOCK_SHARED(pVM);
844#ifndef IN_RING3
845 if (rc == VERR_SEM_BUSY)
846 return VINF_IOM_R3_MMIO_WRITE;
847#endif
848 AssertRC(VBOXSTRICTRC_VAL(rc));
849#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
850 IEMNotifyMMIORead(pVM, GCPhys, cbValue);
851#endif
852
853 /*
854 * Lookup the current context range node and statistics.
855 */
856 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhys);
857 if (!pRange)
858 {
859 AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%RGp cbValue=%d\n", GCPhys, cbValue));
860 IOM_UNLOCK_SHARED(pVM);
861 return VERR_IOM_MMIO_RANGE_NOT_FOUND;
862 }
863 iomMmioRetainRange(pRange);
864#ifndef VBOX_WITH_STATISTICS
865 IOM_UNLOCK_SHARED(pVM);
866
867#else /* VBOX_WITH_STATISTICS */
868 PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhys, pRange);
869 if (!pStats)
870 {
871 iomMmioReleaseRange(pVM, pRange);
872# ifdef IN_RING3
873 return VERR_NO_MEMORY;
874# else
875 return VINF_IOM_R3_MMIO_READ;
876# endif
877 }
878 STAM_COUNTER_INC(&pStats->Accesses);
879#endif /* VBOX_WITH_STATISTICS */
880
881 if (pRange->CTX_SUFF(pfnReadCallback))
882 {
883 /*
884 * Perform locking.
885 */
886 PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
887 rc = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_WRITE);
888 if (rc != VINF_SUCCESS)
889 {
890 iomMmioReleaseRange(pVM, pRange);
891 return rc;
892 }
893
894 /*
895 * Perform the read and deal with the result.
896 */
897 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfRead), a);
898 if ( (cbValue == 4 && !(GCPhys & 3))
899 || (pRange->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_PASSTHRU
900 || (cbValue == 8 && !(GCPhys & 7)) )
901 rc = pRange->CTX_SUFF(pfnReadCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser), GCPhys,
902 pu32Value, (unsigned)cbValue);
903 else
904 rc = iomMMIODoComplicatedRead(pVM, pRange, GCPhys, pu32Value, (unsigned)cbValue);
905 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfRead), a);
906 switch (VBOXSTRICTRC_VAL(rc))
907 {
908 case VINF_SUCCESS:
909 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
910 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
911 iomMmioReleaseRange(pVM, pRange);
912 return rc;
913#ifndef IN_RING3
914 case VINF_IOM_R3_MMIO_READ:
915 case VINF_IOM_R3_MMIO_READ_WRITE:
916 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Read,ToR3));
917#endif
918 default:
919 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
920 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
921 iomMmioReleaseRange(pVM, pRange);
922 return rc;
923
924 case VINF_IOM_MMIO_UNUSED_00:
925 iomMMIODoRead00s(pu32Value, cbValue);
926 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
927 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
928 iomMmioReleaseRange(pVM, pRange);
929 return VINF_SUCCESS;
930
931 case VINF_IOM_MMIO_UNUSED_FF:
932 iomMMIODoReadFFs(pu32Value, cbValue);
933 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
934 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
935 iomMmioReleaseRange(pVM, pRange);
936 return VINF_SUCCESS;
937 }
938 /* not reached */
939 }
940#ifndef IN_RING3
941 if (pRange->pfnReadCallbackR3)
942 {
943 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Read,ToR3));
944 iomMmioReleaseRange(pVM, pRange);
945 return VINF_IOM_R3_MMIO_READ;
946 }
947#endif
948
949 /*
950 * Unassigned memory - this is actually not supposed t happen...
951 */
952 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfRead), a); /** @todo STAM_PROFILE_ADD_ZERO_PERIOD */
953 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfRead), a);
954 iomMMIODoReadFFs(pu32Value, cbValue);
955 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
956 iomMmioReleaseRange(pVM, pRange);
957 return VINF_SUCCESS;
958}
959
960
961/**
962 * Writes to a MMIO register.
963 *
964 * @returns VBox status code.
965 *
966 * @param pVM The cross context VM structure.
967 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
968 * @param GCPhys The physical address to write to.
969 * @param u32Value The value to write.
970 * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
971 */
972VMMDECL(VBOXSTRICTRC) IOMMMIOWrite(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue)
973{
974 Assert(pVCpu->iom.s.PendingMmioWrite.cbValue == 0);
975 /* Take the IOM lock before performing any MMIO. */
976 VBOXSTRICTRC rc = IOM_LOCK_SHARED(pVM);
977#ifndef IN_RING3
978 if (rc == VERR_SEM_BUSY)
979 return VINF_IOM_R3_MMIO_WRITE;
980#endif
981 AssertRC(VBOXSTRICTRC_VAL(rc));
982#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
983 IEMNotifyMMIOWrite(pVM, GCPhys, u32Value, cbValue);
984#endif
985
986 /*
987 * Lookup the current context range node.
988 */
989 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhys);
990 if (!pRange)
991 {
992 AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%RGp cbValue=%d\n", GCPhys, cbValue));
993 IOM_UNLOCK_SHARED(pVM);
994 return VERR_IOM_MMIO_RANGE_NOT_FOUND;
995 }
996 iomMmioRetainRange(pRange);
997#ifndef VBOX_WITH_STATISTICS
998 IOM_UNLOCK_SHARED(pVM);
999
1000#else /* VBOX_WITH_STATISTICS */
1001 PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhys, pRange);
1002 if (!pStats)
1003 {
1004 iomMmioReleaseRange(pVM, pRange);
1005# ifdef IN_RING3
1006 return VERR_NO_MEMORY;
1007# else
1008 return VINF_IOM_R3_MMIO_WRITE;
1009# endif
1010 }
1011 STAM_COUNTER_INC(&pStats->Accesses);
1012#endif /* VBOX_WITH_STATISTICS */
1013
1014 if (pRange->CTX_SUFF(pfnWriteCallback))
1015 {
1016 /*
1017 * Perform locking.
1018 */
1019 PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
1020 rc = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ);
1021 if (rc != VINF_SUCCESS)
1022 {
1023 iomMmioReleaseRange(pVM, pRange);
1024 return rc;
1025 }
1026
1027 /*
1028 * Perform the write.
1029 */
1030 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfWrite), a);
1031 if ( (cbValue == 4 && !(GCPhys & 3))
1032 || (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_PASSTHRU
1033 || (cbValue == 8 && !(GCPhys & 7)) )
1034 rc = pRange->CTX_SUFF(pfnWriteCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
1035 GCPhys, &u32Value, (unsigned)cbValue);
1036 else
1037 rc = iomMMIODoComplicatedWrite(pVM, pVCpu, pRange, GCPhys, &u32Value, (unsigned)cbValue);
1038 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfWrite), a);
1039#ifndef IN_RING3
1040 if ( rc == VINF_IOM_R3_MMIO_WRITE
1041 || rc == VINF_IOM_R3_MMIO_READ_WRITE)
1042 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Write,ToR3));
1043#endif
1044 Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, u32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
1045 iomMmioReleaseRange(pVM, pRange);
1046 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
1047 return rc;
1048 }
1049#ifndef IN_RING3
1050 if (pRange->pfnWriteCallbackR3)
1051 {
1052 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Write,ToR3));
1053 iomMmioReleaseRange(pVM, pRange);
1054 return VINF_IOM_R3_MMIO_WRITE;
1055 }
1056#endif
1057
1058 /*
1059 * No write handler, nothing to do.
1060 */
1061 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfWrite), a);
1062 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfWrite), a);
1063 Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, u32Value, cbValue, VINF_SUCCESS));
1064 iomMmioReleaseRange(pVM, pRange);
1065 return VINF_SUCCESS;
1066}
1067
1068#endif /* IN_RING3 - only used by REM. */
1069#ifndef IN_RC
1070
1071/**
1072 * Mapping an MMIO2 page in place of an MMIO page for direct access.
1073 *
1074 * (This is a special optimization used by the VGA device.)
1075 *
1076 * @returns VBox status code. This API may return VINF_SUCCESS even if no
1077 * remapping is made,.
1078 *
1079 * @param pVM The cross context VM structure.
1080 * @param GCPhys The address of the MMIO page to be changed.
1081 * @param GCPhysRemapped The address of the MMIO2 page.
1082 * @param fPageFlags Page flags to set. Must be (X86_PTE_RW | X86_PTE_P)
1083 * for the time being.
1084 */
1085VMMDECL(int) IOMMMIOMapMMIO2Page(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped, uint64_t fPageFlags)
1086{
1087# ifndef IEM_VERIFICATION_MODE_FULL
1088 /* Currently only called from the VGA device during MMIO. */
1089 Log(("IOMMMIOMapMMIO2Page %RGp -> %RGp flags=%RX64\n", GCPhys, GCPhysRemapped, fPageFlags));
1090 AssertReturn(fPageFlags == (X86_PTE_RW | X86_PTE_P), VERR_INVALID_PARAMETER);
1091 PVMCPU pVCpu = VMMGetCpu(pVM);
1092
1093 /* This currently only works in real mode, protected mode without paging or with nested paging. */
1094 if ( !HMIsEnabled(pVM) /* useless without VT-x/AMD-V */
1095 || ( CPUMIsGuestInPagedProtectedMode(pVCpu)
1096 && !HMIsNestedPagingActive(pVM)))
1097 return VINF_SUCCESS; /* ignore */
1098
1099 int rc = IOM_LOCK_SHARED(pVM);
1100 if (RT_FAILURE(rc))
1101 return VINF_SUCCESS; /* better luck the next time around */
1102
1103 /*
1104 * Lookup the context range node the page belongs to.
1105 */
1106 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhys);
1107 AssertMsgReturn(pRange,
1108 ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
1109
1110 Assert((pRange->GCPhys & PAGE_OFFSET_MASK) == 0);
1111 Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
1112
1113 /*
1114 * Do the aliasing; page align the addresses since PGM is picky.
1115 */
1116 GCPhys &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
1117 GCPhysRemapped &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
1118
1119 rc = PGMHandlerPhysicalPageAlias(pVM, pRange->GCPhys, GCPhys, GCPhysRemapped);
1120
1121 IOM_UNLOCK_SHARED(pVM);
1122 AssertRCReturn(rc, rc);
1123
1124 /*
1125 * Modify the shadow page table. Since it's an MMIO page it won't be present and we
1126 * can simply prefetch it.
1127 *
1128 * Note: This is a NOP in the EPT case; we'll just let it fault again to resync the page.
1129 */
1130# if 0 /* The assertion is wrong for the PGM_SYNC_CLEAR_PGM_POOL and VINF_PGM_HANDLER_ALREADY_ALIASED cases. */
1131# ifdef VBOX_STRICT
1132 uint64_t fFlags;
1133 RTHCPHYS HCPhys;
1134 rc = PGMShwGetPage(pVCpu, (RTGCPTR)GCPhys, &fFlags, &HCPhys);
1135 Assert(rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
1136# endif
1137# endif
1138 rc = PGMPrefetchPage(pVCpu, (RTGCPTR)GCPhys);
1139 Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
1140# else
1141 RT_NOREF_PV(pVM); RT_NOREF(GCPhys); RT_NOREF(GCPhysRemapped); RT_NOREF(fPageFlags);
1142# endif /* !IEM_VERIFICATION_MODE_FULL */
1143 return VINF_SUCCESS;
1144}
1145
1146
1147# ifndef IEM_VERIFICATION_MODE_FULL
1148/**
1149 * Mapping a HC page in place of an MMIO page for direct access.
1150 *
1151 * (This is a special optimization used by the APIC in the VT-x case.)
1152 *
1153 * @returns VBox status code.
1154 *
1155 * @param pVM The cross context VM structure.
1156 * @param pVCpu The cross context virtual CPU structure.
1157 * @param GCPhys The address of the MMIO page to be changed.
1158 * @param HCPhys The address of the host physical page.
1159 * @param fPageFlags Page flags to set. Must be (X86_PTE_RW | X86_PTE_P)
1160 * for the time being.
1161 */
1162VMMDECL(int) IOMMMIOMapMMIOHCPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags)
1163{
1164 /* Currently only called from VT-x code during a page fault. */
1165 Log(("IOMMMIOMapMMIOHCPage %RGp -> %RGp flags=%RX64\n", GCPhys, HCPhys, fPageFlags));
1166
1167 AssertReturn(fPageFlags == (X86_PTE_RW | X86_PTE_P), VERR_INVALID_PARAMETER);
1168 Assert(HMIsEnabled(pVM));
1169
1170 /*
1171 * Lookup the context range node the page belongs to.
1172 */
1173# ifdef VBOX_STRICT
1174 /* Can't lock IOM here due to potential deadlocks in the VGA device; not safe to access. */
1175 PIOMMMIORANGE pRange = iomMMIOGetRangeUnsafe(pVM, pVCpu, GCPhys);
1176 AssertMsgReturn(pRange,
1177 ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
1178 Assert((pRange->GCPhys & PAGE_OFFSET_MASK) == 0);
1179 Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
1180# endif
1181
1182 /*
1183 * Do the aliasing; page align the addresses since PGM is picky.
1184 */
1185 GCPhys &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
1186 HCPhys &= ~(RTHCPHYS)PAGE_OFFSET_MASK;
1187
1188 int rc = PGMHandlerPhysicalPageAliasHC(pVM, GCPhys, GCPhys, HCPhys);
1189 AssertRCReturn(rc, rc);
1190
1191 /*
1192 * Modify the shadow page table. Since it's an MMIO page it won't be present and we
1193 * can simply prefetch it.
1194 *
1195 * Note: This is a NOP in the EPT case; we'll just let it fault again to resync the page.
1196 */
1197 rc = PGMPrefetchPage(pVCpu, (RTGCPTR)GCPhys);
1198 Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
1199 return VINF_SUCCESS;
1200}
1201# endif /* !IEM_VERIFICATION_MODE_FULL */
1202
1203
1204/**
1205 * Reset a previously modified MMIO region; restore the access flags.
1206 *
1207 * @returns VBox status code.
1208 *
1209 * @param pVM The cross context VM structure.
1210 * @param GCPhys Physical address that's part of the MMIO region to be reset.
1211 */
1212VMMDECL(int) IOMMMIOResetRegion(PVM pVM, RTGCPHYS GCPhys)
1213{
1214 Log(("IOMMMIOResetRegion %RGp\n", GCPhys));
1215
1216 PVMCPU pVCpu = VMMGetCpu(pVM);
1217
1218 /* This currently only works in real mode, protected mode without paging or with nested paging. */
1219 if ( !HMIsEnabled(pVM) /* useless without VT-x/AMD-V */
1220 || ( CPUMIsGuestInPagedProtectedMode(pVCpu)
1221 && !HMIsNestedPagingActive(pVM)))
1222 return VINF_SUCCESS; /* ignore */
1223
1224 /*
1225 * Lookup the context range node the page belongs to.
1226 */
1227# ifdef VBOX_STRICT
1228 /* Can't lock IOM here due to potential deadlocks in the VGA device; not safe to access. */
1229 PIOMMMIORANGE pRange = iomMMIOGetRangeUnsafe(pVM, pVCpu, GCPhys);
1230 AssertMsgReturn(pRange,
1231 ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
1232 Assert((pRange->GCPhys & PAGE_OFFSET_MASK) == 0);
1233 Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
1234# endif
1235
1236 /*
1237 * Call PGM to do the job work.
1238 *
1239 * After the call, all the pages should be non-present... unless there is
1240 * a page pool flush pending (unlikely).
1241 */
1242 int rc = PGMHandlerPhysicalReset(pVM, GCPhys);
1243 AssertRC(rc);
1244
1245# ifdef VBOX_STRICT
1246 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3))
1247 {
1248 uint32_t cb = pRange->cb;
1249 GCPhys = pRange->GCPhys;
1250 while (cb)
1251 {
1252 uint64_t fFlags;
1253 RTHCPHYS HCPhys;
1254 rc = PGMShwGetPage(pVCpu, (RTGCPTR)GCPhys, &fFlags, &HCPhys);
1255 Assert(rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
1256 cb -= PAGE_SIZE;
1257 GCPhys += PAGE_SIZE;
1258 }
1259 }
1260# endif
1261 return rc;
1262}
1263
1264#endif /* !IN_RC */
1265
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