VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvBlock.cpp@ 53148

Last change on this file since 53148 was 53148, checked in by vboxsync, 10 years ago

Port a part of r95116 (disk encryption changes in 4.3) which was forgotten to trunk. Fixes starting a VM with an encrypted VHD image

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.8 KB
Line 
1/* $Id: DrvBlock.cpp 53148 2014-10-26 18:03:09Z vboxsync $ */
2/** @file
3 * VBox storage devices: Generic block driver
4 */
5
6/*
7 * Copyright (C) 2006-2012 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_DRV_BLOCK
23#include <VBox/vmm/pdmdrv.h>
24#include <iprt/assert.h>
25#include <iprt/string.h>
26#include <iprt/uuid.h>
27
28#include "VBoxDD.h"
29
30
31/** @def VBOX_PERIODIC_FLUSH
32 * Enable support for periodically flushing the VDI to disk. This may prove
33 * useful for those nasty problems with the ultra-slow host filesystems.
34 * If this is enabled, it can be configured via the CFGM key
35 * "VBoxInternal/Devices/piix3ide/0/LUN#<x>/Config/FlushInterval". <x>
36 * must be replaced with the correct LUN number of the disk that should
37 * do the periodic flushes. The value of the key is the number of bytes
38 * written between flushes. A value of 0 (the default) denotes no flushes. */
39#define VBOX_PERIODIC_FLUSH
40
41/** @def VBOX_IGNORE_FLUSH
42 * Enable support for ignoring VDI flush requests. This can be useful for
43 * filesystems that show bad guest IDE write performance (especially with
44 * Windows guests). NOTE that this does not disable the flushes caused by
45 * the periodic flush cache feature above.
46 * If this feature is enabled, it can be configured via the CFGM key
47 * "VBoxInternal/Devices/piix3ide/0/LUN#<x>/Config/IgnoreFlush". <x>
48 * must be replaced with the correct LUN number of the disk that should
49 * ignore flush requests. The value of the key is a boolean. The default
50 * is to ignore flushes, i.e. true. */
51#define VBOX_IGNORE_FLUSH
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57/**
58 * Block driver instance data.
59 *
60 * @implements PDMIBLOCK
61 * @implements PDMIBLOCKBIOS
62 * @implements PDMIMOUNT
63 * @implements PDMIMEDIAASYNCPORT
64 * @implements PDMIBLOCKASYNC
65 */
66typedef struct DRVBLOCK
67{
68 /** Pointer driver instance. */
69 PPDMDRVINS pDrvIns;
70 /** Drive type. */
71 PDMBLOCKTYPE enmType;
72 /** Locked indicator. */
73 bool fLocked;
74 /** Mountable indicator. */
75 bool fMountable;
76 /** Visible to the BIOS. */
77 bool fBiosVisible;
78#ifdef VBOX_PERIODIC_FLUSH
79 /** HACK: Configuration value for number of bytes written after which to flush. */
80 uint32_t cbFlushInterval;
81 /** HACK: Current count for the number of bytes written since the last flush. */
82 uint32_t cbDataWritten;
83#endif /* VBOX_PERIODIC_FLUSH */
84#ifdef VBOX_IGNORE_FLUSH
85 /** HACK: Disable flushes for this drive. */
86 bool fIgnoreFlush;
87 /** Disable async flushes for this drive. */
88 bool fIgnoreFlushAsync;
89#endif /* VBOX_IGNORE_FLUSH */
90 /** Pointer to the media driver below us.
91 * This is NULL if the media is not mounted. */
92 PPDMIMEDIA pDrvMedia;
93 /** Pointer to the block port interface above us. */
94 PPDMIBLOCKPORT pDrvBlockPort;
95 /** Pointer to the mount notify interface above us. */
96 PPDMIMOUNTNOTIFY pDrvMountNotify;
97 /** Our block interface. */
98 PDMIBLOCK IBlock;
99 /** Our block interface. */
100 PDMIBLOCKBIOS IBlockBios;
101 /** Our mountable interface. */
102 PDMIMOUNT IMount;
103 /** Our media port interface. */
104 PDMIMEDIAPORT IMediaPort;
105
106 /** Pointer to the async media driver below us.
107 * This is NULL if the media is not mounted. */
108 PPDMIMEDIAASYNC pDrvMediaAsync;
109 /** Our media async port. */
110 PDMIMEDIAASYNCPORT IMediaAsyncPort;
111 /** Pointer to the async block port interface above us. */
112 PPDMIBLOCKASYNCPORT pDrvBlockAsyncPort;
113 /** Our async block interface. */
114 PDMIBLOCKASYNC IBlockAsync;
115
116 /** Uuid of the drive. */
117 RTUUID Uuid;
118
119 /** BIOS PCHS Geometry. */
120 PDMMEDIAGEOMETRY PCHSGeometry;
121 /** BIOS LCHS Geometry. */
122 PDMMEDIAGEOMETRY LCHSGeometry;
123} DRVBLOCK, *PDRVBLOCK;
124
125
126/* -=-=-=-=- IBlock -=-=-=-=- */
127
128/** Makes a PDRVBLOCK out of a PPDMIBLOCK. */
129#define PDMIBLOCK_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlock)) )
130
131/** @copydoc PDMIBLOCK::pfnRead */
132static DECLCALLBACK(int) drvblockRead(PPDMIBLOCK pInterface, uint64_t off, void *pvBuf, size_t cbRead)
133{
134 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
135
136 /*
137 * Check the state.
138 */
139 if (!pThis->pDrvMedia)
140 {
141 AssertMsgFailed(("Invalid state! Not mounted!\n"));
142 return VERR_PDM_MEDIA_NOT_MOUNTED;
143 }
144
145 int rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
146 return rc;
147}
148
149
150/** @copydoc PDMIBLOCK::pfnReadPcBios */
151static DECLCALLBACK(int) drvblockReadPcBios(PPDMIBLOCK pInterface, uint64_t off, void *pvBuf, size_t cbRead)
152{
153 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
154
155 /*
156 * Check the state.
157 */
158 if (!pThis->pDrvMedia)
159 {
160 AssertMsgFailed(("Invalid state! Not mounted!\n"));
161 return VERR_PDM_MEDIA_NOT_MOUNTED;
162 }
163
164 int rc = pThis->pDrvMedia->pfnReadPcBios(pThis->pDrvMedia, off, pvBuf, cbRead);
165 return rc;
166}
167
168
169/** @copydoc PDMIBLOCK::pfnWrite */
170static DECLCALLBACK(int) drvblockWrite(PPDMIBLOCK pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
171{
172 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
173
174 /*
175 * Check the state.
176 */
177 if (!pThis->pDrvMedia)
178 {
179 AssertMsgFailed(("Invalid state! Not mounted!\n"));
180 return VERR_PDM_MEDIA_NOT_MOUNTED;
181 }
182
183 /* Set an FTM checkpoint as this operation changes the state permanently. */
184 PDMDrvHlpFTSetCheckpoint(pThis->pDrvIns, FTMCHECKPOINTTYPE_STORAGE);
185
186 int rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
187#ifdef VBOX_PERIODIC_FLUSH
188 if (pThis->cbFlushInterval)
189 {
190 pThis->cbDataWritten += (uint32_t)cbWrite;
191 if (pThis->cbDataWritten > pThis->cbFlushInterval)
192 {
193 pThis->cbDataWritten = 0;
194 pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
195 }
196 }
197#endif /* VBOX_PERIODIC_FLUSH */
198
199 return rc;
200}
201
202
203/** @copydoc PDMIBLOCK::pfnFlush */
204static DECLCALLBACK(int) drvblockFlush(PPDMIBLOCK pInterface)
205{
206 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
207
208 /*
209 * Check the state.
210 */
211 if (!pThis->pDrvMedia)
212 {
213 AssertMsgFailed(("Invalid state! Not mounted!\n"));
214 return VERR_PDM_MEDIA_NOT_MOUNTED;
215 }
216
217#ifdef VBOX_IGNORE_FLUSH
218 if (pThis->fIgnoreFlush)
219 return VINF_SUCCESS;
220#endif /* VBOX_IGNORE_FLUSH */
221
222 int rc = pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
223 if (rc == VERR_NOT_IMPLEMENTED)
224 rc = VINF_SUCCESS;
225 return rc;
226}
227
228
229/** @copydoc PDMIBLOCK::pfnMerge */
230static DECLCALLBACK(int) drvblockMerge(PPDMIBLOCK pInterface,
231 PFNSIMPLEPROGRESS pfnProgress,
232 void *pvUser)
233{
234 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
235
236 /*
237 * Check the state.
238 */
239 if (!pThis->pDrvMedia)
240 {
241 AssertMsgFailed(("Invalid state! Not mounted!\n"));
242 return VERR_PDM_MEDIA_NOT_MOUNTED;
243 }
244
245 if (!pThis->pDrvMedia->pfnMerge)
246 return VERR_NOT_SUPPORTED;
247
248 int rc = pThis->pDrvMedia->pfnMerge(pThis->pDrvMedia, pfnProgress, pvUser);
249 return rc;
250}
251
252
253/** @copydoc PDMIBLOCK::pfnIsReadOnly */
254static DECLCALLBACK(bool) drvblockIsReadOnly(PPDMIBLOCK pInterface)
255{
256 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
257
258 /*
259 * Check the state.
260 */
261 if (!pThis->pDrvMedia)
262 return false;
263
264 bool fRc = pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
265 return fRc;
266}
267
268
269/** @copydoc PDMIBLOCK::pfnGetSize */
270static DECLCALLBACK(uint64_t) drvblockGetSize(PPDMIBLOCK pInterface)
271{
272 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
273
274 /*
275 * Check the state.
276 */
277 if (!pThis->pDrvMedia)
278 return 0;
279
280 uint64_t cb = pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
281 LogFlow(("drvblockGetSize: returns %llu\n", cb));
282 return cb;
283}
284
285
286/** @copydoc PDMIBLOCK::pfnGetSize */
287static DECLCALLBACK(uint32_t) drvblockGetSectorSize(PPDMIBLOCK pInterface)
288{
289 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
290
291 /*
292 * Check the state.
293 */
294 if (!pThis->pDrvMedia)
295 return 0;
296
297 uint32_t cb = pThis->pDrvMedia->pfnGetSectorSize(pThis->pDrvMedia);
298 LogFlowFunc(("returns %u\n", cb));
299 return cb;
300}
301
302
303/** @copydoc PDMIBLOCK::pfnGetType */
304static DECLCALLBACK(PDMBLOCKTYPE) drvblockGetType(PPDMIBLOCK pInterface)
305{
306 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
307 LogFlow(("drvblockGetType: returns %d\n", pThis->enmType));
308 return pThis->enmType;
309}
310
311
312/** @copydoc PDMIBLOCK::pfnGetUuid */
313static DECLCALLBACK(int) drvblockGetUuid(PPDMIBLOCK pInterface, PRTUUID pUuid)
314{
315 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
316
317 /*
318 * Copy the uuid.
319 */
320 *pUuid = pThis->Uuid;
321 return VINF_SUCCESS;
322}
323
324static DECLCALLBACK(int) drvblockDiscard(PPDMIBLOCK pInterface, PCRTRANGE paRanges, unsigned cRanges)
325{
326 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
327
328 return pThis->pDrvMedia->pfnDiscard(pThis->pDrvMedia, paRanges, cRanges);
329}
330
331/** @copydoc PDMIBLOCK::pfnIoBufAlloc */
332static DECLCALLBACK(int) drvblockIoBufAlloc(PPDMIBLOCK pInterface, size_t cb, void **ppvNew)
333{
334 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
335
336 return pThis->pDrvMedia->pfnIoBufAlloc(pThis->pDrvMedia, cb, ppvNew);
337}
338
339/** @copydoc PDMIBLOCK::pfnIoBufFree */
340static DECLCALLBACK(int) drvblockIoBufFree(PPDMIBLOCK pInterface, void *pv, size_t cb)
341{
342 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
343
344 return pThis->pDrvMedia->pfnIoBufFree(pThis->pDrvMedia, pv, cb);
345}
346
347/* -=-=-=-=- IBlockAsync -=-=-=-=- */
348
349/** Makes a PDRVBLOCK out of a PPDMIBLOCKASYNC. */
350#define PDMIBLOCKASYNC_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlockAsync)) )
351
352/** @copydoc PDMIBLOCKASYNC::pfnStartRead */
353static DECLCALLBACK(int) drvblockAsyncReadStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PCRTSGSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser)
354{
355 PDRVBLOCK pThis = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
356
357 /*
358 * Check the state.
359 */
360 if (!pThis->pDrvMediaAsync)
361 {
362 AssertMsgFailed(("Invalid state! Not mounted!\n"));
363 return VERR_PDM_MEDIA_NOT_MOUNTED;
364 }
365
366 int rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, off, pSeg, cSeg, cbRead, pvUser);
367 return rc;
368}
369
370
371/** @copydoc PDMIBLOCKASYNC::pfnStartWrite */
372static DECLCALLBACK(int) drvblockAsyncWriteStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PCRTSGSEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser)
373{
374 PDRVBLOCK pThis = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
375
376 /*
377 * Check the state.
378 */
379 if (!pThis->pDrvMediaAsync)
380 {
381 AssertMsgFailed(("Invalid state! Not mounted!\n"));
382 return VERR_PDM_MEDIA_NOT_MOUNTED;
383 }
384
385 int rc = pThis->pDrvMediaAsync->pfnStartWrite(pThis->pDrvMediaAsync, off, pSeg, cSeg, cbWrite, pvUser);
386
387 return rc;
388}
389
390
391/** @copydoc PDMIBLOCKASYNC::pfnStartFlush */
392static DECLCALLBACK(int) drvblockAsyncFlushStart(PPDMIBLOCKASYNC pInterface, void *pvUser)
393{
394 PDRVBLOCK pThis = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
395
396 /*
397 * Check the state.
398 */
399 if (!pThis->pDrvMediaAsync)
400 {
401 AssertMsgFailed(("Invalid state! Not mounted!\n"));
402 return VERR_PDM_MEDIA_NOT_MOUNTED;
403 }
404
405#ifdef VBOX_IGNORE_FLUSH
406 if (pThis->fIgnoreFlushAsync)
407 return VINF_VD_ASYNC_IO_FINISHED;
408#endif /* VBOX_IGNORE_FLUSH */
409
410 int rc = pThis->pDrvMediaAsync->pfnStartFlush(pThis->pDrvMediaAsync, pvUser);
411
412 return rc;
413}
414
415
416/** @copydoc PDMIBLOCKASYNC::pfnStartDiscard */
417static DECLCALLBACK(int) drvblockStartDiscard(PPDMIBLOCKASYNC pInterface, PCRTRANGE paRanges, unsigned cRanges, void *pvUser)
418{
419 PDRVBLOCK pThis = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
420
421 /*
422 * Check the state.
423 */
424 if (!pThis->pDrvMediaAsync)
425 {
426 AssertMsgFailed(("Invalid state! Not mounted!\n"));
427 return VERR_PDM_MEDIA_NOT_MOUNTED;
428 }
429
430 return pThis->pDrvMediaAsync->pfnStartDiscard(pThis->pDrvMediaAsync, paRanges, cRanges, pvUser);
431}
432
433/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
434
435/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
436#define PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface) ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMediaAsyncPort))) )
437
438static DECLCALLBACK(int) drvblockAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
439{
440 PDRVBLOCK pThis = PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface);
441
442 return pThis->pDrvBlockAsyncPort->pfnTransferCompleteNotify(pThis->pDrvBlockAsyncPort, pvUser, rcReq);
443}
444
445/* -=-=-=-=- IBlockBios -=-=-=-=- */
446
447/** Makes a PDRVBLOCK out of a PPDMIBLOCKBIOS. */
448#define PDMIBLOCKBIOS_2_DRVBLOCK(pInterface) ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlockBios))) )
449
450
451/** @copydoc PDMIBLOCKBIOS::pfnGetPCHSGeometry */
452static DECLCALLBACK(int) drvblockGetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
453{
454 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
455
456 /*
457 * Check the state.
458 */
459 if (!pThis->pDrvMedia)
460 return VERR_PDM_MEDIA_NOT_MOUNTED;
461
462 /*
463 * Use configured/cached values if present.
464 */
465 if ( pThis->PCHSGeometry.cCylinders > 0
466 && pThis->PCHSGeometry.cHeads > 0
467 && pThis->PCHSGeometry.cSectors > 0)
468 {
469 *pPCHSGeometry = pThis->PCHSGeometry;
470 LogFlow(("%s: returns VINF_SUCCESS {%d,%d,%d}\n", __FUNCTION__, pThis->PCHSGeometry.cCylinders, pThis->PCHSGeometry.cHeads, pThis->PCHSGeometry.cSectors));
471 return VINF_SUCCESS;
472 }
473
474 /*
475 * Call media.
476 */
477 int rc = pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, &pThis->PCHSGeometry);
478
479 if (RT_SUCCESS(rc))
480 {
481 *pPCHSGeometry = pThis->PCHSGeometry;
482 LogFlow(("%s: returns %Rrc {%d,%d,%d}\n", __FUNCTION__, rc, pThis->PCHSGeometry.cCylinders, pThis->PCHSGeometry.cHeads, pThis->PCHSGeometry.cSectors));
483 }
484 else if (rc == VERR_NOT_IMPLEMENTED)
485 {
486 rc = VERR_PDM_GEOMETRY_NOT_SET;
487 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
488 }
489 return rc;
490}
491
492
493/** @copydoc PDMIBLOCKBIOS::pfnSetPCHSGeometry */
494static DECLCALLBACK(int) drvblockSetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
495{
496 LogFlow(("%s: cCylinders=%d cHeads=%d cSectors=%d\n", __FUNCTION__, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
497 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
498
499 /*
500 * Check the state.
501 */
502 if (!pThis->pDrvMedia)
503 {
504 AssertMsgFailed(("Invalid state! Not mounted!\n"));
505 return VERR_PDM_MEDIA_NOT_MOUNTED;
506 }
507
508 /*
509 * Call media. Ignore the not implemented return code.
510 */
511 int rc = pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
512
513 if ( RT_SUCCESS(rc)
514 || rc == VERR_NOT_IMPLEMENTED)
515 {
516 pThis->PCHSGeometry = *pPCHSGeometry;
517 rc = VINF_SUCCESS;
518 }
519 return rc;
520}
521
522
523/** @copydoc PDMIBLOCKBIOS::pfnGetLCHSGeometry */
524static DECLCALLBACK(int) drvblockGetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
525{
526 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
527
528 /*
529 * Check the state.
530 */
531 if (!pThis->pDrvMedia)
532 return VERR_PDM_MEDIA_NOT_MOUNTED;
533
534 /*
535 * Use configured/cached values if present.
536 */
537 if ( pThis->LCHSGeometry.cCylinders > 0
538 && pThis->LCHSGeometry.cHeads > 0
539 && pThis->LCHSGeometry.cSectors > 0)
540 {
541 *pLCHSGeometry = pThis->LCHSGeometry;
542 LogFlow(("%s: returns VINF_SUCCESS {%d,%d,%d}\n", __FUNCTION__, pThis->LCHSGeometry.cCylinders, pThis->LCHSGeometry.cHeads, pThis->LCHSGeometry.cSectors));
543 return VINF_SUCCESS;
544 }
545
546 /*
547 * Call media.
548 */
549 int rc = pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, &pThis->LCHSGeometry);
550
551 if (RT_SUCCESS(rc))
552 {
553 *pLCHSGeometry = pThis->LCHSGeometry;
554 LogFlow(("%s: returns %Rrc {%d,%d,%d}\n", __FUNCTION__, rc, pThis->LCHSGeometry.cCylinders, pThis->LCHSGeometry.cHeads, pThis->LCHSGeometry.cSectors));
555 }
556 else if (rc == VERR_NOT_IMPLEMENTED)
557 {
558 rc = VERR_PDM_GEOMETRY_NOT_SET;
559 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
560 }
561 return rc;
562}
563
564
565/** @copydoc PDMIBLOCKBIOS::pfnSetLCHSGeometry */
566static DECLCALLBACK(int) drvblockSetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
567{
568 LogFlow(("%s: cCylinders=%d cHeads=%d cSectors=%d\n", __FUNCTION__, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
569 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
570
571 /*
572 * Check the state.
573 */
574 if (!pThis->pDrvMedia)
575 {
576 AssertMsgFailed(("Invalid state! Not mounted!\n"));
577 return VERR_PDM_MEDIA_NOT_MOUNTED;
578 }
579
580 /*
581 * Call media. Ignore the not implemented return code.
582 */
583 int rc = pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
584
585 if ( RT_SUCCESS(rc)
586 || rc == VERR_NOT_IMPLEMENTED)
587 {
588 pThis->LCHSGeometry = *pLCHSGeometry;
589 rc = VINF_SUCCESS;
590 }
591 return rc;
592}
593
594
595/** @copydoc PDMIBLOCKBIOS::pfnIsVisible */
596static DECLCALLBACK(bool) drvblockIsVisible(PPDMIBLOCKBIOS pInterface)
597{
598 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
599 LogFlow(("drvblockIsVisible: returns %d\n", pThis->fBiosVisible));
600 return pThis->fBiosVisible;
601}
602
603
604/** @copydoc PDMIBLOCKBIOS::pfnGetType */
605static DECLCALLBACK(PDMBLOCKTYPE) drvblockBiosGetType(PPDMIBLOCKBIOS pInterface)
606{
607 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
608 LogFlow(("drvblockBiosGetType: returns %d\n", pThis->enmType));
609 return pThis->enmType;
610}
611
612
613
614/* -=-=-=-=- IMount -=-=-=-=- */
615
616/** Makes a PDRVBLOCK out of a PPDMIMOUNT. */
617#define PDMIMOUNT_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMount)) )
618
619
620/** @copydoc PDMIMOUNT::pfnMount */
621static DECLCALLBACK(int) drvblockMount(PPDMIMOUNT pInterface, const char *pszFilename, const char *pszCoreDriver)
622{
623 LogFlow(("drvblockMount: pszFilename=%p:{%s} pszCoreDriver=%p:{%s}\n", pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
624 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
625
626 /*
627 * Validate state.
628 */
629 if (pThis->pDrvMedia)
630 {
631 AssertMsgFailed(("Already mounted\n"));
632 return VERR_PDM_MEDIA_MOUNTED;
633 }
634
635 /*
636 * Prepare configuration.
637 */
638 if (pszFilename)
639 {
640 int rc = PDMDrvHlpMountPrepare(pThis->pDrvIns, pszFilename, pszCoreDriver);
641 if (RT_FAILURE(rc))
642 {
643 Log(("drvblockMount: Prepare failed for \"%s\" rc=%Rrc\n", pszFilename, rc));
644 return rc;
645 }
646 }
647
648 /*
649 * Attach the media driver and query it's interface.
650 */
651 uint32_t fTachFlags = 0; /** @todo figure attachment flags for mount. */
652 PPDMIBASE pBase;
653 int rc = PDMDrvHlpAttach(pThis->pDrvIns, fTachFlags, &pBase);
654 if (RT_FAILURE(rc))
655 {
656 Log(("drvblockMount: Attach failed rc=%Rrc\n", rc));
657 return rc;
658 }
659
660 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
661 if (pThis->pDrvMedia)
662 {
663 /** @todo r=klaus missing async handling, this is just a band aid to
664 * avoid using stale information */
665 pThis->pDrvMediaAsync = NULL;
666
667 /*
668 * Initialize state.
669 */
670 pThis->fLocked = false;
671 pThis->PCHSGeometry.cCylinders = 0;
672 pThis->PCHSGeometry.cHeads = 0;
673 pThis->PCHSGeometry.cSectors = 0;
674 pThis->LCHSGeometry.cCylinders = 0;
675 pThis->LCHSGeometry.cHeads = 0;
676 pThis->LCHSGeometry.cSectors = 0;
677#ifdef VBOX_PERIODIC_FLUSH
678 pThis->cbDataWritten = 0;
679#endif /* VBOX_PERIODIC_FLUSH */
680
681 /*
682 * Notify driver/device above us.
683 */
684 if (pThis->pDrvMountNotify)
685 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
686 Log(("drvblockMount: Success\n"));
687 return VINF_SUCCESS;
688 }
689 else
690 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
691
692 /*
693 * Failed, detatch the media driver.
694 */
695 AssertMsgFailed(("No media interface!\n"));
696 int rc2 = PDMDrvHlpDetach(pThis->pDrvIns, fTachFlags);
697 AssertRC(rc2);
698 pThis->pDrvMedia = NULL;
699 return rc;
700}
701
702
703/** @copydoc PDMIMOUNT::pfnUnmount */
704static DECLCALLBACK(int) drvblockUnmount(PPDMIMOUNT pInterface, bool fForce, bool fEject)
705{
706 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
707
708 /*
709 * Validate state.
710 */
711 if (!pThis->pDrvMedia)
712 {
713 Log(("drvblockUmount: Not mounted\n"));
714 return VERR_PDM_MEDIA_NOT_MOUNTED;
715 }
716 if (pThis->fLocked && !fForce)
717 {
718 Log(("drvblockUmount: Locked\n"));
719 return VERR_PDM_MEDIA_LOCKED;
720 }
721
722 /* Media is no longer locked even if it was previously. */
723 pThis->fLocked = false;
724
725 /*
726 * Detach the media driver and query it's interface.
727 */
728 int rc = PDMDrvHlpDetach(pThis->pDrvIns, 0 /*fFlags*/);
729 if (RT_FAILURE(rc))
730 {
731 Log(("drvblockUnmount: Detach failed rc=%Rrc\n", rc));
732 return rc;
733 }
734 Assert(!pThis->pDrvMedia);
735
736 /*
737 * Notify driver/device above us.
738 */
739 if (pThis->pDrvMountNotify)
740 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
741 Log(("drvblockUnmount: success\n"));
742 return VINF_SUCCESS;
743}
744
745
746/** @copydoc PDMIMOUNT::pfnIsMounted */
747static DECLCALLBACK(bool) drvblockIsMounted(PPDMIMOUNT pInterface)
748{
749 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
750 return pThis->pDrvMedia != NULL;
751}
752
753/** @copydoc PDMIMOUNT::pfnLock */
754static DECLCALLBACK(int) drvblockLock(PPDMIMOUNT pInterface)
755{
756 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
757 Log(("drvblockLock: %d -> %d\n", pThis->fLocked, true));
758 pThis->fLocked = true;
759 return VINF_SUCCESS;
760}
761
762/** @copydoc PDMIMOUNT::pfnUnlock */
763static DECLCALLBACK(int) drvblockUnlock(PPDMIMOUNT pInterface)
764{
765 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
766 Log(("drvblockUnlock: %d -> %d\n", pThis->fLocked, false));
767 pThis->fLocked = false;
768 return VINF_SUCCESS;
769}
770
771/** @copydoc PDMIMOUNT::pfnIsLocked */
772static DECLCALLBACK(bool) drvblockIsLocked(PPDMIMOUNT pInterface)
773{
774 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
775 return pThis->fLocked;
776}
777
778
779
780/* -=-=-=-=- IMediaPort -=-=-=-=- */
781
782/** Makes a PDRVBLOCK out of a PPDMIMEDIAPORT. */
783#define PDMIMEDIAPORT_2_DRVBLOCK(pInterface) ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMediaPort))) )
784
785/**
786 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
787 */
788static DECLCALLBACK(int) drvblockQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
789 uint32_t *piInstance, uint32_t *piLUN)
790{
791 PDRVBLOCK pThis = PDMIMEDIAPORT_2_DRVBLOCK(pInterface);
792
793 return pThis->pDrvBlockPort->pfnQueryDeviceLocation(pThis->pDrvBlockPort, ppcszController,
794 piInstance, piLUN);
795}
796
797/* -=-=-=-=- IBase -=-=-=-=- */
798
799/**
800 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
801 */
802static DECLCALLBACK(void *) drvblockQueryInterface(PPDMIBASE pInterface, const char *pszIID)
803{
804 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
805 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
806
807 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
808 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCK, &pThis->IBlock);
809 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKBIOS, pThis->fBiosVisible ? &pThis->IBlockBios : NULL);
810 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNT, pThis->fMountable ? &pThis->IMount : NULL);
811 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKASYNC, pThis->pDrvMediaAsync ? &pThis->IBlockAsync : NULL);
812 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, pThis->pDrvBlockAsyncPort ? &pThis->IMediaAsyncPort : NULL);
813 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->IMediaPort);
814 return NULL;
815}
816
817
818/* -=-=-=-=- driver interface -=-=-=-=- */
819
820/** @copydoc FNPDMDRVDETACH. */
821static DECLCALLBACK(void) drvblockDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
822{
823 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
824 pThis->pDrvMedia = NULL;
825 pThis->pDrvMediaAsync = NULL;
826 NOREF(fFlags);
827}
828
829
830/**
831 * Reset notification.
832 *
833 * @returns VBox status.
834 * @param pDevIns The driver instance data.
835 */
836static DECLCALLBACK(void) drvblockReset(PPDMDRVINS pDrvIns)
837{
838 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
839
840 pThis->fLocked = false;
841}
842
843
844/**
845 * Translates a PDMBLOCKTYPE value into a string.
846 *
847 * @returns Read only string.
848 * @param enmType The type value.
849 */
850static const char *drvblockGetTypeName(PDMBLOCKTYPE enmType)
851{
852 switch (enmType)
853 {
854 case PDMBLOCKTYPE_ERROR: return "ERROR";
855 case PDMBLOCKTYPE_FLOPPY_360: return "FLOPPY_360";
856 case PDMBLOCKTYPE_FLOPPY_720: return "FLOPPY_720";
857 case PDMBLOCKTYPE_FLOPPY_1_20: return "FLOPPY_1_20";
858 case PDMBLOCKTYPE_FLOPPY_1_44: return "FLOPPY_1_44";
859 case PDMBLOCKTYPE_FLOPPY_2_88: return "FLOPPY_2_88";
860 case PDMBLOCKTYPE_FLOPPY_FAKE_15_6: return "FLOPPY_FAKE_15_6";
861 case PDMBLOCKTYPE_FLOPPY_FAKE_63_5: return "FLOPPY_FAKE_63_5";
862 case PDMBLOCKTYPE_CDROM: return "CDROM";
863 case PDMBLOCKTYPE_DVD: return "DVD";
864 case PDMBLOCKTYPE_HARD_DISK: return "HARD_DISK";
865 default: return "Unknown";
866
867 }
868}
869
870
871/**
872 * Construct a block driver instance.
873 *
874 * @copydoc FNPDMDRVCONSTRUCT
875 */
876static DECLCALLBACK(int) drvblockConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
877{
878 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
879 LogFlow(("drvblockConstruct: iInstance=%d\n", pDrvIns->iInstance));
880 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
881
882 /*
883 * Validate configuration.
884 */
885#if defined(VBOX_PERIODIC_FLUSH) || defined(VBOX_IGNORE_FLUSH)
886 if (!CFGMR3AreValuesValid(pCfg, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Mountable\0FlushInterval\0IgnoreFlush\0IgnoreFlushAsync\0"))
887#else /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
888 if (!CFGMR3AreValuesValid(pCfg, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Mountable\0"))
889#endif /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
890 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
891
892 /*
893 * Initialize most of the data members.
894 */
895 pThis->pDrvIns = pDrvIns;
896
897 /* IBase. */
898 pDrvIns->IBase.pfnQueryInterface = drvblockQueryInterface;
899
900 /* IBlock. */
901 pThis->IBlock.pfnRead = drvblockRead;
902 pThis->IBlock.pfnReadPcBios = drvblockReadPcBios;
903 pThis->IBlock.pfnWrite = drvblockWrite;
904 pThis->IBlock.pfnFlush = drvblockFlush;
905 pThis->IBlock.pfnMerge = drvblockMerge;
906 pThis->IBlock.pfnIsReadOnly = drvblockIsReadOnly;
907 pThis->IBlock.pfnGetSize = drvblockGetSize;
908 pThis->IBlock.pfnGetSectorSize = drvblockGetSectorSize;
909 pThis->IBlock.pfnGetType = drvblockGetType;
910 pThis->IBlock.pfnGetUuid = drvblockGetUuid;
911 pThis->IBlock.pfnIoBufAlloc = drvblockIoBufAlloc;
912 pThis->IBlock.pfnIoBufFree = drvblockIoBufFree;
913
914 /* IBlockBios. */
915 pThis->IBlockBios.pfnGetPCHSGeometry = drvblockGetPCHSGeometry;
916 pThis->IBlockBios.pfnSetPCHSGeometry = drvblockSetPCHSGeometry;
917 pThis->IBlockBios.pfnGetLCHSGeometry = drvblockGetLCHSGeometry;
918 pThis->IBlockBios.pfnSetLCHSGeometry = drvblockSetLCHSGeometry;
919 pThis->IBlockBios.pfnIsVisible = drvblockIsVisible;
920 pThis->IBlockBios.pfnGetType = drvblockBiosGetType;
921
922 /* IMount. */
923 pThis->IMount.pfnMount = drvblockMount;
924 pThis->IMount.pfnUnmount = drvblockUnmount;
925 pThis->IMount.pfnIsMounted = drvblockIsMounted;
926 pThis->IMount.pfnLock = drvblockLock;
927 pThis->IMount.pfnUnlock = drvblockUnlock;
928 pThis->IMount.pfnIsLocked = drvblockIsLocked;
929
930 /* IBlockAsync. */
931 pThis->IBlockAsync.pfnStartRead = drvblockAsyncReadStart;
932 pThis->IBlockAsync.pfnStartWrite = drvblockAsyncWriteStart;
933 pThis->IBlockAsync.pfnStartFlush = drvblockAsyncFlushStart;
934
935 /* IMediaAsyncPort. */
936 pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvblockAsyncTransferCompleteNotify;
937
938 /* IMediaPort */
939 pThis->IMediaPort.pfnQueryDeviceLocation = drvblockQueryDeviceLocation;
940
941 /*
942 * Get the IBlockPort & IMountNotify interfaces of the above driver/device.
943 */
944 pThis->pDrvBlockPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIBLOCKPORT);
945 if (!pThis->pDrvBlockPort)
946 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
947 N_("No block port interface above"));
948
949 /* Try to get the optional async block port interface above. */
950 pThis->pDrvBlockAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIBLOCKASYNCPORT);
951 pThis->pDrvMountNotify = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMOUNTNOTIFY);
952
953 /*
954 * Query configuration.
955 */
956 /* type */
957 char *psz;
958 int rc = CFGMR3QueryStringAlloc(pCfg, "Type", &psz);
959 if (RT_FAILURE(rc))
960 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_BLOCK_NO_TYPE, N_("Failed to obtain the type"));
961 if (!strcmp(psz, "HardDisk"))
962 pThis->enmType = PDMBLOCKTYPE_HARD_DISK;
963 else if (!strcmp(psz, "DVD"))
964 pThis->enmType = PDMBLOCKTYPE_DVD;
965 else if (!strcmp(psz, "CDROM"))
966 pThis->enmType = PDMBLOCKTYPE_CDROM;
967 else if (!strcmp(psz, "Floppy 2.88"))
968 pThis->enmType = PDMBLOCKTYPE_FLOPPY_2_88;
969 else if (!strcmp(psz, "Floppy 1.44"))
970 pThis->enmType = PDMBLOCKTYPE_FLOPPY_1_44;
971 else if (!strcmp(psz, "Floppy 1.20"))
972 pThis->enmType = PDMBLOCKTYPE_FLOPPY_1_20;
973 else if (!strcmp(psz, "Floppy 720"))
974 pThis->enmType = PDMBLOCKTYPE_FLOPPY_720;
975 else if (!strcmp(psz, "Floppy 360"))
976 pThis->enmType = PDMBLOCKTYPE_FLOPPY_360;
977 else if (!strcmp(psz, "Floppy 15.6"))
978 pThis->enmType = PDMBLOCKTYPE_FLOPPY_FAKE_15_6;
979 else if (!strcmp(psz, "Floppy 63.5"))
980 pThis->enmType = PDMBLOCKTYPE_FLOPPY_FAKE_63_5;
981 else
982 {
983 PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_BLOCK_UNKNOWN_TYPE, RT_SRC_POS,
984 N_("Unknown type \"%s\""), psz);
985 MMR3HeapFree(psz);
986 return VERR_PDM_BLOCK_UNKNOWN_TYPE;
987 }
988 Log2(("drvblockConstruct: enmType=%d\n", pThis->enmType));
989 MMR3HeapFree(psz); psz = NULL;
990
991 /* Mountable */
992 rc = CFGMR3QueryBoolDef(pCfg, "Mountable", &pThis->fMountable, false);
993 if (RT_FAILURE(rc))
994 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Mountable\" from the config"));
995
996 /* Locked */
997 rc = CFGMR3QueryBoolDef(pCfg, "Locked", &pThis->fLocked, false);
998 if (RT_FAILURE(rc))
999 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Locked\" from the config"));
1000
1001 /* BIOS visible */
1002 rc = CFGMR3QueryBoolDef(pCfg, "BIOSVisible", &pThis->fBiosVisible, true);
1003 if (RT_FAILURE(rc))
1004 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"BIOSVisible\" from the config"));
1005
1006 /** @todo AttachFailError is currently completely ignored. */
1007
1008 /* Cylinders */
1009 rc = CFGMR3QueryU32Def(pCfg, "Cylinders", &pThis->LCHSGeometry.cCylinders, 0);
1010 if (RT_FAILURE(rc))
1011 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Cylinders\" from the config"));
1012
1013 /* Heads */
1014 rc = CFGMR3QueryU32Def(pCfg, "Heads", &pThis->LCHSGeometry.cHeads, 0);
1015 if (RT_FAILURE(rc))
1016 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Heads\" from the config"));
1017
1018 /* Sectors */
1019 rc = CFGMR3QueryU32Def(pCfg, "Sectors", &pThis->LCHSGeometry.cSectors, 0);
1020 if (RT_FAILURE(rc))
1021 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Sectors\" from the config"));
1022
1023 /* Uuid */
1024 rc = CFGMR3QueryStringAlloc(pCfg, "Uuid", &psz);
1025 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1026 RTUuidClear(&pThis->Uuid);
1027 else if (RT_SUCCESS(rc))
1028 {
1029 rc = RTUuidFromStr(&pThis->Uuid, psz);
1030 if (RT_FAILURE(rc))
1031 {
1032 PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, "%s",
1033 N_("Uuid from string failed on \"%s\""), psz);
1034 MMR3HeapFree(psz);
1035 return rc;
1036 }
1037 MMR3HeapFree(psz); psz = NULL;
1038 }
1039 else
1040 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Uuid\" from the config"));
1041
1042#ifdef VBOX_PERIODIC_FLUSH
1043 rc = CFGMR3QueryU32Def(pCfg, "FlushInterval", &pThis->cbFlushInterval, 0);
1044 if (RT_FAILURE(rc))
1045 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"FlushInterval\" from the config"));
1046#endif /* VBOX_PERIODIC_FLUSH */
1047
1048#ifdef VBOX_IGNORE_FLUSH
1049 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreFlush", &pThis->fIgnoreFlush, true);
1050 if (RT_FAILURE(rc))
1051 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"IgnoreFlush\" from the config"));
1052
1053 if (pThis->fIgnoreFlush)
1054 LogRel(("DrvBlock: Flushes will be ignored\n"));
1055 else
1056 LogRel(("DrvBlock: Flushes will be passed to the disk\n"));
1057
1058 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreFlushAsync", &pThis->fIgnoreFlushAsync, false);
1059 if (RT_FAILURE(rc))
1060 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"IgnoreFlushAsync\" from the config"));
1061
1062 if (pThis->fIgnoreFlushAsync)
1063 LogRel(("DrvBlock: Async flushes will be ignored\n"));
1064 else
1065 LogRel(("DrvBlock: Async flushes will be passed to the disk\n"));
1066#endif /* VBOX_IGNORE_FLUSH */
1067
1068 /*
1069 * Try attach driver below and query it's media interface.
1070 */
1071 PPDMIBASE pBase;
1072 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
1073 if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
1074 && pThis->enmType != PDMBLOCKTYPE_HARD_DISK)
1075 return VINF_SUCCESS;
1076 if (RT_FAILURE(rc))
1077 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1078 N_("Failed to attach driver below us! %Rrf"), rc);
1079
1080 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
1081 if (!pThis->pDrvMedia)
1082 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1083 N_("No media or async media interface below"));
1084
1085 /* Try to get the optional async interface. */
1086 pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
1087
1088 if (pThis->pDrvMedia->pfnDiscard)
1089 pThis->IBlock.pfnDiscard = drvblockDiscard;
1090
1091 if ( pThis->pDrvMediaAsync
1092 && pThis->pDrvMediaAsync->pfnStartDiscard)
1093 pThis->IBlockAsync.pfnStartDiscard = drvblockStartDiscard;
1094
1095 if (RTUuidIsNull(&pThis->Uuid))
1096 {
1097 if (pThis->enmType == PDMBLOCKTYPE_HARD_DISK)
1098 pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, &pThis->Uuid);
1099 }
1100
1101 /*
1102 * Automatically upgrade the floppy drive if the specified one is too
1103 * small to represent the whole boot time image. (We cannot do this later
1104 * since the BIOS (and others) gets the info via CMOS.)
1105 *
1106 * This trick should make 2.88 images as well as the fake 15.6 and 63.5 MB
1107 * images despite the hardcoded default 1.44 drive.
1108 */
1109 if ( PDMBLOCKTYPE_IS_FLOPPY(pThis->enmType)
1110 && pThis->pDrvMedia)
1111 {
1112 uint64_t const cbFloppyImg = pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
1113 PDMBLOCKTYPE const enmCfgType = pThis->enmType;
1114 switch (enmCfgType)
1115 {
1116 default:
1117 AssertFailed();
1118 case PDMBLOCKTYPE_FLOPPY_360:
1119 if (cbFloppyImg > 40 * 2 * 9 * 512)
1120 pThis->enmType = PDMBLOCKTYPE_FLOPPY_360;
1121 /* fall thru */
1122 case PDMBLOCKTYPE_FLOPPY_720:
1123 if (cbFloppyImg > 80 * 2 * 14 * 512)
1124 pThis->enmType = PDMBLOCKTYPE_FLOPPY_1_20;
1125 /* fall thru */
1126 case PDMBLOCKTYPE_FLOPPY_1_20:
1127 if (cbFloppyImg > 80 * 2 * 20 * 512)
1128 pThis->enmType = PDMBLOCKTYPE_FLOPPY_1_44;
1129 /* fall thru */
1130 case PDMBLOCKTYPE_FLOPPY_1_44:
1131 if (cbFloppyImg > 80 * 2 * 24 * 512)
1132 pThis->enmType = PDMBLOCKTYPE_FLOPPY_2_88;
1133 /* fall thru */
1134 case PDMBLOCKTYPE_FLOPPY_2_88:
1135 if (cbFloppyImg > 80 * 2 * 48 * 512)
1136 pThis->enmType = PDMBLOCKTYPE_FLOPPY_FAKE_15_6;
1137 /* fall thru */
1138 case PDMBLOCKTYPE_FLOPPY_FAKE_15_6:
1139 if (cbFloppyImg > 255 * 2 * 63 * 512)
1140 pThis->enmType = PDMBLOCKTYPE_FLOPPY_FAKE_63_5;
1141 case PDMBLOCKTYPE_FLOPPY_FAKE_63_5:
1142 if (cbFloppyImg > 255 * 2 * 255 * 512)
1143 LogRel(("Warning: Floppy image is larger that 63.5 MB! (%llu bytes)\n", cbFloppyImg));
1144 break;
1145 }
1146 if (pThis->enmType != enmCfgType)
1147 LogRel(("Automatically upgraded floppy drive from %s to %s to better support the %u byte image\n",
1148 drvblockGetTypeName(enmCfgType), drvblockGetTypeName(pThis->enmType), cbFloppyImg));
1149 }
1150
1151 return VINF_SUCCESS;
1152}
1153
1154
1155/**
1156 * Block driver registration record.
1157 */
1158const PDMDRVREG g_DrvBlock =
1159{
1160 /* u32Version */
1161 PDM_DRVREG_VERSION,
1162 /* szName */
1163 "Block",
1164 /* szRCMod */
1165 "",
1166 /* szR0Mod */
1167 "",
1168 /* pszDescription */
1169 "Generic block driver.",
1170 /* fFlags */
1171 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1172 /* fClass. */
1173 PDM_DRVREG_CLASS_BLOCK,
1174 /* cMaxInstances */
1175 ~0U,
1176 /* cbInstance */
1177 sizeof(DRVBLOCK),
1178 /* pfnConstruct */
1179 drvblockConstruct,
1180 /* pfnDestruct */
1181 NULL,
1182 /* pfnRelocate */
1183 NULL,
1184 /* pfnIOCtl */
1185 NULL,
1186 /* pfnPowerOn */
1187 NULL,
1188 /* pfnReset */
1189 drvblockReset,
1190 /* pfnSuspend */
1191 NULL,
1192 /* pfnResume */
1193 NULL,
1194 /* pfnAttach */
1195 NULL,
1196 /* pfnDetach */
1197 drvblockDetach,
1198 /* pfnPowerOff */
1199 NULL,
1200 /* pfnSoftReset */
1201 NULL,
1202 /* u32EndVersion */
1203 PDM_DRVREG_VERSION
1204};
1205
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