Home | History | Annotate | Download | only in QemuFlashFvbServicesRuntimeDxe
      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