VirtualBox

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

Last change on this file since 47829 was 47829, checked in by vboxsync, 11 years ago

Devices/Storage: Preparations for non 512 byte sector sizes. Add a new getter in the block and media interfaces and remove uses of 512 constants and use the reported sector size from the underlying medium

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