| /** @file | |
| SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP) | |
| SMM driver. | |
| Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| @par Revision Reference: | |
| - JEDEC Standard, JESD216F.02 | |
| https://www.jedec.org/document_search?search_api_views_fulltext=JESD216 | |
| @par Glossary: | |
| - SFDP - Serial Flash Discoverable Parameters | |
| - PTP - Parameter Table Pointer | |
| **/ | |
| #include <Base.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/SmmServicesTableLib.h> | |
| #include <Protocol/SpiSmmConfiguration.h> | |
| #include <Protocol/SpiSmmNorFlash.h> | |
| #include <Protocol/SpiIo.h> | |
| #include <IndustryStandard/SpiNorFlashJedecSfdp.h> | |
| #include "SpiNorFlash.h" | |
| #include "SpiNorFlashJedecSfdpInternal.h" | |
| /** | |
| Function to create SPI_NOR_FLASH_INSTANCE for this SPI part. | |
| @param[in] SpiIoHandle The handle with SPI I/O protocol installed. | |
| @retval EFI_SUCCESS Succeed. | |
| @retval EFI_OUT_OF_RESOURCES Not enough resource to create SPI_NOR_FLASH_INSTANCE. | |
| @retval otherwise Fail to create SPI NOR Flash SFDP Instance | |
| **/ | |
| EFI_STATUS | |
| CreateSpiNorFlashSfdpInstance ( | |
| IN EFI_HANDLE SpiIoHandle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| SPI_NOR_FLASH_INSTANCE *Instance; | |
| // Allocate SPI_NOR_FLASH_INSTANCE Instance. | |
| Instance = AllocateZeroPool (sizeof (SPI_NOR_FLASH_INSTANCE)); | |
| ASSERT (Instance != NULL); | |
| if (Instance == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // Locate the SPI IO Protocol. | |
| Status = gSmst->SmmHandleProtocol ( | |
| SpiIoHandle, | |
| &gEdk2JedecSfdpSpiSmmDriverGuid, | |
| (VOID **)&Instance->SpiIo | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to locate SPI I/O protocol.\n", __func__)); | |
| FreePool (Instance); | |
| } else { | |
| Status = InitialSpiNorFlashSfdpInstance (Instance); | |
| ASSERT_EFI_ERROR (Status); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to initial SPI_NOR_FLASH_INSTANCE.\n", __func__)); | |
| FreePool (Instance); | |
| } else { | |
| // Install SPI NOR Flash Protocol. | |
| Status = gSmst->SmmInstallProtocolInterface ( | |
| &Instance->Handle, | |
| &gEfiSpiSmmNorFlashProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| &Instance->Protocol | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to Install gEfiSpiSmmNorFlashProtocolGuid protocol.\n", __func__)); | |
| FreePool (Instance); | |
| } | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Callback function executed when the EFI_SPI_IO_PROTOCOL | |
| protocol interface is installed. | |
| @param[in] Protocol Points to the protocol's unique identifier. | |
| @param[in] Interface Points to the interface instance. | |
| @param[in] Handle The handle on which the interface was installed. | |
| @return Status Code | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SpiIoProtocolInstalledCallback ( | |
| IN CONST EFI_GUID *Protocol, | |
| IN VOID *Interface, | |
| IN EFI_HANDLE Handle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| DEBUG ((DEBUG_INFO, "%a: Entry.\n", __func__)); | |
| Status = CreateSpiNorFlashSfdpInstance (Handle); | |
| return Status; | |
| } | |
| /** | |
| Register notification for the later installed SPI I/O protocol. | |
| @retval EFI_SUCCESS Succeed. | |
| @retval otherwise Fail to register the notification of | |
| SPI I/O protocol installation. | |
| **/ | |
| EFI_STATUS | |
| RegisterSpioProtocolNotification ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| VOID *Registration; | |
| Status = gSmst->SmmRegisterProtocolNotify ( | |
| &gEdk2JedecSfdpSpiSmmDriverGuid, | |
| SpiIoProtocolInstalledCallback, | |
| &Registration | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the SPI I/O Protocol installation.", __func__)); | |
| } else { | |
| DEBUG ((DEBUG_INFO, "%a: Notification for SPI I/O Protocol installation was registered.", __func__)); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Entry point of the SPI NOR Flash SFDP SMM driver. | |
| @param ImageHandle Image handle of this driver. | |
| @param SystemTable Pointer to standard EFI system table. | |
| @retval EFI_SUCCESS Succeed. | |
| @retval EFI_NOT_FOUND No gEdk2JedecSfdpSpiSmmDriverGuid installed on | |
| system yet. | |
| @retval EFI_OUT_OF_RESOURCES Not enough resource for SPI NOR Flash JEDEC SFDP | |
| initialization. | |
| @retval Otherwise Other errors. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SpiNorFlashJedecSfdpSmmEntry ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE *InstanceBuffer; | |
| UINTN InstanceIndex; | |
| UINTN InstanceBufferSize; | |
| DEBUG ((DEBUG_INFO, "%a - ENTRY.\n", __func__)); | |
| // | |
| // Register notification for the later SPI I/O protocol installation. | |
| // | |
| RegisterSpioProtocolNotification (); | |
| DEBUG ((DEBUG_INFO, "Check if there were already some gEdk2JedecSfdpSpiSmmDriverGuid handles installed.\n")); | |
| // | |
| // Check if there were already some gEdk2JedecSfdpSpiSmmDriverGuid | |
| // handles installed. | |
| // | |
| // Locate the SPI I/O Protocol for the SPI flash part | |
| // that supports JEDEC SFDP specification. | |
| // | |
| InstanceBufferSize = 0; | |
| InstanceBuffer = NULL; | |
| Status = gSmst->SmmLocateHandle ( | |
| ByProtocol, | |
| &gEdk2JedecSfdpSpiSmmDriverGuid, | |
| NULL, | |
| &InstanceBufferSize, | |
| InstanceBuffer | |
| ); | |
| if (Status == EFI_NOT_FOUND) { | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "No gEdk2JedecSfdpSpiSmmDriverGuid handles found at the moment, wait for the notification of SPI I/O protocol installation.\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status)); | |
| return EFI_SUCCESS; | |
| } else if (Status == EFI_BUFFER_TOO_SMALL) { | |
| InstanceBuffer = (EFI_HANDLE *)AllocateZeroPool (InstanceBufferSize); | |
| ASSERT (InstanceBuffer != NULL); | |
| if (InstanceBuffer == NULL) { | |
| DEBUG ((DEBUG_ERROR, "Not enough resource for gEdk2JedecSfdpSpiSmmDriverGuid handles.\n")); | |
| DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status)); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| } else if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "Error to locate gEdk2JedecSfdpSpiSmmDriverGuid - Status = %r.\n", Status)); | |
| DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status)); | |
| return Status; | |
| } | |
| Status = gSmst->SmmLocateHandle ( | |
| ByProtocol, | |
| &gEdk2JedecSfdpSpiSmmDriverGuid, | |
| NULL, | |
| &InstanceBufferSize, | |
| InstanceBuffer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "Fail to locate all gEdk2JedecSfdpSpiSmmDriverGuid handles.\n")); | |
| DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status)); | |
| return Status; | |
| } | |
| DEBUG ((DEBUG_INFO, "%d of gEdk2JedecSfdpSpiSmmDriverGuid handles are found.\n", InstanceBufferSize / sizeof (EFI_HANDLE))); | |
| for (InstanceIndex = 0; InstanceIndex < InstanceBufferSize / sizeof (EFI_HANDLE); InstanceIndex++) { | |
| Status = CreateSpiNorFlashSfdpInstance (*(InstanceBuffer + InstanceIndex)); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "Fail to create SPI NOR Flash SFDP instance #%d.\n", InstanceIndex)); | |
| } | |
| } | |
| DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status)); | |
| return Status; | |
| } |