/** @file SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #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; }