1 /** @file 2 3 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 **/ 13 14 #include "SdBlockIoPei.h" 15 16 // 17 // Template for SD HC Slot Data. 18 // 19 SD_PEIM_HC_SLOT gSdHcSlotTemplate = { 20 SD_PEIM_SLOT_SIG, // Signature 21 { // Media 22 MSG_SD_DP, 23 FALSE, 24 TRUE, 25 FALSE, 26 0x200, 27 0 28 }, 29 0, // SdHcBase 30 { // Capability 31 0, 32 }, 33 { // Csd 34 0, 35 }, 36 TRUE, // SectorAddressing 37 NULL // Private 38 }; 39 40 // 41 // Template for SD HC Private Data. 42 // 43 SD_PEIM_HC_PRIVATE_DATA gSdHcPrivateTemplate = { 44 SD_PEIM_SIG, // Signature 45 NULL, // Pool 46 { // BlkIoPpi 47 SdBlockIoPeimGetDeviceNo, 48 SdBlockIoPeimGetMediaInfo, 49 SdBlockIoPeimReadBlocks 50 }, 51 { // BlkIo2Ppi 52 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION, 53 SdBlockIoPeimGetDeviceNo2, 54 SdBlockIoPeimGetMediaInfo2, 55 SdBlockIoPeimReadBlocks2 56 }, 57 { // BlkIoPpiList 58 EFI_PEI_PPI_DESCRIPTOR_PPI, 59 &gEfiPeiVirtualBlockIoPpiGuid, 60 NULL 61 }, 62 { // BlkIo2PpiList 63 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, 64 &gEfiPeiVirtualBlockIo2PpiGuid, 65 NULL 66 }, 67 { // Slot 68 { 69 0, 70 }, 71 { 72 0, 73 }, 74 { 75 0, 76 }, 77 { 78 0, 79 }, 80 { 81 0, 82 }, 83 { 84 0, 85 } 86 }, 87 0, // SlotNum 88 0 // TotalBlkIoDevices 89 }; 90 /** 91 Gets the count of block I/O devices that one specific block driver detects. 92 93 This function is used for getting the count of block I/O devices that one 94 specific block driver detects. To the PEI ATAPI driver, it returns the number 95 of all the detected ATAPI devices it detects during the enumeration process. 96 To the PEI legacy floppy driver, it returns the number of all the legacy 97 devices it finds during its enumeration process. If no device is detected, 98 then the function will return zero. 99 100 @param[in] PeiServices General-purpose services that are available 101 to every PEIM. 102 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI 103 instance. 104 @param[out] NumberBlockDevices The number of block I/O devices discovered. 105 106 @retval EFI_SUCCESS The operation performed successfully. 107 108 **/ 109 EFI_STATUS 110 EFIAPI 111 SdBlockIoPeimGetDeviceNo ( 112 IN EFI_PEI_SERVICES **PeiServices, 113 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 114 OUT UINTN *NumberBlockDevices 115 ) 116 { 117 SD_PEIM_HC_PRIVATE_DATA *Private; 118 119 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); 120 *NumberBlockDevices = Private->TotalBlkIoDevices; 121 return EFI_SUCCESS; 122 } 123 124 /** 125 Gets a block device's media information. 126 127 This function will provide the caller with the specified block device's media 128 information. If the media changes, calling this function will update the media 129 information accordingly. 130 131 @param[in] PeiServices General-purpose services that are available to every 132 PEIM 133 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. 134 @param[in] DeviceIndex Specifies the block device to which the function wants 135 to talk. Because the driver that implements Block I/O 136 PPIs will manage multiple block devices, the PPIs that 137 want to talk to a single device must specify the 138 device index that was assigned during the enumeration 139 process. This index is a number from one to 140 NumberBlockDevices. 141 @param[out] MediaInfo The media information of the specified block media. 142 The caller is responsible for the ownership of this 143 data structure. 144 145 @par Note: 146 The MediaInfo structure describes an enumeration of possible block device 147 types. This enumeration exists because no device paths are actually passed 148 across interfaces that describe the type or class of hardware that is publishing 149 the block I/O interface. This enumeration will allow for policy decisions 150 in the Recovery PEIM, such as "Try to recover from legacy floppy first, 151 LS-120 second, CD-ROM third." If there are multiple partitions abstracted 152 by a given device type, they should be reported in ascending order; this 153 order also applies to nested partitions, such as legacy MBR, where the 154 outermost partitions would have precedence in the reporting order. The 155 same logic applies to systems such as IDE that have precedence relationships 156 like "Master/Slave" or "Primary/Secondary". The master device should be 157 reported first, the slave second. 158 159 @retval EFI_SUCCESS Media information about the specified block device 160 was obtained successfully. 161 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware 162 error. 163 164 **/ 165 EFI_STATUS 166 EFIAPI 167 SdBlockIoPeimGetMediaInfo ( 168 IN EFI_PEI_SERVICES **PeiServices, 169 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 170 IN UINTN DeviceIndex, 171 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo 172 ) 173 { 174 SD_PEIM_HC_PRIVATE_DATA *Private; 175 176 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); 177 178 if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) { 179 return EFI_INVALID_PARAMETER; 180 } 181 182 MediaInfo->DeviceType = SD; 183 MediaInfo->MediaPresent = TRUE; 184 MediaInfo->LastBlock = (UINTN)Private->Slot[DeviceIndex - 1].Media.LastBlock; 185 MediaInfo->BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize; 186 187 return EFI_SUCCESS; 188 } 189 190 /** 191 Reads the requested number of blocks from the specified block device. 192 193 The function reads the requested number of blocks from the device. All the 194 blocks are read, or an error is returned. If there is no media in the device, 195 the function returns EFI_NO_MEDIA. 196 197 @param[in] PeiServices General-purpose services that are available to 198 every PEIM. 199 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. 200 @param[in] DeviceIndex Specifies the block device to which the function wants 201 to talk. Because the driver that implements Block I/O 202 PPIs will manage multiple block devices, PPIs that 203 want to talk to a single device must specify the device 204 index that was assigned during the enumeration process. 205 This index is a number from one to NumberBlockDevices. 206 @param[in] StartLBA The starting logical block address (LBA) to read from 207 on the device 208 @param[in] BufferSize The size of the Buffer in bytes. This number must be 209 a multiple of the intrinsic block size of the device. 210 @param[out] Buffer A pointer to the destination buffer for the data. 211 The caller is responsible for the ownership of the 212 buffer. 213 214 @retval EFI_SUCCESS The data was read correctly from the device. 215 @retval EFI_DEVICE_ERROR The device reported an error while attempting 216 to perform the read operation. 217 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not 218 valid, or the buffer is not properly aligned. 219 @retval EFI_NO_MEDIA There is no media in the device. 220 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of 221 the intrinsic block size of the device. 222 223 **/ 224 EFI_STATUS 225 EFIAPI 226 SdBlockIoPeimReadBlocks ( 227 IN EFI_PEI_SERVICES **PeiServices, 228 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 229 IN UINTN DeviceIndex, 230 IN EFI_PEI_LBA StartLBA, 231 IN UINTN BufferSize, 232 OUT VOID *Buffer 233 ) 234 { 235 EFI_STATUS Status; 236 UINT32 BlockSize; 237 UINTN NumberOfBlocks; 238 SD_PEIM_HC_PRIVATE_DATA *Private; 239 UINTN Remaining; 240 UINT32 MaxBlock; 241 242 Status = EFI_SUCCESS; 243 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); 244 245 // 246 // Check parameters 247 // 248 if (Buffer == NULL) { 249 return EFI_INVALID_PARAMETER; 250 } 251 252 if (BufferSize == 0) { 253 return EFI_SUCCESS; 254 } 255 256 if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) { 257 return EFI_INVALID_PARAMETER; 258 } 259 260 BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize; 261 if (BufferSize % BlockSize != 0) { 262 return EFI_BAD_BUFFER_SIZE; 263 } 264 265 if (StartLBA > Private->Slot[DeviceIndex - 1].Media.LastBlock) { 266 return EFI_INVALID_PARAMETER; 267 } 268 269 NumberOfBlocks = BufferSize / BlockSize; 270 271 // 272 // Start to execute data transfer. The max block number in single cmd is 65535 blocks. 273 // 274 Remaining = NumberOfBlocks; 275 MaxBlock = 0xFFFF; 276 277 while (Remaining > 0) { 278 if (Remaining <= MaxBlock) { 279 NumberOfBlocks = Remaining; 280 } else { 281 NumberOfBlocks = MaxBlock; 282 } 283 284 BufferSize = NumberOfBlocks * BlockSize; 285 if (NumberOfBlocks != 1) { 286 Status = SdPeimRwMultiBlocks (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE); 287 } else { 288 Status = SdPeimRwSingleBlock (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE); 289 } 290 if (EFI_ERROR (Status)) { 291 return Status; 292 } 293 294 StartLBA += NumberOfBlocks; 295 Buffer = (UINT8*)Buffer + BufferSize; 296 Remaining -= NumberOfBlocks; 297 } 298 return Status; 299 } 300 301 /** 302 Gets the count of block I/O devices that one specific block driver detects. 303 304 This function is used for getting the count of block I/O devices that one 305 specific block driver detects. To the PEI ATAPI driver, it returns the number 306 of all the detected ATAPI devices it detects during the enumeration process. 307 To the PEI legacy floppy driver, it returns the number of all the legacy 308 devices it finds during its enumeration process. If no device is detected, 309 then the function will return zero. 310 311 @param[in] PeiServices General-purpose services that are available 312 to every PEIM. 313 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI 314 instance. 315 @param[out] NumberBlockDevices The number of block I/O devices discovered. 316 317 @retval EFI_SUCCESS The operation performed successfully. 318 319 **/ 320 EFI_STATUS 321 EFIAPI 322 SdBlockIoPeimGetDeviceNo2 ( 323 IN EFI_PEI_SERVICES **PeiServices, 324 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 325 OUT UINTN *NumberBlockDevices 326 ) 327 { 328 SD_PEIM_HC_PRIVATE_DATA *Private; 329 330 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); 331 *NumberBlockDevices = Private->TotalBlkIoDevices; 332 333 return EFI_SUCCESS; 334 } 335 336 /** 337 Gets a block device's media information. 338 339 This function will provide the caller with the specified block device's media 340 information. If the media changes, calling this function will update the media 341 information accordingly. 342 343 @param[in] PeiServices General-purpose services that are available to every 344 PEIM 345 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. 346 @param[in] DeviceIndex Specifies the block device to which the function wants 347 to talk. Because the driver that implements Block I/O 348 PPIs will manage multiple block devices, the PPIs that 349 want to talk to a single device must specify the 350 device index that was assigned during the enumeration 351 process. This index is a number from one to 352 NumberBlockDevices. 353 @param[out] MediaInfo The media information of the specified block media. 354 The caller is responsible for the ownership of this 355 data structure. 356 357 @par Note: 358 The MediaInfo structure describes an enumeration of possible block device 359 types. This enumeration exists because no device paths are actually passed 360 across interfaces that describe the type or class of hardware that is publishing 361 the block I/O interface. This enumeration will allow for policy decisions 362 in the Recovery PEIM, such as "Try to recover from legacy floppy first, 363 LS-120 second, CD-ROM third." If there are multiple partitions abstracted 364 by a given device type, they should be reported in ascending order; this 365 order also applies to nested partitions, such as legacy MBR, where the 366 outermost partitions would have precedence in the reporting order. The 367 same logic applies to systems such as IDE that have precedence relationships 368 like "Master/Slave" or "Primary/Secondary". The master device should be 369 reported first, the slave second. 370 371 @retval EFI_SUCCESS Media information about the specified block device 372 was obtained successfully. 373 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware 374 error. 375 376 **/ 377 EFI_STATUS 378 EFIAPI 379 SdBlockIoPeimGetMediaInfo2 ( 380 IN EFI_PEI_SERVICES **PeiServices, 381 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 382 IN UINTN DeviceIndex, 383 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo 384 ) 385 { 386 EFI_STATUS Status; 387 SD_PEIM_HC_PRIVATE_DATA *Private; 388 EFI_PEI_BLOCK_IO_MEDIA Media; 389 390 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); 391 392 Status = SdBlockIoPeimGetMediaInfo ( 393 PeiServices, 394 &Private->BlkIoPpi, 395 DeviceIndex, 396 &Media 397 ); 398 if (EFI_ERROR (Status)) { 399 return Status; 400 } 401 402 CopyMem (MediaInfo, &(Private->Slot[DeviceIndex - 1].Media), sizeof (EFI_PEI_BLOCK_IO2_MEDIA)); 403 return EFI_SUCCESS; 404 } 405 406 /** 407 Reads the requested number of blocks from the specified block device. 408 409 The function reads the requested number of blocks from the device. All the 410 blocks are read, or an error is returned. If there is no media in the device, 411 the function returns EFI_NO_MEDIA. 412 413 @param[in] PeiServices General-purpose services that are available to 414 every PEIM. 415 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. 416 @param[in] DeviceIndex Specifies the block device to which the function wants 417 to talk. Because the driver that implements Block I/O 418 PPIs will manage multiple block devices, PPIs that 419 want to talk to a single device must specify the device 420 index that was assigned during the enumeration process. 421 This index is a number from one to NumberBlockDevices. 422 @param[in] StartLBA The starting logical block address (LBA) to read from 423 on the device 424 @param[in] BufferSize The size of the Buffer in bytes. This number must be 425 a multiple of the intrinsic block size of the device. 426 @param[out] Buffer A pointer to the destination buffer for the data. 427 The caller is responsible for the ownership of the 428 buffer. 429 430 @retval EFI_SUCCESS The data was read correctly from the device. 431 @retval EFI_DEVICE_ERROR The device reported an error while attempting 432 to perform the read operation. 433 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not 434 valid, or the buffer is not properly aligned. 435 @retval EFI_NO_MEDIA There is no media in the device. 436 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of 437 the intrinsic block size of the device. 438 439 **/ 440 EFI_STATUS 441 EFIAPI 442 SdBlockIoPeimReadBlocks2 ( 443 IN EFI_PEI_SERVICES **PeiServices, 444 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 445 IN UINTN DeviceIndex, 446 IN EFI_PEI_LBA StartLBA, 447 IN UINTN BufferSize, 448 OUT VOID *Buffer 449 ) 450 { 451 EFI_STATUS Status; 452 SD_PEIM_HC_PRIVATE_DATA *Private; 453 454 Status = EFI_SUCCESS; 455 Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); 456 457 Status = SdBlockIoPeimReadBlocks ( 458 PeiServices, 459 &Private->BlkIoPpi, 460 DeviceIndex, 461 StartLBA, 462 BufferSize, 463 Buffer 464 ); 465 return Status; 466 } 467 468 /** 469 The user code starts with this function. 470 471 @param FileHandle Handle of the file being invoked. 472 @param PeiServices Describes the list of possible PEI Services. 473 474 @retval EFI_SUCCESS The driver is successfully initialized. 475 @retval Others Can't initialize the driver. 476 477 **/ 478 EFI_STATUS 479 EFIAPI 480 InitializeSdBlockIoPeim ( 481 IN EFI_PEI_FILE_HANDLE FileHandle, 482 IN CONST EFI_PEI_SERVICES **PeiServices 483 ) 484 { 485 EFI_STATUS Status; 486 SD_PEIM_HC_PRIVATE_DATA *Private; 487 EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi; 488 UINT32 Index; 489 UINTN *MmioBase; 490 UINT8 BarNum; 491 UINT8 SlotNum; 492 UINT8 Controller; 493 UINT64 Capacity; 494 SD_HC_SLOT_CAP Capability; 495 SD_PEIM_HC_SLOT *Slot; 496 SD_CSD *Csd; 497 SD_CSD2 *Csd2; 498 UINT32 CSize; 499 UINT32 CSizeMul; 500 UINT32 ReadBlLen; 501 502 // 503 // Shadow this PEIM to run from memory 504 // 505 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { 506 return EFI_SUCCESS; 507 } 508 509 // 510 // locate Sd host controller PPI 511 // 512 Status = PeiServicesLocatePpi ( 513 &gEdkiiPeiSdMmcHostControllerPpiGuid, 514 0, 515 NULL, 516 (VOID **) &SdMmcHcPpi 517 ); 518 if (EFI_ERROR (Status)) { 519 return EFI_DEVICE_ERROR; 520 } 521 522 Controller = 0; 523 MmioBase = NULL; 524 while (TRUE) { 525 Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum); 526 // 527 // When status is error, meant no controller is found 528 // 529 if (EFI_ERROR (Status)) { 530 break; 531 } 532 533 if (BarNum == 0) { 534 Controller++; 535 continue; 536 } 537 538 Private = AllocateCopyPool (sizeof (SD_PEIM_HC_PRIVATE_DATA), &gSdHcPrivateTemplate); 539 if (Private == NULL) { 540 Status = EFI_OUT_OF_RESOURCES; 541 break; 542 } 543 Private->BlkIoPpiList.Ppi = (VOID*)&Private->BlkIoPpi; 544 Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi; 545 // 546 // Initialize the memory pool which will be used in all transactions. 547 // 548 Status = SdPeimInitMemPool (Private); 549 if (EFI_ERROR (Status)) { 550 Status = EFI_OUT_OF_RESOURCES; 551 break; 552 } 553 554 for (Index = 0; Index < BarNum; Index++) { 555 Status = SdPeimHcGetCapability (MmioBase[Index], &Capability); 556 if (EFI_ERROR (Status)) { 557 continue; 558 } 559 if (Capability.SlotType != 0x1) { 560 DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index])); 561 Status = EFI_UNSUPPORTED; 562 continue; 563 } 564 565 Status = SdPeimHcReset (MmioBase[Index]); 566 if (EFI_ERROR (Status)) { 567 continue; 568 } 569 Status = SdPeimHcCardDetect (MmioBase[Index]); 570 if (EFI_ERROR (Status)) { 571 continue; 572 } 573 Status = SdPeimHcInitHost (MmioBase[Index]); 574 if (EFI_ERROR (Status)) { 575 continue; 576 } 577 578 SlotNum = Private->SlotNum; 579 Slot = &Private->Slot[SlotNum]; 580 CopyMem (Slot, &gSdHcSlotTemplate, sizeof (SD_PEIM_HC_SLOT)); 581 Slot->Private = Private; 582 Slot->SdHcBase = MmioBase[Index]; 583 CopyMem (&Slot->Capability, &Capability, sizeof (Capability)); 584 585 Status = SdPeimIdentification (Slot); 586 if (EFI_ERROR (Status)) { 587 continue; 588 } 589 590 Csd = &Slot->Csd; 591 if (Csd->CsdStructure == 0) { 592 Slot->SectorAddressing = FALSE; 593 CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1; 594 CSizeMul = (1 << (Csd->CSizeMul + 2)); 595 ReadBlLen = (1 << (Csd->ReadBlLen)); 596 Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen); 597 } else { 598 Slot->SectorAddressing = TRUE; 599 Csd2 = (SD_CSD2*)(VOID*)Csd; 600 CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1; 601 Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB); 602 } 603 604 Slot->Media.LastBlock = DivU64x32 (Capacity, Slot->Media.BlockSize) - 1; 605 606 Private->TotalBlkIoDevices++; 607 Private->SlotNum++; 608 } 609 610 Controller++; 611 if (!EFI_ERROR (Status)) { 612 PeiServicesInstallPpi (&Private->BlkIoPpiList); 613 } 614 } 615 616 return EFI_SUCCESS; 617 } 618