| /** @file | |
| RedfishHostInterfaceDxe builds up SMBIOS Type 42h host interface | |
| record for Redfish service host interface using EFI MBIOS Protocol. | |
| RedfishHostInterfacePlatformLib is the platform-level library which | |
| provides the content of Redfish host interface type 42h record. | |
| Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> | |
| (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR> | |
| Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved.<BR> | |
| Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Uefi.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/PrintLib.h> | |
| #include <Library/RedfishHostInterfaceLib.h> | |
| #include <Library/UefiLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/UefiRuntimeServicesTableLib.h> | |
| static EFI_EVENT mPlatformHostInterfaceReadylEvent = NULL; | |
| static VOID *mPlatformHostInterfaceReadyRegistration = NULL; | |
| /** | |
| Create SMBIOS type 42 record for Redfish host interface. | |
| @retval EFI_SUCCESS SMBIOS type 42 record is created. | |
| @retval Others Fail to create SMBIOS 42 record. | |
| **/ | |
| EFI_STATUS | |
| RedfishCreateSmbiosTable42 ( | |
| VOID | |
| ) | |
| { | |
| REDFISH_INTERFACE_DATA *DeviceDescriptor; | |
| UINT8 DeviceDataLength; | |
| UINT8 DeviceType; | |
| EFI_STATUS Status; | |
| MC_HOST_INTERFACE_PROTOCOL_RECORD *ProtocolRecord; | |
| VOID *ProtocolRecords; | |
| VOID *NewProtocolRecords; | |
| UINT8 ProtocolCount; | |
| UINT8 CurrentProtocolsDataLength; | |
| UINT8 NewProtocolsDataLength; | |
| UINT8 ProtocolDataSize; | |
| SMBIOS_TABLE_TYPE42 *Type42Record; | |
| EFI_SMBIOS_PROTOCOL *Smbios; | |
| EFI_SMBIOS_HANDLE MemArrayMappedAddrSmbiosHandle; | |
| EFI_HANDLE Handle; | |
| Handle = NULL; | |
| // | |
| // Get platform Redfish host interface device type descriptor data. | |
| // | |
| Status = RedfishPlatformHostInterfaceDeviceDescriptor (&DeviceType, &DeviceDescriptor); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_FOUND) { | |
| DEBUG ((DEBUG_ERROR, "%a: No Redfish host interface descriptor is provided on this platform.\n", __func__)); | |
| return EFI_NOT_FOUND; | |
| } | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to get device descriptor, %r.", __func__, Status)); | |
| return Status; | |
| } | |
| if ((DeviceType != REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2) && | |
| (DeviceType != REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) | |
| ) | |
| { | |
| DEBUG ((DEBUG_ERROR, "%a: Only support either protocol type 04h or 05h as Redfish host interface.", __func__)); | |
| return EFI_UNSUPPORTED; | |
| } | |
| if (DeviceType == REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) { | |
| DeviceDataLength = DeviceDescriptor->DeviceDescriptor.PciPcieDeviceV2.Length; | |
| } else { | |
| DeviceDataLength = DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.Length; | |
| } | |
| // | |
| // Loop to get platform Redfish host interface protocol type data. | |
| // | |
| ProtocolRecord = NULL; | |
| ProtocolRecords = NULL; | |
| NewProtocolRecords = NULL; | |
| Type42Record = NULL; | |
| ProtocolCount = 0; | |
| CurrentProtocolsDataLength = 0; | |
| NewProtocolsDataLength = 0; | |
| while (TRUE) { | |
| Status = RedfishPlatformHostInterfaceProtocolData (&ProtocolRecord, ProtocolCount); | |
| if (Status == EFI_NOT_FOUND) { | |
| break; | |
| } | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to get Redfish host interafce protocol type data.", __func__)); | |
| if (ProtocolRecords != NULL) { | |
| FreePool (ProtocolRecords); | |
| } | |
| if (ProtocolRecord != NULL) { | |
| FreePool (ProtocolRecord); | |
| } | |
| return Status; | |
| } | |
| ProtocolDataSize = sizeof (MC_HOST_INTERFACE_PROTOCOL_RECORD) - sizeof (ProtocolRecord->ProtocolTypeData) + ProtocolRecord->ProtocolTypeDataLen; | |
| NewProtocolsDataLength += ProtocolDataSize; | |
| if (ProtocolRecords == NULL) { | |
| ProtocolRecords = AllocateZeroPool (NewProtocolsDataLength); | |
| if (ProtocolRecords == NULL) { | |
| FreePool (ProtocolRecord); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| CopyMem ((VOID *)ProtocolRecords, (VOID *)ProtocolRecord, ProtocolDataSize); | |
| NewProtocolRecords = ProtocolRecords; | |
| } else { | |
| NewProtocolRecords = ReallocatePool (CurrentProtocolsDataLength, NewProtocolsDataLength, (VOID *)ProtocolRecords); | |
| if (NewProtocolRecords == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for Redfish host interface protocol data.", __func__)); | |
| FreePool (ProtocolRecords); | |
| FreePool (ProtocolRecord); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| CopyMem ( | |
| (VOID *)((UINT8 *)NewProtocolRecords + CurrentProtocolsDataLength), | |
| (VOID *)ProtocolRecord, | |
| ProtocolDataSize | |
| ); | |
| } | |
| FreePool (ProtocolRecord); | |
| CurrentProtocolsDataLength = NewProtocolsDataLength; | |
| ProtocolCount++; | |
| } | |
| if (ProtocolCount == 0) { | |
| goto ON_EXIT; | |
| } | |
| // | |
| // Construct SMBIOS Type 42h for Redfish host inteface. | |
| // | |
| // SMBIOS type 42 Record for Redfish Interface | |
| // 00h Type BYTE 42 Management Controller Host Interface structure indicator | |
| // 01h Length BYTE Varies Length of the structure, a minimum of 09h | |
| // 02h Handle WORD Varies | |
| // 04h Interface Type BYTE Varies Management Controller Interface Type. | |
| // 05h Interface Specific Data Length (n) | |
| // 06h Interface Specific data | |
| // 06h+n number of protocols defined for the host interface (typically 1) | |
| // 07h+n Include a Protocol Record for each protocol supported. | |
| // | |
| Type42Record = (SMBIOS_TABLE_TYPE42 *)AllocateZeroPool ( | |
| sizeof (SMBIOS_TABLE_TYPE42) - 4 | |
| + DeviceDataLength | |
| + 1 /// For Protocol Record Count | |
| + CurrentProtocolsDataLength | |
| + 2 /// Double NULL terminator/ | |
| ); | |
| if (Type42Record == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto ON_EXIT; | |
| } | |
| Type42Record->Hdr.Type = EFI_SMBIOS_TYPE_MANAGEMENT_CONTROLLER_HOST_INTERFACE; | |
| Type42Record->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE42) - 4 | |
| + DeviceDataLength | |
| + 1 | |
| + CurrentProtocolsDataLength; | |
| Type42Record->Hdr.Handle = 0; | |
| Type42Record->InterfaceType = MCHostInterfaceTypeNetworkHostInterface; // Network Host Interface | |
| // | |
| // Fill in InterfaceTypeSpecificDataLength field | |
| // | |
| Type42Record->InterfaceTypeSpecificDataLength = DeviceDataLength; | |
| // | |
| // Fill in InterfaceTypeSpecificData field | |
| // | |
| CopyMem (Type42Record->InterfaceTypeSpecificData, DeviceDescriptor, DeviceDataLength); | |
| FreePool (DeviceDescriptor); | |
| DeviceDescriptor = NULL; | |
| // | |
| // Fill in InterfaceTypeSpecificData Protocol Count field | |
| // | |
| *(Type42Record->InterfaceTypeSpecificData + DeviceDataLength) = ProtocolCount; | |
| // | |
| // Fill in Redfish Protocol Data | |
| // | |
| CopyMem ( | |
| Type42Record->InterfaceTypeSpecificData + DeviceDataLength + 1, | |
| NewProtocolRecords, | |
| CurrentProtocolsDataLength | |
| ); | |
| // | |
| // 5. Add Redfish interface data record to SMBIOS table 42 | |
| // | |
| Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_EXIT; | |
| } | |
| MemArrayMappedAddrSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; | |
| Status = Smbios->Add ( | |
| Smbios, | |
| NULL, | |
| &MemArrayMappedAddrSmbiosHandle, | |
| (EFI_SMBIOS_TABLE_HEADER *)Type42Record | |
| ); | |
| DEBUG ((DEBUG_MANAGEABILITY, "RedfishPlatformDxe: Smbios->Add() - %r\n", Status)); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_EXIT; | |
| } | |
| // | |
| // Install Redfish Host Interface ready protocol. | |
| // | |
| Status = gBS->InstallProtocolInterface ( | |
| &Handle, | |
| &gEdkIIRedfishHostInterfaceReadyProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| (VOID *)NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "Failed to install gEdkIIRedfishHostInterfaceReadyProtocolGuid.\n")); | |
| DEBUG ((DEBUG_ERROR, "PlatformConfigHandler driver may not be triggered to acquire Redfish service.\n")); | |
| } | |
| // Set Status to EFI_SUCCESS that indicates SMBIOS 42 record was installed | |
| // on the platform sucessfully. | |
| Status = EFI_SUCCESS; | |
| ON_EXIT: | |
| if (DeviceDescriptor != NULL) { | |
| FreePool (DeviceDescriptor); | |
| } | |
| if (NewProtocolRecords != NULL) { | |
| FreePool (NewProtocolRecords); | |
| } | |
| if (Type42Record != NULL) { | |
| FreePool (Type42Record); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Notification event of platform Redfish Host Interface readiness. | |
| @param[in] Event Event whose notification function is being invoked. | |
| @param[in] Context The pointer to the notification function's context, | |
| which is implementation-dependent. | |
| **/ | |
| VOID | |
| EFIAPI | |
| PlatformHostInterfaceInformationReady ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| DEBUG ((DEBUG_MANAGEABILITY, "%a: Platform Redfish Host Interface informtion is ready\n", __func__)); | |
| RedfishCreateSmbiosTable42 (); | |
| // | |
| // Close event so we don't create multiple type 42 records | |
| // | |
| gBS->CloseEvent (Event); | |
| mPlatformHostInterfaceReadylEvent = NULL; | |
| return; | |
| } | |
| /** | |
| Main entry for this driver. | |
| @param ImageHandle Image handle this driver. | |
| @param SystemTable Pointer to SystemTable. | |
| @retval EFI_SUCCESS This function always complete successfully. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RedfishHostInterfaceDxeEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_GUID *ReadyGuid; | |
| DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n.", __func__)); | |
| // | |
| // Check if the Redfish Host Interface depends on | |
| // the specific protocol installation. | |
| // | |
| Status = RedfishPlatformHostInterfaceNotification (&ReadyGuid); | |
| if (Status == EFI_SUCCESS) { | |
| DEBUG ((DEBUG_MANAGEABILITY, " Create protocol install notification to know the installation of platform Redfish host interface readiness\n")); | |
| DEBUG ((DEBUG_MANAGEABILITY, " Protocol GUID: %g\n", ReadyGuid)); | |
| // | |
| // Register event for ReadyGuid protocol installed by | |
| // platform Redfish host interface library. | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_CALLBACK, | |
| PlatformHostInterfaceInformationReady, | |
| NULL, | |
| &mPlatformHostInterfaceReadylEvent | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, " Fail to create event for the installation of platform Redfish host interface readiness.\n")); | |
| return Status; | |
| } | |
| Status = gBS->RegisterProtocolNotify ( | |
| ReadyGuid, | |
| mPlatformHostInterfaceReadylEvent, | |
| &mPlatformHostInterfaceReadyRegistration | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, " Fail to register event for the installation of platform Redfish host interface readiness.\n")); | |
| return Status; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| if ((Status == EFI_UNSUPPORTED) || (Status == EFI_ALREADY_STARTED)) { | |
| Status = RedfishCreateSmbiosTable42 (); | |
| } | |
| // Return other erros. | |
| return Status; | |
| } |