VirtualBox

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

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