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 This program and the accompanying materials are licensed and made available 7 under the terms and conditions of the BSD License which accompanies this 8 distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include <Library/BaseMemoryLib.h> 17 #include <Library/DebugLib.h> 18 #include <Library/PcdLib.h> 19 20 #include "QemuFlash.h" 21 22 #define WRITE_BYTE_CMD 0x10 23 #define BLOCK_ERASE_CMD 0x20 24 #define CLEAR_STATUS_CMD 0x50 25 #define READ_STATUS_CMD 0x70 26 #define READ_DEVID_CMD 0x90 27 #define BLOCK_ERASE_CONFIRM_CMD 0xd0 28 #define READ_ARRAY_CMD 0xff 29 30 #define CLEARED_ARRAY_STATUS 0x00 31 32 33 UINT8 *mFlashBase; 34 35 STATIC UINTN mFdBlockSize = 0; 36 STATIC UINTN mFdBlockCount = 0; 37 38 STATIC 39 volatile UINT8* 40 QemuFlashPtr ( 41 IN EFI_LBA Lba, 42 IN UINTN Offset 43 ) 44 { 45 return mFlashBase + ((UINTN)Lba * mFdBlockSize) + Offset; 46 } 47 48 49 /** 50 Determines if the QEMU flash memory device is present. 51 52 @retval FALSE The QEMU flash device is not present. 53 @retval TRUE The QEMU flash device is present. 54 55 **/ 56 STATIC 57 BOOLEAN 58 QemuFlashDetected ( 59 VOID 60 ) 61 { 62 BOOLEAN FlashDetected; 63 volatile UINT8 *Ptr; 64 65 UINTN Offset; 66 UINT8 OriginalUint8; 67 UINT8 ProbeUint8; 68 69 FlashDetected = FALSE; 70 Ptr = QemuFlashPtr (0, 0); 71 72 for (Offset = 0; Offset < mFdBlockSize; Offset++) { 73 Ptr = QemuFlashPtr (0, Offset); 74 ProbeUint8 = *Ptr; 75 if (ProbeUint8 != CLEAR_STATUS_CMD && 76 ProbeUint8 != READ_STATUS_CMD && 77 ProbeUint8 != CLEARED_ARRAY_STATUS) { 78 break; 79 } 80 } 81 82 if (Offset >= mFdBlockSize) { 83 DEBUG ((EFI_D_INFO, "QEMU Flash: Failed to find probe location\n")); 84 return FALSE; 85 } 86 87 DEBUG ((EFI_D_INFO, "QEMU Flash: Attempting flash detection at %p\n", Ptr)); 88 89 OriginalUint8 = *Ptr; 90 *Ptr = CLEAR_STATUS_CMD; 91 ProbeUint8 = *Ptr; 92 if (OriginalUint8 != CLEAR_STATUS_CMD && 93 ProbeUint8 == CLEAR_STATUS_CMD) { 94 DEBUG ((EFI_D_INFO, "QemuFlashDetected => FD behaves as RAM\n")); 95 *Ptr = OriginalUint8; 96 } else { 97 *Ptr = READ_STATUS_CMD; 98 ProbeUint8 = *Ptr; 99 if (ProbeUint8 == OriginalUint8) { 100 DEBUG ((EFI_D_INFO, "QemuFlashDetected => FD behaves as ROM\n")); 101 } else if (ProbeUint8 == READ_STATUS_CMD) { 102 DEBUG ((EFI_D_INFO, "QemuFlashDetected => FD behaves as RAM\n")); 103 *Ptr = OriginalUint8; 104 } else if (ProbeUint8 == CLEARED_ARRAY_STATUS) { 105 DEBUG ((EFI_D_INFO, "QemuFlashDetected => FD behaves as FLASH\n")); 106 FlashDetected = TRUE; 107 *Ptr = READ_ARRAY_CMD; 108 } 109 } 110 111 DEBUG ((EFI_D_INFO, "QemuFlashDetected => %a\n", 112 FlashDetected ? "Yes" : "No")); 113 return FlashDetected; 114 } 115 116 117 /** 118 Read from QEMU Flash 119 120 @param[in] Lba The starting logical block index to read from. 121 @param[in] Offset Offset into the block at which to begin reading. 122 @param[in] NumBytes On input, indicates the requested read size. On 123 output, indicates the actual number of bytes read 124 @param[in] Buffer Pointer to the buffer to read into. 125 126 **/ 127 EFI_STATUS 128 QemuFlashRead ( 129 IN EFI_LBA Lba, 130 IN UINTN Offset, 131 IN UINTN *NumBytes, 132 IN UINT8 *Buffer 133 ) 134 { 135 UINT8 *Ptr; 136 137 // 138 // Only write to the first 64k. We don't bother saving the FTW Spare 139 // block into the flash memory. 140 // 141 if (Lba >= mFdBlockCount) { 142 return EFI_INVALID_PARAMETER; 143 } 144 145 // 146 // Get flash address 147 // 148 Ptr = (UINT8*) QemuFlashPtr (Lba, Offset); 149 150 CopyMem (Buffer, Ptr, *NumBytes); 151 152 return EFI_SUCCESS; 153 } 154 155 156 /** 157 Write to QEMU Flash 158 159 @param[in] Lba The starting logical block index to write to. 160 @param[in] Offset Offset into the block at which to begin writing. 161 @param[in] NumBytes On input, indicates the requested write size. On 162 output, indicates the actual number of bytes written 163 @param[in] Buffer Pointer to the data to write. 164 165 **/ 166 EFI_STATUS 167 QemuFlashWrite ( 168 IN EFI_LBA Lba, 169 IN UINTN Offset, 170 IN UINTN *NumBytes, 171 IN UINT8 *Buffer 172 ) 173 { 174 volatile UINT8 *Ptr; 175 UINTN Loop; 176 177 // 178 // Only write to the first 64k. We don't bother saving the FTW Spare 179 // block into the flash memory. 180 // 181 if (Lba >= mFdBlockCount) { 182 return EFI_INVALID_PARAMETER; 183 } 184 185 // 186 // Program flash 187 // 188 Ptr = QemuFlashPtr (Lba, Offset); 189 for (Loop = 0; Loop < *NumBytes; Loop++) { 190 *Ptr = WRITE_BYTE_CMD; 191 *Ptr = Buffer[Loop]; 192 Ptr++; 193 } 194 195 // 196 // Restore flash to read mode 197 // 198 if (*NumBytes > 0) { 199 *(Ptr - 1) = READ_ARRAY_CMD; 200 } 201 202 return EFI_SUCCESS; 203 } 204 205 206 /** 207 Erase a QEMU Flash block 208 209 @param Lba The logical block index to erase. 210 211 **/ 212 EFI_STATUS 213 QemuFlashEraseBlock ( 214 IN EFI_LBA Lba 215 ) 216 { 217 volatile UINT8 *Ptr; 218 219 if (Lba >= mFdBlockCount) { 220 return EFI_INVALID_PARAMETER; 221 } 222 223 Ptr = QemuFlashPtr (Lba, 0); 224 *Ptr = BLOCK_ERASE_CMD; 225 *Ptr = BLOCK_ERASE_CONFIRM_CMD; 226 return EFI_SUCCESS; 227 } 228 229 230 /** 231 Initializes QEMU flash memory support 232 233 @retval EFI_WRITE_PROTECTED The QEMU flash device is not present. 234 @retval EFI_SUCCESS The QEMU flash device is supported. 235 236 **/ 237 EFI_STATUS 238 QemuFlashInitialize ( 239 VOID 240 ) 241 { 242 mFlashBase = (UINT8*)(UINTN) PcdGet32 (PcdOvmfFdBaseAddress); 243 mFdBlockSize = PcdGet32 (PcdOvmfFirmwareBlockSize); 244 ASSERT(PcdGet32 (PcdOvmfFirmwareFdSize) % mFdBlockSize == 0); 245 mFdBlockCount = PcdGet32 (PcdOvmfFirmwareFdSize) / mFdBlockSize; 246 247 if (!QemuFlashDetected ()) { 248 ASSERT (!FeaturePcdGet (PcdSmmSmramRequire)); 249 return EFI_WRITE_PROTECTED; 250 } 251 252 return EFI_SUCCESS; 253 } 254 255