VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/DevFlash.cpp@ 96499

Last change on this file since 96499 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.9 KB
Line 
1/* $Id: DevFlash.cpp 96407 2022-08-22 17:43:14Z 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 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/*********************************************************************************************************************************
52* Structures and Typedefs *
53*********************************************************************************************************************************/
54/**
55 * The flash device, shared state.
56 */
57typedef struct DEVFLASH
58{
59 /** The flash core device instance.*/
60 FLASHCORE Core;
61 /** The guest physical memory base address. */
62 RTGCPHYS GCPhysFlashBase;
63 /** The handle to the MMIO region. */
64 IOMMMIOHANDLE hMmio;
65} DEVFLASH;
66/** Pointer to the Flash device state. */
67typedef DEVFLASH *PDEVFLASH;
68
69/**
70 * The flash device, ring-3 state.
71 */
72typedef struct DEVFLASHR3
73{
74 /** The file conaining the flash content. */
75 char *pszFlashFile;
76} DEVFLASHR3;
77/** Pointer to the ring-3 Flash device state. */
78typedef DEVFLASHR3 *PDEVFLASHR3;
79
80
81#ifndef VBOX_DEVICE_STRUCT_TESTCASE
82
83
84/**
85 * @callback_method_impl{FNIOMMMIONEWWRITE, Flash memory write}
86 */
87static DECLCALLBACK(VBOXSTRICTRC) flashMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
88{
89 PDEVFLASH pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASH);
90 RT_NOREF1(pvUser);
91 return flashWrite(&pThis->Core, off, pv, cb);
92}
93
94
95/**
96 * @callback_method_impl{FNIOMMMIONEWREAD, Flash memory read}
97 */
98static DECLCALLBACK(VBOXSTRICTRC) flashMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
99{
100 PDEVFLASH pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASH);
101 RT_NOREF1(pvUser);
102 return flashRead(&pThis->Core, off, pv, cb);
103}
104
105#ifdef IN_RING3
106
107/**
108 * @callback_method_impl{FNSSMDEVSAVEEXEC}
109 */
110static DECLCALLBACK(int) flashSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
111{
112 PDEVFLASH pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASH);
113 return flashR3SaveExec(&pThis->Core, pDevIns, pSSM);
114}
115
116
117/**
118 * @callback_method_impl{FNSSMDEVLOADEXEC}
119 */
120static DECLCALLBACK(int) flashLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
121{
122 PDEVFLASH pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASH);
123 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
124
125 /* Fend off unsupported versions. */
126 if (uVersion != FLASH_SAVED_STATE_VERSION)
127 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
128
129 return flashR3LoadExec(&pThis->Core, pDevIns, pSSM);
130}
131
132
133/**
134 * @interface_method_impl{PDMDEVREG,pfnReset}
135 */
136static DECLCALLBACK(void) flashReset(PPDMDEVINS pDevIns)
137{
138 PDEVFLASH pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASH);
139 flashR3Reset(&pThis->Core);
140}
141
142
143/**
144 * @interface_method_impl{PDMDEVREG,pfnDestruct}
145 */
146static DECLCALLBACK(int) flashDestruct(PPDMDEVINS pDevIns)
147{
148 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
149 PDEVFLASH pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASH);
150 PDEVFLASHR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PDEVFLASHR3);
151
152 if (pThisR3->pszFlashFile)
153 {
154 int rc = flashR3SaveToFile(&pThis->Core, pDevIns, pThisR3->pszFlashFile);
155 if (RT_FAILURE(rc))
156 LogRel(("Flash: Failed to save flash file: %Rrc\n", rc));
157
158 PDMDevHlpMMHeapFree(pDevIns, pThisR3->pszFlashFile);
159 pThisR3->pszFlashFile = NULL;
160 }
161
162 flashR3Destruct(&pThis->Core, pDevIns);
163 return VINF_SUCCESS;
164}
165
166
167/**
168 * @interface_method_impl{PDMDEVREG,pfnConstruct}
169 */
170static DECLCALLBACK(int) flashConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
171{
172 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
173 PDEVFLASH pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASH);
174 PDEVFLASHR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PDEVFLASHR3);
175 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
176
177 Assert(iInstance == 0); RT_NOREF1(iInstance);
178
179 /*
180 * Validate configuration.
181 */
182 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DeviceId|BaseAddress|Size|BlockSize|FlashFile", "");
183
184 /*
185 * Read configuration.
186 */
187
188 /* The default device ID is Intel 28F800SA. */
189 uint16_t u16FlashId = 0;
190 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "DeviceId", &u16FlashId, 0xA289);
191 if (RT_FAILURE(rc))
192 return PDMDEV_SET_ERROR(pDevIns, rc,
193 N_("Configuration error: Querying \"DeviceId\" as an integer failed"));
194
195 /* The default base address is 2MB below 4GB. */
196 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "BaseAddress", &pThis->GCPhysFlashBase, 0xFFE00000);
197 if (RT_FAILURE(rc))
198 return PDMDEV_SET_ERROR(pDevIns, rc,
199 N_("Configuration error: Querying \"BaseAddress\" as an integer failed"));
200
201 /* The default flash device size is 128K. */
202 uint32_t cbFlash = 0;
203 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "Size", &cbFlash, 128 * _1K);
204 if (RT_FAILURE(rc))
205 return PDMDEV_SET_ERROR(pDevIns, rc,
206 N_("Configuration error: Querying \"Size\" as an integer failed"));
207
208 /* The default flash device block size is 4K. */
209 uint16_t cbBlock = 0;
210 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BlockSize", &cbBlock, _4K);
211 if (RT_FAILURE(rc))
212 return PDMDEV_SET_ERROR(pDevIns, rc,
213 N_("Configuration error: Querying \"BlockSize\" as an integer failed"));
214
215 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "FlashFile", &pThisR3->pszFlashFile);
216 if (RT_FAILURE(rc))
217 return PDMDEV_SET_ERROR(pDevIns, rc,
218 N_("Configuration error: Querying \"FlashFile\" as a string failed"));
219
220 /*
221 * Initialize the flash core.
222 */
223 rc = flashR3Init(&pThis->Core, pDevIns, u16FlashId, cbFlash, cbBlock);
224 if (RT_FAILURE(rc))
225 return PDMDEV_SET_ERROR(pDevIns, rc,
226 N_("Flash: Failed to initialize core flash device"));
227
228 /* Try to load the flash content from file. */
229 rc = flashR3LoadFromFile(&pThis->Core, pDevIns, pThisR3->pszFlashFile);
230 if (RT_FAILURE(rc))
231 return PDMDEV_SET_ERROR(pDevIns, rc,
232 N_("Flash: Failed to load flash content from given file"));
233
234 /*
235 * Register MMIO region.
236 */
237 rc = PDMDevHlpMmioCreateExAndMap(pDevIns, pThis->GCPhysFlashBase, cbFlash,
238 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, NULL, UINT32_MAX,
239 flashMMIOWrite, flashMMIORead, NULL, NULL, "Flash Memory", &pThis->hMmio);
240 AssertRCReturn(rc, rc);
241 LogRel(("Registered %uKB flash at %RGp\n", pThis->Core.cbFlashSize / _1K, pThis->GCPhysFlashBase));
242
243 /*
244 * Register saved state.
245 */
246 rc = PDMDevHlpSSMRegister(pDevIns, FLASH_SAVED_STATE_VERSION, sizeof(*pThis), flashSaveExec, flashLoadExec);
247 AssertRCReturn(rc, rc);
248
249 return VINF_SUCCESS;
250}
251
252#else /* !IN_RING3 */
253
254/**
255 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
256 */
257static DECLCALLBACK(int) flashRZConstruct(PPDMDEVINS pDevIns)
258{
259 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
260 PDEVFLASH pThis = PDMDEVINS_2_DATA(pDevIns, PDEVFLASH);
261
262# if 1
263 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, flashMMIOWrite, flashMMIORead, NULL /*pvUser*/);
264 AssertRCReturn(rc, rc);
265# else
266 RT_NOREF(pDevIns, pThis); (void)&flashMMIOWrite; (void)&flashMMIORead;
267# endif
268
269 return VINF_SUCCESS;
270}
271
272#endif /* !IN_RING3 */
273
274/**
275 * The device registration structure.
276 */
277const PDMDEVREG g_DeviceFlash =
278{
279 /* .u32Version = */ PDM_DEVREG_VERSION,
280 /* .uReserved0 = */ 0,
281 /* .szName = */ "flash",
282 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
283 /* .fClass = */ PDM_DEVREG_CLASS_ARCH,
284 /* .cMaxInstances = */ 1,
285 /* .uSharedVersion = */ 42,
286 /* .cbInstanceShared = */ sizeof(DEVFLASH),
287 /* .cbInstanceCC = */ 0,
288 /* .cbInstanceRC = */ 0,
289 /* .cMaxPciDevices = */ 0,
290 /* .cMaxMsixVectors = */ 0,
291 /* .pszDescription = */ "Flash Memory Device",
292#if defined(IN_RING3)
293 /* .pszRCMod = */ "VBoxDDRC.rc",
294 /* .pszR0Mod = */ "VBoxDDR0.r0",
295 /* .pfnConstruct = */ flashConstruct,
296 /* .pfnDestruct = */ flashDestruct,
297 /* .pfnRelocate = */ NULL,
298 /* .pfnMemSetup = */ NULL,
299 /* .pfnPowerOn = */ NULL,
300 /* .pfnReset = */ flashReset,
301 /* .pfnSuspend = */ NULL,
302 /* .pfnResume = */ NULL,
303 /* .pfnAttach = */ NULL,
304 /* .pfnDetach = */ NULL,
305 /* .pfnQueryInterface = */ NULL,
306 /* .pfnInitComplete = */ NULL,
307 /* .pfnPowerOff = */ NULL,
308 /* .pfnSoftReset = */ NULL,
309 /* .pfnReserved0 = */ NULL,
310 /* .pfnReserved1 = */ NULL,
311 /* .pfnReserved2 = */ NULL,
312 /* .pfnReserved3 = */ NULL,
313 /* .pfnReserved4 = */ NULL,
314 /* .pfnReserved5 = */ NULL,
315 /* .pfnReserved6 = */ NULL,
316 /* .pfnReserved7 = */ NULL,
317#elif defined(IN_RING0)
318 /* .pfnEarlyConstruct = */ NULL,
319 /* .pfnConstruct = */ flashRZConstruct,
320 /* .pfnDestruct = */ NULL,
321 /* .pfnFinalDestruct = */ NULL,
322 /* .pfnRequest = */ NULL,
323 /* .pfnReserved0 = */ NULL,
324 /* .pfnReserved1 = */ NULL,
325 /* .pfnReserved2 = */ NULL,
326 /* .pfnReserved3 = */ NULL,
327 /* .pfnReserved4 = */ NULL,
328 /* .pfnReserved5 = */ NULL,
329 /* .pfnReserved6 = */ NULL,
330 /* .pfnReserved7 = */ NULL,
331#elif defined(IN_RC)
332 /* .pfnConstruct = */ NULL,
333 /* .pfnReserved0 = */ flashRZConstruct,
334 /* .pfnReserved1 = */ NULL,
335 /* .pfnReserved2 = */ NULL,
336 /* .pfnReserved3 = */ NULL,
337 /* .pfnReserved4 = */ NULL,
338 /* .pfnReserved5 = */ NULL,
339 /* .pfnReserved6 = */ NULL,
340 /* .pfnReserved7 = */ NULL,
341#else
342# error "Not in IN_RING3, IN_RING0 or IN_RC!"
343#endif
344 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
345};
346
347#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