TianoCore EDK2 master
Loading...
Searching...
No Matches
QemuFlash.c
Go to the documentation of this file.
1
11#include <Library/DebugLib.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
33volatile UINT8 *
34QemuFlashPtr (
35 IN EFI_LBA Lba,
36 IN UINTN Offset
37 )
38{
39 return mFlashBase + ((UINTN)Lba * mFdBlockSize) + Offset;
40}
41
50BOOLEAN
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
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
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
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
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
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}
UINT64 UINTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define DEBUG(Expression)
Definition: DebugLib.h:434
BOOLEAN EFIAPI MemEncryptSevEsIsEnabled(VOID)
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define FeaturePcdGet(TokenName)
Definition: PcdLib.h:50
STATIC BOOLEAN QemuFlashDetected(VOID)
Definition: QemuFlash.c:51
EFI_STATUS QemuFlashWrite(IN EFI_LBA Lba, IN UINTN Offset, IN UINTN *NumBytes, IN UINT8 *Buffer)
Definition: QemuFlash.c:188
EFI_STATUS QemuFlashEraseBlock(IN EFI_LBA Lba)
Definition: QemuFlash.c:234
EFI_STATUS QemuFlashRead(IN EFI_LBA Lba, IN UINTN Offset, IN UINTN *NumBytes, IN UINT8 *Buffer)
Definition: QemuFlash.c:150
EFI_STATUS QemuFlashInitialize(VOID)
Definition: QemuFlash.c:258
VOID QemuFlashPtrWrite(IN volatile UINT8 *Ptr, IN UINT8 Value)
Definition: QemuFlashDxe.c:53
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
UINT64 EFI_LBA
Definition: UefiBaseType.h:45
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112