VirtualBox

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

Last change on this file since 980 was 1, checked in by vboxsync, 55 years ago

import

  • 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 InnoTek Systemberatung 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)
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)
524 {
525 Log(("drvblockUmount: Locked\n"));
526 return VERR_PDM_MEDIA_LOCKED;
527 }
528
529 /*
530 * Detach the media driver and query it's interface.
531 */
532 int rc = pData->pDrvIns->pDrvHlp->pfnDetach(pData->pDrvIns);
533 if (VBOX_FAILURE(rc))
534 {
535 Log(("drvblockUnmount: Detach failed rc=%Vrc\n", rc));
536 return rc;
537 }
538 Assert(!pData->pDrvMedia);
539
540 /*
541 * Notify driver/device above us.
542 */
543 if (pData->pDrvMountNotify)
544 pData->pDrvMountNotify->pfnUnmountNotify(pData->pDrvMountNotify);
545 Log(("drvblockUnmount: success\n"));
546 return VINF_SUCCESS;
547}
548
549
550/** @copydoc PDMIMOUNT::pfnIsMounted */
551static DECLCALLBACK(bool) drvblockIsMounted(PPDMIMOUNT pInterface)
552{
553 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
554 return pData->pDrvMedia != NULL;
555}
556
557/** @copydoc PDMIMOUNT::pfnLock */
558static DECLCALLBACK(int) drvblockLock(PPDMIMOUNT pInterface)
559{
560 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
561 Log(("drvblockLock: %d -> %d\n", pData->fLocked, true));
562 pData->fLocked = true;
563 return VINF_SUCCESS;
564}
565
566/** @copydoc PDMIMOUNT::pfnUnlock */
567static DECLCALLBACK(int) drvblockUnlock(PPDMIMOUNT pInterface)
568{
569 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
570 Log(("drvblockUnlock: %d -> %d\n", pData->fLocked, false));
571 pData->fLocked = false;
572 return VINF_SUCCESS;
573}
574
575/** @copydoc PDMIMOUNT::pfnIsLocked */
576static DECLCALLBACK(bool) drvblockIsLocked(PPDMIMOUNT pInterface)
577{
578 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
579 return pData->fLocked;
580}
581
582
583/* -=-=-=-=- IBase -=-=-=-=- */
584
585/** @copydoc PDMIBASE::pfnQueryInterface. */
586static DECLCALLBACK(void *) drvblockQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
587{
588 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
589 PDRVBLOCK pData = PDMINS2DATA(pDrvIns, PDRVBLOCK);
590 switch (enmInterface)
591 {
592 case PDMINTERFACE_BASE:
593 return &pDrvIns->IBase;
594 case PDMINTERFACE_BLOCK:
595 return &pData->IBlock;
596 case PDMINTERFACE_BLOCK_BIOS:
597 return pData->fBiosVisible ? &pData->IBlockBios : NULL;
598 case PDMINTERFACE_MOUNT:
599 return pData->fMountable ? &pData->IMount : NULL;
600 default:
601 return NULL;
602 }
603}
604
605
606/* -=-=-=-=- driver interface -=-=-=-=- */
607
608/** @copydoc FNPDMDRVDETACH. */
609static DECLCALLBACK(void) drvblockDetach(PPDMDRVINS pDrvIns)
610{
611 PDRVBLOCK pData = PDMINS2DATA(pDrvIns, PDRVBLOCK);
612 pData->pDrvMedia = NULL;
613}
614
615
616/**
617 * Construct a block driver instance.
618 *
619 * @returns VBox status.
620 * @param pDrvIns The driver instance data.
621 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
622 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
623 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
624 * iInstance it's expected to be used a bit in this function.
625 */
626static DECLCALLBACK(int) drvblockConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
627{
628 PDRVBLOCK pData = PDMINS2DATA(pDrvIns, PDRVBLOCK);
629 LogFlow(("drvblockConstruct: iInstance=%d\n", pDrvIns->iInstance));
630
631 /*
632 * Validate configuration.
633 */
634#if defined(VBOX_PERIODIC_FLUSH) || defined(VBOX_IGNORE_FLUSH)
635 if (!CFGMR3AreValuesValid(pCfgHandle, "Type\0Locked\0BIOSVisible\0Cylinders\0Heads\0Sectors\0Translation\0Mountable\0FlushInterval\0IgnoreFlush\0"))
636#else /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
637 if (!CFGMR3AreValuesValid(pCfgHandle, "Type\0Locked\0BIOSVisible\0Cylinders\0Heads\0Sectors\0Translation\0Mountable\0"))
638#endif /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
639 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
640
641 /*
642 * Initialize most of the data members.
643 */
644 pData->pDrvIns = pDrvIns;
645
646 /* IBase. */
647 pDrvIns->IBase.pfnQueryInterface = drvblockQueryInterface;
648
649 /* IBlock. */
650 pData->IBlock.pfnRead = drvblockRead;
651 pData->IBlock.pfnWrite = drvblockWrite;
652 pData->IBlock.pfnFlush = drvblockFlush;
653 pData->IBlock.pfnIsReadOnly = drvblockIsReadOnly;
654 pData->IBlock.pfnGetSize = drvblockGetSize;
655 pData->IBlock.pfnGetType = drvblockGetType;
656 pData->IBlock.pfnGetUuid = drvblockGetUuid;
657
658 /* IBlockBios. */
659 pData->IBlockBios.pfnGetGeometry = drvblockGetGeometry;
660 pData->IBlockBios.pfnSetGeometry = drvblockSetGeometry;
661 pData->IBlockBios.pfnGetTranslation = drvblockGetTranslation;
662 pData->IBlockBios.pfnSetTranslation = drvblockSetTranslation;
663 pData->IBlockBios.pfnIsVisible = drvblockIsVisible;
664 pData->IBlockBios.pfnGetType = drvblockBiosGetType;
665
666 /* IMount. */
667 pData->IMount.pfnMount = drvblockMount;
668 pData->IMount.pfnUnmount = drvblockUnmount;
669 pData->IMount.pfnIsMounted = drvblockIsMounted;
670 pData->IMount.pfnLock = drvblockLock;
671 pData->IMount.pfnUnlock = drvblockUnlock;
672 pData->IMount.pfnIsLocked = drvblockIsLocked;
673
674 /*
675 * Get the IBlockPort & IMountNotify interfaces of the above driver/device.
676 */
677 pData->pDrvBlockPort = (PPDMIBLOCKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_BLOCK_PORT);
678 if (!pData->pDrvBlockPort)
679 {
680 AssertMsgFailed(("Configuration error: No block port interface above!\n"));
681 return VERR_PDM_MISSING_INTERFACE_ABOVE;
682 }
683 pData->pDrvMountNotify = (PPDMIMOUNTNOTIFY)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_MOUNT_NOTIFY);
684
685 /*
686 * Query configuration.
687 */
688 /* type */
689 char *psz;
690 int rc = CFGMR3QueryStringAlloc(pCfgHandle, "Type", &psz);
691 if (VBOX_FAILURE(rc))
692 {
693 AssertMsgFailed(("Configuration error: Failed to obtain the type, rc=%Vrc.\n", rc));
694 return VERR_PDM_BLOCK_NO_TYPE;
695 }
696 if (!strcmp(psz, "HardDisk"))
697 pData->enmType = PDMBLOCKTYPE_HARD_DISK;
698 else if (!strcmp(psz, "DVD"))
699 pData->enmType = PDMBLOCKTYPE_DVD;
700 else if (!strcmp(psz, "CDROM"))
701 pData->enmType = PDMBLOCKTYPE_CDROM;
702 else if (!strcmp(psz, "Floppy 2.88"))
703 pData->enmType = PDMBLOCKTYPE_FLOPPY_2_88;
704 else if (!strcmp(psz, "Floppy 1.44"))
705 pData->enmType = PDMBLOCKTYPE_FLOPPY_1_44;
706 else if (!strcmp(psz, "Floppy 1.20"))
707 pData->enmType = PDMBLOCKTYPE_FLOPPY_1_20;
708 else if (!strcmp(psz, "Floppy 720"))
709 pData->enmType = PDMBLOCKTYPE_FLOPPY_720;
710 else if (!strcmp(psz, "Floppy 360"))
711 pData->enmType = PDMBLOCKTYPE_FLOPPY_360;
712 else
713 {
714 AssertMsgFailed(("Configuration error: Unknown type \"%s\".\n", psz));
715 MMR3HeapFree(psz);
716 return VERR_PDM_BLOCK_UNKNOWN_TYPE;
717 }
718 Log2(("drvblockConstruct: enmType=%d\n", pData->enmType));
719 MMR3HeapFree(psz); psz = NULL;
720
721 /* Mountable */
722 rc = CFGMR3QueryBool(pCfgHandle, "Mountable", &pData->fMountable);
723 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
724 pData->fMountable = false;
725 else if (VBOX_FAILURE(rc))
726 {
727 AssertMsgFailed(("Configuration error: Query \"Mountable\" resulted in %Vrc.\n", rc));
728 return rc;
729 }
730
731 /* Locked */
732 rc = CFGMR3QueryBool(pCfgHandle, "Locked", &pData->fLocked);
733 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
734 pData->fLocked = false;
735 else if (VBOX_FAILURE(rc))
736 {
737 AssertMsgFailed(("Configuration error: Query \"Locked\" resulted in %Vrc.\n", rc));
738 return rc;
739 }
740
741 /* BIOS visible */
742 rc = CFGMR3QueryBool(pCfgHandle, "BIOSVisible", &pData->fBiosVisible);
743 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
744 pData->fBiosVisible = true;
745 else if (VBOX_FAILURE(rc))
746 {
747 AssertMsgFailed(("Configuration error: Query \"BIOSVisible\" resulted in %Vrc.\n", rc));
748 return rc;
749 }
750
751 /* Cylinders */
752 rc = CFGMR3QueryU32(pCfgHandle, "Cylinders", &pData->cCylinders);
753 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
754 pData->cCylinders = 0;
755 else if (VBOX_FAILURE(rc))
756 {
757 AssertMsgFailed(("Configuration error: Query \"Cylinders\" resulted in %Vrc.\n", rc));
758 return rc;
759 }
760
761 /* Heads */
762 rc = CFGMR3QueryU32(pCfgHandle, "Heads", &pData->cHeads);
763 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
764 pData->cHeads = 0;
765 else if (VBOX_FAILURE(rc))
766 {
767 AssertMsgFailed(("Configuration error: Query \"Heads\" resulted in %Vrc.\n", rc));
768 return rc;
769 }
770
771 /* Sectors */
772 rc = CFGMR3QueryU32(pCfgHandle, "Sectors", &pData->cSectors);
773 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
774 pData->cSectors = 0;
775 else if (VBOX_FAILURE(rc))
776 {
777 AssertMsgFailed(("Configuration error: Query \"Sectors\" resulted in %Vrc.\n", rc));
778 return rc;
779 }
780
781 /* Translation */
782 rc = CFGMR3QueryStringAlloc(pCfgHandle, "Translation", &psz);
783 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
784 {
785 pData->enmTranslation = PDMBIOSTRANSLATION_NONE;
786 pData->fTranslationSet = false;
787 }
788 else if (VBOX_SUCCESS(rc))
789 {
790 if (!strcmp(psz, "None"))
791 pData->enmTranslation = PDMBIOSTRANSLATION_NONE;
792 else if (!strcmp(psz, "LBA"))
793 pData->enmTranslation = PDMBIOSTRANSLATION_LBA;
794 else if (!strcmp(psz, "Auto"))
795 pData->enmTranslation = PDMBIOSTRANSLATION_AUTO;
796 else
797 {
798 AssertMsgFailed(("Configuration error: Unknown translation \"%s\".\n", psz));
799 MMR3HeapFree(psz);
800 return VERR_PDM_BLOCK_UNKNOWN_TRANSLATION;
801 }
802 MMR3HeapFree(psz); psz = NULL;
803 pData->fTranslationSet = true;
804 }
805 else
806 {
807 AssertMsgFailed(("Configuration error: Failed to obtain the translation, rc=%Vrc.\n", rc));
808 return VERR_PDM_BLOCK_NO_TYPE;
809 }
810
811 /* Uuid */
812 rc = CFGMR3QueryStringAlloc(pCfgHandle, "Uuid", &psz);
813 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
814 RTUuidClear(&pData->Uuid);
815 else if (VBOX_SUCCESS(rc))
816 {
817 rc = RTUuidFromStr(&pData->Uuid, psz);
818 if (VBOX_FAILURE(rc))
819 {
820 AssertMsgFailed(("Configuration error: Uuid from string failed on \"%s\", rc=%Vrc.\n", psz, rc));
821 MMR3HeapFree(psz);
822 return rc;
823 }
824 MMR3HeapFree(psz); psz = NULL;
825 }
826 else
827 {
828 AssertMsgFailed(("Configuration error: Failed to obtain the type, rc=%Vrc.\n", rc));
829 return VERR_PDM_BLOCK_NO_TYPE;
830 }
831
832#ifdef VBOX_PERIODIC_FLUSH
833 rc = CFGMR3QueryU32(pCfgHandle, "FlushInterval", &pData->cbFlushInterval);
834 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
835 pData->cbFlushInterval = 0;
836 else if (VBOX_FAILURE(rc))
837 {
838 AssertMsgFailed(("Configuration error: Query \"FlushInterval\" resulted in %Vrc.\n", rc));
839 return rc;
840 }
841#endif /* VBOX_PERIODIC_FLUSH */
842
843#ifdef VBOX_IGNORE_FLUSH
844 rc = CFGMR3QueryBool(pCfgHandle, "IgnoreFlush", &pData->fIgnoreFlush);
845 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
846 pData->fIgnoreFlush = true; /* The default is to ignore flushes. */
847 else if (VBOX_FAILURE(rc))
848 {
849 AssertMsgFailed(("Configuration error: Query \"IgnoreFlush\" resulted in %Vrc.\n", rc));
850 return rc;
851 }
852#endif /* VBOX_IGNORE_FLUSH */
853
854 /*
855 * Try attach driver below and query it's media interface.
856 */
857 PPDMIBASE pBase;
858 rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBase);
859 if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
860 && pData->enmType != PDMBLOCKTYPE_HARD_DISK)
861 return VINF_SUCCESS;
862 if (VBOX_FAILURE(rc))
863 {
864 AssertMsgFailed(("Failed to attach driver below us! rc=%Vra\n", rc));
865 return rc;
866 }
867 pData->pDrvMedia = (PPDMIMEDIA)pBase->pfnQueryInterface(pBase, PDMINTERFACE_MEDIA);
868 if (!pData->pDrvMedia)
869 {
870 AssertMsgFailed(("Configuration error: No media interface below!\n"));
871 return VERR_PDM_MISSING_INTERFACE_BELOW;
872 }
873 if (RTUuidIsNull(&pData->Uuid))
874 {
875 if (pData->enmType == PDMBLOCKTYPE_HARD_DISK)
876 pData->pDrvMedia->pfnGetUuid(pData->pDrvMedia, &pData->Uuid);
877 }
878
879 return VINF_SUCCESS;
880}
881
882
883/**
884 * Block driver registration record.
885 */
886const PDMDRVREG g_DrvBlock =
887{
888 /* u32Version */
889 PDM_DRVREG_VERSION,
890 /* szDriverName */
891 "Block",
892 /* pszDescription */
893 "Generic block driver.",
894 /* fFlags */
895 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
896 /* fClass. */
897 PDM_DRVREG_CLASS_BLOCK,
898 /* cMaxInstances */
899 ~0,
900 /* cbInstance */
901 sizeof(DRVBLOCK),
902 /* pfnConstruct */
903 drvblockConstruct,
904 /* pfnDestruct */
905 NULL,
906 /* pfnIOCtl */
907 NULL,
908 /* pfnPowerOn */
909 NULL,
910 /* pfnReset */
911 NULL,
912 /* pfnSuspend */
913 NULL,
914 /* pfnResume */
915 NULL,
916 /* pfnDetach */
917 drvblockDetach
918};
919
920
921
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