VirtualBox

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

Last change on this file since 99531 was 99531, checked in by vboxsync, 13 months ago

Devices/DevFlash: Fix implementation after the R0/R3 separation, bugref:9281

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

© 2023 Oracle
ContactPrivacy policyTerms of Use