]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AhciPei / AhciPei.c
1 /** @file
2 The AhciPei driver is used to manage ATA hard disk device working under AHCI
3 mode at PEI phase.
4
5 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "AhciPei.h"
12 #include <Ppi/PciDevice.h>
13 #include <Library/DevicePathLib.h>
14 #include <IndustryStandard/Pci.h>
15
16 EFI_PEI_PPI_DESCRIPTOR mAhciAtaPassThruPpiListTemplate = {
17 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
18 &gEdkiiPeiAtaPassThruPpiGuid,
19 NULL
20 };
21
22 EFI_PEI_PPI_DESCRIPTOR mAhciBlkIoPpiListTemplate = {
23 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
24 &gEfiPeiVirtualBlockIoPpiGuid,
25 NULL
26 };
27
28 EFI_PEI_PPI_DESCRIPTOR mAhciBlkIo2PpiListTemplate = {
29 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
30 &gEfiPeiVirtualBlockIo2PpiGuid,
31 NULL
32 };
33
34 EFI_PEI_PPI_DESCRIPTOR mAhciStorageSecurityPpiListTemplate = {
35 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
36 &gEdkiiPeiStorageSecurityCommandPpiGuid,
37 NULL
38 };
39
40 EFI_PEI_NOTIFY_DESCRIPTOR mAhciEndOfPeiNotifyListTemplate = {
41 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
42 &gEfiEndOfPeiSignalPpiGuid,
43 AhciPeimEndOfPei
44 };
45
46 EFI_PEI_NOTIFY_DESCRIPTOR mAtaAhciHostControllerNotify = {
47 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
48 &gEdkiiPeiAtaAhciHostControllerPpiGuid,
49 AtaAhciHostControllerPpiInstallationCallback
50 };
51
52 EFI_PEI_NOTIFY_DESCRIPTOR mPciDevicePpiNotify = {
53 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
54 &gEdkiiPeiPciDevicePpiGuid,
55 AtaAhciPciDevicePpiInstallationCallback
56 };
57
58 /**
59 Free the DMA resources allocated by an ATA AHCI controller.
60
61 @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA data
62 structure.
63
64 **/
65 VOID
66 AhciFreeDmaResource (
67 IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private
68 )
69 {
70 EFI_AHCI_REGISTERS *AhciRegisters;
71
72 ASSERT (Private != NULL);
73
74 AhciRegisters = &Private->AhciRegisters;
75
76 if (AhciRegisters->AhciRFisMap != NULL) {
77 IoMmuFreeBuffer (
78 EFI_SIZE_TO_PAGES (AhciRegisters->MaxRFisSize),
79 AhciRegisters->AhciRFis,
80 AhciRegisters->AhciRFisMap
81 );
82 }
83
84 if (AhciRegisters->AhciCmdListMap != NULL) {
85 IoMmuFreeBuffer (
86 EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdListSize),
87 AhciRegisters->AhciCmdList,
88 AhciRegisters->AhciCmdListMap
89 );
90 }
91
92 if (AhciRegisters->AhciCmdTableMap != NULL) {
93 IoMmuFreeBuffer (
94 EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdTableSize),
95 AhciRegisters->AhciCmdTable,
96 AhciRegisters->AhciCmdTableMap
97 );
98 }
99 }
100
101 /**
102 One notified function to cleanup the allocated DMA buffers at EndOfPei.
103
104 @param[in] PeiServices Pointer to PEI Services Table.
105 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
106 event that caused this function to execute.
107 @param[in] Ppi Pointer to the PPI data associated with this function.
108
109 @retval EFI_SUCCESS The function completes successfully
110
111 **/
112 EFI_STATUS
113 EFIAPI
114 AhciPeimEndOfPei (
115 IN EFI_PEI_SERVICES **PeiServices,
116 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
117 IN VOID *Ppi
118 )
119 {
120 PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
121
122 Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
123 AhciFreeDmaResource (Private);
124
125 return EFI_SUCCESS;
126 }
127
128 /**
129 Initialize and install PrivateData PPIs.
130
131 @param[in] MmioBase MMIO base address of specific AHCI controller
132 @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
133 structure.
134 @param[in] DevicePathLength Length of the device path.
135
136 @retval EFI_SUCCESS AHCI controller initialized and PPIs installed
137 @retval others Failed to initialize AHCI controller
138 **/
139 EFI_STATUS
140 AtaAhciInitPrivateData (
141 IN UINTN MmioBase,
142 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
143 IN UINTN DevicePathLength
144 )
145 {
146 EFI_STATUS Status;
147 UINT32 PortBitMap;
148 UINT8 NumberOfPorts;
149 PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
150 EFI_BOOT_MODE BootMode;
151
152 DEBUG ((DEBUG_INFO, "Initializing private data for ATA\n"));
153
154 //
155 // Get the current boot mode.
156 //
157 Status = PeiServicesGetBootMode (&BootMode);
158 if (EFI_ERROR (Status)) {
159 DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));
160 return Status;
161 }
162
163 //
164 // Check validity of the device path of the ATA AHCI controller.
165 //
166 Status = AhciIsHcDevicePathValid (DevicePath, DevicePathLength);
167 if (EFI_ERROR (Status)) {
168 DEBUG ((
169 DEBUG_ERROR,
170 "%a: The device path is invalid.\n",
171 __FUNCTION__
172 ));
173 return Status;
174 }
175
176 //
177 // For S3 resume performance consideration, not all ports on an ATA AHCI
178 // controller will be enumerated/initialized. The driver consumes the
179 // content within S3StorageDeviceInitList LockBox to get the ports that
180 // will be enumerated/initialized during S3 resume.
181 //
182 if (BootMode == BOOT_ON_S3_RESUME) {
183 NumberOfPorts = AhciS3GetEumeratePorts (DevicePath, DevicePathLength, &PortBitMap);
184 if (NumberOfPorts == 0) {
185 return EFI_SUCCESS;
186 }
187 } else {
188 PortBitMap = MAX_UINT32;
189 }
190
191 //
192 // Memory allocation for controller private data.
193 //
194 Private = AllocateZeroPool (sizeof (PEI_AHCI_CONTROLLER_PRIVATE_DATA));
195 if (Private == NULL) {
196 DEBUG ((
197 DEBUG_ERROR,
198 "%a: Fail to allocate private data.\n",
199 __FUNCTION__
200 ));
201 return EFI_OUT_OF_RESOURCES;
202 }
203
204 //
205 // Initialize controller private data.
206 //
207 Private->Signature = AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;
208 Private->MmioBase = MmioBase;
209 Private->DevicePathLength = DevicePathLength;
210 Private->DevicePath = DevicePath;
211 Private->PortBitMap = PortBitMap;
212 InitializeListHead (&Private->DeviceList);
213
214 Status = AhciModeInitialization (Private);
215 if (EFI_ERROR (Status)) {
216 return Status;
217 }
218
219 Private->AtaPassThruMode.Attributes = EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL |
220 EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL;
221 Private->AtaPassThruMode.IoAlign = sizeof (UINTN);
222 Private->AtaPassThruPpi.Revision = EDKII_PEI_ATA_PASS_THRU_PPI_REVISION;
223 Private->AtaPassThruPpi.Mode = &Private->AtaPassThruMode;
224 Private->AtaPassThruPpi.PassThru = AhciAtaPassThruPassThru;
225 Private->AtaPassThruPpi.GetNextPort = AhciAtaPassThruGetNextPort;
226 Private->AtaPassThruPpi.GetNextDevice = AhciAtaPassThruGetNextDevice;
227 Private->AtaPassThruPpi.GetDevicePath = AhciAtaPassThruGetDevicePath;
228 CopyMem (
229 &Private->AtaPassThruPpiList,
230 &mAhciAtaPassThruPpiListTemplate,
231 sizeof (EFI_PEI_PPI_DESCRIPTOR)
232 );
233 Private->AtaPassThruPpiList.Ppi = &Private->AtaPassThruPpi;
234 PeiServicesInstallPpi (&Private->AtaPassThruPpiList);
235
236 Private->BlkIoPpi.GetNumberOfBlockDevices = AhciBlockIoGetDeviceNo;
237 Private->BlkIoPpi.GetBlockDeviceMediaInfo = AhciBlockIoGetMediaInfo;
238 Private->BlkIoPpi.ReadBlocks = AhciBlockIoReadBlocks;
239 CopyMem (
240 &Private->BlkIoPpiList,
241 &mAhciBlkIoPpiListTemplate,
242 sizeof (EFI_PEI_PPI_DESCRIPTOR)
243 );
244 Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;
245 PeiServicesInstallPpi (&Private->BlkIoPpiList);
246
247 Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;
248 Private->BlkIo2Ppi.GetNumberOfBlockDevices = AhciBlockIoGetDeviceNo2;
249 Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = AhciBlockIoGetMediaInfo2;
250 Private->BlkIo2Ppi.ReadBlocks = AhciBlockIoReadBlocks2;
251 CopyMem (
252 &Private->BlkIo2PpiList,
253 &mAhciBlkIo2PpiListTemplate,
254 sizeof (EFI_PEI_PPI_DESCRIPTOR)
255 );
256 Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
257 PeiServicesInstallPpi (&Private->BlkIo2PpiList);
258
259 if (Private->TrustComputingDevices != 0) {
260 DEBUG ((
261 DEBUG_INFO,
262 "%a: Security Security Command PPI will be produced.\n",
263 __FUNCTION__
264 ));
265 Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION;
266 Private->StorageSecurityPpi.GetNumberofDevices = AhciStorageSecurityGetDeviceNo;
267 Private->StorageSecurityPpi.GetDevicePath = AhciStorageSecurityGetDevicePath;
268 Private->StorageSecurityPpi.ReceiveData = AhciStorageSecurityReceiveData;
269 Private->StorageSecurityPpi.SendData = AhciStorageSecuritySendData;
270 CopyMem (
271 &Private->StorageSecurityPpiList,
272 &mAhciStorageSecurityPpiListTemplate,
273 sizeof (EFI_PEI_PPI_DESCRIPTOR)
274 );
275 Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi;
276 PeiServicesInstallPpi (&Private->StorageSecurityPpiList);
277 }
278
279 CopyMem (
280 &Private->EndOfPeiNotifyList,
281 &mAhciEndOfPeiNotifyListTemplate,
282 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)
283 );
284 PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
285
286 return EFI_SUCCESS;
287 }
288
289 /**
290 Initialize AHCI controller from EDKII_ATA_AHCI_HOST_CONTROLLER_PPI instance.
291
292 @param[in] AhciHcPpi Pointer to the AHCI Host Controller PPI instance.
293
294 @retval EFI_SUCCESS PPI successfully installed.
295 **/
296 EFI_STATUS
297 AtaAhciInitPrivateDataFromHostControllerPpi (
298 IN EDKII_ATA_AHCI_HOST_CONTROLLER_PPI *AhciHcPpi
299 )
300 {
301 UINT8 Controller;
302 UINTN MmioBase;
303 UINTN DevicePathLength;
304 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
305 EFI_STATUS Status;
306
307 Controller = 0;
308 MmioBase = 0;
309 while (TRUE) {
310 Status = AhciHcPpi->GetAhciHcMmioBar (
311 AhciHcPpi,
312 Controller,
313 &MmioBase
314 );
315 //
316 // When status is error, meant no controller is found.
317 //
318 if (EFI_ERROR (Status)) {
319 break;
320 }
321
322 Status = AhciHcPpi->GetAhciHcDevicePath (
323 AhciHcPpi,
324 Controller,
325 &DevicePathLength,
326 &DevicePath
327 );
328 if (EFI_ERROR (Status)) {
329 DEBUG ((
330 DEBUG_ERROR,
331 "%a: Fail to allocate get the device path for Controller %d.\n",
332 __FUNCTION__,
333 Controller
334 ));
335 return Status;
336 }
337
338 Status = AtaAhciInitPrivateData (MmioBase, DevicePath, DevicePathLength);
339 if (EFI_ERROR (Status)) {
340 DEBUG ((
341 DEBUG_ERROR,
342 "%a: Controller initialization fail for Controller %d with Status - %r.\n",
343 __FUNCTION__,
344 Controller,
345 Status
346 ));
347 } else {
348 DEBUG ((
349 DEBUG_INFO,
350 "%a: Controller %d has been successfully initialized.\n",
351 __FUNCTION__,
352 Controller
353 ));
354 }
355
356 Controller++;
357 }
358
359 return EFI_SUCCESS;
360 }
361
362 /**
363 Callback for EDKII_ATA_AHCI_HOST_CONTROLLER_PPI installation.
364
365 @param[in] PeiServices Pointer to PEI Services Table.
366 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
367 event that caused this function to execute.
368 @param[in] Ppi Pointer to the PPI data associated with this function.
369
370 @retval EFI_SUCCESS The function completes successfully
371 @retval Others Cannot initialize AHCI controller from given EDKII_ATA_AHCI_HOST_CONTROLLER_PPI
372
373 **/
374 EFI_STATUS
375 EFIAPI
376 AtaAhciHostControllerPpiInstallationCallback (
377 IN EFI_PEI_SERVICES **PeiServices,
378 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
379 IN VOID *Ppi
380 )
381 {
382 EDKII_ATA_AHCI_HOST_CONTROLLER_PPI *AhciHcPpi;
383
384 if (Ppi == NULL) {
385 return EFI_INVALID_PARAMETER;
386 }
387
388 AhciHcPpi = (EDKII_ATA_AHCI_HOST_CONTROLLER_PPI *)Ppi;
389
390 return AtaAhciInitPrivateDataFromHostControllerPpi (AhciHcPpi);
391 }
392
393 /**
394 Initialize AHCI controller from fiven PCI_DEVICE_PPI.
395
396 @param[in] PciDevice Pointer to the PCI Device PPI instance.
397
398 @retval EFI_SUCCESS The function completes successfully
399 @retval Others Cannot initialize AHCI controller for given device
400 **/
401 EFI_STATUS
402 AtaAhciInitPrivateDataFromPciDevice (
403 EDKII_PCI_DEVICE_PPI *PciDevice
404 )
405 {
406 EFI_STATUS Status;
407 PCI_TYPE00 PciData;
408 UINT32 MmioBase;
409 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
410 UINTN DevicePathLength;
411 UINT64 EnabledPciAttributes;
412
413 //
414 // Now further check the PCI header: Base Class (offset 0x0B) and
415 // Sub Class (offset 0x0A). This controller should be an SATA controller
416 //
417 Status = PciDevice->PciIo.Pci.Read (
418 &PciDevice->PciIo,
419 EfiPciIoWidthUint8,
420 PCI_CLASSCODE_OFFSET,
421 sizeof (PciData.Hdr.ClassCode),
422 PciData.Hdr.ClassCode
423 );
424 if (EFI_ERROR (Status)) {
425 return EFI_UNSUPPORTED;
426 }
427
428 if (!IS_PCI_IDE (&PciData) && !IS_PCI_SATADPA (&PciData)) {
429 return EFI_UNSUPPORTED;
430 }
431
432 Status = PciDevice->PciIo.Attributes (
433 &PciDevice->PciIo,
434 EfiPciIoAttributeOperationSupported,
435 0,
436 &EnabledPciAttributes
437 );
438 if (EFI_ERROR (Status)) {
439 return EFI_UNSUPPORTED;
440 } else {
441 EnabledPciAttributes &= (UINT64)EFI_PCI_DEVICE_ENABLE;
442 Status = PciDevice->PciIo.Attributes (
443 &PciDevice->PciIo,
444 EfiPciIoAttributeOperationEnable,
445 EnabledPciAttributes,
446 NULL
447 );
448 if (EFI_ERROR (Status)) {
449 return EFI_UNSUPPORTED;
450 }
451 }
452
453 Status = PciDevice->PciIo.Pci.Read (
454 &PciDevice->PciIo,
455 EfiPciIoWidthUint32,
456 0x24,
457 1,
458 &MmioBase
459 );
460 if (EFI_ERROR (Status)) {
461 return EFI_UNSUPPORTED;
462 }
463
464 MmioBase &= 0xFFFFFFF0;
465
466 DevicePathLength = GetDevicePathSize (PciDevice->DevicePath);
467 DevicePath = PciDevice->DevicePath;
468
469 Status = AtaAhciInitPrivateData (MmioBase, DevicePath, DevicePathLength);
470 if (EFI_ERROR (Status)) {
471 DEBUG ((
472 DEBUG_INFO,
473 "%a: Failed to init controller, with Status - %r\n",
474 __FUNCTION__,
475 Status
476 ));
477 }
478
479 return EFI_SUCCESS;
480 }
481
482 /**
483 Callback for EDKII_PCI_DEVICE_PPI installation.
484
485 @param[in] PeiServices Pointer to PEI Services Table.
486 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
487 event that caused this function to execute.
488 @param[in] Ppi Pointer to the PPI data associated with this function.
489
490 @retval EFI_SUCCESS The function completes successfully
491 @retval Others Cannot initialize AHCI controller from given PCI_DEVICE_PPI
492
493 **/
494 EFI_STATUS
495 EFIAPI
496 AtaAhciPciDevicePpiInstallationCallback (
497 IN EFI_PEI_SERVICES **PeiServices,
498 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
499 IN VOID *Ppi
500 )
501 {
502 EDKII_PCI_DEVICE_PPI *PciDevice;
503
504 PciDevice = (EDKII_PCI_DEVICE_PPI *)Ppi;
505
506 return AtaAhciInitPrivateDataFromPciDevice (PciDevice);
507 }
508
509 /**
510 Entry point of the PEIM.
511
512 @param[in] FileHandle Handle of the file being invoked.
513 @param[in] PeiServices Describes the list of possible PEI Services.
514
515 @retval EFI_SUCCESS PPI successfully installed.
516
517 **/
518 EFI_STATUS
519 EFIAPI
520 AtaAhciPeimEntry (
521 IN EFI_PEI_FILE_HANDLE FileHandle,
522 IN CONST EFI_PEI_SERVICES **PeiServices
523 )
524 {
525 DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));
526
527 PeiServicesNotifyPpi (&mAtaAhciHostControllerNotify);
528
529 PeiServicesNotifyPpi (&mPciDevicePpiNotify);
530
531 return EFI_SUCCESS;
532 }