123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587 |
- /** @file
- The UEFI driver model driver which is responsible for locating the
- Redfish service through Redfish host interface and executing EDKII
- Redfish feature drivers.
- Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
- (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "RedfishConfigHandlerDriver.h"
- EFI_EVENT gEfiRedfishDiscoverProtocolEvent = NULL;
- //
- // Variables for using RFI Redfish Discover Protocol
- //
- VOID *gEfiRedfishDiscoverRegistration;
- EFI_HANDLE gEfiRedfishDiscoverControllerHandle = NULL;
- EFI_REDFISH_DISCOVER_PROTOCOL *gEfiRedfishDiscoverProtocol = NULL;
- BOOLEAN gRedfishDiscoverActivated = FALSE;
- BOOLEAN gRedfishServiceDiscovered = FALSE;
- //
- // Network interfaces discovered by EFI Redfish Discover Protocol.
- //
- UINTN gNumberOfNetworkInterfaces;
- EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *gNetworkInterfaceInstances = NULL;
- EFI_REDFISH_DISCOVERED_TOKEN *gRedfishDiscoveredToken = NULL;
- ///
- /// Driver Binding Protocol instance
- ///
- EFI_DRIVER_BINDING_PROTOCOL gRedfishConfigDriverBinding = {
- RedfishConfigDriverBindingSupported,
- RedfishConfigDriverBindingStart,
- RedfishConfigDriverBindingStop,
- REDFISH_CONFIG_VERSION,
- NULL,
- NULL
- };
- /**
- Stop acquiring Redfish service.
- **/
- VOID
- RedfishConfigStopRedfishDiscovery (
- VOID
- )
- {
- if (gRedfishDiscoverActivated) {
- //
- // No more EFI Discover Protocol.
- //
- if (gEfiRedfishDiscoverProtocolEvent != NULL) {
- gBS->CloseEvent (gEfiRedfishDiscoverProtocolEvent);
- }
- //
- // Stop Redfish service discovery.
- //
- gEfiRedfishDiscoverProtocol->AbortAcquireRedfishService (
- gEfiRedfishDiscoverProtocol,
- gNetworkInterfaceInstances
- );
- gEfiRedfishDiscoverControllerHandle = NULL;
- gEfiRedfishDiscoverProtocol = NULL;
- gRedfishDiscoverActivated = FALSE;
- gRedfishServiceDiscovered = FALSE;
- }
- }
- /**
- Callback function executed when a Redfish Config Handler Protocol is installed.
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context Pointer to the REDFISH_CONFIG_DRIVER_DATA buffer.
- **/
- VOID
- EFIAPI
- RedfishConfigHandlerInstalledCallback (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- if (!gRedfishDiscoverActivated) {
- //
- // No Redfish service is discovered yet.
- //
- return;
- }
- RedfishConfigHandlerInitialization ();
- }
- /**
- Tests to see if this driver supports a given controller. If a child device is provided,
- it further tests to see if this driver supports creating a handle for the specified child device.
- This function checks to see if the driver specified by This supports the device specified by
- ControllerHandle. Drivers will typically use the device path attached to
- ControllerHandle and/or the services from the bus I/O abstraction attached to
- ControllerHandle to determine if the driver supports ControllerHandle. This function
- may be called many times during platform initialization. In order to reduce boot times, the tests
- performed by this function must be very small, and take as little time as possible to execute. This
- function must not change the state of any hardware devices, and this function must be aware that the
- device specified by ControllerHandle may already be managed by the same driver or a
- different driver. This function must match its calls to AllocatePages() with FreePages(),
- AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
- Because ControllerHandle may have been previously started by the same driver, if a protocol is
- already in the opened state, then it must not be closed with CloseProtocol(). This is required
- to guarantee the state of ControllerHandle is not modified by this function.
- @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
- @param[in] ControllerHandle The handle of the controller to test. This handle
- must support a protocol interface that supplies
- an I/O abstraction to the driver.
- @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
- parameter is ignored by device drivers, and is optional for bus
- drivers. For bus drivers, if this parameter is not NULL, then
- the bus driver must determine if the bus controller specified
- by ControllerHandle and the child controller specified
- by RemainingDevicePath are both supported by this
- bus driver.
- @retval EFI_SUCCESS The device specified by ControllerHandle and
- RemainingDevicePath is supported by the driver specified by This.
- @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
- RemainingDevicePath is not supported by the driver specified by This.
- **/
- EFI_STATUS
- EFIAPI
- RedfishConfigDriverBindingSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
- {
- EFI_REST_EX_PROTOCOL *RestEx;
- EFI_STATUS Status;
- EFI_HANDLE ChildHandle;
- ChildHandle = NULL;
- //
- // Check if REST EX is ready. This just makes sure
- // the network stack is brought up.
- //
- Status = NetLibCreateServiceChild (
- ControllerHandle,
- This->ImageHandle,
- &gEfiRestExServiceBindingProtocolGuid,
- &ChildHandle
- );
- if (EFI_ERROR (Status)) {
- return EFI_UNSUPPORTED;
- }
- //
- // Test if REST EX protocol is ready.
- //
- Status = gBS->OpenProtocol(
- ChildHandle,
- &gEfiRestExProtocolGuid,
- (VOID**) &RestEx,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- Status = EFI_UNSUPPORTED;
- }
- NetLibDestroyServiceChild (
- ControllerHandle,
- This->ImageHandle,
- &gEfiRestExServiceBindingProtocolGuid,
- ChildHandle
- );
- return Status;
- }
- /**
- Starts a device controller or a bus controller.
- The Start() function is designed to be invoked from the EFI boot service ConnectController().
- As a result, much of the error checking on the parameters to Start() has been moved into this
- common boot service. It is legal to call Start() from other locations,
- but the following calling restrictions must be followed, or the system behavior will not be deterministic.
- 1. ControllerHandle must be a valid EFI_HANDLE.
- 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
- EFI_DEVICE_PATH_PROTOCOL.
- 3. Prior to calling Start(), the Supported() function for the driver specified by This must
- have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
- @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
- @param[in] ControllerHandle The handle of the controller to start. This handle
- must support a protocol interface that supplies
- an I/O abstraction to the driver.
- @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
- parameter is ignored by device drivers, and is optional for bus
- drivers. For a bus driver, if this parameter is NULL, then handles
- for all the children of Controller are created by this driver.
- If this parameter is not NULL and the first Device Path Node is
- not the End of Device Path Node, then only the handle for the
- child device specified by the first Device Path Node of
- RemainingDevicePath is created by this driver.
- If the first Device Path Node of RemainingDevicePath is
- the End of Device Path Node, no child handle is created by this
- driver.
- @retval EFI_SUCCESS The driver is started.
- @retval EFI_ALREADY_STARTED The driver was already started.
- **/
- EFI_STATUS
- EFIAPI
- RedfishConfigDriverBindingStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
- {
- VOID *ConfigHandlerRegistration;
- if (gRedfishConfigData.Event != NULL) {
- return EFI_ALREADY_STARTED;
- }
- gRedfishConfigData.Event = EfiCreateProtocolNotifyEvent (
- &gEdkIIRedfishConfigHandlerProtocolGuid,
- TPL_CALLBACK,
- RedfishConfigHandlerInstalledCallback,
- (VOID *)&gRedfishConfigData,
- &ConfigHandlerRegistration
- );
- return EFI_SUCCESS;
- }
- /**
- Stops a device controller or a bus controller.
- The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
- As a result, much of the error checking on the parameters to Stop() has been moved
- into this common boot service. It is legal to call Stop() from other locations,
- but the following calling restrictions must be followed, or the system behavior will not be deterministic.
- 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
- same driver's Start() function.
- 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
- EFI_HANDLE. In addition, all of these handles must have been created in this driver's
- Start() function, and the Start() function must have called OpenProtocol() on
- ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
- @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
- @param[in] ControllerHandle A handle to the device being stopped. The handle must
- support a bus specific I/O protocol for the driver
- to use to stop the device.
- @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
- @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
- if NumberOfChildren is 0.
- @retval EFI_SUCCESS The device was stopped.
- @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
- **/
- EFI_STATUS
- EFIAPI
- RedfishConfigDriverBindingStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
- )
- {
- EFI_STATUS Status;
- if (ControllerHandle == gEfiRedfishDiscoverControllerHandle) {
- RedfishConfigStopRedfishDiscovery ();
- }
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiRedfishDiscoverProtocolGuid,
- gRedfishConfigData.Image,
- gRedfishConfigData.Image
- );
- Status = RedfishConfigCommonStop ();
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
- if (gRedfishConfigData.Event != NULL) {
- gBS->CloseEvent (gRedfishConfigData.Event);
- gRedfishConfigData.Event = NULL;
- }
- return EFI_SUCCESS;
- }
- /**
- Callback function when Redfish service is discovered.
- @param[in] Event Event whose notification function is being invoked.
- @param[out] Context Pointer to the Context buffer
- **/
- VOID
- EFIAPI
- RedfishServiceDiscoveredCallback (
- IN EFI_EVENT Event,
- OUT VOID *Context
- )
- {
- EFI_REDFISH_DISCOVERED_TOKEN *RedfishDiscoveredToken;
- EFI_REDFISH_DISCOVERED_INSTANCE *RedfishInstance;
- if (gRedfishServiceDiscovered) {
- //
- // Only support one Redfish service on platform.
- //
- return;
- }
- RedfishDiscoveredToken = (EFI_REDFISH_DISCOVERED_TOKEN *)Context;
- RedfishInstance = RedfishDiscoveredToken->DiscoverList.RedfishInstances;
- //
- // Only pick up the first found Redfish service.
- //
- if (RedfishInstance->Status == EFI_SUCCESS) {
- gRedfishConfigData.RedfishServiceInfo.RedfishServiceRestExHandle = RedfishInstance->Information.RedfishRestExHandle;
- gRedfishConfigData.RedfishServiceInfo.RedfishServiceVersion = RedfishInstance->Information.RedfishVersion;
- gRedfishConfigData.RedfishServiceInfo.RedfishServiceLocation = RedfishInstance->Information.Location;
- gRedfishConfigData.RedfishServiceInfo.RedfishServiceUuid = RedfishInstance->Information.Uuid;
- gRedfishConfigData.RedfishServiceInfo.RedfishServiceOs = RedfishInstance->Information.Os;
- gRedfishConfigData.RedfishServiceInfo.RedfishServiceOsVersion = RedfishInstance->Information.OsVersion;
- gRedfishConfigData.RedfishServiceInfo.RedfishServiceProduct = RedfishInstance->Information.Product;
- gRedfishConfigData.RedfishServiceInfo.RedfishServiceProductVer = RedfishInstance->Information.ProductVer;
- gRedfishConfigData.RedfishServiceInfo.RedfishServiceUseHttps = RedfishInstance->Information.UseHttps;
- gRedfishServiceDiscovered = TRUE;
- }
- //
- // Invoke RedfishConfigHandlerInstalledCallback to execute
- // the initialization of Redfish Configure Handler instance.
- //
- RedfishConfigHandlerInstalledCallback (gRedfishConfigData.Event, &gRedfishConfigData);
- }
- /**
- Callback function executed when the EFI_REDFISH_DISCOVER_PROTOCOL
- protocol interface is installed.
- @param[in] Event Event whose notification function is being invoked.
- @param[out] Context Pointer to the Context buffer
- **/
- VOID
- EFIAPI
- RedfishDiscoverProtocolInstalled (
- IN EFI_EVENT Event,
- OUT VOID *Context
- )
- {
- EFI_STATUS Status;
- UINTN BufferSize;
- EFI_HANDLE HandleBuffer;
- UINTN NetworkInterfaceIndex;
- EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *ThisNetworkInterface;
- EFI_REDFISH_DISCOVERED_TOKEN *ThisRedfishDiscoveredToken;
- DEBUG((DEBUG_INFO, "%a: New network interface is installed on system by EFI Redfish discover driver.\n", __FUNCTION__));
- BufferSize = sizeof (EFI_HANDLE);
- Status = gBS->LocateHandle (
- ByRegisterNotify,
- NULL,
- gEfiRedfishDiscoverRegistration,
- &BufferSize,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- DEBUG((DEBUG_ERROR, "%a: Can't locate handle with EFI_REDFISH_DISCOVER_PROTOCOL installed.\n", __FUNCTION__));
- }
- gRedfishDiscoverActivated = TRUE;
- if (gEfiRedfishDiscoverProtocol == NULL) {
- gEfiRedfishDiscoverControllerHandle = HandleBuffer;
- //
- // First time to open EFI_REDFISH_DISCOVER_PROTOCOL.
- //
- Status = gBS->OpenProtocol(
- gEfiRedfishDiscoverControllerHandle,
- &gEfiRedfishDiscoverProtocolGuid,
- (VOID **)&gEfiRedfishDiscoverProtocol,
- gRedfishConfigData.Image,
- gRedfishConfigData.Image,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- gEfiRedfishDiscoverProtocol = NULL;
- gRedfishDiscoverActivated = FALSE;
- DEBUG((DEBUG_ERROR, "%a: Can't locate EFI_REDFISH_DISCOVER_PROTOCOL.\n", __FUNCTION__));
- return;
- }
- }
- //
- // Check the new found network interface.
- //
- if (gNetworkInterfaceInstances != NULL) {
- FreePool (gNetworkInterfaceInstances);
- }
- Status = gEfiRedfishDiscoverProtocol->GetNetworkInterfaceList(
- gEfiRedfishDiscoverProtocol,
- gRedfishConfigData.Image,
- &gNumberOfNetworkInterfaces,
- &gNetworkInterfaceInstances
- );
- if (EFI_ERROR (Status) || gNumberOfNetworkInterfaces == 0) {
- DEBUG((DEBUG_ERROR, "%a: No network interfaces found on the handle.\n", __FUNCTION__));
- return;
- }
- gRedfishDiscoveredToken = AllocateZeroPool (gNumberOfNetworkInterfaces * sizeof (EFI_REDFISH_DISCOVERED_TOKEN));
- if (gRedfishDiscoveredToken == NULL) {
- DEBUG((DEBUG_ERROR, "%a: Not enough memory for EFI_REDFISH_DISCOVERED_TOKEN.\n", __FUNCTION__));
- return;
- }
- ThisNetworkInterface = gNetworkInterfaceInstances;
- ThisRedfishDiscoveredToken = gRedfishDiscoveredToken;
- //
- // Loop to discover Redfish service on each network interface.
- //
- for (NetworkInterfaceIndex = 0; NetworkInterfaceIndex < gNumberOfNetworkInterfaces; NetworkInterfaceIndex ++) {
- //
- // Initial this Redfish Discovered Token
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- RedfishServiceDiscoveredCallback,
- (VOID *)ThisRedfishDiscoveredToken,
- &ThisRedfishDiscoveredToken->Event
- );
- if (EFI_ERROR (Status)) {
- DEBUG((DEBUG_ERROR, "%a: Failed to create event for Redfish discovered token.\n", __FUNCTION__));
- goto ErrorReturn;
- }
- ThisRedfishDiscoveredToken->Signature = REDFISH_DISCOVER_TOKEN_SIGNATURE;
- ThisRedfishDiscoveredToken->DiscoverList.NumberOfServiceFound = 0;
- ThisRedfishDiscoveredToken->DiscoverList.RedfishInstances = NULL;
- //
- // Acquire for Redfish service which is reported by
- // Redfish Host Interface.
- //
- Status = gEfiRedfishDiscoverProtocol->AcquireRedfishService(
- gEfiRedfishDiscoverProtocol,
- gRedfishConfigData.Image,
- ThisNetworkInterface,
- EFI_REDFISH_DISCOVER_HOST_INTERFACE,
- ThisRedfishDiscoveredToken
- );
- ThisNetworkInterface ++;
- ThisRedfishDiscoveredToken ++;
- }
- if (EFI_ERROR (Status)) {
- DEBUG((DEBUG_ERROR, "%a: Acquire Redfish service fail.\n", __FUNCTION__));
- goto ErrorReturn;
- }
- return;
- ErrorReturn:
- if (gRedfishDiscoveredToken != NULL) {
- FreePool(gRedfishDiscoveredToken);
- }
- }
- /**
- Unloads an image.
- @param[in] ImageHandle Handle that identifies the image to be unloaded.
- @retval EFI_SUCCESS The image has been unloaded.
- **/
- EFI_STATUS
- EFIAPI
- RedfishConfigHandlerDriverUnload (
- IN EFI_HANDLE ImageHandle
- )
- {
- EFI_REDFISH_DISCOVERED_TOKEN *ThisRedfishDiscoveredToken;
- UINTN NumberOfNetworkInterfacesIndex;
- RedfishConfigDriverCommonUnload (ImageHandle);
- RedfishConfigStopRedfishDiscovery ();
- if (gRedfishDiscoveredToken != NULL) {
- ThisRedfishDiscoveredToken = gRedfishDiscoveredToken;
- for (NumberOfNetworkInterfacesIndex = 0; NumberOfNetworkInterfacesIndex < gNumberOfNetworkInterfaces; NumberOfNetworkInterfacesIndex ++) {
- if (ThisRedfishDiscoveredToken->Event != NULL) {
- gBS->CloseEvent (ThisRedfishDiscoveredToken->Event);
- }
- FreePool (ThisRedfishDiscoveredToken);
- ThisRedfishDiscoveredToken ++;
- }
- gRedfishDiscoveredToken = NULL;
- }
- return EFI_SUCCESS;
- }
- /**
- This is the declaration of an EFI image entry point. This entry point is
- the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
- both device drivers and bus drivers.
- @param[in] ImageHandle The firmware allocated handle for the UEFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
- @retval EFI_SUCCESS The operation completed successfully.
- @retval Others An unexpected error occurred.
- **/
- EFI_STATUS
- EFIAPI
- RedfishConfigHandlerDriverEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- ZeroMem ((VOID *)&gRedfishConfigData, sizeof (REDFISH_CONFIG_DRIVER_DATA));
- gRedfishConfigData.Image = ImageHandle;
- //
- // Register event for EFI_REDFISH_DISCOVER_PROTOCOL protocol install
- // notification.
- //
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- RedfishDiscoverProtocolInstalled,
- NULL,
- &gEfiRedfishDiscoverProtocolGuid,
- &gEfiRedfishDiscoverProtocolEvent
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "%a: Fail to create event for the installation of EFI_REDFISH_DISCOVER_PROTOCOL.", __FUNCTION__));
- return Status;
- }
- Status = gBS->RegisterProtocolNotify (
- &gEfiRedfishDiscoverProtocolGuid,
- gEfiRedfishDiscoverProtocolEvent,
- &gEfiRedfishDiscoverRegistration
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the installation of EFI_REDFISH_DISCOVER_PROTOCOL.", __FUNCTION__));
- return Status;
- }
- Status = RedfishConfigCommonInit (ImageHandle, SystemTable);
- if (EFI_ERROR (Status)) {
- gBS->CloseEvent (gEfiRedfishDiscoverProtocolEvent);
- gEfiRedfishDiscoverProtocolEvent = NULL;
- return Status;
- }
- //
- // Install UEFI Driver Model protocol(s).
- //
- Status = EfiLibInstallDriverBinding (
- ImageHandle,
- SystemTable,
- &gRedfishConfigDriverBinding,
- ImageHandle
- );
- if (EFI_ERROR (Status)) {
- gBS->CloseEvent (gEndOfDxeEvent);
- gEndOfDxeEvent = NULL;
- gBS->CloseEvent (gExitBootServiceEvent);
- gExitBootServiceEvent = NULL;
- gBS->CloseEvent (gEfiRedfishDiscoverProtocolEvent);
- gEfiRedfishDiscoverProtocolEvent = NULL;
- DEBUG ((DEBUG_ERROR, "%a: Fail to install EFI Binding Protocol of EFI Redfish Config driver.", __FUNCTION__));
- return Status;
- }
- return Status;
- }
|