VirtualBox

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

Last change on this file since 3199 was 3199, checked in by vboxsync, 17 years ago

Ignore AttachFailError config in Block driver. Otherwise changing the
config from host DVD to unmounted causes VM start failures if the option
is configured.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.3 KB
Line 
1/** @file
2 *
3 * VBox storage devices:
4 * Generic block driver
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_DRV_BLOCK
28#include <VBox/pdm.h>
29#include <VBox/cfgm.h>
30#include <VBox/mm.h>
31#include <VBox/err.h>
32
33#include <VBox/log.h>
34#include <iprt/assert.h>
35#include <iprt/uuid.h>
36
37#include <string.h>
38
39#include "Builtins.h"
40
41
42/** @def VBOX_PERIODIC_FLUSH
43 * Enable support for periodically flushing the VDI to disk. This may prove
44 * useful for those nasty problems with the ultra-slow host filesystems.
45 * If this is enabled, it can be configured via the CFGM key
46 * "VBoxInternal/Devices/piix3ide/0/LUN#<x>/Config/FlushInterval". <x>
47 * must be replaced with the correct LUN number of the disk that should
48 * do the periodic flushes. The value of the key is the number of bytes
49 * written between flushes. A value of 0 (the default) denotes no flushes. */
50#define VBOX_PERIODIC_FLUSH
51
52/** @def VBOX_IGNORE_FLUSH
53 * Enable support for ignoring VDI flush requests. This can be useful for
54 * filesystems that show bad guest IDE write performance (especially with
55 * Windows guests). NOTE that this does not disable the flushes caused by
56 * the periodic flush cache feature above.
57 * If this feature is enabled, it can be configured via the CFGM key
58 * "VBoxInternal/Devices/piix3ide/0/LUN#<x>/Config/IgnoreFlush". <x>
59 * must be replaced with the correct LUN number of the disk that should
60 * ignore flush requests. The value of the key is a boolean. The default
61 * is to honor flushes, i.e. false. */
62#define VBOX_IGNORE_FLUSH
63
64/*******************************************************************************
65* Structures and Typedefs *
66*******************************************************************************/
67/**
68 * Block driver instance data.
69 */
70typedef struct DRVBLOCK
71{
72 /** Pointer driver instance. */
73 PPDMDRVINS pDrvIns;
74 /** Drive type. */
75 PDMBLOCKTYPE enmType;
76 /** Locked indicator. */
77 bool fLocked;
78 /** Mountable indicator. */
79 bool fMountable;
80 /** Visible to the BIOS. */
81 bool fBiosVisible;
82 /** Whether or not enmTranslation is valid. */
83 bool fTranslationSet;
84#ifdef VBOX_PERIODIC_FLUSH
85 /** HACK: Configuration value for number of bytes written after which to flush. */
86 uint32_t cbFlushInterval;
87 /** HACK: Current count for the number of bytes written since the last flush. */
88 uint32_t cbDataWritten;
89#endif /* VBOX_PERIODIC_FLUSH */
90#ifdef VBOX_IGNORE_FLUSH
91 /** HACK: Disable flushes for this drive. */
92 bool fIgnoreFlush;
93#endif /* VBOX_IGNORE_FLUSH */
94 /** Pointer to the media driver below us.
95 * This is NULL if the media is not mounted. */
96 PPDMIMEDIA pDrvMedia;
97 /** Pointer to the block port interface above us. */
98 PPDMIBLOCKPORT pDrvBlockPort;
99 /** Pointer to the mount notify interface above us. */
100 PPDMIMOUNTNOTIFY pDrvMountNotify;
101 /** Our block interface. */
102 PDMIBLOCK IBlock;
103 /** Our block interface. */
104 PDMIBLOCKBIOS IBlockBios;
105 /** Our mountable interface. */
106 PDMIMOUNT IMount;
107
108 /** Uuid of the drive. */
109 RTUUID Uuid;
110
111 /** BIOS Geometry: Translation mode. */
112 PDMBIOSTRANSLATION enmTranslation;
113 /** BIOS Geometry: Cylinders. */
114 uint32_t cCylinders;
115 /** BIOS Geometry: Heads. */
116 uint32_t cHeads;
117 /** BIOS Geometry: Sectors. */
118 uint32_t cSectors;
119} DRVBLOCK, *PDRVBLOCK;
120
121
122/* -=-=-=-=- IBlock -=-=-=-=- */
123
124/** Makes a PDRVBLOCK out of a PPDMIBLOCK. */
125#define PDMIBLOCK_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlock)) )
126
127
128/** @copydoc PDMIBLOCK::pfnRead */
129static DECLCALLBACK(int) drvblockRead(PPDMIBLOCK pInterface, uint64_t off, void *pvBuf, size_t cbRead)
130{
131 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
132
133 /*
134 * Check the state.
135 */
136 if (!pData->pDrvMedia)
137 {
138 AssertMsgFailed(("Invalid state! Not mounted!\n"));
139 return VERR_PDM_MEDIA_NOT_MOUNTED;
140 }
141
142 int rc = pData->pDrvMedia->pfnRead(pData->pDrvMedia, off, pvBuf, cbRead);
143 return rc;
144}
145
146
147/** @copydoc PDMIBLOCK::pfnWrite */
148static DECLCALLBACK(int) drvblockWrite(PPDMIBLOCK pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
149{
150 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
151
152 /*
153 * Check the state.
154 */
155 if (!pData->pDrvMedia)
156 {
157 AssertMsgFailed(("Invalid state! Not mounted!\n"));
158 return VERR_PDM_MEDIA_NOT_MOUNTED;
159 }
160
161 int rc = pData->pDrvMedia->pfnWrite(pData->pDrvMedia, off, pvBuf, cbWrite);
162#ifdef VBOX_PERIODIC_FLUSH
163 if (pData->cbFlushInterval)
164 {
165 pData->cbDataWritten += cbWrite;
166 if (pData->cbDataWritten > pData->cbFlushInterval)
167 {
168 pData->cbDataWritten = 0;
169 pData->pDrvMedia->pfnFlush(pData->pDrvMedia);
170 }
171 }
172#endif /* VBOX_PERIODIC_FLUSH */
173
174 return rc;
175}
176
177
178/** @copydoc PDMIBLOCK::pfnFlush */
179static DECLCALLBACK(int) drvblockFlush(PPDMIBLOCK pInterface)
180{
181 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
182
183 /*
184 * Check the state.
185 */
186 if (!pData->pDrvMedia)
187 {
188 AssertMsgFailed(("Invalid state! Not mounted!\n"));
189 return VERR_PDM_MEDIA_NOT_MOUNTED;
190 }
191
192#ifdef VBOX_IGNORE_FLUSH
193 if (pData->fIgnoreFlush)
194 return VINF_SUCCESS;
195#endif /* VBOX_IGNORE_FLUSH */
196
197 int rc = pData->pDrvMedia->pfnFlush(pData->pDrvMedia);
198 if (rc == VERR_NOT_IMPLEMENTED)
199 rc = VINF_SUCCESS;
200 return rc;
201}
202
203
204/** @copydoc PDMIBLOCK::pfnIsReadOnly */
205static DECLCALLBACK(bool) drvblockIsReadOnly(PPDMIBLOCK pInterface)
206{
207 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
208
209 /*
210 * Check the state.
211 */
212 if (!pData->pDrvMedia)
213 return false;
214
215 bool fRc = pData->pDrvMedia->pfnIsReadOnly(pData->pDrvMedia);
216 return fRc;
217}
218
219
220/** @copydoc PDMIBLOCK::pfnGetSize */
221static DECLCALLBACK(uint64_t) drvblockGetSize(PPDMIBLOCK pInterface)
222{
223 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
224
225 /*
226 * Check the state.
227 */
228 if (!pData->pDrvMedia)
229 return 0;
230
231 uint64_t cb = pData->pDrvMedia->pfnGetSize(pData->pDrvMedia);
232 LogFlow(("drvblockGetSize: returns %llu\n", cb));
233 return cb;
234}
235
236
237/** @copydoc PDMIBLOCK::pfnGetType */
238static DECLCALLBACK(PDMBLOCKTYPE) drvblockGetType(PPDMIBLOCK pInterface)
239{
240 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
241 LogFlow(("drvblockGetType: returns %d\n", pData->enmType));
242 return pData->enmType;
243}
244
245
246/** @copydoc PDMIBLOCK::pfnGetUuid */
247static DECLCALLBACK(int) drvblockGetUuid(PPDMIBLOCK pInterface, PRTUUID pUuid)
248{
249 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
250
251 /*
252 * Copy the uuid.
253 */
254 *pUuid = pData->Uuid;
255 return VINF_SUCCESS;
256}
257
258
259/* -=-=-=-=- IBlockBios -=-=-=-=- */
260
261/** Makes a PDRVBLOCK out of a PPDMIBLOCKBIOS. */
262#define PDMIBLOCKBIOS_2_DRVBLOCK(pInterface) ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlockBios))) )
263
264
265/** @copydoc PDMIBLOCKBIOS::pfnGetGeometry */
266static DECLCALLBACK(int) drvblockGetGeometry(PPDMIBLOCKBIOS pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
267{
268 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
269
270 /*
271 * Check the state.
272 */
273 if (!pData->pDrvMedia)
274 return VERR_PDM_MEDIA_NOT_MOUNTED;
275
276 /*
277 * Use configured/cached values if present.
278 */
279 if ( pData->cCylinders > 0
280 && pData->cHeads > 0
281 && pData->cSectors > 0)
282 {
283 *pcCylinders = pData->cCylinders;
284 *pcHeads = pData->cHeads;
285 *pcSectors = pData->cSectors;
286 LogFlow(("drvblockGetGeometry: returns VINF_SUCCESS {%d,%d,%d}\n", pData->cCylinders, pData->cHeads, pData->cSectors));
287 return VINF_SUCCESS;
288 }
289
290 /*
291 * Call media.
292 */
293 int rc = pData->pDrvMedia->pfnBiosGetGeometry(pData->pDrvMedia, pcCylinders, pcHeads, pcSectors);
294 if (VBOX_SUCCESS(rc))
295 {
296 pData->cCylinders = *pcCylinders;
297 pData->cHeads = *pcHeads;
298 pData->cSectors = *pcSectors;
299 LogFlow(("drvblockGetGeometry: returns %Vrc {%d,%d,%d}\n", rc, pData->cCylinders, pData->cHeads, pData->cSectors));
300 }
301 else if (rc == VERR_NOT_IMPLEMENTED)
302 {
303 rc = VERR_PDM_GEOMETRY_NOT_SET;
304 LogFlow(("drvblockGetGeometry: returns %Vrc\n", rc));
305 }
306 return rc;
307}
308
309
310/** @copydoc PDMIBLOCKBIOS::pfnSetGeometry */
311static DECLCALLBACK(int) drvblockSetGeometry(PPDMIBLOCKBIOS pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
312{
313 LogFlow(("drvblockSetGeometry: cCylinders=%d cHeads=%d cSectors=%d\n", cCylinders, cHeads, cSectors));
314 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
315
316 /*
317 * Check the state.
318 */
319 if (!pData->pDrvMedia)
320 {
321 AssertMsgFailed(("Invalid state! Not mounted!\n"));
322 return VERR_PDM_MEDIA_NOT_MOUNTED;
323 }
324
325 /*
326 * Call media. Ignore the not implemented return code.
327 */
328 int rc = pData->pDrvMedia->pfnBiosSetGeometry(pData->pDrvMedia, cCylinders, cHeads, cSectors);
329 if ( VBOX_SUCCESS(rc)
330 || rc == VERR_NOT_IMPLEMENTED)
331 {
332 pData->cCylinders = cCylinders;
333 pData->cHeads = cHeads;
334 pData->cSectors = cSectors;
335 rc = VINF_SUCCESS;
336 }
337 return rc;
338}
339
340
341/** @copydoc PDMIBLOCKBIOS::pfnGetTranslation */
342static DECLCALLBACK(int) drvblockGetTranslation(PPDMIBLOCKBIOS pInterface, PPDMBIOSTRANSLATION penmTranslation)
343{
344 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
345
346 /*
347 * Check the state.
348 */
349 if (!pData->pDrvMedia)
350 {
351 LogFlow(("drvblockGetTranslation: returns VERR_PDM_MEDIA_NOT_MOUNTED\n"));
352 return VERR_PDM_MEDIA_NOT_MOUNTED;
353 }
354
355 /*
356 * Use configured/cached data if present.
357 */
358 if (pData->fTranslationSet)
359 {
360 *penmTranslation = pData->enmTranslation;
361 LogFlow(("drvblockGetTranslation: returns VINF_SUCCESS *penmTranslation=%d\n", *penmTranslation));
362 return VINF_SUCCESS;
363 }
364
365 /*
366 * Call media. Handle the not implemented status code.
367 */
368 int rc = pData->pDrvMedia->pfnBiosGetTranslation(pData->pDrvMedia, penmTranslation);
369 if (VBOX_SUCCESS(rc))
370 {
371 pData->enmTranslation = *penmTranslation;
372 pData->fTranslationSet = true;
373 }
374 else if (rc == VERR_NOT_IMPLEMENTED)
375 rc = VERR_PDM_TRANSLATION_NOT_SET;
376 LogFlow(("drvblockGetTranslation: returns %Vrc *penmTranslation=%d\n", rc, *penmTranslation));
377 return rc;
378}
379
380
381/** @copydoc PDMIBLOCKBIOS::pfnSetTranslation */
382static DECLCALLBACK(int) drvblockSetTranslation(PPDMIBLOCKBIOS pInterface, PDMBIOSTRANSLATION enmTranslation)
383{
384 LogFlow(("drvblockSetTranslation: enmTranslation=%d\n", enmTranslation));
385 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
386
387 /*
388 * Check the state.
389 */
390 if (!pData->pDrvMedia)
391 {
392 AssertMsgFailed(("Invalid state! Not mounted!\n"));
393 return VERR_PDM_MEDIA_NOT_MOUNTED;
394 }
395
396 /*
397 * Call media. Ignore the not implemented return code.
398 */
399 int rc = pData->pDrvMedia->pfnBiosSetTranslation(pData->pDrvMedia, enmTranslation);
400 if ( VBOX_SUCCESS(rc)
401 || rc == VERR_NOT_IMPLEMENTED)
402 {
403 pData->fTranslationSet = true;
404 pData->enmTranslation = enmTranslation;
405 rc = VINF_SUCCESS;
406 }
407 return rc;
408}
409
410
411/** @copydoc PDMIBLOCKBIOS::pfnIsVisible */
412static DECLCALLBACK(bool) drvblockIsVisible(PPDMIBLOCKBIOS pInterface)
413{
414 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
415 LogFlow(("drvblockIsVisible: returns %d\n", pData->fBiosVisible));
416 return pData->fBiosVisible;
417}
418
419
420/** @copydoc PDMIBLOCKBIOS::pfnGetType */
421static DECLCALLBACK(PDMBLOCKTYPE) drvblockBiosGetType(PPDMIBLOCKBIOS pInterface)
422{
423 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
424 LogFlow(("drvblockBiosGetType: returns %d\n", pData->enmType));
425 return pData->enmType;
426}
427
428
429
430/* -=-=-=-=- IMount -=-=-=-=- */
431
432/** Makes a PDRVBLOCK out of a PPDMIMOUNT. */
433#define PDMIMOUNT_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMount)) )
434
435
436/** @copydoc PDMIMOUNT::pfnMount */
437static DECLCALLBACK(int) drvblockMount(PPDMIMOUNT pInterface, const char *pszFilename, const char *pszCoreDriver)
438{
439 LogFlow(("drvblockMount: pszFilename=%p:{%s} pszCoreDriver=%p:{%s}\n", pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
440 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
441
442 /*
443 * Validate state.
444 */
445 if (pData->pDrvMedia)
446 {
447 AssertMsgFailed(("Already mounted\n"));
448 return VERR_PDM_MEDIA_MOUNTED;
449 }
450
451 /*
452 * Prepare configuration.
453 */
454 if (pszFilename)
455 {
456 int rc = pData->pDrvIns->pDrvHlp->pfnMountPrepare(pData->pDrvIns, pszFilename, pszCoreDriver);
457 if (VBOX_FAILURE(rc))
458 {
459 Log(("drvblockMount: Prepare failed for \"%s\" rc=%Vrc\n", pszFilename, rc));
460 return rc;
461 }
462 }
463
464 /*
465 * Attach the media driver and query it's interface.
466 */
467 PPDMIBASE pBase;
468 int rc = pData->pDrvIns->pDrvHlp->pfnAttach(pData->pDrvIns, &pBase);
469 if (VBOX_FAILURE(rc))
470 {
471 Log(("drvblockMount: Attach failed rc=%Vrc\n", rc));
472 return rc;
473 }
474
475 pData->pDrvMedia = (PPDMIMEDIA)pBase->pfnQueryInterface(pBase, PDMINTERFACE_MEDIA);
476 if (pData->pDrvMedia)
477 {
478 /*
479 * Initialize state.
480 */
481 pData->fLocked = false;
482 pData->enmTranslation = PDMBIOSTRANSLATION_NONE;
483 pData->cCylinders = pData->cHeads = pData->cSectors = 0;
484#ifdef VBOX_PERIODIC_FLUSH
485 pData->cbDataWritten = 0;
486#endif /* VBOX_PERIODIC_FLUSH */
487
488 /*
489 * Notify driver/device above us.
490 */
491 if (pData->pDrvMountNotify)
492 pData->pDrvMountNotify->pfnMountNotify(pData->pDrvMountNotify);
493 Log(("drvblockMount: Success\n"));
494 return VINF_SUCCESS;
495 }
496 else
497 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
498
499 /*
500 * Failed, detatch the media driver.
501 */
502 AssertMsgFailed(("No media interface!\n"));
503 int rc2 = pData->pDrvIns->pDrvHlp->pfnDetach(pData->pDrvIns);
504 AssertRC(rc2);
505 pData->pDrvMedia = NULL;
506 return rc;
507}
508
509
510/** @copydoc PDMIMOUNT::pfnUnmount */
511static DECLCALLBACK(int) drvblockUnmount(PPDMIMOUNT pInterface, bool fForce)
512{
513 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
514
515 /*
516 * Validate state.
517 */
518 if (!pData->pDrvMedia)
519 {
520 Log(("drvblockUmount: Not mounted\n"));
521 return VERR_PDM_MEDIA_NOT_MOUNTED;
522 }
523 if (pData->fLocked && !fForce)
524 {
525 Log(("drvblockUmount: Locked\n"));
526 return VERR_PDM_MEDIA_LOCKED;
527 }
528
529 /* Media is no longer locked even if it was previously. */
530 pData->fLocked = false;
531
532 /*
533 * Detach the media driver and query it's interface.
534 */
535 int rc = pData->pDrvIns->pDrvHlp->pfnDetach(pData->pDrvIns);
536 if (VBOX_FAILURE(rc))
537 {
538 Log(("drvblockUnmount: Detach failed rc=%Vrc\n", rc));
539 return rc;
540 }
541 Assert(!pData->pDrvMedia);
542
543 /*
544 * Notify driver/device above us.
545 */
546 if (pData->pDrvMountNotify)
547 pData->pDrvMountNotify->pfnUnmountNotify(pData->pDrvMountNotify);
548 Log(("drvblockUnmount: success\n"));
549 return VINF_SUCCESS;
550}
551
552
553/** @copydoc PDMIMOUNT::pfnIsMounted */
554static DECLCALLBACK(bool) drvblockIsMounted(PPDMIMOUNT pInterface)
555{
556 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
557 return pData->pDrvMedia != NULL;
558}
559
560/** @copydoc PDMIMOUNT::pfnLock */
561static DECLCALLBACK(int) drvblockLock(PPDMIMOUNT pInterface)
562{
563 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
564 Log(("drvblockLock: %d -> %d\n", pData->fLocked, true));
565 pData->fLocked = true;
566 return VINF_SUCCESS;
567}
568
569/** @copydoc PDMIMOUNT::pfnUnlock */
570static DECLCALLBACK(int) drvblockUnlock(PPDMIMOUNT pInterface)
571{
572 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
573 Log(("drvblockUnlock: %d -> %d\n", pData->fLocked, false));
574 pData->fLocked = false;
575 return VINF_SUCCESS;
576}
577
578/** @copydoc PDMIMOUNT::pfnIsLocked */
579static DECLCALLBACK(bool) drvblockIsLocked(PPDMIMOUNT pInterface)
580{
581 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
582 return pData->fLocked;
583}
584
585
586/* -=-=-=-=- IBase -=-=-=-=- */
587
588/** @copydoc PDMIBASE::pfnQueryInterface. */
589static DECLCALLBACK(void *) drvblockQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
590{
591 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
592 PDRVBLOCK pData = PDMINS2DATA(pDrvIns, PDRVBLOCK);
593 switch (enmInterface)
594 {
595 case PDMINTERFACE_BASE:
596 return &pDrvIns->IBase;
597 case PDMINTERFACE_BLOCK:
598 return &pData->IBlock;
599 case PDMINTERFACE_BLOCK_BIOS:
600 return pData->fBiosVisible ? &pData->IBlockBios : NULL;
601 case PDMINTERFACE_MOUNT:
602 return pData->fMountable ? &pData->IMount : NULL;
603 default:
604 return NULL;
605 }
606}
607
608
609/* -=-=-=-=- driver interface -=-=-=-=- */
610
611/** @copydoc FNPDMDRVDETACH. */
612static DECLCALLBACK(void) drvblockDetach(PPDMDRVINS pDrvIns)
613{
614 PDRVBLOCK pData = PDMINS2DATA(pDrvIns, PDRVBLOCK);
615 pData->pDrvMedia = NULL;
616}
617
618
619/**
620 * Construct a block driver instance.
621 *
622 * @returns VBox status.
623 * @param pDrvIns The driver instance data.
624 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
625 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
626 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
627 * iInstance it's expected to be used a bit in this function.
628 */
629static DECLCALLBACK(int) drvblockConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
630{
631 PDRVBLOCK pData = PDMINS2DATA(pDrvIns, PDRVBLOCK);
632 LogFlow(("drvblockConstruct: iInstance=%d\n", pDrvIns->iInstance));
633
634 /*
635 * Validate configuration.
636 */
637#if defined(VBOX_PERIODIC_FLUSH) || defined(VBOX_IGNORE_FLUSH)
638 if (!CFGMR3AreValuesValid(pCfgHandle, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Translation\0Mountable\0FlushInterval\0IgnoreFlush\0"))
639#else /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
640 if (!CFGMR3AreValuesValid(pCfgHandle, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Translation\0Mountable\0"))
641#endif /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
642 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
643
644 /*
645 * Initialize most of the data members.
646 */
647 pData->pDrvIns = pDrvIns;
648
649 /* IBase. */
650 pDrvIns->IBase.pfnQueryInterface = drvblockQueryInterface;
651
652 /* IBlock. */
653 pData->IBlock.pfnRead = drvblockRead;
654 pData->IBlock.pfnWrite = drvblockWrite;
655 pData->IBlock.pfnFlush = drvblockFlush;
656 pData->IBlock.pfnIsReadOnly = drvblockIsReadOnly;
657 pData->IBlock.pfnGetSize = drvblockGetSize;
658 pData->IBlock.pfnGetType = drvblockGetType;
659 pData->IBlock.pfnGetUuid = drvblockGetUuid;
660
661 /* IBlockBios. */
662 pData->IBlockBios.pfnGetGeometry = drvblockGetGeometry;
663 pData->IBlockBios.pfnSetGeometry = drvblockSetGeometry;
664 pData->IBlockBios.pfnGetTranslation = drvblockGetTranslation;
665 pData->IBlockBios.pfnSetTranslation = drvblockSetTranslation;
666 pData->IBlockBios.pfnIsVisible = drvblockIsVisible;
667 pData->IBlockBios.pfnGetType = drvblockBiosGetType;
668
669 /* IMount. */
670 pData->IMount.pfnMount = drvblockMount;
671 pData->IMount.pfnUnmount = drvblockUnmount;
672 pData->IMount.pfnIsMounted = drvblockIsMounted;
673 pData->IMount.pfnLock = drvblockLock;
674 pData->IMount.pfnUnlock = drvblockUnlock;
675 pData->IMount.pfnIsLocked = drvblockIsLocked;
676
677 /*
678 * Get the IBlockPort & IMountNotify interfaces of the above driver/device.
679 */
680 pData->pDrvBlockPort = (PPDMIBLOCKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_BLOCK_PORT);
681 if (!pData->pDrvBlockPort)
682 {
683 AssertMsgFailed(("Configuration error: No block port interface above!\n"));
684 return VERR_PDM_MISSING_INTERFACE_ABOVE;
685 }
686 pData->pDrvMountNotify = (PPDMIMOUNTNOTIFY)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_MOUNT_NOTIFY);
687
688 /*
689 * Query configuration.
690 */
691 /* type */
692 char *psz;
693 int rc = CFGMR3QueryStringAlloc(pCfgHandle, "Type", &psz);
694 if (VBOX_FAILURE(rc))
695 {
696 AssertMsgFailed(("Configuration error: Failed to obtain the type, rc=%Vrc.\n", rc));
697 return VERR_PDM_BLOCK_NO_TYPE;
698 }
699 if (!strcmp(psz, "HardDisk"))
700 pData->enmType = PDMBLOCKTYPE_HARD_DISK;
701 else if (!strcmp(psz, "DVD"))
702 pData->enmType = PDMBLOCKTYPE_DVD;
703 else if (!strcmp(psz, "CDROM"))
704 pData->enmType = PDMBLOCKTYPE_CDROM;
705 else if (!strcmp(psz, "Floppy 2.88"))
706 pData->enmType = PDMBLOCKTYPE_FLOPPY_2_88;
707 else if (!strcmp(psz, "Floppy 1.44"))
708 pData->enmType = PDMBLOCKTYPE_FLOPPY_1_44;
709 else if (!strcmp(psz, "Floppy 1.20"))
710 pData->enmType = PDMBLOCKTYPE_FLOPPY_1_20;
711 else if (!strcmp(psz, "Floppy 720"))
712 pData->enmType = PDMBLOCKTYPE_FLOPPY_720;
713 else if (!strcmp(psz, "Floppy 360"))
714 pData->enmType = PDMBLOCKTYPE_FLOPPY_360;
715 else
716 {
717 AssertMsgFailed(("Configuration error: Unknown type \"%s\".\n", psz));
718 MMR3HeapFree(psz);
719 return VERR_PDM_BLOCK_UNKNOWN_TYPE;
720 }
721 Log2(("drvblockConstruct: enmType=%d\n", pData->enmType));
722 MMR3HeapFree(psz); psz = NULL;
723
724 /* Mountable */
725 rc = CFGMR3QueryBool(pCfgHandle, "Mountable", &pData->fMountable);
726 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
727 pData->fMountable = false;
728 else if (VBOX_FAILURE(rc))
729 {
730 AssertMsgFailed(("Configuration error: Query \"Mountable\" resulted in %Vrc.\n", rc));
731 return rc;
732 }
733
734 /* Locked */
735 rc = CFGMR3QueryBool(pCfgHandle, "Locked", &pData->fLocked);
736 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
737 pData->fLocked = false;
738 else if (VBOX_FAILURE(rc))
739 {
740 AssertMsgFailed(("Configuration error: Query \"Locked\" resulted in %Vrc.\n", rc));
741 return rc;
742 }
743
744 /* BIOS visible */
745 rc = CFGMR3QueryBool(pCfgHandle, "BIOSVisible", &pData->fBiosVisible);
746 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
747 pData->fBiosVisible = true;
748 else if (VBOX_FAILURE(rc))
749 {
750 AssertMsgFailed(("Configuration error: Query \"BIOSVisible\" resulted in %Vrc.\n", rc));
751 return rc;
752 }
753
754 /** @todo AttachFailError is currently completely ignored. */
755
756 /* Cylinders */
757 rc = CFGMR3QueryU32(pCfgHandle, "Cylinders", &pData->cCylinders);
758 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
759 pData->cCylinders = 0;
760 else if (VBOX_FAILURE(rc))
761 {
762 AssertMsgFailed(("Configuration error: Query \"Cylinders\" resulted in %Vrc.\n", rc));
763 return rc;
764 }
765
766 /* Heads */
767 rc = CFGMR3QueryU32(pCfgHandle, "Heads", &pData->cHeads);
768 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
769 pData->cHeads = 0;
770 else if (VBOX_FAILURE(rc))
771 {
772 AssertMsgFailed(("Configuration error: Query \"Heads\" resulted in %Vrc.\n", rc));
773 return rc;
774 }
775
776 /* Sectors */
777 rc = CFGMR3QueryU32(pCfgHandle, "Sectors", &pData->cSectors);
778 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
779 pData->cSectors = 0;
780 else if (VBOX_FAILURE(rc))
781 {
782 AssertMsgFailed(("Configuration error: Query \"Sectors\" resulted in %Vrc.\n", rc));
783 return rc;
784 }
785
786 /* Translation */
787 rc = CFGMR3QueryStringAlloc(pCfgHandle, "Translation", &psz);
788 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
789 {
790 pData->enmTranslation = PDMBIOSTRANSLATION_NONE;
791 pData->fTranslationSet = false;
792 }
793 else if (VBOX_SUCCESS(rc))
794 {
795 if (!strcmp(psz, "None"))
796 pData->enmTranslation = PDMBIOSTRANSLATION_NONE;
797 else if (!strcmp(psz, "LBA"))
798 pData->enmTranslation = PDMBIOSTRANSLATION_LBA;
799 else if (!strcmp(psz, "Auto"))
800 pData->enmTranslation = PDMBIOSTRANSLATION_AUTO;
801 else
802 {
803 AssertMsgFailed(("Configuration error: Unknown translation \"%s\".\n", psz));
804 MMR3HeapFree(psz);
805 return VERR_PDM_BLOCK_UNKNOWN_TRANSLATION;
806 }
807 MMR3HeapFree(psz); psz = NULL;
808 pData->fTranslationSet = true;
809 }
810 else
811 {
812 AssertMsgFailed(("Configuration error: Failed to obtain the translation, rc=%Vrc.\n", rc));
813 return VERR_PDM_BLOCK_NO_TYPE;
814 }
815
816 /* Uuid */
817 rc = CFGMR3QueryStringAlloc(pCfgHandle, "Uuid", &psz);
818 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
819 RTUuidClear(&pData->Uuid);
820 else if (VBOX_SUCCESS(rc))
821 {
822 rc = RTUuidFromStr(&pData->Uuid, psz);
823 if (VBOX_FAILURE(rc))
824 {
825 AssertMsgFailed(("Configuration error: Uuid from string failed on \"%s\", rc=%Vrc.\n", psz, rc));
826 MMR3HeapFree(psz);
827 return rc;
828 }
829 MMR3HeapFree(psz); psz = NULL;
830 }
831 else
832 {
833 AssertMsgFailed(("Configuration error: Failed to obtain the type, rc=%Vrc.\n", rc));
834 return VERR_PDM_BLOCK_NO_TYPE;
835 }
836
837#ifdef VBOX_PERIODIC_FLUSH
838 rc = CFGMR3QueryU32(pCfgHandle, "FlushInterval", &pData->cbFlushInterval);
839 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
840 pData->cbFlushInterval = 0;
841 else if (VBOX_FAILURE(rc))
842 {
843 AssertMsgFailed(("Configuration error: Query \"FlushInterval\" resulted in %Vrc.\n", rc));
844 return rc;
845 }
846#endif /* VBOX_PERIODIC_FLUSH */
847
848#ifdef VBOX_IGNORE_FLUSH
849 rc = CFGMR3QueryBool(pCfgHandle, "IgnoreFlush", &pData->fIgnoreFlush);
850 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
851 pData->fIgnoreFlush = true; /* The default is to ignore flushes. */
852 else if (VBOX_FAILURE(rc))
853 {
854 AssertMsgFailed(("Configuration error: Query \"IgnoreFlush\" resulted in %Vrc.\n", rc));
855 return rc;
856 }
857#endif /* VBOX_IGNORE_FLUSH */
858
859 /*
860 * Try attach driver below and query it's media interface.
861 */
862 PPDMIBASE pBase;
863 rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBase);
864 if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
865 && pData->enmType != PDMBLOCKTYPE_HARD_DISK)
866 return VINF_SUCCESS;
867 if (VBOX_FAILURE(rc))
868 {
869 AssertMsgFailed(("Failed to attach driver below us! rc=%Vra\n", rc));
870 return rc;
871 }
872 pData->pDrvMedia = (PPDMIMEDIA)pBase->pfnQueryInterface(pBase, PDMINTERFACE_MEDIA);
873 if (!pData->pDrvMedia)
874 {
875 AssertMsgFailed(("Configuration error: No media interface below!\n"));
876 return VERR_PDM_MISSING_INTERFACE_BELOW;
877 }
878 if (RTUuidIsNull(&pData->Uuid))
879 {
880 if (pData->enmType == PDMBLOCKTYPE_HARD_DISK)
881 pData->pDrvMedia->pfnGetUuid(pData->pDrvMedia, &pData->Uuid);
882 }
883
884 return VINF_SUCCESS;
885}
886
887
888/**
889 * Block driver registration record.
890 */
891const PDMDRVREG g_DrvBlock =
892{
893 /* u32Version */
894 PDM_DRVREG_VERSION,
895 /* szDriverName */
896 "Block",
897 /* pszDescription */
898 "Generic block driver.",
899 /* fFlags */
900 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
901 /* fClass. */
902 PDM_DRVREG_CLASS_BLOCK,
903 /* cMaxInstances */
904 ~0,
905 /* cbInstance */
906 sizeof(DRVBLOCK),
907 /* pfnConstruct */
908 drvblockConstruct,
909 /* pfnDestruct */
910 NULL,
911 /* pfnIOCtl */
912 NULL,
913 /* pfnPowerOn */
914 NULL,
915 /* pfnReset */
916 NULL,
917 /* pfnSuspend */
918 NULL,
919 /* pfnResume */
920 NULL,
921 /* pfnDetach */
922 drvblockDetach
923};
924
925
926
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