Home | History | Annotate | Download | only in QemuFwCfgLib
      1 /** @file
      2 
      3   Stateful and implicitly initialized fw_cfg library implementation.
      4 
      5   Copyright (C) 2013 - 2014, Red Hat, Inc.
      6   Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
      7 
      8   This program and the accompanying materials are licensed and made available
      9   under the terms and conditions of the BSD License which accompanies this
     10   distribution.  The full text of the license may be found at
     11   http://opensource.org/licenses/bsd-license.php
     12 
     13   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
     14   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 **/
     16 
     17 #include <Library/BaseLib.h>
     18 #include <Library/BaseMemoryLib.h>
     19 #include <Library/DebugLib.h>
     20 #include <Library/IoLib.h>
     21 #include <Library/PcdLib.h>
     22 #include <Library/QemuFwCfgLib.h>
     23 
     24 STATIC UINTN mFwCfgSelectorAddress;
     25 STATIC UINTN mFwCfgDataAddress;
     26 STATIC UINTN mFwCfgDmaAddress;
     27 
     28 /**
     29   Reads firmware configuration bytes into a buffer
     30 
     31   @param[in] Size    Size in bytes to read
     32   @param[in] Buffer  Buffer to store data into  (OPTIONAL if Size is 0)
     33 
     34 **/
     35 typedef
     36 VOID (EFIAPI READ_BYTES_FUNCTION) (
     37   IN UINTN Size,
     38   IN VOID  *Buffer OPTIONAL
     39   );
     40 
     41 //
     42 // Forward declaration of the two implementations we have.
     43 //
     44 STATIC READ_BYTES_FUNCTION MmioReadBytes;
     45 STATIC READ_BYTES_FUNCTION DmaReadBytes;
     46 
     47 //
     48 // This points to the one we detect at runtime.
     49 //
     50 STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;
     51 
     52 //
     53 // Communication structure for DmaReadBytes(). All fields are encoded in big
     54 // endian.
     55 //
     56 #pragma pack (1)
     57 typedef struct {
     58   UINT32 Control;
     59   UINT32 Length;
     60   UINT64 Address;
     61 } FW_CFG_DMA_ACCESS;
     62 #pragma pack ()
     63 
     64 //
     65 // Macros for the FW_CFG_DMA_ACCESS.Control bitmap (in native encoding).
     66 //
     67 #define FW_CFG_DMA_CTL_ERROR  BIT0
     68 #define FW_CFG_DMA_CTL_READ   BIT1
     69 #define FW_CFG_DMA_CTL_SKIP   BIT2
     70 #define FW_CFG_DMA_CTL_SELECT BIT3
     71 
     72 
     73 /**
     74   Returns a boolean indicating if the firmware configuration interface is
     75   available for library-internal purposes.
     76 
     77   This function never changes fw_cfg state.
     78 
     79   @retval TRUE   The interface is available internally.
     80   @retval FALSE  The interface is not available internally.
     81 **/
     82 BOOLEAN
     83 EFIAPI
     84 InternalQemuFwCfgIsAvailable (
     85   VOID
     86   )
     87 {
     88   return (BOOLEAN)(mFwCfgSelectorAddress != 0 && mFwCfgDataAddress != 0);
     89 }
     90 
     91 
     92 /**
     93   Returns a boolean indicating if the firmware configuration interface
     94   is available or not.
     95 
     96   This function may change fw_cfg state.
     97 
     98   @retval TRUE   The interface is available
     99   @retval FALSE  The interface is not available
    100 
    101 **/
    102 BOOLEAN
    103 EFIAPI
    104 QemuFwCfgIsAvailable (
    105   VOID
    106   )
    107 {
    108   return InternalQemuFwCfgIsAvailable ();
    109 }
    110 
    111 
    112 RETURN_STATUS
    113 EFIAPI
    114 QemuFwCfgInitialize (
    115   VOID
    116   )
    117 {
    118   mFwCfgSelectorAddress = (UINTN)PcdGet64 (PcdFwCfgSelectorAddress);
    119   mFwCfgDataAddress     = (UINTN)PcdGet64 (PcdFwCfgDataAddress);
    120 
    121   if (InternalQemuFwCfgIsAvailable ()) {
    122     UINT32 Signature;
    123 
    124     QemuFwCfgSelectItem (QemuFwCfgItemSignature);
    125     Signature = QemuFwCfgRead32 ();
    126     if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {
    127       //
    128       // For DMA support, we require the DTB to advertise the register, and the
    129       // feature bitmap (which we read without DMA) to confirm the feature.
    130       //
    131       if (PcdGet64 (PcdFwCfgDmaAddress) != 0) {
    132         UINT32 Features;
    133 
    134         QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
    135         Features = QemuFwCfgRead32 ();
    136         if ((Features & BIT1) != 0) {
    137           mFwCfgDmaAddress = PcdGet64 (PcdFwCfgDmaAddress);
    138           InternalQemuFwCfgReadBytes = DmaReadBytes;
    139         }
    140       }
    141     } else {
    142       mFwCfgSelectorAddress = 0;
    143       mFwCfgDataAddress     = 0;
    144     }
    145   }
    146   return RETURN_SUCCESS;
    147 }
    148 
    149 
    150 /**
    151   Selects a firmware configuration item for reading.
    152 
    153   Following this call, any data read from this item will start from the
    154   beginning of the configuration item's data.
    155 
    156   @param[in] QemuFwCfgItem  Firmware Configuration item to read
    157 
    158 **/
    159 VOID
    160 EFIAPI
    161 QemuFwCfgSelectItem (
    162   IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem
    163   )
    164 {
    165   if (InternalQemuFwCfgIsAvailable ()) {
    166     MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem));
    167   }
    168 }
    169 
    170 
    171 /**
    172   Slow READ_BYTES_FUNCTION.
    173 **/
    174 STATIC
    175 VOID
    176 EFIAPI
    177 MmioReadBytes (
    178   IN UINTN Size,
    179   IN VOID  *Buffer OPTIONAL
    180   )
    181 {
    182   UINTN Left;
    183   UINT8 *Ptr;
    184   UINT8 *End;
    185 
    186 #ifdef MDE_CPU_AARCH64
    187   Left = Size & 7;
    188 #else
    189   Left = Size & 3;
    190 #endif
    191 
    192   Size -= Left;
    193   Ptr = Buffer;
    194   End = Ptr + Size;
    195 
    196 #ifdef MDE_CPU_AARCH64
    197   while (Ptr < End) {
    198     *(UINT64 *)Ptr = MmioRead64 (mFwCfgDataAddress);
    199     Ptr += 8;
    200   }
    201   if (Left & 4) {
    202     *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);
    203     Ptr += 4;
    204   }
    205 #else
    206   while (Ptr < End) {
    207     *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);
    208     Ptr += 4;
    209   }
    210 #endif
    211 
    212   if (Left & 2) {
    213     *(UINT16 *)Ptr = MmioRead16 (mFwCfgDataAddress);
    214     Ptr += 2;
    215   }
    216   if (Left & 1) {
    217     *Ptr = MmioRead8 (mFwCfgDataAddress);
    218   }
    219 }
    220 
    221 
    222 /**
    223   Fast READ_BYTES_FUNCTION.
    224 **/
    225 STATIC
    226 VOID
    227 EFIAPI
    228 DmaReadBytes (
    229   IN UINTN Size,
    230   IN VOID  *Buffer OPTIONAL
    231   )
    232 {
    233   volatile FW_CFG_DMA_ACCESS Access;
    234   UINT32                     Status;
    235 
    236   if (Size == 0) {
    237     return;
    238   }
    239 
    240   ASSERT (Size <= MAX_UINT32);
    241 
    242   Access.Control = SwapBytes32 (FW_CFG_DMA_CTL_READ);
    243   Access.Length  = SwapBytes32 ((UINT32)Size);
    244   Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);
    245 
    246   //
    247   // We shouldn't start the transfer before setting up Access.
    248   //
    249   MemoryFence ();
    250 
    251   //
    252   // This will fire off the transfer.
    253   //
    254 #ifdef MDE_CPU_AARCH64
    255   MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));
    256 #else
    257   MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access));
    258 #endif
    259 
    260   //
    261   // We shouldn't look at Access.Control before starting the transfer.
    262   //
    263   MemoryFence ();
    264 
    265   do {
    266     Status = SwapBytes32 (Access.Control);
    267     ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
    268   } while (Status != 0);
    269 
    270   //
    271   // The caller will want to access the transferred data.
    272   //
    273   MemoryFence ();
    274 }
    275 
    276 
    277 /**
    278   Reads firmware configuration bytes into a buffer
    279 
    280   If called multiple times, then the data read will continue at the offset of
    281   the firmware configuration item where the previous read ended.
    282 
    283   @param[in] Size    Size in bytes to read
    284   @param[in] Buffer  Buffer to store data into
    285 
    286 **/
    287 VOID
    288 EFIAPI
    289 QemuFwCfgReadBytes (
    290   IN UINTN Size,
    291   IN VOID  *Buffer
    292   )
    293 {
    294   if (InternalQemuFwCfgIsAvailable ()) {
    295     InternalQemuFwCfgReadBytes (Size, Buffer);
    296   } else {
    297     ZeroMem (Buffer, Size);
    298   }
    299 }
    300 
    301 /**
    302   Write firmware configuration bytes from a buffer
    303 
    304   If called multiple times, then the data written will continue at the offset
    305   of the firmware configuration item where the previous write ended.
    306 
    307   @param[in] Size    Size in bytes to write
    308   @param[in] Buffer  Buffer to read data from
    309 
    310 **/
    311 VOID
    312 EFIAPI
    313 QemuFwCfgWriteBytes (
    314   IN UINTN                  Size,
    315   IN VOID                   *Buffer
    316   )
    317 {
    318   if (InternalQemuFwCfgIsAvailable ()) {
    319     UINTN Idx;
    320 
    321     for (Idx = 0; Idx < Size; ++Idx) {
    322       MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);
    323     }
    324   }
    325 }
    326 
    327 
    328 /**
    329   Reads a UINT8 firmware configuration value
    330 
    331   @return  Value of Firmware Configuration item read
    332 
    333 **/
    334 UINT8
    335 EFIAPI
    336 QemuFwCfgRead8 (
    337   VOID
    338   )
    339 {
    340   UINT8 Result;
    341 
    342   QemuFwCfgReadBytes (sizeof Result, &Result);
    343   return Result;
    344 }
    345 
    346 
    347 /**
    348   Reads a UINT16 firmware configuration value
    349 
    350   @return  Value of Firmware Configuration item read
    351 
    352 **/
    353 UINT16
    354 EFIAPI
    355 QemuFwCfgRead16 (
    356   VOID
    357   )
    358 {
    359   UINT16 Result;
    360 
    361   QemuFwCfgReadBytes (sizeof Result, &Result);
    362   return Result;
    363 }
    364 
    365 
    366 /**
    367   Reads a UINT32 firmware configuration value
    368 
    369   @return  Value of Firmware Configuration item read
    370 
    371 **/
    372 UINT32
    373 EFIAPI
    374 QemuFwCfgRead32 (
    375   VOID
    376   )
    377 {
    378   UINT32 Result;
    379 
    380   QemuFwCfgReadBytes (sizeof Result, &Result);
    381   return Result;
    382 }
    383 
    384 
    385 /**
    386   Reads a UINT64 firmware configuration value
    387 
    388   @return  Value of Firmware Configuration item read
    389 
    390 **/
    391 UINT64
    392 EFIAPI
    393 QemuFwCfgRead64 (
    394   VOID
    395   )
    396 {
    397   UINT64 Result;
    398 
    399   QemuFwCfgReadBytes (sizeof Result, &Result);
    400   return Result;
    401 }
    402 
    403 
    404 /**
    405   Find the configuration item corresponding to the firmware configuration file.
    406 
    407   @param[in]  Name  Name of file to look up.
    408   @param[out] Item  Configuration item corresponding to the file, to be passed
    409                     to QemuFwCfgSelectItem ().
    410   @param[out] Size  Number of bytes in the file.
    411 
    412   @retval RETURN_SUCCESS      If file is found.
    413   @retval RETURN_NOT_FOUND    If file is not found.
    414   @retval RETURN_UNSUPPORTED  If firmware configuration is unavailable.
    415 
    416 **/
    417 RETURN_STATUS
    418 EFIAPI
    419 QemuFwCfgFindFile (
    420   IN   CONST CHAR8           *Name,
    421   OUT  FIRMWARE_CONFIG_ITEM  *Item,
    422   OUT  UINTN                 *Size
    423   )
    424 {
    425   UINT32 Count;
    426   UINT32 Idx;
    427 
    428   if (!InternalQemuFwCfgIsAvailable ()) {
    429     return RETURN_UNSUPPORTED;
    430   }
    431 
    432   QemuFwCfgSelectItem (QemuFwCfgItemFileDir);
    433   Count = SwapBytes32 (QemuFwCfgRead32 ());
    434 
    435   for (Idx = 0; Idx < Count; ++Idx) {
    436     UINT32 FileSize;
    437     UINT16 FileSelect;
    438     CHAR8  FName[QEMU_FW_CFG_FNAME_SIZE];
    439 
    440     FileSize   = QemuFwCfgRead32 ();
    441     FileSelect = QemuFwCfgRead16 ();
    442     QemuFwCfgRead16 (); // skip the field called "reserved"
    443     InternalQemuFwCfgReadBytes (sizeof (FName), FName);
    444 
    445     if (AsciiStrCmp (Name, FName) == 0) {
    446       *Item = (FIRMWARE_CONFIG_ITEM) SwapBytes16 (FileSelect);
    447       *Size = SwapBytes32 (FileSize);
    448       return RETURN_SUCCESS;
    449     }
    450   }
    451 
    452   return RETURN_NOT_FOUND;
    453 }
    454 
    455 
    456 /**
    457   Determine if S3 support is explicitly enabled.
    458 
    459   @retval TRUE   if S3 support is explicitly enabled.
    460           FALSE  otherwise. This includes unavailability of the firmware
    461                  configuration interface.
    462 **/
    463 BOOLEAN
    464 EFIAPI
    465 QemuFwCfgS3Enabled (
    466   VOID
    467   )
    468 {
    469   return FALSE;
    470 }
    471