1 /** @file 2 3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> 4 5 This program and the accompanying materials are licensed and made available under 7 the terms and conditions of the BSD License that accompanies this distribution. 9 The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php. 13 15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 21 23 24 **/ 25 26 #include <PiDxe.h> 27 28 #include <Library/FlashDeviceLib.h> 29 #include <Library/DebugLib.h> 30 #include <Library/BaseLib.h> 31 #include <Library/UefiBootServicesTableLib.h> 32 #include <Library/UefiRuntimeServicesTableLib.h> 33 #include <Library/BaseMemoryLib.h> 34 #include <Library/UefiRuntimeLib.h> 35 #include <Protocol/SmmBase2.h> 36 #include <Guid/EventGroup.h> 37 #include "SpiChipDefinitions.h" 38 39 UINTN FlashDeviceBase = FLASH_DEVICE_BASE_ADDRESS; 40 41 EFI_SPI_PROTOCOL *mSpiProtocol = NULL; 42 43 EFI_STATUS 44 SpiFlashErase ( 45 UINT8 *BaseAddress, 46 UINTN NumBytes 47 ) 48 { 49 EFI_STATUS Status = EFI_SUCCESS; 50 UINT32 SectorSize; 51 UINT32 SpiAddress; 52 53 SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase; 54 SectorSize = SECTOR_SIZE_4KB; 55 while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) { 56 Status = mSpiProtocol->Execute ( 57 mSpiProtocol, 58 SPI_SERASE, 59 SPI_WREN, 60 FALSE, 61 TRUE, 62 FALSE, 63 (UINT32) SpiAddress, 64 0, 65 NULL, 66 EnumSpiRegionBios 67 ); 68 if (EFI_ERROR (Status)) { 69 break; 70 } 71 SpiAddress += SectorSize; 72 NumBytes -= SectorSize; 73 } 74 75 return Status; 76 } 77 78 79 EFI_STATUS 80 SpiFlashBlockErase ( 81 UINT8 *BaseAddress, 82 UINTN NumBytes 83 ) 84 { 85 EFI_STATUS Status = EFI_SUCCESS; 86 UINT32 SectorSize; 87 UINT32 SpiAddress; 88 89 SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase; 90 SectorSize = SECTOR_SIZE_64KB; 91 while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) { 92 Status = mSpiProtocol->Execute ( 93 mSpiProtocol, 94 SPI_BERASE, 95 SPI_WREN, 96 FALSE, 97 TRUE, 98 FALSE, 99 (UINT32) SpiAddress, 100 0, 101 NULL, 102 EnumSpiRegionBios 103 ); 104 if (EFI_ERROR (Status)) { 105 break; 106 } 107 SpiAddress += SectorSize; 108 NumBytes -= SectorSize; 109 } 110 111 return Status; 112 } 113 114 115 static 116 EFI_STATUS 117 SpiFlashWrite ( 118 UINT8 *DstBufferPtr, 119 UINT8 *Byte, 120 IN UINTN Length 121 ) 122 { 123 EFI_STATUS Status; 124 UINT32 NumBytes = (UINT32)Length; 125 UINT8* pBuf8 = Byte; 126 UINT32 SpiAddress; 127 128 SpiAddress = (UINT32)(UINTN)(DstBufferPtr) - (UINT32)FlashDeviceBase; 129 Status = mSpiProtocol->Execute ( 130 mSpiProtocol, 131 SPI_PROG, 132 SPI_WREN, 133 TRUE, 134 TRUE, 135 TRUE, 136 (UINT32)SpiAddress, 137 NumBytes, 138 pBuf8, 139 EnumSpiRegionBios 140 ); 141 return Status; 142 } 143 144 /** 145 Read the Serial Flash Status Registers. 146 147 @param SpiStatus Pointer to a caller-allocated UINT8. On successful return, it contains the 148 status data read from the Serial Flash Status Register. 149 150 151 @retval EFI_SUCCESS Operation success, status is returned in SpiStatus. 152 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and the operation failed. 153 154 **/ 155 EFI_STATUS 156 ReadStatusRegister ( 157 UINT8 *SpiStatus 158 ) 159 { 160 EFI_STATUS Status; 161 162 Status = mSpiProtocol->Execute ( 163 mSpiProtocol, 164 SPI_RDSR, 165 SPI_WREN, 166 TRUE, 167 FALSE, 168 FALSE, 169 0, 170 1, 171 SpiStatus, 172 EnumSpiRegionBios 173 ); 174 return Status; 175 } 176 177 EFI_STATUS 178 SpiFlashLock ( 179 IN UINT8 *BaseAddress, 180 IN UINTN NumBytes, 181 IN BOOLEAN Lock 182 ) 183 { 184 EFI_STATUS Status; 185 UINT8 SpiData; 186 UINT8 SpiStatus; 187 188 if (Lock) { 189 SpiData = SF_SR_WPE; 190 } else { 191 SpiData = 0; 192 } 193 194 // 195 // Always disable block protection to workaround tool issue. 196 // Feature may be re-enabled in a future bios. 197 // 198 SpiData = 0; 199 Status = mSpiProtocol->Execute ( 200 mSpiProtocol, 201 SPI_WRSR, 202 SPI_EWSR, 203 TRUE, 204 TRUE, 205 TRUE, 206 0, 207 1, 208 &SpiData, 209 EnumSpiRegionBios 210 ); 211 if (EFI_ERROR (Status)) { 212 return Status; 213 } 214 215 Status = ReadStatusRegister (&SpiStatus); 216 if (EFI_ERROR (Status)) { 217 return Status; 218 } 219 220 if ((SpiStatus & SpiData) != SpiData) { 221 Status = EFI_DEVICE_ERROR; 222 } 223 224 return Status; 225 } 226 227 228 /** 229 Read NumBytes bytes of data from the address specified by 230 PAddress into Buffer. 231 232 @param[in] PAddress The starting physical address of the read. 233 @param[in,out] NumBytes On input, the number of bytes to read. On output, the number 234 of bytes actually read. 235 @param[out] Buffer The destination data buffer for the read. 236 237 @retval EFI_SUCCESS. Opertion is successful. 238 @retval EFI_DEVICE_ERROR If there is any device errors. 239 240 **/ 241 EFI_STATUS 242 EFIAPI 243 LibFvbFlashDeviceRead ( 244 IN UINTN PAddress, 245 IN OUT UINTN *NumBytes, 246 OUT UINT8 *Buffer 247 ) 248 { 249 CopyMem(Buffer, (VOID*)PAddress, *NumBytes); 250 return EFI_SUCCESS; 251 } 252 253 254 /** 255 Write NumBytes bytes of data from Buffer to the address specified by 256 PAddresss. 257 258 @param[in] PAddress The starting physical address of the write. 259 @param[in,out] NumBytes On input, the number of bytes to write. On output, 260 the actual number of bytes written. 261 @param[in] Buffer The source data buffer for the write. 262 263 @retval EFI_SUCCESS. Opertion is successful. 264 @retval EFI_DEVICE_ERROR If there is any device errors. 265 266 **/ 267 EFI_STATUS 268 EFIAPI 269 LibFvbFlashDeviceWrite ( 270 IN UINTN PAddress, 271 IN OUT UINTN *NumBytes, 272 IN UINT8 *Buffer 273 ) 274 { 275 EFI_STATUS Status; 276 Status = SpiFlashWrite((UINT8 *)PAddress, Buffer, *NumBytes); 277 return Status; 278 } 279 280 281 /** 282 Erase the block staring at PAddress. 283 284 @param[in] PAddress The starting physical address of the block to be erased. 285 This library assume that caller garantee that the PAddress 286 is at the starting address of this block. 287 @param[in] LbaLength The length of the logical block to be erased. 288 289 @retval EFI_SUCCESS. Opertion is successful. 290 @retval EFI_DEVICE_ERROR If there is any device errors. 291 292 **/ 293 EFI_STATUS 294 EFIAPI 295 LibFvbFlashDeviceBlockErase ( 296 IN UINTN PAddress, 297 IN UINTN LbaLength 298 ) 299 { 300 EFI_STATUS Status; 301 Status = SpiFlashBlockErase((UINT8 *)PAddress, LbaLength); 302 303 return Status; 304 } 305 306 307 /** 308 Lock or unlock the block staring at PAddress. 309 310 @param[in] PAddress The starting physical address of region to be (un)locked. 311 @param[in] LbaLength The length of the logical block to be erased. 312 @param[in] Lock TRUE to lock. FALSE to unlock. 313 314 @retval EFI_SUCCESS. Opertion is successful. 315 @retval EFI_DEVICE_ERROR If there is any device errors. 316 317 **/ 318 EFI_STATUS 319 EFIAPI 320 LibFvbFlashDeviceBlockLock ( 321 IN UINTN PAddress, 322 IN UINTN LbaLength, 323 IN BOOLEAN Lock 324 ) 325 { 326 EFI_STATUS Status; 327 328 Status = SpiFlashLock((UINT8*)PAddress, LbaLength, Lock); 329 return Status; 330 } 331 332 VOID 333 EFIAPI 334 LibFvbFlashDeviceVirtualAddressChangeNotifyEvent ( 335 IN EFI_EVENT Event, 336 IN VOID *Context 337 ) 338 { 339 gRT->ConvertPointer (0, (VOID **) &mSpiProtocol); 340 gRT->ConvertPointer (0, (VOID **) &FlashDeviceBase); 341 } 342 343 344 /** 345 The library constructuor. 346 347 The function does the necessary initialization work for this library 348 instance. Please put all initialization works in it. 349 350 @param[in] ImageHandle The firmware allocated handle for the UEFI image. 351 @param[in] SystemTable A pointer to the EFI system table. 352 353 @retval EFI_SUCCESS The function always return EFI_SUCCESS for now. 354 It will ASSERT on error for debug version. 355 @retval EFI_ERROR Please reference LocateProtocol for error code details. 356 357 **/ 358 EFI_STATUS 359 EFIAPI 360 LibFvbFlashDeviceSupportInit ( 361 IN EFI_HANDLE ImageHandle, 362 IN EFI_SYSTEM_TABLE *SystemTable 363 ) 364 { 365 EFI_STATUS Status; 366 EFI_EVENT Event; 367 UINT8 SfId[3]; 368 UINT8 FlashIndex; 369 UINT8 SpiReadError; 370 UINT8 SpiNotMatchError; 371 EFI_SMM_BASE2_PROTOCOL *SmmBase; 372 BOOLEAN InSmm; 373 374 SpiReadError = 0x00; 375 SpiNotMatchError = 0x00; 376 377 InSmm = FALSE; 378 Status = gBS->LocateProtocol ( 379 &gEfiSmmBase2ProtocolGuid, 380 NULL, 381 (void **)&SmmBase 382 ); 383 if (!EFI_ERROR(Status)) { 384 Status = SmmBase->InSmm(SmmBase, &InSmm); 385 if (EFI_ERROR(Status)) { 386 InSmm = FALSE; 387 } 388 } 389 390 if (!InSmm) { 391 Status = gBS->LocateProtocol ( 392 &gEfiSpiProtocolGuid, 393 NULL, 394 (VOID **)&mSpiProtocol 395 ); 396 ASSERT_EFI_ERROR (Status); 397 398 Status = gBS->CreateEventEx ( 399 EVT_NOTIFY_SIGNAL, 400 TPL_NOTIFY, 401 LibFvbFlashDeviceVirtualAddressChangeNotifyEvent, 402 NULL, 403 &gEfiEventVirtualAddressChangeGuid, 404 &Event 405 ); 406 ASSERT_EFI_ERROR (Status); 407 } else { 408 Status = gBS->LocateProtocol ( 409 &gEfiSmmSpiProtocolGuid, 410 NULL, 411 (VOID **)&mSpiProtocol 412 ); 413 ASSERT_EFI_ERROR (Status); 414 } 415 416 417 for (FlashIndex = EnumSpiFlashW25Q64; FlashIndex < EnumSpiFlashMax; FlashIndex++) { 418 Status = mSpiProtocol->Init (mSpiProtocol, &(mInitTable[FlashIndex])); 419 if (!EFI_ERROR (Status)) { 420 // 421 // Read Vendor/Device IDs to check if the driver supports the Serial Flash device. 422 // 423 Status = mSpiProtocol->Execute ( 424 mSpiProtocol, 425 SPI_READ_ID, 426 SPI_WREN, 427 TRUE, 428 FALSE, 429 FALSE, 430 0, 431 3, 432 SfId, 433 EnumSpiRegionAll 434 ); 435 if (!EFI_ERROR (Status)) { 436 if ((SfId[0] == mInitTable[FlashIndex].VendorId) && 437 (SfId[1] == mInitTable[FlashIndex].DeviceId0) && 438 (SfId[2] == mInitTable[FlashIndex].DeviceId1)) { 439 // 440 // Found a matching SPI device, FlashIndex now contains flash device. 441 // 442 DEBUG ((EFI_D_ERROR, "OK - Found SPI Flash Type in SPI Flash Driver, Device Type ID 0 = 0x%02x!\n", mInitTable[FlashIndex].DeviceId0)); 443 DEBUG ((EFI_D_ERROR, "Device Type ID 1 = 0x%02x!\n", mInitTable[FlashIndex].DeviceId1)); 444 445 if (mInitTable[FlashIndex].BiosStartOffset == (UINTN) (-1)) { 446 DEBUG ((EFI_D_ERROR, "ERROR - The size of BIOS image is bigger than SPI Flash device!\n")); 447 CpuDeadLoop (); 448 } 449 break; 450 } else { 451 SpiNotMatchError++; 452 } 453 } else { 454 SpiReadError++; 455 } 456 } 457 } 458 459 DEBUG ((EFI_D_ERROR, "SPI flash chip VID = 0x%X, DID0 = 0x%X, DID1 = 0x%X\n", SfId[0], SfId[1], SfId[2])); 460 461 if (FlashIndex < EnumSpiFlashMax) { 462 return EFI_SUCCESS; 463 } else { 464 if (SpiReadError != 0) { 465 DEBUG ((EFI_D_ERROR, "ERROR - SPI Read ID execution failed! Error Count = %d\n", SpiReadError)); 466 } 467 else { 468 if (SpiNotMatchError != 0) { 469 DEBUG ((EFI_D_ERROR, "ERROR - No supported SPI flash chip found! Error Count = %d\n", SpiNotMatchError)); 470 DEBUG ((EFI_D_ERROR, "SPI flash chip VID = 0x%X, DID0 = 0x%X, DID1 = 0x%X\n", SfId[0], SfId[1], SfId[2])); 471 } 472 } 473 return EFI_UNSUPPORTED; 474 } 475 } 476 477