VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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