VirtualBox

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

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

iomMmioHandler: pDevIns can be NULL in R0 and RC, return to ring-3.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 45.8 KB
Line 
1/* $Id: IOMAllMMIO.cpp 71211 2018-03-05 20:26:21Z 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#ifdef IN_RING3
764 VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ_WRITE);
765#else
766 VBOXSTRICTRC rcStrict = pDevIns ? PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ_WRITE)
767 : VINF_IOM_R3_MMIO_READ_WRITE;
768#endif
769 if (rcStrict == VINF_SUCCESS)
770 {
771 /*
772 * Perform the access.
773 */
774 if (enmAccessType == PGMACCESSTYPE_READ)
775 rcStrict = iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, pvBuf, (unsigned)cbBuf);
776 else
777 {
778 rcStrict = iomMMIODoWrite(pVM, pVCpu, pRange, GCPhysFault, pvBuf, (unsigned)cbBuf);
779#ifndef IN_RING3
780 if (rcStrict == VINF_IOM_R3_MMIO_WRITE)
781 rcStrict = iomMmioRing3WritePending(pVCpu, GCPhysFault, pvBuf, cbBuf, pRange);
782#endif
783 }
784
785 /* Check the return code. */
786#ifdef IN_RING3
787 AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc - %RGp - %s\n", VBOXSTRICTRC_VAL(rcStrict), GCPhysFault, pRange->pszDesc));
788#else
789 AssertMsg( rcStrict == VINF_SUCCESS
790 || rcStrict == (enmAccessType == PGMACCESSTYPE_READ ? VINF_IOM_R3_MMIO_READ : VINF_IOM_R3_MMIO_WRITE)
791 || (rcStrict == VINF_IOM_R3_MMIO_COMMIT_WRITE && enmAccessType == PGMACCESSTYPE_WRITE)
792 || rcStrict == VINF_IOM_R3_MMIO_READ_WRITE
793 || rcStrict == VINF_EM_DBG_STOP
794 || rcStrict == VINF_EM_DBG_EVENT
795 || rcStrict == VINF_EM_DBG_BREAKPOINT
796 || rcStrict == VINF_EM_OFF
797 || rcStrict == VINF_EM_SUSPEND
798 || rcStrict == VINF_EM_RESET
799 || rcStrict == VINF_EM_RAW_EMULATE_IO_BLOCK
800 //|| rcStrict == VINF_EM_HALT /* ?? */
801 //|| rcStrict == VINF_EM_NO_MEMORY /* ?? */
802 , ("%Rrc - %RGp - %p\n", VBOXSTRICTRC_VAL(rcStrict), GCPhysFault, pDevIns));
803#endif
804
805 iomMmioReleaseRange(pVM, pRange);
806 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
807 }
808#ifdef IN_RING3
809 else
810 iomMmioReleaseRange(pVM, pRange);
811#else
812 else
813 {
814 if (rcStrict == VINF_IOM_R3_MMIO_READ_WRITE)
815 {
816 if (enmAccessType == PGMACCESSTYPE_READ)
817 rcStrict = VINF_IOM_R3_MMIO_READ;
818 else
819 {
820 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
821 rcStrict = iomMmioRing3WritePending(pVCpu, GCPhysFault, pvBuf, cbBuf, pRange);
822 }
823 }
824 iomMmioReleaseRange(pVM, pRange);
825 }
826#endif
827 return rcStrict;
828}
829
830
831#ifdef IN_RING3 /* Only used by REM. */
832
833/**
834 * Reads a MMIO register.
835 *
836 * @returns VBox status code.
837 *
838 * @param pVM The cross context VM structure.
839 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
840 * @param GCPhys The physical address to read.
841 * @param pu32Value Where to store the value read.
842 * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
843 */
844VMMDECL(VBOXSTRICTRC) IOMMMIORead(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, uint32_t *pu32Value, size_t cbValue)
845{
846 Assert(pVCpu->iom.s.PendingMmioWrite.cbValue == 0);
847 /* Take the IOM lock before performing any MMIO. */
848 VBOXSTRICTRC rc = IOM_LOCK_SHARED(pVM);
849#ifndef IN_RING3
850 if (rc == VERR_SEM_BUSY)
851 return VINF_IOM_R3_MMIO_WRITE;
852#endif
853 AssertRC(VBOXSTRICTRC_VAL(rc));
854#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
855 IEMNotifyMMIORead(pVM, GCPhys, cbValue);
856#endif
857
858 /*
859 * Lookup the current context range node and statistics.
860 */
861 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhys);
862 if (!pRange)
863 {
864 AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%RGp cbValue=%d\n", GCPhys, cbValue));
865 IOM_UNLOCK_SHARED(pVM);
866 return VERR_IOM_MMIO_RANGE_NOT_FOUND;
867 }
868 iomMmioRetainRange(pRange);
869#ifndef VBOX_WITH_STATISTICS
870 IOM_UNLOCK_SHARED(pVM);
871
872#else /* VBOX_WITH_STATISTICS */
873 PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhys, pRange);
874 if (!pStats)
875 {
876 iomMmioReleaseRange(pVM, pRange);
877# ifdef IN_RING3
878 return VERR_NO_MEMORY;
879# else
880 return VINF_IOM_R3_MMIO_READ;
881# endif
882 }
883 STAM_COUNTER_INC(&pStats->Accesses);
884#endif /* VBOX_WITH_STATISTICS */
885
886 if (pRange->CTX_SUFF(pfnReadCallback))
887 {
888 /*
889 * Perform locking.
890 */
891 PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
892 rc = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_WRITE);
893 if (rc != VINF_SUCCESS)
894 {
895 iomMmioReleaseRange(pVM, pRange);
896 return rc;
897 }
898
899 /*
900 * Perform the read and deal with the result.
901 */
902 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfRead), a);
903 if ( (cbValue == 4 && !(GCPhys & 3))
904 || (pRange->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_PASSTHRU
905 || (cbValue == 8 && !(GCPhys & 7)) )
906 rc = pRange->CTX_SUFF(pfnReadCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser), GCPhys,
907 pu32Value, (unsigned)cbValue);
908 else
909 rc = iomMMIODoComplicatedRead(pVM, pRange, GCPhys, pu32Value, (unsigned)cbValue);
910 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfRead), a);
911 switch (VBOXSTRICTRC_VAL(rc))
912 {
913 case VINF_SUCCESS:
914 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
915 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
916 iomMmioReleaseRange(pVM, pRange);
917 return rc;
918#ifndef IN_RING3
919 case VINF_IOM_R3_MMIO_READ:
920 case VINF_IOM_R3_MMIO_READ_WRITE:
921 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Read,ToR3));
922#endif
923 default:
924 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
925 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
926 iomMmioReleaseRange(pVM, pRange);
927 return rc;
928
929 case VINF_IOM_MMIO_UNUSED_00:
930 iomMMIODoRead00s(pu32Value, cbValue);
931 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
932 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
933 iomMmioReleaseRange(pVM, pRange);
934 return VINF_SUCCESS;
935
936 case VINF_IOM_MMIO_UNUSED_FF:
937 iomMMIODoReadFFs(pu32Value, cbValue);
938 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
939 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
940 iomMmioReleaseRange(pVM, pRange);
941 return VINF_SUCCESS;
942 }
943 /* not reached */
944 }
945#ifndef IN_RING3
946 if (pRange->pfnReadCallbackR3)
947 {
948 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Read,ToR3));
949 iomMmioReleaseRange(pVM, pRange);
950 return VINF_IOM_R3_MMIO_READ;
951 }
952#endif
953
954 /*
955 * Unassigned memory - this is actually not supposed t happen...
956 */
957 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfRead), a); /** @todo STAM_PROFILE_ADD_ZERO_PERIOD */
958 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfRead), a);
959 iomMMIODoReadFFs(pu32Value, cbValue);
960 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
961 iomMmioReleaseRange(pVM, pRange);
962 return VINF_SUCCESS;
963}
964
965
966/**
967 * Writes to a MMIO register.
968 *
969 * @returns VBox status code.
970 *
971 * @param pVM The cross context VM structure.
972 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
973 * @param GCPhys The physical address to write to.
974 * @param u32Value The value to write.
975 * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
976 */
977VMMDECL(VBOXSTRICTRC) IOMMMIOWrite(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue)
978{
979 Assert(pVCpu->iom.s.PendingMmioWrite.cbValue == 0);
980 /* Take the IOM lock before performing any MMIO. */
981 VBOXSTRICTRC rc = IOM_LOCK_SHARED(pVM);
982#ifndef IN_RING3
983 if (rc == VERR_SEM_BUSY)
984 return VINF_IOM_R3_MMIO_WRITE;
985#endif
986 AssertRC(VBOXSTRICTRC_VAL(rc));
987#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
988 IEMNotifyMMIOWrite(pVM, GCPhys, u32Value, cbValue);
989#endif
990
991 /*
992 * Lookup the current context range node.
993 */
994 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhys);
995 if (!pRange)
996 {
997 AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%RGp cbValue=%d\n", GCPhys, cbValue));
998 IOM_UNLOCK_SHARED(pVM);
999 return VERR_IOM_MMIO_RANGE_NOT_FOUND;
1000 }
1001 iomMmioRetainRange(pRange);
1002#ifndef VBOX_WITH_STATISTICS
1003 IOM_UNLOCK_SHARED(pVM);
1004
1005#else /* VBOX_WITH_STATISTICS */
1006 PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhys, pRange);
1007 if (!pStats)
1008 {
1009 iomMmioReleaseRange(pVM, pRange);
1010# ifdef IN_RING3
1011 return VERR_NO_MEMORY;
1012# else
1013 return VINF_IOM_R3_MMIO_WRITE;
1014# endif
1015 }
1016 STAM_COUNTER_INC(&pStats->Accesses);
1017#endif /* VBOX_WITH_STATISTICS */
1018
1019 if (pRange->CTX_SUFF(pfnWriteCallback))
1020 {
1021 /*
1022 * Perform locking.
1023 */
1024 PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
1025 rc = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ);
1026 if (rc != VINF_SUCCESS)
1027 {
1028 iomMmioReleaseRange(pVM, pRange);
1029 return rc;
1030 }
1031
1032 /*
1033 * Perform the write.
1034 */
1035 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfWrite), a);
1036 if ( (cbValue == 4 && !(GCPhys & 3))
1037 || (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_PASSTHRU
1038 || (cbValue == 8 && !(GCPhys & 7)) )
1039 rc = pRange->CTX_SUFF(pfnWriteCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
1040 GCPhys, &u32Value, (unsigned)cbValue);
1041 else
1042 rc = iomMMIODoComplicatedWrite(pVM, pVCpu, pRange, GCPhys, &u32Value, (unsigned)cbValue);
1043 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfWrite), a);
1044#ifndef IN_RING3
1045 if ( rc == VINF_IOM_R3_MMIO_WRITE
1046 || rc == VINF_IOM_R3_MMIO_READ_WRITE)
1047 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Write,ToR3));
1048#endif
1049 Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, u32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
1050 iomMmioReleaseRange(pVM, pRange);
1051 PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
1052 return rc;
1053 }
1054#ifndef IN_RING3
1055 if (pRange->pfnWriteCallbackR3)
1056 {
1057 STAM_COUNTER_INC(&pStats->CTX_MID_Z(Write,ToR3));
1058 iomMmioReleaseRange(pVM, pRange);
1059 return VINF_IOM_R3_MMIO_WRITE;
1060 }
1061#endif
1062
1063 /*
1064 * No write handler, nothing to do.
1065 */
1066 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfWrite), a);
1067 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfWrite), a);
1068 Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, u32Value, cbValue, VINF_SUCCESS));
1069 iomMmioReleaseRange(pVM, pRange);
1070 return VINF_SUCCESS;
1071}
1072
1073#endif /* IN_RING3 - only used by REM. */
1074#ifndef IN_RC
1075
1076/**
1077 * Mapping an MMIO2 page in place of an MMIO page for direct access.
1078 *
1079 * (This is a special optimization used by the VGA device.)
1080 *
1081 * @returns VBox status code. This API may return VINF_SUCCESS even if no
1082 * remapping is made,.
1083 *
1084 * @param pVM The cross context VM structure.
1085 * @param GCPhys The address of the MMIO page to be changed.
1086 * @param GCPhysRemapped The address of the MMIO2 page.
1087 * @param fPageFlags Page flags to set. Must be (X86_PTE_RW | X86_PTE_P)
1088 * for the time being.
1089 */
1090VMMDECL(int) IOMMMIOMapMMIO2Page(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped, uint64_t fPageFlags)
1091{
1092# ifndef IEM_VERIFICATION_MODE_FULL
1093 /* Currently only called from the VGA device during MMIO. */
1094 Log(("IOMMMIOMapMMIO2Page %RGp -> %RGp flags=%RX64\n", GCPhys, GCPhysRemapped, fPageFlags));
1095 AssertReturn(fPageFlags == (X86_PTE_RW | X86_PTE_P), VERR_INVALID_PARAMETER);
1096 PVMCPU pVCpu = VMMGetCpu(pVM);
1097
1098 /* This currently only works in real mode, protected mode without paging or with nested paging. */
1099 /** @todo NEM: MMIO page aliasing. */
1100 if ( !HMIsEnabled(pVM) /* useless without VT-x/AMD-V */
1101 || ( CPUMIsGuestInPagedProtectedMode(pVCpu)
1102 && !HMIsNestedPagingActive(pVM)))
1103 return VINF_SUCCESS; /* ignore */
1104
1105 int rc = IOM_LOCK_SHARED(pVM);
1106 if (RT_FAILURE(rc))
1107 return VINF_SUCCESS; /* better luck the next time around */
1108
1109 /*
1110 * Lookup the context range node the page belongs to.
1111 */
1112 PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhys);
1113 AssertMsgReturn(pRange,
1114 ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
1115
1116 Assert((pRange->GCPhys & PAGE_OFFSET_MASK) == 0);
1117 Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
1118
1119 /*
1120 * Do the aliasing; page align the addresses since PGM is picky.
1121 */
1122 GCPhys &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
1123 GCPhysRemapped &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
1124
1125 rc = PGMHandlerPhysicalPageAlias(pVM, pRange->GCPhys, GCPhys, GCPhysRemapped);
1126
1127 IOM_UNLOCK_SHARED(pVM);
1128 AssertRCReturn(rc, rc);
1129
1130 /*
1131 * Modify the shadow page table. Since it's an MMIO page it won't be present and we
1132 * can simply prefetch it.
1133 *
1134 * Note: This is a NOP in the EPT case; we'll just let it fault again to resync the page.
1135 */
1136# if 0 /* The assertion is wrong for the PGM_SYNC_CLEAR_PGM_POOL and VINF_PGM_HANDLER_ALREADY_ALIASED cases. */
1137# ifdef VBOX_STRICT
1138 uint64_t fFlags;
1139 RTHCPHYS HCPhys;
1140 rc = PGMShwGetPage(pVCpu, (RTGCPTR)GCPhys, &fFlags, &HCPhys);
1141 Assert(rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
1142# endif
1143# endif
1144 rc = PGMPrefetchPage(pVCpu, (RTGCPTR)GCPhys);
1145 Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
1146# else
1147 RT_NOREF_PV(pVM); RT_NOREF(GCPhys); RT_NOREF(GCPhysRemapped); RT_NOREF(fPageFlags);
1148# endif /* !IEM_VERIFICATION_MODE_FULL */
1149 return VINF_SUCCESS;
1150}
1151
1152
1153# ifndef IEM_VERIFICATION_MODE_FULL
1154/**
1155 * Mapping a HC page in place of an MMIO page for direct access.
1156 *
1157 * (This is a special optimization used by the APIC in the VT-x case.)
1158 *
1159 * @returns VBox status code.
1160 *
1161 * @param pVM The cross context VM structure.
1162 * @param pVCpu The cross context virtual CPU structure.
1163 * @param GCPhys The address of the MMIO page to be changed.
1164 * @param HCPhys The address of the host physical page.
1165 * @param fPageFlags Page flags to set. Must be (X86_PTE_RW | X86_PTE_P)
1166 * for the time being.
1167 */
1168VMMDECL(int) IOMMMIOMapMMIOHCPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags)
1169{
1170 /* Currently only called from VT-x code during a page fault. */
1171 Log(("IOMMMIOMapMMIOHCPage %RGp -> %RGp flags=%RX64\n", GCPhys, HCPhys, fPageFlags));
1172
1173 AssertReturn(fPageFlags == (X86_PTE_RW | X86_PTE_P), VERR_INVALID_PARAMETER);
1174 /** @todo NEM: MMIO page aliasing. */
1175 Assert(HMIsEnabled(pVM));
1176
1177 /*
1178 * Lookup the context range node the page belongs to.
1179 */
1180# ifdef VBOX_STRICT
1181 /* Can't lock IOM here due to potential deadlocks in the VGA device; not safe to access. */
1182 PIOMMMIORANGE pRange = iomMMIOGetRangeUnsafe(pVM, pVCpu, GCPhys);
1183 AssertMsgReturn(pRange,
1184 ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
1185 Assert((pRange->GCPhys & PAGE_OFFSET_MASK) == 0);
1186 Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
1187# endif
1188
1189 /*
1190 * Do the aliasing; page align the addresses since PGM is picky.
1191 */
1192 GCPhys &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
1193 HCPhys &= ~(RTHCPHYS)PAGE_OFFSET_MASK;
1194
1195 int rc = PGMHandlerPhysicalPageAliasHC(pVM, GCPhys, GCPhys, HCPhys);
1196 AssertRCReturn(rc, rc);
1197
1198 /*
1199 * Modify the shadow page table. Since it's an MMIO page it won't be present and we
1200 * can simply prefetch it.
1201 *
1202 * Note: This is a NOP in the EPT case; we'll just let it fault again to resync the page.
1203 */
1204 rc = PGMPrefetchPage(pVCpu, (RTGCPTR)GCPhys);
1205 Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
1206 return VINF_SUCCESS;
1207}
1208# endif /* !IEM_VERIFICATION_MODE_FULL */
1209
1210
1211/**
1212 * Reset a previously modified MMIO region; restore the access flags.
1213 *
1214 * @returns VBox status code.
1215 *
1216 * @param pVM The cross context VM structure.
1217 * @param GCPhys Physical address that's part of the MMIO region to be reset.
1218 */
1219VMMDECL(int) IOMMMIOResetRegion(PVM pVM, RTGCPHYS GCPhys)
1220{
1221 Log(("IOMMMIOResetRegion %RGp\n", GCPhys));
1222
1223 PVMCPU pVCpu = VMMGetCpu(pVM);
1224
1225 /* This currently only works in real mode, protected mode without paging or with nested paging. */
1226 /** @todo NEM: MMIO page aliasing. */
1227 if ( !HMIsEnabled(pVM) /* useless without VT-x/AMD-V */
1228 || ( CPUMIsGuestInPagedProtectedMode(pVCpu)
1229 && !HMIsNestedPagingActive(pVM)))
1230 return VINF_SUCCESS; /* ignore */
1231
1232 /*
1233 * Lookup the context range node the page belongs to.
1234 */
1235# ifdef VBOX_STRICT
1236 /* Can't lock IOM here due to potential deadlocks in the VGA device; not safe to access. */
1237 PIOMMMIORANGE pRange = iomMMIOGetRangeUnsafe(pVM, pVCpu, GCPhys);
1238 AssertMsgReturn(pRange,
1239 ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
1240 Assert((pRange->GCPhys & PAGE_OFFSET_MASK) == 0);
1241 Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
1242# endif
1243
1244 /*
1245 * Call PGM to do the job work.
1246 *
1247 * After the call, all the pages should be non-present... unless there is
1248 * a page pool flush pending (unlikely).
1249 */
1250 int rc = PGMHandlerPhysicalReset(pVM, GCPhys);
1251 AssertRC(rc);
1252
1253# ifdef VBOX_STRICT
1254 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3))
1255 {
1256 uint32_t cb = pRange->cb;
1257 GCPhys = pRange->GCPhys;
1258 while (cb)
1259 {
1260 uint64_t fFlags;
1261 RTHCPHYS HCPhys;
1262 rc = PGMShwGetPage(pVCpu, (RTGCPTR)GCPhys, &fFlags, &HCPhys);
1263 Assert(rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
1264 cb -= PAGE_SIZE;
1265 GCPhys += PAGE_SIZE;
1266 }
1267 }
1268# endif
1269 return rc;
1270}
1271
1272#endif /* !IN_RC */
1273
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