VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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