VirtualBox

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

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

BIOS,DevFdc,DrvBlock: The floppy controller should query the block/host driver for the drive type, or it'll all go real bad if the guest code trusts CMOS/BIOS drive info. Changed the block driver to automatically upgrade the drive type (for fdc and bios/cmos setup only) if the image is larger than the configured drive capacity. Introduced two fake drive types with max capacities, 15.6 MB and 63.5 MB, the first is the max that INT13 can officially access, the second is reinterpreting CL as holding an 8-bit wide sector number and no cylinder bits (which actually seems to be how real bioses work with floppies).

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