3 Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
8 #include "SdBlockIoPei.h"
11 // Template for SD HC Slot Data.
13 SD_PEIM_HC_SLOT gSdHcSlotTemplate
= {
14 SD_PEIM_SLOT_SIG
, // Signature
30 TRUE
, // SectorAddressing
35 // Template for SD HC Private Data.
37 SD_PEIM_HC_PRIVATE_DATA gSdHcPrivateTemplate
= {
38 SD_PEIM_SIG
, // Signature
41 SdBlockIoPeimGetDeviceNo
,
42 SdBlockIoPeimGetMediaInfo
,
43 SdBlockIoPeimReadBlocks
46 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
,
47 SdBlockIoPeimGetDeviceNo2
,
48 SdBlockIoPeimGetMediaInfo2
,
49 SdBlockIoPeimReadBlocks2
52 EFI_PEI_PPI_DESCRIPTOR_PPI
,
53 &gEfiPeiVirtualBlockIoPpiGuid
,
57 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
58 &gEfiPeiVirtualBlockIo2PpiGuid
,
62 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
63 &gEfiEndOfPeiSignalPpiGuid
,
87 0 // TotalBlkIoDevices
90 Gets the count of block I/O devices that one specific block driver detects.
92 This function is used for getting the count of block I/O devices that one
93 specific block driver detects. To the PEI ATAPI driver, it returns the number
94 of all the detected ATAPI devices it detects during the enumeration process.
95 To the PEI legacy floppy driver, it returns the number of all the legacy
96 devices it finds during its enumeration process. If no device is detected,
97 then the function will return zero.
99 @param[in] PeiServices General-purpose services that are available
101 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
103 @param[out] NumberBlockDevices The number of block I/O devices discovered.
105 @retval EFI_SUCCESS The operation performed successfully.
110 SdBlockIoPeimGetDeviceNo (
111 IN EFI_PEI_SERVICES
**PeiServices
,
112 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
113 OUT UINTN
*NumberBlockDevices
116 SD_PEIM_HC_PRIVATE_DATA
*Private
;
118 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
119 *NumberBlockDevices
= Private
->TotalBlkIoDevices
;
124 Gets a block device's media information.
126 This function will provide the caller with the specified block device's media
127 information. If the media changes, calling this function will update the media
128 information accordingly.
130 @param[in] PeiServices General-purpose services that are available to every
132 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
133 @param[in] DeviceIndex Specifies the block device to which the function wants
134 to talk. Because the driver that implements Block I/O
135 PPIs will manage multiple block devices, the PPIs that
136 want to talk to a single device must specify the
137 device index that was assigned during the enumeration
138 process. This index is a number from one to
140 @param[out] MediaInfo The media information of the specified block media.
141 The caller is responsible for the ownership of this
145 The MediaInfo structure describes an enumeration of possible block device
146 types. This enumeration exists because no device paths are actually passed
147 across interfaces that describe the type or class of hardware that is publishing
148 the block I/O interface. This enumeration will allow for policy decisions
149 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
150 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
151 by a given device type, they should be reported in ascending order; this
152 order also applies to nested partitions, such as legacy MBR, where the
153 outermost partitions would have precedence in the reporting order. The
154 same logic applies to systems such as IDE that have precedence relationships
155 like "Master/Slave" or "Primary/Secondary". The master device should be
156 reported first, the slave second.
158 @retval EFI_SUCCESS Media information about the specified block device
159 was obtained successfully.
160 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
166 SdBlockIoPeimGetMediaInfo (
167 IN EFI_PEI_SERVICES
**PeiServices
,
168 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
169 IN UINTN DeviceIndex
,
170 OUT EFI_PEI_BLOCK_IO_MEDIA
*MediaInfo
173 SD_PEIM_HC_PRIVATE_DATA
*Private
;
175 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
177 if ((DeviceIndex
== 0) || (DeviceIndex
> Private
->TotalBlkIoDevices
)) {
178 return EFI_INVALID_PARAMETER
;
181 MediaInfo
->DeviceType
= SD
;
182 MediaInfo
->MediaPresent
= TRUE
;
183 MediaInfo
->LastBlock
= (UINTN
)Private
->Slot
[DeviceIndex
- 1].Media
.LastBlock
;
184 MediaInfo
->BlockSize
= Private
->Slot
[DeviceIndex
- 1].Media
.BlockSize
;
190 Reads the requested number of blocks from the specified block device.
192 The function reads the requested number of blocks from the device. All the
193 blocks are read, or an error is returned. If there is no media in the device,
194 the function returns EFI_NO_MEDIA.
196 @param[in] PeiServices General-purpose services that are available to
198 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
199 @param[in] DeviceIndex Specifies the block device to which the function wants
200 to talk. Because the driver that implements Block I/O
201 PPIs will manage multiple block devices, PPIs that
202 want to talk to a single device must specify the device
203 index that was assigned during the enumeration process.
204 This index is a number from one to NumberBlockDevices.
205 @param[in] StartLBA The starting logical block address (LBA) to read from
207 @param[in] BufferSize The size of the Buffer in bytes. This number must be
208 a multiple of the intrinsic block size of the device.
209 @param[out] Buffer A pointer to the destination buffer for the data.
210 The caller is responsible for the ownership of the
213 @retval EFI_SUCCESS The data was read correctly from the device.
214 @retval EFI_DEVICE_ERROR The device reported an error while attempting
215 to perform the read operation.
216 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
217 valid, or the buffer is not properly aligned.
218 @retval EFI_NO_MEDIA There is no media in the device.
219 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
220 the intrinsic block size of the device.
225 SdBlockIoPeimReadBlocks (
226 IN EFI_PEI_SERVICES
**PeiServices
,
227 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
228 IN UINTN DeviceIndex
,
229 IN EFI_PEI_LBA StartLBA
,
236 UINTN NumberOfBlocks
;
237 SD_PEIM_HC_PRIVATE_DATA
*Private
;
241 Status
= EFI_SUCCESS
;
242 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
247 if (Buffer
== NULL
) {
248 return EFI_INVALID_PARAMETER
;
251 if (BufferSize
== 0) {
255 if ((DeviceIndex
== 0) || (DeviceIndex
> Private
->TotalBlkIoDevices
)) {
256 return EFI_INVALID_PARAMETER
;
259 BlockSize
= Private
->Slot
[DeviceIndex
- 1].Media
.BlockSize
;
260 if (BufferSize
% BlockSize
!= 0) {
261 return EFI_BAD_BUFFER_SIZE
;
264 if (StartLBA
> Private
->Slot
[DeviceIndex
- 1].Media
.LastBlock
) {
265 return EFI_INVALID_PARAMETER
;
268 NumberOfBlocks
= BufferSize
/ BlockSize
;
271 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
273 Remaining
= NumberOfBlocks
;
276 while (Remaining
> 0) {
277 if (Remaining
<= MaxBlock
) {
278 NumberOfBlocks
= Remaining
;
280 NumberOfBlocks
= MaxBlock
;
283 BufferSize
= NumberOfBlocks
* BlockSize
;
284 if (NumberOfBlocks
!= 1) {
285 Status
= SdPeimRwMultiBlocks (&Private
->Slot
[DeviceIndex
- 1], StartLBA
, BlockSize
, Buffer
, BufferSize
, TRUE
);
287 Status
= SdPeimRwSingleBlock (&Private
->Slot
[DeviceIndex
- 1], StartLBA
, BlockSize
, Buffer
, BufferSize
, TRUE
);
289 if (EFI_ERROR (Status
)) {
293 StartLBA
+= NumberOfBlocks
;
294 Buffer
= (UINT8
*)Buffer
+ BufferSize
;
295 Remaining
-= NumberOfBlocks
;
301 Gets the count of block I/O devices that one specific block driver detects.
303 This function is used for getting the count of block I/O devices that one
304 specific block driver detects. To the PEI ATAPI driver, it returns the number
305 of all the detected ATAPI devices it detects during the enumeration process.
306 To the PEI legacy floppy driver, it returns the number of all the legacy
307 devices it finds during its enumeration process. If no device is detected,
308 then the function will return zero.
310 @param[in] PeiServices General-purpose services that are available
312 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
314 @param[out] NumberBlockDevices The number of block I/O devices discovered.
316 @retval EFI_SUCCESS The operation performed successfully.
321 SdBlockIoPeimGetDeviceNo2 (
322 IN EFI_PEI_SERVICES
**PeiServices
,
323 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
324 OUT UINTN
*NumberBlockDevices
327 SD_PEIM_HC_PRIVATE_DATA
*Private
;
329 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
330 *NumberBlockDevices
= Private
->TotalBlkIoDevices
;
336 Gets a block device's media information.
338 This function will provide the caller with the specified block device's media
339 information. If the media changes, calling this function will update the media
340 information accordingly.
342 @param[in] PeiServices General-purpose services that are available to every
344 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
345 @param[in] DeviceIndex Specifies the block device to which the function wants
346 to talk. Because the driver that implements Block I/O
347 PPIs will manage multiple block devices, the PPIs that
348 want to talk to a single device must specify the
349 device index that was assigned during the enumeration
350 process. This index is a number from one to
352 @param[out] MediaInfo The media information of the specified block media.
353 The caller is responsible for the ownership of this
357 The MediaInfo structure describes an enumeration of possible block device
358 types. This enumeration exists because no device paths are actually passed
359 across interfaces that describe the type or class of hardware that is publishing
360 the block I/O interface. This enumeration will allow for policy decisions
361 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
362 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
363 by a given device type, they should be reported in ascending order; this
364 order also applies to nested partitions, such as legacy MBR, where the
365 outermost partitions would have precedence in the reporting order. The
366 same logic applies to systems such as IDE that have precedence relationships
367 like "Master/Slave" or "Primary/Secondary". The master device should be
368 reported first, the slave second.
370 @retval EFI_SUCCESS Media information about the specified block device
371 was obtained successfully.
372 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
378 SdBlockIoPeimGetMediaInfo2 (
379 IN EFI_PEI_SERVICES
**PeiServices
,
380 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
381 IN UINTN DeviceIndex
,
382 OUT EFI_PEI_BLOCK_IO2_MEDIA
*MediaInfo
386 SD_PEIM_HC_PRIVATE_DATA
*Private
;
387 EFI_PEI_BLOCK_IO_MEDIA Media
;
389 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
391 Status
= SdBlockIoPeimGetMediaInfo (
397 if (EFI_ERROR (Status
)) {
401 CopyMem (MediaInfo
, &(Private
->Slot
[DeviceIndex
- 1].Media
), sizeof (EFI_PEI_BLOCK_IO2_MEDIA
));
406 Reads the requested number of blocks from the specified block device.
408 The function reads the requested number of blocks from the device. All the
409 blocks are read, or an error is returned. If there is no media in the device,
410 the function returns EFI_NO_MEDIA.
412 @param[in] PeiServices General-purpose services that are available to
414 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
415 @param[in] DeviceIndex Specifies the block device to which the function wants
416 to talk. Because the driver that implements Block I/O
417 PPIs will manage multiple block devices, PPIs that
418 want to talk to a single device must specify the device
419 index that was assigned during the enumeration process.
420 This index is a number from one to NumberBlockDevices.
421 @param[in] StartLBA The starting logical block address (LBA) to read from
423 @param[in] BufferSize The size of the Buffer in bytes. This number must be
424 a multiple of the intrinsic block size of the device.
425 @param[out] Buffer A pointer to the destination buffer for the data.
426 The caller is responsible for the ownership of the
429 @retval EFI_SUCCESS The data was read correctly from the device.
430 @retval EFI_DEVICE_ERROR The device reported an error while attempting
431 to perform the read operation.
432 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
433 valid, or the buffer is not properly aligned.
434 @retval EFI_NO_MEDIA There is no media in the device.
435 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
436 the intrinsic block size of the device.
441 SdBlockIoPeimReadBlocks2 (
442 IN EFI_PEI_SERVICES
**PeiServices
,
443 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
444 IN UINTN DeviceIndex
,
445 IN EFI_PEI_LBA StartLBA
,
451 SD_PEIM_HC_PRIVATE_DATA
*Private
;
453 Status
= EFI_SUCCESS
;
454 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
456 Status
= SdBlockIoPeimReadBlocks (
468 One notified function to cleanup the allocated DMA buffers at the end of PEI.
470 @param[in] PeiServices Pointer to PEI Services Table.
471 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
472 event that caused this function to execute.
473 @param[in] Ppi Pointer to the PPI data associated with this function.
475 @retval EFI_SUCCESS The function completes successfully
480 SdBlockIoPeimEndOfPei (
481 IN EFI_PEI_SERVICES
**PeiServices
,
482 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
486 SD_PEIM_HC_PRIVATE_DATA
*Private
;
488 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor
);
490 if ((Private
->Pool
!= NULL
) && (Private
->Pool
->Head
!= NULL
)) {
491 SdPeimFreeMemPool (Private
->Pool
);
498 The user code starts with this function.
500 @param FileHandle Handle of the file being invoked.
501 @param PeiServices Describes the list of possible PEI Services.
503 @retval EFI_SUCCESS The driver is successfully initialized.
504 @retval Others Can't initialize the driver.
509 InitializeSdBlockIoPeim (
510 IN EFI_PEI_FILE_HANDLE FileHandle
,
511 IN CONST EFI_PEI_SERVICES
**PeiServices
515 SD_PEIM_HC_PRIVATE_DATA
*Private
;
516 EDKII_SD_MMC_HOST_CONTROLLER_PPI
*SdMmcHcPpi
;
523 SD_HC_SLOT_CAP Capability
;
524 SD_PEIM_HC_SLOT
*Slot
;
532 // Shadow this PEIM to run from memory
534 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
539 // locate Sd host controller PPI
541 Status
= PeiServicesLocatePpi (
542 &gEdkiiPeiSdMmcHostControllerPpiGuid
,
545 (VOID
**) &SdMmcHcPpi
547 if (EFI_ERROR (Status
)) {
548 return EFI_DEVICE_ERROR
;
556 Status
= SdMmcHcPpi
->GetSdMmcHcMmioBar (SdMmcHcPpi
, Controller
, &MmioBase
, &BarNum
);
558 // When status is error, meant no controller is found
560 if (EFI_ERROR (Status
)) {
569 Private
= AllocateCopyPool (sizeof (SD_PEIM_HC_PRIVATE_DATA
), &gSdHcPrivateTemplate
);
570 if (Private
== NULL
) {
571 Status
= EFI_OUT_OF_RESOURCES
;
574 Private
->BlkIoPpiList
.Ppi
= (VOID
*)&Private
->BlkIoPpi
;
575 Private
->BlkIo2PpiList
.Ppi
= (VOID
*)&Private
->BlkIo2Ppi
;
577 // Initialize the memory pool which will be used in all transactions.
579 Status
= SdPeimInitMemPool (Private
);
580 if (EFI_ERROR (Status
)) {
581 Status
= EFI_OUT_OF_RESOURCES
;
585 for (Index
= 0; Index
< BarNum
; Index
++) {
586 Status
= SdPeimHcGetCapability (MmioBase
[Index
], &Capability
);
587 if (EFI_ERROR (Status
)) {
590 if (Capability
.SlotType
!= 0x1) {
591 DEBUG ((EFI_D_INFO
, "The slot at 0x%x is not embedded slot type\n", MmioBase
[Index
]));
592 Status
= EFI_UNSUPPORTED
;
596 Status
= SdPeimHcReset (MmioBase
[Index
]);
597 if (EFI_ERROR (Status
)) {
600 Status
= SdPeimHcCardDetect (MmioBase
[Index
]);
601 if (EFI_ERROR (Status
)) {
604 Status
= SdPeimHcInitHost (MmioBase
[Index
]);
605 if (EFI_ERROR (Status
)) {
609 SlotNum
= Private
->SlotNum
;
610 Slot
= &Private
->Slot
[SlotNum
];
611 CopyMem (Slot
, &gSdHcSlotTemplate
, sizeof (SD_PEIM_HC_SLOT
));
612 Slot
->Private
= Private
;
613 Slot
->SdHcBase
= MmioBase
[Index
];
614 CopyMem (&Slot
->Capability
, &Capability
, sizeof (Capability
));
616 Status
= SdPeimIdentification (Slot
);
617 if (EFI_ERROR (Status
)) {
622 if (Csd
->CsdStructure
== 0) {
623 Slot
->SectorAddressing
= FALSE
;
624 CSize
= (Csd
->CSizeHigh
<< 2 | Csd
->CSizeLow
) + 1;
625 CSizeMul
= (1 << (Csd
->CSizeMul
+ 2));
626 ReadBlLen
= (1 << (Csd
->ReadBlLen
));
627 Capacity
= MultU64x32 (MultU64x32 ((UINT64
)CSize
, CSizeMul
), ReadBlLen
);
629 Slot
->SectorAddressing
= TRUE
;
630 Csd2
= (SD_CSD2
*)(VOID
*)Csd
;
631 CSize
= (Csd2
->CSizeHigh
<< 16 | Csd2
->CSizeLow
) + 1;
632 Capacity
= MultU64x32 ((UINT64
)CSize
, SIZE_512KB
);
635 Slot
->Media
.LastBlock
= DivU64x32 (Capacity
, Slot
->Media
.BlockSize
) - 1;
637 Private
->TotalBlkIoDevices
++;
642 if (!EFI_ERROR (Status
)) {
643 PeiServicesInstallPpi (&Private
->BlkIoPpiList
);
644 PeiServicesNotifyPpi (&Private
->EndOfPeiNotifyList
);
646 if (Private
->Pool
->Head
!= NULL
) {
647 SdPeimFreeMemPool (Private
->Pool
);