VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c@ 105381

Last change on this file since 105381 was 101291, checked in by vboxsync, 14 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

  • Property svn:eol-style set to native
File size: 6.7 KB
Line 
1/** @file
2 OVMF support for QEMU system firmware flash device
3
4 Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include <Library/BaseMemoryLib.h>
11#include <Library/DebugLib.h>
12#include <Library/MemEncryptSevLib.h>
13#include <Library/PcdLib.h>
14
15#include "QemuFlash.h"
16
17#define WRITE_BYTE_CMD 0x10
18#define BLOCK_ERASE_CMD 0x20
19#define CLEAR_STATUS_CMD 0x50
20#define READ_STATUS_CMD 0x70
21#define READ_DEVID_CMD 0x90
22#define BLOCK_ERASE_CONFIRM_CMD 0xd0
23#define READ_ARRAY_CMD 0xff
24
25#define CLEARED_ARRAY_STATUS 0x00
26
27UINT8 *mFlashBase;
28
29STATIC UINTN mFdBlockSize = 0;
30STATIC UINTN mFdBlockCount = 0;
31
32STATIC
33volatile UINT8 *
34QemuFlashPtr (
35 IN EFI_LBA Lba,
36 IN UINTN Offset
37 )
38{
39 return mFlashBase + ((UINTN)Lba * mFdBlockSize) + Offset;
40}
41
42/**
43 Determines if the QEMU flash memory device is present.
44
45 @retval FALSE The QEMU flash device is not present.
46 @retval TRUE The QEMU flash device is present.
47
48**/
49STATIC
50BOOLEAN
51QemuFlashDetected (
52 VOID
53 )
54{
55 BOOLEAN FlashDetected;
56 volatile UINT8 *Ptr;
57
58 UINTN Offset;
59 UINT8 OriginalUint8;
60 UINT8 ProbeUint8;
61
62 FlashDetected = FALSE;
63 Ptr = QemuFlashPtr (0, 0);
64
65 for (Offset = 0; Offset < mFdBlockSize; Offset++) {
66 Ptr = QemuFlashPtr (0, Offset);
67 ProbeUint8 = *Ptr;
68 if ((ProbeUint8 != CLEAR_STATUS_CMD) &&
69 (ProbeUint8 != READ_STATUS_CMD) &&
70 (ProbeUint8 != CLEARED_ARRAY_STATUS))
71 {
72 break;
73 }
74 }
75
76 if (Offset >= mFdBlockSize) {
77 DEBUG ((DEBUG_INFO, "QEMU Flash: Failed to find probe location\n"));
78 return FALSE;
79 }
80
81 DEBUG ((DEBUG_INFO, "QEMU Flash: Attempting flash detection at %p\n", Ptr));
82
83 if (MemEncryptSevEsIsEnabled ()) {
84 //
85 // When SEV-ES is enabled, the check below can result in an infinite
86 // loop with respect to a nested page fault. When the memslot is mapped
87 // read-only, the nested page table entry is read-only. The check below
88 // will cause a nested page fault that cannot be emulated, causing
89 // the instruction to retried over and over. For SEV-ES, acknowledge that
90 // the FD appears as ROM and not as FLASH, but report FLASH anyway because
91 // FLASH behavior can be simulated using VMGEXIT.
92 //
93 DEBUG ((
94 DEBUG_INFO,
95 "QEMU Flash: SEV-ES enabled, assuming FD behaves as FLASH\n"
96 ));
97 return TRUE;
98 }
99
100 OriginalUint8 = *Ptr;
101 *Ptr = CLEAR_STATUS_CMD;
102 ProbeUint8 = *Ptr;
103 if ((OriginalUint8 != CLEAR_STATUS_CMD) &&
104 (ProbeUint8 == CLEAR_STATUS_CMD))
105 {
106 DEBUG ((DEBUG_INFO, "QemuFlashDetected => FD behaves as RAM\n"));
107 *Ptr = OriginalUint8;
108 } else {
109 *Ptr = READ_STATUS_CMD;
110 ProbeUint8 = *Ptr;
111 if (ProbeUint8 == OriginalUint8) {
112 DEBUG ((DEBUG_INFO, "QemuFlashDetected => FD behaves as ROM\n"));
113 } else if (ProbeUint8 == READ_STATUS_CMD) {
114 DEBUG ((DEBUG_INFO, "QemuFlashDetected => FD behaves as RAM\n"));
115 *Ptr = OriginalUint8;
116 } else if (ProbeUint8 == CLEARED_ARRAY_STATUS) {
117 *Ptr = WRITE_BYTE_CMD;
118 *Ptr = OriginalUint8;
119 *Ptr = READ_STATUS_CMD;
120 ProbeUint8 = *Ptr;
121 *Ptr = READ_ARRAY_CMD;
122 if (ProbeUint8 & 0x10 /* programming error */) {
123 DEBUG ((DEBUG_INFO, "QemuFlashDetected => FD behaves as FLASH, write-protected\n"));
124 } else {
125 DEBUG ((DEBUG_INFO, "QemuFlashDetected => FD behaves as FLASH, writable\n"));
126 FlashDetected = TRUE;
127 }
128 }
129 }
130
131 DEBUG ((
132 DEBUG_INFO,
133 "QemuFlashDetected => %a\n",
134 FlashDetected ? "Yes" : "No"
135 ));
136 return FlashDetected;
137}
138
139/**
140 Read from QEMU Flash
141
142 @param[in] Lba The starting logical block index to read from.
143 @param[in] Offset Offset into the block at which to begin reading.
144 @param[in] NumBytes On input, indicates the requested read size. On
145 output, indicates the actual number of bytes read
146 @param[in] Buffer Pointer to the buffer to read into.
147
148**/
149EFI_STATUS
150QemuFlashRead (
151 IN EFI_LBA Lba,
152 IN UINTN Offset,
153 IN UINTN *NumBytes,
154 IN UINT8 *Buffer
155 )
156{
157 UINT8 *Ptr;
158
159 //
160 // Only write to the first 64k. We don't bother saving the FTW Spare
161 // block into the flash memory.
162 //
163 if (Lba >= mFdBlockCount) {
164 return EFI_INVALID_PARAMETER;
165 }
166
167 //
168 // Get flash address
169 //
170 Ptr = (UINT8 *)QemuFlashPtr (Lba, Offset);
171
172 CopyMem (Buffer, Ptr, *NumBytes);
173
174 return EFI_SUCCESS;
175}
176
177/**
178 Write to QEMU Flash
179
180 @param[in] Lba The starting logical block index to write to.
181 @param[in] Offset Offset into the block at which to begin writing.
182 @param[in] NumBytes On input, indicates the requested write size. On
183 output, indicates the actual number of bytes written
184 @param[in] Buffer Pointer to the data to write.
185
186**/
187EFI_STATUS
188QemuFlashWrite (
189 IN EFI_LBA Lba,
190 IN UINTN Offset,
191 IN UINTN *NumBytes,
192 IN UINT8 *Buffer
193 )
194{
195 volatile UINT8 *Ptr;
196 UINTN Loop;
197
198 //
199 // Only write to the first 64k. We don't bother saving the FTW Spare
200 // block into the flash memory.
201 //
202 if (Lba >= mFdBlockCount) {
203 return EFI_INVALID_PARAMETER;
204 }
205
206 //
207 // Program flash
208 //
209 Ptr = QemuFlashPtr (Lba, Offset);
210 for (Loop = 0; Loop < *NumBytes; Loop++) {
211 QemuFlashPtrWrite (Ptr, WRITE_BYTE_CMD);
212 QemuFlashPtrWrite (Ptr, Buffer[Loop]);
213
214 Ptr++;
215 }
216
217 //
218 // Restore flash to read mode
219 //
220 if (*NumBytes > 0) {
221 QemuFlashPtrWrite (Ptr - 1, READ_ARRAY_CMD);
222 }
223
224 return EFI_SUCCESS;
225}
226
227/**
228 Erase a QEMU Flash block
229
230 @param Lba The logical block index to erase.
231
232**/
233EFI_STATUS
234QemuFlashEraseBlock (
235 IN EFI_LBA Lba
236 )
237{
238 volatile UINT8 *Ptr;
239
240 if (Lba >= mFdBlockCount) {
241 return EFI_INVALID_PARAMETER;
242 }
243
244 Ptr = QemuFlashPtr (Lba, 0);
245 QemuFlashPtrWrite (Ptr, BLOCK_ERASE_CMD);
246 QemuFlashPtrWrite (Ptr, BLOCK_ERASE_CONFIRM_CMD);
247 return EFI_SUCCESS;
248}
249
250/**
251 Initializes QEMU flash memory support
252
253 @retval EFI_WRITE_PROTECTED The QEMU flash device is not present.
254 @retval EFI_SUCCESS The QEMU flash device is supported.
255
256**/
257EFI_STATUS
258QemuFlashInitialize (
259 VOID
260 )
261{
262 mFlashBase = (UINT8 *)(UINTN)PcdGet32 (PcdOvmfFdBaseAddress);
263 mFdBlockSize = PcdGet32 (PcdOvmfFirmwareBlockSize);
264 ASSERT (PcdGet32 (PcdOvmfFirmwareFdSize) % mFdBlockSize == 0);
265 mFdBlockCount = PcdGet32 (PcdOvmfFirmwareFdSize) / mFdBlockSize;
266
267 //
268 // execute module specific hooks before probing the flash
269 //
270 QemuFlashBeforeProbe (
271 (EFI_PHYSICAL_ADDRESS)(UINTN)mFlashBase,
272 mFdBlockSize,
273 mFdBlockCount
274 );
275
276 if (!QemuFlashDetected ()) {
277 ASSERT (!FeaturePcdGet (PcdSmmSmramRequire));
278 return EFI_WRITE_PROTECTED;
279 }
280
281 return EFI_SUCCESS;
282}
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