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