VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FlashCore.cpp@ 94368

Last change on this file since 94368 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.3 KB
Line 
1/* $Id: FlashCore.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * DevFlash - A simple Flash device
4 *
5 * A simple non-volatile byte-wide (x8) memory device modeled after Intel 28F008
6 * FlashFile. See 28F008SA datasheet, Intel order number 290429-007.
7 *
8 * Implemented as an MMIO device attached directly to the CPU, not behind any
9 * bus. Typically mapped as part of the firmware image.
10 */
11
12/*
13 * Copyright (C) 2018-2022 Oracle Corporation
14 *
15 * This file is part of VirtualBox Open Source Edition (OSE), as
16 * available from http://www.virtualbox.org. This file is free software;
17 * you can redistribute it and/or modify it under the terms of the GNU
18 * General Public License (GPL) as published by the Free Software
19 * Foundation, in version 2 as it comes in the "COPYING" file of the
20 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22 */
23
24
25/*********************************************************************************************************************************
26* Header Files *
27*********************************************************************************************************************************/
28#define LOG_GROUP LOG_GROUP_DEV_FLASH
29#include <VBox/vmm/pdmdev.h>
30#include <VBox/log.h>
31#include <VBox/err.h>
32#include <iprt/assert.h>
33#include <iprt/string.h>
34#include <iprt/file.h>
35
36#include "VBoxDD.h"
37#include "FlashCore.h"
38
39
40/*********************************************************************************************************************************
41* Defined Constants And Macros *
42*********************************************************************************************************************************/
43/** @name CUI (Command User Interface) Commands.
44 * @{ */
45#define FLASH_CMD_ALT_WRITE 0x10
46#define FLASH_CMD_ERASE_SETUP 0x20
47#define FLASH_CMD_WRITE 0x40
48#define FLASH_CMD_STS_CLEAR 0x50
49#define FLASH_CMD_STS_READ 0x70
50#define FLASH_CMD_READ_ID 0x90
51#define FLASH_CMD_ERASE_SUS_RES 0xB0
52#define FLASH_CMD_ERASE_CONFIRM 0xD0
53#define FLASH_CMD_ARRAY_READ 0xFF
54/** @} */
55
56/** @name Status register bits.
57 * @{ */
58#define FLASH_STATUS_WSMS 0x80 /* Write State Machine Status, 1=Ready */
59#define FLASH_STATUS_ESS 0x40 /* Erase Suspend Status, 1=Suspended */
60#define FLASH_STATUS_ES 0x20 /* Erase Status, 1=Error */
61#define FLASH_STATUS_BWS 0x10 /* Byte Write Status, 1=Error */
62#define FLASH_STATUS_VPPS 0x08 /* Vpp Status, 1=Low Vpp */
63/* The remaining bits 0-2 are reserved/unused */
64/** @} */
65
66
67/*********************************************************************************************************************************
68* Structures and Typedefs *
69*********************************************************************************************************************************/
70#ifndef VBOX_DEVICE_STRUCT_TESTCASE
71
72
73
74/**
75 * Worker for flashWrite that deals with a single byte.
76 *
77 * @retval VINF_SUCCESS on success, which is always the case in ring-3.
78 * @retval VINF_IOM_R3_MMIO_WRITE can be returned when not in ring-3.
79 */
80static int flashMemWriteByte(PFLASHCORE pThis, uint32_t off, uint8_t bCmd)
81{
82 /* NB: Older datasheets (e.g. 28F008SA) suggest that for two-cycle commands like byte write or
83 * erase setup, the address is significant in both cycles, but do not explain what happens
84 * should the addresses not match. Newer datasheets (e.g. 28F008B3) clearly say that the address
85 * in the first byte cycle never matters. We prefer the latter interpretation.
86 */
87
88 if (pThis->cBusCycle == 0)
89 {
90 /* First bus write cycle, start processing a new command. Address is ignored. */
91 switch (bCmd)
92 {
93 case FLASH_CMD_ARRAY_READ:
94 case FLASH_CMD_STS_READ:
95 case FLASH_CMD_ERASE_SUS_RES:
96 case FLASH_CMD_READ_ID:
97 /* Single-cycle write commands, only change the current command. */
98 pThis->bCmd = bCmd;
99 break;
100 case FLASH_CMD_STS_CLEAR:
101 /* Status clear continues in read mode. */
102 pThis->bStatus = 0;
103 pThis->bCmd = FLASH_CMD_ARRAY_READ;
104 break;
105 case FLASH_CMD_WRITE:
106 case FLASH_CMD_ALT_WRITE:
107 case FLASH_CMD_ERASE_SETUP:
108 /* Two-cycle commands, advance the bus write cycle. */
109 pThis->bCmd = bCmd;
110 pThis->cBusCycle++;
111 break;
112 default:
113 LogFunc(("1st cycle command %02X, current cmd %02X\n", bCmd, pThis->bCmd));
114 break;
115 }
116 }
117 else
118 {
119 /* Second write of a two-cycle command. */
120 Assert(pThis->cBusCycle == 1);
121 switch (pThis->bCmd)
122 {
123 case FLASH_CMD_WRITE:
124 case FLASH_CMD_ALT_WRITE:
125 if (off < pThis->cbFlashSize)
126 {
127#ifdef IN_RING3
128 pThis->pbFlash[off] = bCmd;
129# ifdef FLASH_WITH_RZ_READ_CACHE_SIZE
130 uint32_t const offInCache = off - pThis->offCache;
131 if (offInCache < sizeof(pThis->CacheData) && pThis->offCache != UINT32_MAX)
132 pThis->CacheData.ab[offInCache] = bCmd;
133# endif
134
135 /* NB: Writes are instant and never fail. */
136 LogFunc(("wrote byte to flash at %08RX32: %02X\n", off, bCmd));
137#else
138 return VINF_IOM_R3_MMIO_WRITE;
139#endif
140 }
141 else
142 LogFunc(("ignoring write at %08RX32: %02X\n", off, bCmd));
143 break;
144 case FLASH_CMD_ERASE_SETUP:
145 if (bCmd == FLASH_CMD_ERASE_CONFIRM)
146 {
147#ifdef IN_RING3
148 /* The current address determines the block to erase. */
149 unsigned uOffset = off & ~(pThis->cbBlockSize - 1);
150 memset(pThis->pbFlash + uOffset, 0xff, pThis->cbBlockSize);
151 LogFunc(("Erasing block at offset %u\n", uOffset));
152#else
153 return VINF_IOM_R3_MMIO_WRITE;
154#endif
155 }
156 else
157 {
158 /* Anything else is a command erorr. Transition to status read mode. */
159 LogFunc(("2st cycle erase command is %02X, should be confirm (%02X)\n", bCmd, FLASH_CMD_ERASE_CONFIRM));
160 pThis->bCmd = FLASH_CMD_STS_READ;
161 pThis->bStatus |= FLASH_STATUS_BWS | FLASH_STATUS_ES;
162 }
163 break;
164 default:
165 LogFunc(("2st cycle bad command %02X, current cmd %02X\n", bCmd, pThis->bCmd));
166 break;
167 }
168 pThis->cBusCycle = 0;
169 }
170 LogFlow(("flashMemWriteByte: write access at %08RX32: %#x\n", off, bCmd));
171 return VINF_SUCCESS;
172}
173
174/**
175 * Performs a write to the given flash offset.
176 *
177 * Parent device calls this from its MMIO write callback.
178 *
179 * @returns Strict VBox status code.
180 * @retval VINF_SUCCESS on success, which is always the case in ring-3.
181 * @retval VINF_IOM_R3_MMIO_WRITE can be returned when not in ring-3.
182 *
183 * @param pThis The UART core instance.
184 * @param off Offset to start writing to.
185 * @param pv The value to write.
186 * @param cb Number of bytes to write.
187 */
188DECLHIDDEN(VBOXSTRICTRC) flashWrite(PFLASHCORE pThis, uint32_t off, const void *pv, size_t cb)
189{
190 const uint8_t *pbSrc = (const uint8_t *)pv;
191
192#ifndef IN_RING3
193 /*
194 * If multiple bytes are written, just go to ring-3 and do it there as it's
195 * too much trouble to validate the sequence in adanvce and it is usually
196 * not restartable as device state changes.
197 */
198 VBOXSTRICTRC rcStrict;
199 if (cb == 1)
200 {
201 rcStrict = flashMemWriteByte(pThis, off, *pbSrc);
202 if (rcStrict == VINF_SUCCESS)
203 LogFlow(("flashWrite: completed write at %08RX32 (LB %u)\n", off, cb));
204 else
205 LogFlow(("flashWrite: incomplete write at %08RX32 (LB %u): rc=%Rrc bCmd=%#x cBusCycle=%u\n",
206 off, cb, VBOXSTRICTRC_VAL(rcStrict), *pbSrc, pThis->cBusCycle));
207 }
208 else
209 {
210 LogFlow(("flashWrite: deferring multi-byte write at %08RX32 (LB %u) to ring-3\n", off, cb));
211 rcStrict = VINF_IOM_R3_IOPORT_WRITE;
212 }
213 return rcStrict;
214
215#else /* IN_RING3 */
216
217 for (uint32_t offWrite = 0; offWrite < cb; ++offWrite)
218 flashMemWriteByte(pThis, off + offWrite, pbSrc[offWrite]);
219
220 LogFlow(("flashWrite: completed write at %08RX32 (LB %u)\n", off, cb));
221 return VINF_SUCCESS;
222#endif /* IN_RING3 */
223}
224
225#if defined(FLASH_WITH_RZ_READ_CACHE_SIZE) && defined(IN_RING3)
226/**
227 * Fills the RZ cache with data.
228 */
229DECL_FORCE_INLINE(void) flashFillRzCache(PFLASHCORE pThis, uint32_t off)
230{
231 AssertCompile(RT_IS_POWER_OF_TWO(sizeof(pThis->CacheData)));
232 uint32_t const offCache = (off + 1) & ~(sizeof(pThis->CacheData) - 1);
233 if (offCache < pThis->cbFlashSize)
234 {
235 Log2(("flashMemReadByte: Filling RZ cache: offset %#x\n", offCache));
236# if FLASH_WITH_RZ_READ_CACHE_SIZE < 8
237 uint64_t const * const pu64Src = ((uint64_t const *)&pThis->pbFlash[offCache]);
238 pThis->CacheData.au64[0] = pu64Src[0];
239# if FLASH_WITH_RZ_READ_CACHE_SIZE > 1
240 pThis->CacheData.au64[1] = pu64Src[1];
241# endif
242# if FLASH_WITH_RZ_READ_CACHE_SIZE > 2
243 pThis->CacheData.au64[2] = pu64Src[2];
244# endif
245# if FLASH_WITH_RZ_READ_CACHE_SIZE > 3
246 pThis->CacheData.au64[3] = pu64Src[3];
247# endif
248# if FLASH_WITH_RZ_READ_CACHE_SIZE > 4
249 pThis->CacheData.au64[4] = pu64Src[4];
250# endif
251# if FLASH_WITH_RZ_READ_CACHE_SIZE > 5
252 pThis->CacheData.au64[5] = pu64Src[5];
253# endif
254# if FLASH_WITH_RZ_READ_CACHE_SIZE > 6
255 pThis->CacheData.au64[6] = pu64Src[6];
256# endif
257# if FLASH_WITH_RZ_READ_CACHE_SIZE > 7
258 pThis->CacheData.au64[7] = pu64Src[7];
259# endif
260# if FLASH_WITH_RZ_READ_CACHE_SIZE > 8
261 pThis->CacheData.au64[8] = pu64Src[8];
262# endif
263# else
264 memcpy(pThis->CacheData.ab, &pThis->pbFlash[offCache], sizeof(pThis->CacheData.ab));
265# endif
266 pThis->offCache = offCache;
267 }
268}
269#endif /* FLASH_WITH_RZ_READ_CACHE_SIZE && IN_RING3 */
270
271/**
272 * Worker for flashRead that deals with a single byte.
273 *
274 * @retval VINF_SUCCESS on success, which is always the case in ring-3.
275 * @retval VINF_IOM_R3_MMIO_READ can be returned when not in ring-3.
276 */
277static int flashMemReadByte(PFLASHCORE pThis, uint32_t off, uint8_t *pbData)
278{
279 uint8_t bValue;
280
281 /*
282 * Reads are only defined in three states: Array read, status register read,
283 * and ID read.
284 */
285 switch (pThis->bCmd)
286 {
287 case FLASH_CMD_ARRAY_READ:
288 if (off < pThis->cbFlashSize)
289 {
290#ifdef IN_RING3
291# ifdef FLASH_WITH_RZ_READ_CACHE_SIZE
292 AssertCompile(RT_IS_POWER_OF_TWO(sizeof(pThis->CacheData)));
293 if (off + 1 - pThis->offCache < sizeof(pThis->CacheData) && pThis->offCache != UINT32_MAX)
294 { }
295 else
296 flashFillRzCache(pThis, off);
297# endif
298 bValue = pThis->pbFlash[off];
299#else
300# ifdef FLASH_WITH_RZ_READ_CACHE_SIZE
301 uint32_t const offInCache = off - pThis->offCache;
302 if (offInCache < sizeof(pThis->CacheData) && pThis->offCache != UINT32_MAX)
303 {
304 Log2(("flashMemReadByte: cache hit (at %#RX32 in cache)\n", offInCache));
305 bValue = pThis->CacheData.ab[offInCache];
306 }
307 else
308 {
309 Log2(("flashMemReadByte: cache miss: offInCache=%#RX32 offCache=%#RX32\n", offInCache, pThis->offCache));
310 return VINF_IOM_R3_MMIO_READ;
311 }
312# else
313 return VINF_IOM_R3_MMIO_READ;
314# endif
315#endif
316 }
317 else
318 bValue = 0xff; /* Play safe and return the default value of non initialized flash. */
319 LogFunc(("read byte at %08RX32: %02X\n", off, bValue));
320 break;
321 case FLASH_CMD_STS_READ:
322 bValue = pThis->bStatus;
323 break;
324 case FLASH_CMD_READ_ID:
325 bValue = off & 1 ? RT_HI_U8(pThis->u16FlashId) : RT_LO_U8(pThis->u16FlashId);
326 break;
327 default:
328 bValue = 0xff;
329 break;
330 }
331 *pbData = bValue;
332
333 LogFlow(("flashMemReadByte: read access at %08RX32: %02X (cmd=%02X)\n", off, bValue, pThis->bCmd));
334 return VINF_SUCCESS;
335}
336
337/**
338 * Performs a read from the given flash offset.
339 *
340 * Parent device calls this from its MMIO read callback.
341 *
342 * @returns Strict VBox status code.
343 * @retval VINF_SUCCESS on success, which is always the case in ring-3.
344 * @retval VINF_IOM_R3_MMIO_READ can be returned when not in ring-3.
345 *
346 * @param pThis The UART core instance.
347 * @param off Offset to start reading from.
348 * @param pv Where to store the read data.
349 * @param cb Number of bytes to read.
350 */
351DECLHIDDEN(VBOXSTRICTRC) flashRead(PFLASHCORE pThis, uint32_t off, void *pv, size_t cb)
352{
353 uint8_t *pbDst = (uint8_t *)pv;
354
355 /*
356 * Reads do not change the device state, so we don't need to take any
357 * precautions when we're not in ring-3 as the read can always be restarted.
358 */
359 for (uint32_t offRead = 0; offRead < cb; ++offRead)
360 {
361#ifdef IN_RING3
362 flashMemReadByte(pThis, off + offRead, &pbDst[offRead]);
363#else
364 VBOXSTRICTRC rcStrict = flashMemReadByte(pThis, off + offRead, &pbDst[offRead]);
365 if (rcStrict != VINF_SUCCESS)
366 {
367 LogFlow(("flashRead: incomplete read at %08RX32+%#x (LB %u): rc=%Rrc bCmd=%#x\n",
368 off, offRead, cb, VBOXSTRICTRC_VAL(rcStrict), pThis->bCmd));
369 return rcStrict;
370 }
371#endif
372 }
373
374 LogFlow(("flashRead: completed read at %08RX32 (LB %u)\n", off, cb));
375 return VINF_SUCCESS;
376}
377
378#ifdef IN_RING3
379
380/**
381 * Initialiizes the given flash device instance.
382 *
383 * @returns VBox status code.
384 * @param pThis The flash device core instance.
385 * @param pDevIns Pointer to the owning device instance.
386 * @param idFlashDev The flash device ID.
387 * @param GCPhysFlashBase Base MMIO address where the flash is located.
388 * @param cbFlash Size of the flash device in bytes.
389 * @param cbBlock Size of a flash block.
390 */
391DECLHIDDEN(int) flashR3Init(PFLASHCORE pThis, PPDMDEVINS pDevIns, uint16_t idFlashDev, uint32_t cbFlash, uint16_t cbBlock)
392{
393 pThis->u16FlashId = idFlashDev;
394 pThis->cbBlockSize = cbBlock;
395 pThis->cbFlashSize = cbFlash;
396#ifdef FLASH_WITH_RZ_READ_CACHE_SIZE
397 pThis->offCache = UINT32_MAX;
398#endif
399
400 /* Set up the flash data. */
401 pThis->pbFlash = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbFlashSize);
402 if (!pThis->pbFlash)
403 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("Failed to allocate heap memory"));
404
405 /* Default value for empty flash. */
406 memset(pThis->pbFlash, 0xff, pThis->cbFlashSize);
407
408 /* Reset the dynamic state.*/
409 flashR3Reset(pThis);
410 return VINF_SUCCESS;
411}
412
413/**
414 * Destroys the given flash device instance.
415 *
416 * @returns nothing.
417 * @param pDevIns The parent device instance.
418 * @param pThis The flash device core instance.
419 */
420DECLHIDDEN(void) flashR3Destruct(PFLASHCORE pThis, PPDMDEVINS pDevIns)
421{
422 if (pThis->pbFlash)
423 {
424 PDMDevHlpMMHeapFree(pDevIns, pThis->pbFlash);
425 pThis->pbFlash = NULL;
426 }
427}
428
429/**
430 * Loads the flash content from the given file.
431 *
432 * @returns VBox status code.
433 * @param pThis The flash device core instance.
434 * @param pDevIns The parent device instance.
435 * @param pszFilename The file to load the flash content from.
436 */
437DECLHIDDEN(int) flashR3LoadFromFile(PFLASHCORE pThis, PPDMDEVINS pDevIns, const char *pszFilename)
438{
439 RTFILE hFlashFile = NIL_RTFILE;
440
441 int rc = RTFileOpen(&hFlashFile, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
442 if (RT_FAILURE(rc))
443 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to open flash file"));
444
445 size_t cbRead = 0;
446 rc = RTFileRead(hFlashFile, pThis->pbFlash, pThis->cbFlashSize, &cbRead);
447 if (RT_FAILURE(rc))
448 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to read flash file"));
449 Log(("Read %zu bytes from file (asked for %u)\n.", cbRead, pThis->cbFlashSize));
450
451 RTFileClose(hFlashFile);
452 return VINF_SUCCESS;
453}
454
455/**
456 * Loads the flash content from the given buffer.
457 *
458 * @returns VBox status code.
459 * @param pThis The flash device core instance.
460 * @param pvBuf The buffer to load the content from.
461 * @param cbBuf Size of the buffer in bytes.
462 */
463DECLHIDDEN(int) flashR3LoadFromBuf(PFLASHCORE pThis, void const *pvBuf, size_t cbBuf)
464{
465 AssertReturn(pThis->cbFlashSize >= cbBuf, VERR_BUFFER_OVERFLOW);
466
467 memcpy(pThis->pbFlash, pvBuf, RT_MIN(cbBuf, pThis->cbFlashSize));
468 return VINF_SUCCESS;
469}
470
471/**
472 * Loads the flash content using the PDM VFS interface.
473 *
474 * @returns VBox status code.
475 * @param pThis The flash device core instance.
476 * @param pDevIns The owning device instance.
477 * @param pDrvVfs Pointer to the VFS interface.
478 * @param pszNamespace The namespace to load from.
479 * @param pszPath The path to the flash content to load.
480 */
481DECLHIDDEN(int) flashR3LoadFromVfs(PFLASHCORE pThis, PPDMDEVINS pDevIns, PPDMIVFSCONNECTOR pDrvVfs,
482 const char *pszNamespace, const char *pszPath)
483{
484 uint64_t cbFlash = 0;
485 int rc = pDrvVfs->pfnQuerySize(pDrvVfs, pszNamespace, pszPath, &cbFlash);
486 if (RT_SUCCESS(rc))
487 {
488 if (cbFlash <= pThis->cbFlashSize)
489 rc = pDrvVfs->pfnReadAll(pDrvVfs, pszNamespace, pszPath, pThis->pbFlash, pThis->cbFlashSize);
490 else
491 return PDMDEV_SET_ERROR(pDevIns, VERR_BUFFER_OVERFLOW, N_("Configured flash size is too small to fit the saved NVRAM content"));
492 }
493
494 return rc;
495}
496
497/**
498 * Saves the flash content to the given file.
499 *
500 * @returns VBox status code.
501 * @param pThis The flash device core instance.
502 * @param pDevIns The parent device instance.
503 * @param pszFilename The file to save the flash content to.
504 */
505DECLHIDDEN(int) flashR3SaveToFile(PFLASHCORE pThis, PPDMDEVINS pDevIns, const char *pszFilename)
506{
507 RTFILE hFlashFile = NIL_RTFILE;
508
509 int rc = RTFileOpen(&hFlashFile, pszFilename, RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
510 if (RT_FAILURE(rc))
511 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to open flash file"));
512
513 rc = RTFileWrite(hFlashFile, pThis->pbFlash, pThis->cbFlashSize, NULL);
514 RTFileClose(hFlashFile);
515 if (RT_FAILURE(rc))
516 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to write flash file"));
517
518 return VINF_SUCCESS;
519}
520
521/**
522 * Saves the flash content to the given buffer.
523 *
524 * @returns VBox status code.
525 * @param pThis The flash device core instance.
526 * @param pvBuf The buffer to save the content to.
527 * @param cbBuf Size of the buffer in bytes.
528 */
529DECLHIDDEN(int) flashR3SaveToBuf(PFLASHCORE pThis, void *pvBuf, size_t cbBuf)
530{
531 AssertReturn(pThis->cbFlashSize <= cbBuf, VERR_BUFFER_OVERFLOW);
532
533 memcpy(pvBuf, pThis->pbFlash, RT_MIN(cbBuf, pThis->cbFlashSize));
534 return VINF_SUCCESS;
535}
536
537/**
538 * Saves the flash content using the given PDM VFS interface.
539 *
540 * @returns VBox status code.
541 * @param pThis The flash device core instance.
542 * @param pDevIns The owning device instance.
543 * @param pDrvVfs Pointer to the VFS interface.
544 * @param pszNamespace The namespace to store to.
545 * @param pszPath The path to store the flash content under.
546 */
547DECLHIDDEN(int) flashR3SaveToVfs(PFLASHCORE pThis, PPDMDEVINS pDevIns, PPDMIVFSCONNECTOR pDrvVfs,
548 const char *pszNamespace, const char *pszPath)
549{
550 RT_NOREF(pDevIns);
551 return pDrvVfs->pfnWriteAll(pDrvVfs, pszNamespace, pszPath, pThis->pbFlash, pThis->cbFlashSize);
552}
553
554/**
555 * Resets the dynamic part of the flash device state.
556 *
557 * @returns nothing.
558 * @param pThis The flash device core instance.
559 */
560DECLHIDDEN(void) flashR3Reset(PFLASHCORE pThis)
561{
562 /*
563 * Initialize the device state.
564 */
565 pThis->bCmd = FLASH_CMD_ARRAY_READ;
566 pThis->bStatus = 0;
567 pThis->cBusCycle = 0;
568}
569
570/**
571 * Saves the flash device state to the given SSM handle.
572 *
573 * @returns VBox status code.
574 * @param pThis The flash device core instance.
575 * @param pDevIns The parent device instance.
576 * @param pSSM The SSM handle to save to.
577 */
578DECLHIDDEN(int) flashR3SaveExec(PFLASHCORE pThis, PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
579{
580 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
581
582 pHlp->pfnSSMPutU32(pSSM, FLASH_SAVED_STATE_VERSION);
583
584 /* Save the device state. */
585 pHlp->pfnSSMPutU8(pSSM, pThis->bCmd);
586 pHlp->pfnSSMPutU8(pSSM, pThis->bStatus);
587 pHlp->pfnSSMPutU8(pSSM, pThis->cBusCycle);
588
589 /* Save the current configuration for validation purposes. */
590 pHlp->pfnSSMPutU16(pSSM, pThis->cbBlockSize);
591 pHlp->pfnSSMPutU16(pSSM, pThis->u16FlashId);
592
593 /* Save the current flash contents. */
594 pHlp->pfnSSMPutU32(pSSM, pThis->cbFlashSize);
595 return pHlp->pfnSSMPutMem(pSSM, pThis->pbFlash, pThis->cbFlashSize);
596}
597
598/**
599 * Loads the flash device state from the given SSM handle.
600 *
601 * @returns VBox status code.
602 * @param pThis The flash device core instance.
603 * @param pDevIns The parent device instance.
604 * @param pSSM The SSM handle to load from.
605 */
606DECLHIDDEN(int) flashR3LoadExec(PFLASHCORE pThis, PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
607{
608 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
609
610 uint32_t uVersion = FLASH_SAVED_STATE_VERSION;
611 int rc = pHlp->pfnSSMGetU32(pSSM, &uVersion);
612 AssertRCReturn(rc, rc);
613
614 /*
615 * Do the actual restoring.
616 */
617 if (uVersion == FLASH_SAVED_STATE_VERSION)
618 {
619 uint16_t u16Val;
620 uint32_t u32Val;
621
622 pHlp->pfnSSMGetU8(pSSM, &pThis->bCmd);
623 pHlp->pfnSSMGetU8(pSSM, &pThis->bStatus);
624 pHlp->pfnSSMGetU8(pSSM, &pThis->cBusCycle);
625
626 /* Make sure configuration didn't change behind our back. */
627 rc = pHlp->pfnSSMGetU16(pSSM, &u16Val);
628 AssertRCReturn(rc, rc);
629 if (u16Val != pThis->cbBlockSize)
630 return VERR_SSM_LOAD_CONFIG_MISMATCH;
631 rc = pHlp->pfnSSMGetU16(pSSM, &u16Val);
632 AssertRCReturn(rc, rc);
633 if (u16Val != pThis->u16FlashId)
634 return VERR_SSM_LOAD_CONFIG_MISMATCH;
635 rc = pHlp->pfnSSMGetU32(pSSM, &u32Val);
636 AssertRCReturn(rc, rc);
637 if (u32Val != pThis->cbFlashSize)
638 return VERR_SSM_LOAD_CONFIG_MISMATCH;
639
640 /* Suck in the flash contents. */
641 rc = pHlp->pfnSSMGetMem(pSSM, pThis->pbFlash, pThis->cbFlashSize);
642 }
643 else
644 rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
645
646 return rc;
647}
648
649#endif /* IN_RING3 */
650
651#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
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