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