VirtualBox

source: vbox/trunk/src/VBox/Devices/Misc/DevFlashCFI.cpp

Last change on this file was 100765, checked in by vboxsync, 10 months ago

Devices/Misc/DevFlashCFI: Only save the flash content on poweroff because the driver is already gone during destruction, bugref:10434

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.3 KB
Line 
1/* $Id: DevFlashCFI.cpp 100765 2023-08-01 10:34:42Z vboxsync $ */
2/** @file
3 * DevFlashCFI - A simple Flash device implementing the Common Flash Interface
4 * using the sepc from https://ia803103.us.archive.org/30/items/m30l0r7000t0/m30l0r7000t0.pdf
5 *
6 * Implemented as an MMIO device attached directly to the CPU, not behind any
7 * bus. Typically mapped as part of the firmware image.
8 */
9
10/*
11 * Copyright (C) 2023 Oracle and/or its affiliates.
12 *
13 * This file is part of VirtualBox base platform packages, as
14 * available from https://www.virtualbox.org.
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation, in version 3 of the
19 * License.
20 *
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see <https://www.gnu.org/licenses>.
28 *
29 * SPDX-License-Identifier: GPL-3.0-only
30 */
31
32
33/*********************************************************************************************************************************
34* Header Files *
35*********************************************************************************************************************************/
36#define LOG_GROUP LOG_GROUP_DEV_FLASH
37#include <VBox/vmm/pdmdev.h>
38#include <VBox/log.h>
39#include <VBox/err.h>
40#include <iprt/assert.h>
41#include <iprt/string.h>
42#include <iprt/file.h>
43#include <iprt/uuid.h>
44
45#include "VBoxDD.h"
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51
52/** Saved state version. */
53#define FLASH_SAVED_STATE_VERSION 1
54
55/** @name CFI (Command User Interface) Commands.
56 * @{ */
57/** Block erase setup */
58#define FLASH_CFI_CMD_BLOCK_ERASE_SETUP 0x20
59/** Clear status register. */
60#define FLASH_CFI_CMD_CLEAR_STATUS_REG 0x50
61/** Read status register. */
62#define FLASH_CFI_CMD_READ_STATUS_REG 0x70
63/** Read status register. */
64#define FLASH_CFI_CMD_READ_DEVICE_ID 0x90
65/** Buffered program setup. */
66#define FLASH_CFI_CMD_BUFFERED_PROGRAM_SETUP 0xe8
67/** Buffered program setup. */
68#define FLASH_CFI_CMD_BUFFERED_PROGRAM_CONFIRM 0xd0
69/** Read from the flash array. */
70#define FLASH_CFI_CMD_ARRAY_READ 0xff
71/** @} */
72
73/** @name Status register bits.
74 * @{ */
75/** Bank Write/Multiple Word Program Status Bit. */
76#define FLASH_CFI_SR_BWS RT_BIT(0)
77/** Block Protection Status Bit. */
78#define FLASH_CFI_SR_BLOCK_PROTETION RT_BIT(1)
79#define FLASH_CFI_SR_PROGRAM_SUSPEND RT_BIT(2)
80#define FLASH_CFI_SR_VPP RT_BIT(3)
81#define FLASH_CFI_SR_PROGRAM RT_BIT(4)
82#define FLASH_CFI_SR_ERASE RT_BIT(5)
83#define FLASH_CFI_SR_ERASE_SUSPEND RT_BIT(6)
84#define FLASH_CFI_SR_PROGRAM_ERASE RT_BIT(7)
85/** @} */
86
87/** The namespace the NVRAM content is stored under (historical reasons). */
88#define FLASH_CFI_VFS_NAMESPACE "efi"
89
90
91/*********************************************************************************************************************************
92* Structures and Typedefs *
93*********************************************************************************************************************************/
94/**
95 * The flash device, shared state.
96 */
97typedef struct DEVFLASHCFI
98{
99 /** The current command. */
100 uint16_t u16Cmd;
101 /** The status register. */
102 uint8_t bStatus;
103 /** Current bus cycle. */
104 uint8_t cBusCycle;
105
106 uint8_t cWordsTransfered;
107
108 /** @name The following state does not change at runtime
109 * @{ */
110 /** When set, indicates the state was saved. */
111 bool fStateSaved;
112 /** Manufacturer (high byte) and device (low byte) ID. */
113 uint16_t u16FlashId;
114 /** The configured block size of the device. */
115 uint16_t cbBlockSize;
116 /** The actual flash memory data. */
117 R3PTRTYPE(uint8_t *) pbFlash;
118 /** The flash memory region size. */
119 uint32_t cbFlashSize;
120 /** @} */
121
122 /** The file conaining the flash content. */
123 char *pszFlashFile;
124 /** The guest physical memory base address. */
125 RTGCPHYS GCPhysFlashBase;
126 /** The handle to the MMIO region. */
127 IOMMMIOHANDLE hMmio;
128
129 /** The offset of the block to write. */
130 uint32_t offBlock;
131 /** Number of bytes to write. */
132 uint32_t cbWrite;
133 /** The word buffer for the buffered program command (32 16-bit words for each emulated chip). */
134 uint8_t abProgramBuf[2 * 32 * sizeof(uint16_t)];
135
136 /**
137 * NVRAM port - LUN\#0.
138 */
139 struct
140 {
141 /** The base interface we provide the NVRAM driver. */
142 PDMIBASE IBase;
143 /** The NVRAM driver base interface. */
144 PPDMIBASE pDrvBase;
145 /** The VFS interface of the driver below for NVRAM state loading and storing. */
146 PPDMIVFSCONNECTOR pDrvVfs;
147 } Lun0;
148} DEVFLASHCFI;
149/** Pointer to the Flash device state. */
150typedef DEVFLASHCFI *PDEVFLASHCFI;
151
152
153#ifndef VBOX_DEVICE_STRUCT_TESTCASE
154
155
156/**
157 * @callback_method_impl{FNIOMMMIONEWWRITE, Flash memory write}
158 */
159static DECLCALLBACK(VBOXSTRICTRC) flashMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
160{
161 PDEVFLASHCFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASHCFI);
162 RT_NOREF1(pvUser);
163
164 /** @todo For now we only emulate a x32 device using two x16 chips so the command must be send to both chips at the same time
165 * (and we don't support sending different commands to both devices). */
166 Assert(cb == sizeof(uint32_t));
167 uint32_t u32Val = *(const uint32_t *)pv;
168
169 LogFlowFunc(("off=%RGp u32Val=%#x cb=%u\n", off, u32Val, cb));
170
171 if (pThis->cBusCycle == 0)
172 {
173 /* Writes new command, the comand must be sent to both chips at the same time. */
174 Assert((u32Val >> 16) == (u32Val & 0xffff));
175 switch (u32Val & 0xffff)
176 {
177 case FLASH_CFI_CMD_READ_STATUS_REG:
178 case FLASH_CFI_CMD_ARRAY_READ:
179 case FLASH_CFI_CMD_READ_DEVICE_ID:
180 pThis->u16Cmd = u32Val;
181 break;
182 case FLASH_CFI_CMD_BLOCK_ERASE_SETUP:
183 pThis->u16Cmd = u32Val;
184 pThis->cBusCycle++;
185 break;
186 case FLASH_CFI_CMD_BUFFERED_PROGRAM_SETUP:
187 Assert(pThis->bStatus & FLASH_CFI_SR_PROGRAM_ERASE);
188 pThis->u16Cmd = u32Val;
189 pThis->offBlock = (uint32_t)off;
190 pThis->cBusCycle++;
191 break;
192 case FLASH_CFI_CMD_CLEAR_STATUS_REG:
193 pThis->bStatus &= ~(FLASH_CFI_SR_BLOCK_PROTETION | FLASH_CFI_SR_VPP | FLASH_CFI_SR_PROGRAM | FLASH_CFI_SR_ERASE);
194 pThis->u16Cmd = FLASH_CFI_CMD_ARRAY_READ;
195 break;
196 default:
197 AssertReleaseFailed();
198 }
199 }
200 else if (pThis->cBusCycle == 1)
201 {
202 switch (pThis->u16Cmd)
203 {
204 case FLASH_CFI_CMD_BLOCK_ERASE_SETUP:
205 {
206 /* This contains the address. */
207 pThis->u16Cmd = FLASH_CFI_CMD_READ_STATUS_REG;
208 pThis->cBusCycle = 0;
209 memset(pThis->pbFlash + off, 0xff, RT_MIN(pThis->cbFlashSize - off, pThis->cbBlockSize));
210 break;
211 }
212 case FLASH_CFI_CMD_BUFFERED_PROGRAM_SETUP:
213 {
214 /* Receives the number of words to be transfered. */
215 pThis->cWordsTransfered = (u32Val & 0xffff) + 1;
216 pThis->cbWrite = pThis->cWordsTransfered * 2 * sizeof(uint16_t);
217 if (pThis->cbWrite <= sizeof(pThis->abProgramBuf))
218 pThis->cBusCycle++;
219 else
220 AssertReleaseFailed();
221 break;
222 }
223 }
224 }
225 else if (pThis->cBusCycle == 2)
226 {
227 switch (pThis->u16Cmd)
228 {
229 case FLASH_CFI_CMD_BUFFERED_PROGRAM_SETUP:
230 {
231 /* Receives the address and data. */
232 if (!pThis->cWordsTransfered)
233 {
234 /* Should be the confirm now. */
235 if ((u32Val & 0xffff) == FLASH_CFI_CMD_BUFFERED_PROGRAM_CONFIRM)
236 {
237 if (pThis->offBlock + pThis->cbWrite <= pThis->cbFlashSize)
238 memcpy(pThis->pbFlash + pThis->offBlock, &pThis->abProgramBuf[0], pThis->cbWrite);
239 /* Reset to read array. */
240 pThis->cBusCycle = 0;
241 pThis->u16Cmd = FLASH_CFI_CMD_ARRAY_READ;
242 }
243 else
244 AssertReleaseFailed();
245 }
246 else
247 {
248 if ( off >= pThis->offBlock
249 && (off + cb >= pThis->offBlock)
250 && ((off + cb) - pThis->offBlock) <= sizeof(pThis->abProgramBuf))
251 memcpy(&pThis->abProgramBuf[off - pThis->offBlock], pv, cb);
252 else
253 AssertReleaseFailed();
254 pThis->cWordsTransfered--;
255 }
256 break;
257 }
258 }
259 }
260 else
261 AssertReleaseFailed();
262
263 LogFlow(("flashWrite: completed write at %08RX32 (LB %u)\n", off, cb));
264 return VINF_SUCCESS;
265}
266
267
268/**
269 * @callback_method_impl{FNIOMMMIONEWREAD, Flash memory read}
270 */
271static DECLCALLBACK(VBOXSTRICTRC) flashMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
272{
273 PDEVFLASHCFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASHCFI);
274 RT_NOREF1(pvUser);
275
276 LogFlowFunc(("off=%RGp cb=%u\n", off, cb));
277
278 if (pThis->u16Cmd == FLASH_CFI_CMD_ARRAY_READ)
279 {
280 size_t cbThisRead = RT_MIN(cb, pThis->cbFlashSize - off);
281 size_t cbSetFf = cb - cbThisRead;
282 if (cbThisRead)
283 memcpy(pv, &pThis->pbFlash[off], cbThisRead);
284 if (cbSetFf)
285 memset((uint8_t *)pv + cbThisRead, 0xff, cbSetFf);
286 }
287 else
288 {
289 /** @todo For now we only emulate a x32 device using two x16 chips so the command must be send to both chips at the same time. */
290 Assert(cb == sizeof(uint32_t));
291
292 uint32_t *pu32 = (uint32_t *)pv;
293 switch (pThis->u16Cmd)
294 {
295 case FLASH_CFI_CMD_READ_DEVICE_ID:
296 *pu32 = 0; /** @todo */
297 break;
298 case FLASH_CFI_CMD_READ_STATUS_REG:
299 case FLASH_CFI_CMD_BUFFERED_PROGRAM_SETUP:
300 *pu32 = ((uint32_t)pThis->bStatus << 16) | pThis->bStatus;
301 break;
302 default:
303 AssertReleaseFailed();
304 }
305 }
306
307 LogFlow(("flashRead: completed read at %08RX32 (LB %u)\n", off, cb));
308 return VINF_SUCCESS;
309}
310
311
312/**
313 * @copydoc(PDMIBASE::pfnQueryInterface)
314 */
315static DECLCALLBACK(void *) flashR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
316{
317 LogFlowFunc(("ENTER: pIBase=%p pszIID=%p\n", pInterface, pszIID));
318 PDEVFLASHCFI pThis = RT_FROM_MEMBER(pInterface, DEVFLASHCFI, Lun0.IBase);
319
320 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
321 return NULL;
322}
323
324
325/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
326
327/**
328 * @callback_method_impl{FNSSMDEVLIVEEXEC}
329 */
330static DECLCALLBACK(int) flashR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
331{
332 PDEVFLASHCFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASHCFI);
333 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
334 RT_NOREF(uPass);
335
336 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysFlashBase);
337 pHlp->pfnSSMPutU32( pSSM, pThis->cbFlashSize);
338 pHlp->pfnSSMPutU16( pSSM, pThis->u16FlashId);
339 pHlp->pfnSSMPutU16( pSSM, pThis->cbBlockSize);
340 return VINF_SSM_DONT_CALL_AGAIN;
341}
342
343
344/**
345 * @callback_method_impl{FNSSMDEVSAVEEXEC}
346 */
347static DECLCALLBACK(int) flashR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
348{
349 PDEVFLASHCFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASHCFI);
350 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
351
352 /* The config. */
353 flashR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
354
355 /* The state. */
356 pHlp->pfnSSMPutU16(pSSM, pThis->u16Cmd);
357 pHlp->pfnSSMPutU8( pSSM, pThis->bStatus);
358 pHlp->pfnSSMPutU8( pSSM, pThis->cBusCycle);
359 pHlp->pfnSSMPutU8( pSSM, pThis->cWordsTransfered);
360 pHlp->pfnSSMPutMem(pSSM, pThis->pbFlash, pThis->cbFlashSize);
361 pHlp->pfnSSMPutU32(pSSM, pThis->offBlock);
362 pHlp->pfnSSMPutU32(pSSM, pThis->cbWrite);
363 pHlp->pfnSSMPutMem(pSSM, &pThis->abProgramBuf[0], sizeof(pThis->abProgramBuf));
364
365 pThis->fStateSaved = true;
366 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
367}
368
369
370/**
371 * @callback_method_impl{FNSSMDEVLOADEXEC}
372 */
373static DECLCALLBACK(int) flashR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
374{
375 PDEVFLASHCFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASHCFI);
376 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
377
378 /* Fend off unsupported versions. */
379 if (uVersion != FLASH_SAVED_STATE_VERSION)
380 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
381
382 /* The config. */
383 RTGCPHYS GCPhysFlashBase;
384 int rc = pHlp->pfnSSMGetGCPhys(pSSM, &GCPhysFlashBase);
385 AssertRCReturn(rc, rc);
386 if (GCPhysFlashBase != pThis->GCPhysFlashBase)
387 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - GCPhysFlashBase: saved=%RGp config=%RGp"),
388 GCPhysFlashBase, pThis->GCPhysFlashBase);
389
390 uint32_t cbFlashSize;
391 rc = pHlp->pfnSSMGetU32(pSSM, &cbFlashSize);
392 AssertRCReturn(rc, rc);
393 if (cbFlashSize != pThis->cbFlashSize)
394 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cbFlashSize: saved=%#x config=%#x"),
395 cbFlashSize, pThis->cbFlashSize);
396
397 uint16_t u16FlashId;
398 rc = pHlp->pfnSSMGetU16(pSSM, &u16FlashId);
399 AssertRCReturn(rc, rc);
400 if (u16FlashId != pThis->u16FlashId)
401 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - u16FlashId: saved=%#x config=%#x"),
402 u16FlashId, pThis->u16FlashId);
403
404 uint16_t cbBlockSize;
405 rc = pHlp->pfnSSMGetU16(pSSM, &cbBlockSize);
406 AssertRCReturn(rc, rc);
407 if (cbBlockSize != pThis->cbBlockSize)
408 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cbBlockSize: saved=%#x config=%#x"),
409 cbBlockSize, pThis->cbBlockSize);
410
411 if (uPass != SSM_PASS_FINAL)
412 return VINF_SUCCESS;
413
414 /* The state. */
415 pHlp->pfnSSMGetU16(pSSM, &pThis->u16Cmd);
416 pHlp->pfnSSMGetU8( pSSM, &pThis->bStatus);
417 pHlp->pfnSSMGetU8( pSSM, &pThis->cBusCycle);
418 pHlp->pfnSSMGetU8( pSSM, &pThis->cWordsTransfered);
419 pHlp->pfnSSMGetMem(pSSM, pThis->pbFlash, pThis->cbFlashSize);
420 pHlp->pfnSSMGetU32(pSSM, &pThis->offBlock);
421 pHlp->pfnSSMGetU32(pSSM, &pThis->cbWrite);
422 pHlp->pfnSSMGetMem(pSSM, &pThis->abProgramBuf[0], sizeof(pThis->abProgramBuf));
423
424 /* The marker. */
425 uint32_t u32;
426 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
427 AssertRCReturn(rc, rc);
428 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
429
430 return VINF_SUCCESS;
431}
432
433
434/**
435 * @interface_method_impl{PDMDEVREG,pfnReset}
436 */
437static DECLCALLBACK(void) flashR3Reset(PPDMDEVINS pDevIns)
438{
439 PDEVFLASHCFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASHCFI);
440
441 /*
442 * Initialize the device state.
443 */
444 pThis->u16Cmd = FLASH_CFI_CMD_ARRAY_READ;
445 pThis->bStatus = FLASH_CFI_SR_PROGRAM_ERASE; /* Prgram/Erase controller is inactive. */
446 pThis->cBusCycle = 0;
447}
448
449
450/**
451 * @interface_method_impl{PDMDEVREG,pfnPowerOff}
452 */
453static DECLCALLBACK(void) flashR3PowerOff(PPDMDEVINS pDevIns)
454{
455 PDEVFLASHCFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASHCFI);
456 int rc = VINF_SUCCESS;
457
458 if (!pThis->fStateSaved)
459 {
460 if (pThis->Lun0.pDrvVfs)
461 {
462 AssertPtr(pThis->pszFlashFile);
463 rc = pThis->Lun0.pDrvVfs->pfnWriteAll(pThis->Lun0.pDrvVfs, FLASH_CFI_VFS_NAMESPACE, pThis->pszFlashFile,
464 pThis->pbFlash, pThis->cbFlashSize);
465 if (RT_FAILURE(rc))
466 LogRel(("FlashCFI: Failed to save flash file to NVRAM store: %Rrc\n", rc));
467 }
468 else if (pThis->pszFlashFile)
469 {
470 RTFILE hFlashFile = NIL_RTFILE;
471
472 rc = RTFileOpen(&hFlashFile, pThis->pszFlashFile, RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
473 if (RT_SUCCESS(rc))
474 {
475 rc = RTFileWrite(hFlashFile, pThis->pbFlash, pThis->cbFlashSize, NULL);
476 RTFileClose(hFlashFile);
477 if (RT_FAILURE(rc))
478 PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to write flash file"));
479 }
480 else
481 PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to open flash file"));
482 }
483 }
484}
485
486
487/**
488 * @interface_method_impl{PDMDEVREG,pfnDestruct}
489 */
490static DECLCALLBACK(int) flashR3Destruct(PPDMDEVINS pDevIns)
491{
492 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
493 PDEVFLASHCFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASHCFI);
494
495 if (pThis->pbFlash)
496 {
497 PDMDevHlpMMHeapFree(pDevIns, pThis->pbFlash);
498 pThis->pbFlash = NULL;
499 }
500
501 return VINF_SUCCESS;
502}
503
504
505/**
506 * @interface_method_impl{PDMDEVREG,pfnConstruct}
507 */
508static DECLCALLBACK(int) flashR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
509{
510 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
511 PDEVFLASHCFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASHCFI);
512 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
513
514 Assert(iInstance == 0); RT_NOREF1(iInstance);
515
516 /*
517 * Initalize the basic variables so that the destructor always works.
518 */
519 pThis->Lun0.IBase.pfnQueryInterface = flashR3QueryInterface;
520
521
522 /*
523 * Validate configuration.
524 */
525 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DeviceId|BaseAddress|Size|BlockSize|FlashFile", "");
526
527 /*
528 * Read configuration.
529 */
530
531 uint16_t u16FlashId = 0;
532 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "DeviceId", &u16FlashId, 0xA289);
533 if (RT_FAILURE(rc))
534 return PDMDEV_SET_ERROR(pDevIns, rc,
535 N_("Configuration error: Querying \"DeviceId\" as an integer failed"));
536
537 /* The default base address is 2MB below 4GB. */
538 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "BaseAddress", &pThis->GCPhysFlashBase, 0xFFE00000);
539 if (RT_FAILURE(rc))
540 return PDMDEV_SET_ERROR(pDevIns, rc,
541 N_("Configuration error: Querying \"BaseAddress\" as an integer failed"));
542
543 /* The default flash device size is 128K. */
544 uint64_t cbFlash = 0;
545 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "Size", &cbFlash, 128 * _1K);
546 if (RT_FAILURE(rc))
547 return PDMDEV_SET_ERROR(pDevIns, rc,
548 N_("Configuration error: Querying \"Size\" as an integer failed"));
549
550 /* The default flash device block size is 4K. */
551 uint16_t cbBlock = 0;
552 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BlockSize", &cbBlock, _4K);
553 if (RT_FAILURE(rc))
554 return PDMDEV_SET_ERROR(pDevIns, rc,
555 N_("Configuration error: Querying \"BlockSize\" as an integer failed"));
556
557 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "FlashFile", &pThis->pszFlashFile);
558 if (RT_FAILURE(rc))
559 return PDMDEV_SET_ERROR(pDevIns, rc,
560 N_("Configuration error: Querying \"FlashFile\" as a string failed"));
561
562 /*
563 * Initialize the flash core.
564 */
565 pThis->u16FlashId = u16FlashId;
566 pThis->cbBlockSize = cbBlock;
567 pThis->cbFlashSize = cbFlash;
568
569 /* Set up the flash data. */
570 pThis->pbFlash = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbFlashSize);
571 if (!pThis->pbFlash)
572 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("Failed to allocate heap memory"));
573
574 /* Default value for empty flash. */
575 memset(pThis->pbFlash, 0xff, pThis->cbFlashSize);
576
577 /* Reset the dynamic state.*/
578 flashR3Reset(pDevIns);
579
580 /*
581 * NVRAM storage.
582 */
583 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "NvramStorage");
584 if (RT_SUCCESS(rc))
585 {
586 pThis->Lun0.pDrvVfs = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIVFSCONNECTOR);
587 if (!pThis->Lun0.pDrvVfs)
588 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS, N_("NVRAM storage driver is missing VFS interface below"));
589 }
590 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
591 rc = VINF_SUCCESS; /* Missing driver is no error condition. */
592 else
593 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Can't attach Nvram Storage driver"));
594
595 if (pThis->Lun0.pDrvVfs)
596 {
597 AssertPtr(pThis->pszFlashFile);
598 rc = pThis->Lun0.pDrvVfs->pfnQuerySize(pThis->Lun0.pDrvVfs, FLASH_CFI_VFS_NAMESPACE, pThis->pszFlashFile, &cbFlash);
599 if (RT_SUCCESS(rc))
600 {
601 if (cbFlash <= pThis->cbFlashSize)
602 rc = pThis->Lun0.pDrvVfs->pfnReadAll(pThis->Lun0.pDrvVfs, FLASH_CFI_VFS_NAMESPACE, pThis->pszFlashFile,
603 pThis->pbFlash, pThis->cbFlashSize);
604 else
605 return PDMDEV_SET_ERROR(pDevIns, VERR_BUFFER_OVERFLOW, N_("Configured flash size is too small to fit the saved NVRAM content"));
606 }
607 }
608 else if (pThis->pszFlashFile)
609 {
610 RTFILE hFlashFile = NIL_RTFILE;
611 rc = RTFileOpen(&hFlashFile, pThis->pszFlashFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
612 if (RT_FAILURE(rc))
613 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to open flash file"));
614
615 size_t cbRead = 0;
616 rc = RTFileRead(hFlashFile, pThis->pbFlash, pThis->cbFlashSize, &cbRead);
617 RTFileClose(hFlashFile);
618 if (RT_FAILURE(rc))
619 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to read flash file"));
620
621 LogRel(("flash-cfi#%u: Read %zu bytes from file (asked for %u)\n.", cbRead, pThis->cbFlashSize, iInstance));
622 }
623
624 /*
625 * Register MMIO region.
626 */
627 rc = PDMDevHlpMmioCreateExAndMap(pDevIns, pThis->GCPhysFlashBase, cbFlash,
628 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, NULL, UINT32_MAX,
629 flashMMIOWrite, flashMMIORead, NULL, NULL, "Flash Memory", &pThis->hMmio);
630 AssertRCReturn(rc, rc);
631 LogRel(("Registered %uKB flash at %RGp\n", pThis->cbFlashSize / _1K, pThis->GCPhysFlashBase));
632
633 /*
634 * Register saved state.
635 */
636 rc = PDMDevHlpSSMRegisterEx(pDevIns, FLASH_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
637 NULL, flashR3LiveExec, NULL,
638 NULL, flashR3SaveExec, NULL,
639 NULL, flashR3LoadExec, NULL);
640 AssertRCReturn(rc, rc);
641
642 return VINF_SUCCESS;
643}
644
645
646/**
647 * The device registration structure.
648 */
649const PDMDEVREG g_DeviceFlashCFI =
650{
651 /* .u32Version = */ PDM_DEVREG_VERSION,
652 /* .uReserved0 = */ 0,
653 /* .szName = */ "flash-cfi",
654 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE,
655 /* .fClass = */ PDM_DEVREG_CLASS_ARCH,
656 /* .cMaxInstances = */ 1,
657 /* .uSharedVersion = */ 42,
658 /* .cbInstanceShared = */ sizeof(DEVFLASHCFI),
659 /* .cbInstanceCC = */ 0,
660 /* .cbInstanceRC = */ 0,
661 /* .cMaxPciDevices = */ 0,
662 /* .cMaxMsixVectors = */ 0,
663 /* .pszDescription = */ "Flash Memory Device",
664#if defined(IN_RING3)
665 /* .pszRCMod = */ "",
666 /* .pszR0Mod = */ "",
667 /* .pfnConstruct = */ flashR3Construct,
668 /* .pfnDestruct = */ flashR3Destruct,
669 /* .pfnRelocate = */ NULL,
670 /* .pfnMemSetup = */ NULL,
671 /* .pfnPowerOn = */ NULL,
672 /* .pfnReset = */ flashR3Reset,
673 /* .pfnSuspend = */ NULL,
674 /* .pfnResume = */ NULL,
675 /* .pfnAttach = */ NULL,
676 /* .pfnDetach = */ NULL,
677 /* .pfnQueryInterface = */ NULL,
678 /* .pfnInitComplete = */ NULL,
679 /* .pfnPowerOff = */ flashR3PowerOff,
680 /* .pfnSoftReset = */ NULL,
681 /* .pfnReserved0 = */ NULL,
682 /* .pfnReserved1 = */ NULL,
683 /* .pfnReserved2 = */ NULL,
684 /* .pfnReserved3 = */ NULL,
685 /* .pfnReserved4 = */ NULL,
686 /* .pfnReserved5 = */ NULL,
687 /* .pfnReserved6 = */ NULL,
688 /* .pfnReserved7 = */ NULL,
689#elif defined(IN_RING0)
690 /* .pfnEarlyConstruct = */ NULL,
691 /* .pfnConstruct = */ NULL,
692 /* .pfnDestruct = */ NULL,
693 /* .pfnFinalDestruct = */ NULL,
694 /* .pfnRequest = */ NULL,
695 /* .pfnReserved0 = */ NULL,
696 /* .pfnReserved1 = */ NULL,
697 /* .pfnReserved2 = */ NULL,
698 /* .pfnReserved3 = */ NULL,
699 /* .pfnReserved4 = */ NULL,
700 /* .pfnReserved5 = */ NULL,
701 /* .pfnReserved6 = */ NULL,
702 /* .pfnReserved7 = */ NULL,
703#elif defined(IN_RC)
704 /* .pfnConstruct = */ NULL,
705 /* .pfnReserved0 = */ NULL,
706 /* .pfnReserved1 = */ NULL,
707 /* .pfnReserved2 = */ NULL,
708 /* .pfnReserved3 = */ NULL,
709 /* .pfnReserved4 = */ NULL,
710 /* .pfnReserved5 = */ NULL,
711 /* .pfnReserved6 = */ NULL,
712 /* .pfnReserved7 = */ NULL,
713#else
714# error "Not in IN_RING3, IN_RING0 or IN_RC!"
715#endif
716 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
717};
718
719#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use