2 OVMF support for QEMU system firmware flash device
4 Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/BaseMemoryLib.h>
11 #include <Library/DebugLib.h>
12 #include <Library/MemEncryptSevLib.h>
13 #include <Library/PcdLib.h>
15 #include "QemuFlash.h"
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
25 #define CLEARED_ARRAY_STATUS 0x00
29 STATIC UINTN mFdBlockSize
= 0;
30 STATIC UINTN mFdBlockCount
= 0;
39 return mFlashBase
+ ((UINTN
)Lba
* mFdBlockSize
) + Offset
;
43 Determines if the QEMU flash memory device is present.
45 @retval FALSE The QEMU flash device is not present.
46 @retval TRUE The QEMU flash device is present.
55 BOOLEAN FlashDetected
;
62 FlashDetected
= FALSE
;
63 Ptr
= QemuFlashPtr (0, 0);
65 for (Offset
= 0; Offset
< mFdBlockSize
; Offset
++) {
66 Ptr
= QemuFlashPtr (0, Offset
);
68 if ((ProbeUint8
!= CLEAR_STATUS_CMD
) &&
69 (ProbeUint8
!= READ_STATUS_CMD
) &&
70 (ProbeUint8
!= CLEARED_ARRAY_STATUS
))
76 if (Offset
>= mFdBlockSize
) {
77 DEBUG ((DEBUG_INFO
, "QEMU Flash: Failed to find probe location\n"));
81 DEBUG ((DEBUG_INFO
, "QEMU Flash: Attempting flash detection at %p\n", Ptr
));
83 if (MemEncryptSevEsIsEnabled ()) {
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.
95 "QEMU Flash: SEV-ES enabled, assuming FD behaves as FLASH\n"
100 OriginalUint8
= *Ptr
;
101 *Ptr
= CLEAR_STATUS_CMD
;
103 if ((OriginalUint8
!= CLEAR_STATUS_CMD
) &&
104 (ProbeUint8
== CLEAR_STATUS_CMD
))
106 DEBUG ((DEBUG_INFO
, "QemuFlashDetected => FD behaves as RAM\n"));
107 *Ptr
= OriginalUint8
;
109 *Ptr
= READ_STATUS_CMD
;
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
;
125 "QemuFlashDetected => %a\n",
126 FlashDetected
? "Yes" : "No"
128 return FlashDetected
;
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.
152 // Only write to the first 64k. We don't bother saving the FTW Spare
153 // block into the flash memory.
155 if (Lba
>= mFdBlockCount
) {
156 return EFI_INVALID_PARAMETER
;
162 Ptr
= (UINT8
*)QemuFlashPtr (Lba
, Offset
);
164 CopyMem (Buffer
, Ptr
, *NumBytes
);
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.
191 // Only write to the first 64k. We don't bother saving the FTW Spare
192 // block into the flash memory.
194 if (Lba
>= mFdBlockCount
) {
195 return EFI_INVALID_PARAMETER
;
201 Ptr
= QemuFlashPtr (Lba
, Offset
);
202 for (Loop
= 0; Loop
< *NumBytes
; Loop
++) {
203 QemuFlashPtrWrite (Ptr
, WRITE_BYTE_CMD
);
204 QemuFlashPtrWrite (Ptr
, Buffer
[Loop
]);
210 // Restore flash to read mode
213 QemuFlashPtrWrite (Ptr
- 1, READ_ARRAY_CMD
);
220 Erase a QEMU Flash block
222 @param Lba The logical block index to erase.
226 QemuFlashEraseBlock (
232 if (Lba
>= mFdBlockCount
) {
233 return EFI_INVALID_PARAMETER
;
236 Ptr
= QemuFlashPtr (Lba
, 0);
237 QemuFlashPtrWrite (Ptr
, BLOCK_ERASE_CMD
);
238 QemuFlashPtrWrite (Ptr
, BLOCK_ERASE_CONFIRM_CMD
);
243 Initializes QEMU flash memory support
245 @retval EFI_WRITE_PROTECTED The QEMU flash device is not present.
246 @retval EFI_SUCCESS The QEMU flash device is supported.
250 QemuFlashInitialize (
254 mFlashBase
= (UINT8
*)(UINTN
)PcdGet32 (PcdOvmfFdBaseAddress
);
255 mFdBlockSize
= PcdGet32 (PcdOvmfFirmwareBlockSize
);
256 ASSERT (PcdGet32 (PcdOvmfFirmwareFdSize
) % mFdBlockSize
== 0);
257 mFdBlockCount
= PcdGet32 (PcdOvmfFirmwareFdSize
) / mFdBlockSize
;
260 // execute module specific hooks before probing the flash
262 QemuFlashBeforeProbe (
263 (EFI_PHYSICAL_ADDRESS
)(UINTN
)mFlashBase
,
268 if (!QemuFlashDetected ()) {
269 ASSERT (!FeaturePcdGet (PcdSmmSmramRequire
));
270 return EFI_WRITE_PROTECTED
;