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