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 24STATIC UINTN mFwCfgSelectorAddress; 25STATIC UINTN mFwCfgDataAddress; 26STATIC 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**/ 35typedef 36VOID (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// 44STATIC READ_BYTES_FUNCTION MmioReadBytes; 45STATIC READ_BYTES_FUNCTION DmaReadBytes; 46 47// 48// This points to the one we detect at runtime. 49// 50STATIC 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) 57typedef 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**/ 82BOOLEAN 83EFIAPI 84InternalQemuFwCfgIsAvailable ( 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**/ 102BOOLEAN 103EFIAPI 104QemuFwCfgIsAvailable ( 105 VOID 106 ) 107{ 108 return InternalQemuFwCfgIsAvailable (); 109} 110 111 112RETURN_STATUS 113EFIAPI 114QemuFwCfgInitialize ( 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**/ 159VOID 160EFIAPI 161QemuFwCfgSelectItem ( 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**/ 174STATIC 175VOID 176EFIAPI 177MmioReadBytes ( 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**/ 225STATIC 226VOID 227EFIAPI 228DmaReadBytes ( 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**/ 287VOID 288EFIAPI 289QemuFwCfgReadBytes ( 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**/ 311VOID 312EFIAPI 313QemuFwCfgWriteBytes ( 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**/ 334UINT8 335EFIAPI 336QemuFwCfgRead8 ( 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**/ 353UINT16 354EFIAPI 355QemuFwCfgRead16 ( 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**/ 372UINT32 373EFIAPI 374QemuFwCfgRead32 ( 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**/ 391UINT64 392EFIAPI 393QemuFwCfgRead64 ( 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**/ 417RETURN_STATUS 418EFIAPI 419QemuFwCfgFindFile ( 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**/ 463BOOLEAN 464EFIAPI 465QemuFwCfgS3Enabled ( 466 VOID 467 ) 468{ 469 return FALSE; 470} 471