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
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.
14 #include "SdBlockIoPei.h"
17 // Template for SD HC Slot Data.
19 SD_PEIM_HC_SLOT gSdHcSlotTemplate
= {
20 SD_PEIM_SLOT_SIG
, // Signature
36 TRUE
, // SectorAddressing
41 // Template for SD HC Private Data.
43 SD_PEIM_HC_PRIVATE_DATA gSdHcPrivateTemplate
= {
44 SD_PEIM_SIG
, // Signature
47 SdBlockIoPeimGetDeviceNo
,
48 SdBlockIoPeimGetMediaInfo
,
49 SdBlockIoPeimReadBlocks
52 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
,
53 SdBlockIoPeimGetDeviceNo2
,
54 SdBlockIoPeimGetMediaInfo2
,
55 SdBlockIoPeimReadBlocks2
58 EFI_PEI_PPI_DESCRIPTOR_PPI
,
59 &gEfiPeiVirtualBlockIoPpiGuid
,
63 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
64 &gEfiPeiVirtualBlockIo2PpiGuid
,
88 0 // TotalBlkIoDevices
91 Gets the count of block I/O devices that one specific block driver detects.
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.
100 @param[in] PeiServices General-purpose services that are available
102 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
104 @param[out] NumberBlockDevices The number of block I/O devices discovered.
106 @retval EFI_SUCCESS The operation performed successfully.
111 SdBlockIoPeimGetDeviceNo (
112 IN EFI_PEI_SERVICES
**PeiServices
,
113 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
114 OUT UINTN
*NumberBlockDevices
117 SD_PEIM_HC_PRIVATE_DATA
*Private
;
119 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
120 *NumberBlockDevices
= Private
->TotalBlkIoDevices
;
125 Gets a block device's media information.
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.
131 @param[in] PeiServices General-purpose services that are available to every
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
141 @param[out] MediaInfo The media information of the specified block media.
142 The caller is responsible for the ownership of this
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.
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
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
174 SD_PEIM_HC_PRIVATE_DATA
*Private
;
176 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
178 if ((DeviceIndex
== 0) || (DeviceIndex
> Private
->TotalBlkIoDevices
)) {
179 return EFI_INVALID_PARAMETER
;
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
;
191 Reads the requested number of blocks from the specified block device.
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.
197 @param[in] PeiServices General-purpose services that are available to
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
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
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.
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
,
237 UINTN NumberOfBlocks
;
238 SD_PEIM_HC_PRIVATE_DATA
*Private
;
242 Status
= EFI_SUCCESS
;
243 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
248 if (Buffer
== NULL
) {
249 return EFI_INVALID_PARAMETER
;
252 if (BufferSize
== 0) {
256 if ((DeviceIndex
== 0) || (DeviceIndex
> Private
->TotalBlkIoDevices
)) {
257 return EFI_INVALID_PARAMETER
;
260 BlockSize
= Private
->Slot
[DeviceIndex
- 1].Media
.BlockSize
;
261 if (BufferSize
% BlockSize
!= 0) {
262 return EFI_BAD_BUFFER_SIZE
;
265 if (StartLBA
> Private
->Slot
[DeviceIndex
- 1].Media
.LastBlock
) {
266 return EFI_INVALID_PARAMETER
;
269 NumberOfBlocks
= BufferSize
/ BlockSize
;
272 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
274 Remaining
= NumberOfBlocks
;
277 while (Remaining
> 0) {
278 if (Remaining
<= MaxBlock
) {
279 NumberOfBlocks
= Remaining
;
281 NumberOfBlocks
= MaxBlock
;
284 BufferSize
= NumberOfBlocks
* BlockSize
;
285 if (NumberOfBlocks
!= 1) {
286 Status
= SdPeimRwMultiBlocks (&Private
->Slot
[DeviceIndex
- 1], StartLBA
, BlockSize
, Buffer
, BufferSize
, TRUE
);
288 Status
= SdPeimRwSingleBlock (&Private
->Slot
[DeviceIndex
- 1], StartLBA
, BlockSize
, Buffer
, BufferSize
, TRUE
);
290 if (EFI_ERROR (Status
)) {
294 StartLBA
+= NumberOfBlocks
;
295 Buffer
= (UINT8
*)Buffer
+ BufferSize
;
296 Remaining
-= NumberOfBlocks
;
302 Gets the count of block I/O devices that one specific block driver detects.
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.
311 @param[in] PeiServices General-purpose services that are available
313 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
315 @param[out] NumberBlockDevices The number of block I/O devices discovered.
317 @retval EFI_SUCCESS The operation performed successfully.
322 SdBlockIoPeimGetDeviceNo2 (
323 IN EFI_PEI_SERVICES
**PeiServices
,
324 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
325 OUT UINTN
*NumberBlockDevices
328 SD_PEIM_HC_PRIVATE_DATA
*Private
;
330 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
331 *NumberBlockDevices
= Private
->TotalBlkIoDevices
;
337 Gets a block device's media information.
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.
343 @param[in] PeiServices General-purpose services that are available to every
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
353 @param[out] MediaInfo The media information of the specified block media.
354 The caller is responsible for the ownership of this
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.
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
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
387 SD_PEIM_HC_PRIVATE_DATA
*Private
;
388 EFI_PEI_BLOCK_IO_MEDIA Media
;
390 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
392 Status
= SdBlockIoPeimGetMediaInfo (
398 if (EFI_ERROR (Status
)) {
402 CopyMem (MediaInfo
, &(Private
->Slot
[DeviceIndex
- 1].Media
), sizeof (EFI_PEI_BLOCK_IO2_MEDIA
));
407 Reads the requested number of blocks from the specified block device.
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.
413 @param[in] PeiServices General-purpose services that are available to
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
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
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.
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
,
452 SD_PEIM_HC_PRIVATE_DATA
*Private
;
454 Status
= EFI_SUCCESS
;
455 Private
= GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
457 Status
= SdBlockIoPeimReadBlocks (
469 The user code starts with this function.
471 @param FileHandle Handle of the file being invoked.
472 @param PeiServices Describes the list of possible PEI Services.
474 @retval EFI_SUCCESS The driver is successfully initialized.
475 @retval Others Can't initialize the driver.
480 InitializeSdBlockIoPeim (
481 IN EFI_PEI_FILE_HANDLE FileHandle
,
482 IN CONST EFI_PEI_SERVICES
**PeiServices
486 SD_PEIM_HC_PRIVATE_DATA
*Private
;
487 EDKII_SD_MMC_HOST_CONTROLLER_PPI
*SdMmcHcPpi
;
494 SD_HC_SLOT_CAP Capability
;
495 SD_PEIM_HC_SLOT
*Slot
;
503 // Shadow this PEIM to run from memory
505 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
510 // locate Sd host controller PPI
512 Status
= PeiServicesLocatePpi (
513 &gEdkiiPeiSdMmcHostControllerPpiGuid
,
516 (VOID
**) &SdMmcHcPpi
518 if (EFI_ERROR (Status
)) {
519 return EFI_DEVICE_ERROR
;
525 Status
= SdMmcHcPpi
->GetSdMmcHcMmioBar (SdMmcHcPpi
, Controller
, &MmioBase
, &BarNum
);
527 // When status is error, meant no controller is found
529 if (EFI_ERROR (Status
)) {
538 Private
= AllocateCopyPool (sizeof (SD_PEIM_HC_PRIVATE_DATA
), &gSdHcPrivateTemplate
);
539 if (Private
== NULL
) {
540 Status
= EFI_OUT_OF_RESOURCES
;
543 Private
->BlkIoPpiList
.Ppi
= (VOID
*)&Private
->BlkIoPpi
;
544 Private
->BlkIo2PpiList
.Ppi
= (VOID
*)&Private
->BlkIo2Ppi
;
546 // Initialize the memory pool which will be used in all transactions.
548 Status
= SdPeimInitMemPool (Private
);
549 if (EFI_ERROR (Status
)) {
550 Status
= EFI_OUT_OF_RESOURCES
;
554 for (Index
= 0; Index
< BarNum
; Index
++) {
555 Status
= SdPeimHcGetCapability (MmioBase
[Index
], &Capability
);
556 if (EFI_ERROR (Status
)) {
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
;
565 Status
= SdPeimHcReset (MmioBase
[Index
]);
566 if (EFI_ERROR (Status
)) {
569 Status
= SdPeimHcCardDetect (MmioBase
[Index
]);
570 if (EFI_ERROR (Status
)) {
573 Status
= SdPeimHcInitHost (MmioBase
[Index
]);
574 if (EFI_ERROR (Status
)) {
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
));
585 Status
= SdPeimIdentification (Slot
);
586 if (EFI_ERROR (Status
)) {
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
);
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
);
604 Slot
->Media
.LastBlock
= DivU64x32 (Capacity
, Slot
->Media
.BlockSize
) - 1;
606 Private
->TotalBlkIoDevices
++;
611 if (!EFI_ERROR (Status
)) {
612 PeiServicesInstallPpi (&Private
->BlkIoPpiList
);