]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / QemuFlashFvbServicesRuntimeDxe / QemuFlash.c
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
27 UINT8 *mFlashBase;
28
29 STATIC UINTN mFdBlockSize = 0;
30 STATIC UINTN mFdBlockCount = 0;
31
32 STATIC
33 volatile UINT8 *
34 QemuFlashPtr (
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 **/
49 STATIC
50 BOOLEAN
51 QemuFlashDetected (
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 DEBUG ((DEBUG_INFO, "QemuFlashDetected => FD behaves as FLASH\n"));
118 FlashDetected = TRUE;
119 *Ptr = READ_ARRAY_CMD;
120 }
121 }
122
123 DEBUG ((
124 DEBUG_INFO,
125 "QemuFlashDetected => %a\n",
126 FlashDetected ? "Yes" : "No"
127 ));
128 return FlashDetected;
129 }
130
131 /**
132 Read from QEMU Flash
133
134 @param[in] Lba The starting logical block index to read from.
135 @param[in] Offset Offset into the block at which to begin reading.
136 @param[in] NumBytes On input, indicates the requested read size. On
137 output, indicates the actual number of bytes read
138 @param[in] Buffer Pointer to the buffer to read into.
139
140 **/
141 EFI_STATUS
142 QemuFlashRead (
143 IN EFI_LBA Lba,
144 IN UINTN Offset,
145 IN UINTN *NumBytes,
146 IN UINT8 *Buffer
147 )
148 {
149 UINT8 *Ptr;
150
151 //
152 // Only write to the first 64k. We don't bother saving the FTW Spare
153 // block into the flash memory.
154 //
155 if (Lba >= mFdBlockCount) {
156 return EFI_INVALID_PARAMETER;
157 }
158
159 //
160 // Get flash address
161 //
162 Ptr = (UINT8 *)QemuFlashPtr (Lba, Offset);
163
164 CopyMem (Buffer, Ptr, *NumBytes);
165
166 return EFI_SUCCESS;
167 }
168
169 /**
170 Write to QEMU Flash
171
172 @param[in] Lba The starting logical block index to write to.
173 @param[in] Offset Offset into the block at which to begin writing.
174 @param[in] NumBytes On input, indicates the requested write size. On
175 output, indicates the actual number of bytes written
176 @param[in] Buffer Pointer to the data to write.
177
178 **/
179 EFI_STATUS
180 QemuFlashWrite (
181 IN EFI_LBA Lba,
182 IN UINTN Offset,
183 IN UINTN *NumBytes,
184 IN UINT8 *Buffer
185 )
186 {
187 volatile UINT8 *Ptr;
188 UINTN Loop;
189
190 //
191 // Only write to the first 64k. We don't bother saving the FTW Spare
192 // block into the flash memory.
193 //
194 if (Lba >= mFdBlockCount) {
195 return EFI_INVALID_PARAMETER;
196 }
197
198 //
199 // Program flash
200 //
201 Ptr = QemuFlashPtr (Lba, Offset);
202 for (Loop = 0; Loop < *NumBytes; Loop++) {
203 QemuFlashPtrWrite (Ptr, WRITE_BYTE_CMD);
204 QemuFlashPtrWrite (Ptr, Buffer[Loop]);
205
206 Ptr++;
207 }
208
209 //
210 // Restore flash to read mode
211 //
212 if (*NumBytes > 0) {
213 QemuFlashPtrWrite (Ptr - 1, READ_ARRAY_CMD);
214 }
215
216 return EFI_SUCCESS;
217 }
218
219 /**
220 Erase a QEMU Flash block
221
222 @param Lba The logical block index to erase.
223
224 **/
225 EFI_STATUS
226 QemuFlashEraseBlock (
227 IN EFI_LBA Lba
228 )
229 {
230 volatile UINT8 *Ptr;
231
232 if (Lba >= mFdBlockCount) {
233 return EFI_INVALID_PARAMETER;
234 }
235
236 Ptr = QemuFlashPtr (Lba, 0);
237 QemuFlashPtrWrite (Ptr, BLOCK_ERASE_CMD);
238 QemuFlashPtrWrite (Ptr, BLOCK_ERASE_CONFIRM_CMD);
239 return EFI_SUCCESS;
240 }
241
242 /**
243 Initializes QEMU flash memory support
244
245 @retval EFI_WRITE_PROTECTED The QEMU flash device is not present.
246 @retval EFI_SUCCESS The QEMU flash device is supported.
247
248 **/
249 EFI_STATUS
250 QemuFlashInitialize (
251 VOID
252 )
253 {
254 mFlashBase = (UINT8 *)(UINTN)PcdGet32 (PcdOvmfFdBaseAddress);
255 mFdBlockSize = PcdGet32 (PcdOvmfFirmwareBlockSize);
256 ASSERT (PcdGet32 (PcdOvmfFirmwareFdSize) % mFdBlockSize == 0);
257 mFdBlockCount = PcdGet32 (PcdOvmfFirmwareFdSize) / mFdBlockSize;
258
259 //
260 // execute module specific hooks before probing the flash
261 //
262 QemuFlashBeforeProbe (
263 (EFI_PHYSICAL_ADDRESS)(UINTN)mFlashBase,
264 mFdBlockSize,
265 mFdBlockCount
266 );
267
268 if (!QemuFlashDetected ()) {
269 ASSERT (!FeaturePcdGet (PcdSmmSmramRequire));
270 return EFI_WRITE_PROTECTED;
271 }
272
273 return EFI_SUCCESS;
274 }