summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/VirtHstiDxe/Flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg/VirtHstiDxe/Flash.c')
-rw-r--r--OvmfPkg/VirtHstiDxe/Flash.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/OvmfPkg/VirtHstiDxe/Flash.c b/OvmfPkg/VirtHstiDxe/Flash.c
new file mode 100644
index 0000000000..e93356793f
--- /dev/null
+++ b/OvmfPkg/VirtHstiDxe/Flash.c
@@ -0,0 +1,90 @@
+/** @file
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#include "VirtHstiDxe.h"
+
+#define WRITE_BYTE_CMD 0x10
+#define BLOCK_ERASE_CMD 0x20
+#define CLEAR_STATUS_CMD 0x50
+#define READ_STATUS_CMD 0x70
+#define READ_DEVID_CMD 0x90
+#define BLOCK_ERASE_CONFIRM_CMD 0xd0
+#define READ_ARRAY_CMD 0xff
+#define CLEARED_ARRAY_STATUS 0x00
+
+/* based on QemuFlashDetected (QemuFlashFvbServicesRuntimeDxe) */
+UINT32
+VirtHstiQemuFirmwareFlashCheck (
+ UINT32 Address
+ )
+{
+ volatile UINT8 *Ptr;
+
+ UINTN Offset;
+ UINT8 OriginalUint8;
+ UINT8 ProbeUint8;
+
+ for (Offset = 0; Offset < EFI_PAGE_SIZE; Offset++) {
+ Ptr = (UINT8 *)(UINTN)(Address + Offset);
+ ProbeUint8 = *Ptr;
+ if ((ProbeUint8 != CLEAR_STATUS_CMD) &&
+ (ProbeUint8 != READ_STATUS_CMD) &&
+ (ProbeUint8 != CLEARED_ARRAY_STATUS))
+ {
+ break;
+ }
+ }
+
+ if (Offset >= EFI_PAGE_SIZE) {
+ DEBUG ((DEBUG_INFO, "%a: check failed\n", __func__));
+ return QEMU_FIRMWARE_FLASH_UNKNOWN;
+ }
+
+ OriginalUint8 = *Ptr;
+ *Ptr = CLEAR_STATUS_CMD;
+ ProbeUint8 = *Ptr;
+ if ((OriginalUint8 != CLEAR_STATUS_CMD) &&
+ (ProbeUint8 == CLEAR_STATUS_CMD))
+ {
+ *Ptr = OriginalUint8;
+ DEBUG ((DEBUG_INFO, "%a: %p behaves as RAM\n", __func__, Ptr));
+ return QEMU_FIRMWARE_FLASH_IS_RAM;
+ }
+
+ *Ptr = READ_STATUS_CMD;
+ ProbeUint8 = *Ptr;
+ if (ProbeUint8 == OriginalUint8) {
+ DEBUG ((DEBUG_INFO, "%a: %p behaves as ROM\n", __func__, Ptr));
+ return QEMU_FIRMWARE_FLASH_IS_ROM;
+ }
+
+ if (ProbeUint8 == READ_STATUS_CMD) {
+ *Ptr = OriginalUint8;
+ DEBUG ((DEBUG_INFO, "%a: %p behaves as RAM\n", __func__, Ptr));
+ return QEMU_FIRMWARE_FLASH_IS_RAM;
+ }
+
+ if (ProbeUint8 == CLEARED_ARRAY_STATUS) {
+ *Ptr = WRITE_BYTE_CMD;
+ *Ptr = OriginalUint8;
+ *Ptr = READ_STATUS_CMD;
+ ProbeUint8 = *Ptr;
+ *Ptr = READ_ARRAY_CMD;
+ if (ProbeUint8 & 0x10 /* programming error */) {
+ DEBUG ((DEBUG_INFO, "%a: %p behaves as FLASH, write-protected\n", __func__, Ptr));
+ return QEMU_FIRMWARE_FLASH_READ_ONLY;
+ } else {
+ DEBUG ((DEBUG_INFO, "%a: %p behaves as FLASH, writable\n", __func__, Ptr));
+ return QEMU_FIRMWARE_FLASH_WRITABLE;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "%a: check failed\n", __func__));
+ return QEMU_FIRMWARE_FLASH_UNKNOWN;
+}