/** @file PiSmmCommunication SMM Driver. Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include "PiSmmCommunicationPrivate.h" EFI_SMM_COMMUNICATION_CONTEXT mSmmCommunicationContext = { SMM_COMMUNICATION_SIGNATURE }; /** Set SMM communication context. **/ VOID SetCommunicationContext ( VOID ) { EFI_STATUS Status; Status = gSmst->SmmInstallConfigurationTable ( gSmst, &gEfiPeiSmmCommunicationPpiGuid, &mSmmCommunicationContext, sizeof(mSmmCommunicationContext) ); ASSERT_EFI_ERROR (Status); } /** Dispatch function for a Software SMI handler. @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). @param Context Points to an optional handler context which was specified when the handler was registered. @param CommBuffer A pointer to a collection of data in memory that will be conveyed from a non-SMM environment into an SMM environment. @param CommBufferSize The size of the CommBuffer. @retval EFI_SUCCESS Command is handled successfully. **/ EFI_STATUS EFIAPI PiSmmCommunicationHandler ( IN EFI_HANDLE DispatchHandle, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL ) { UINTN CommSize; EFI_STATUS Status; EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader; EFI_PHYSICAL_ADDRESS *BufferPtrAddress; DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Enter\n")); BufferPtrAddress = (EFI_PHYSICAL_ADDRESS *)(UINTN)mSmmCommunicationContext.BufferPtrAddress; CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)(UINTN)*BufferPtrAddress; DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader - %x\n", CommunicateHeader)); if (CommunicateHeader == NULL) { DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler is NULL, needn't to call dispatch function\n")); Status = EFI_SUCCESS; } else { if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicateHeader, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))) { DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader invalid - 0x%x\n", CommunicateHeader)); Status = EFI_SUCCESS; goto Done; } CommSize = (UINTN)CommunicateHeader->MessageLength; if (!SmmIsBufferOutsideSmmValid ((UINTN)&CommunicateHeader->Data[0], CommSize)) { DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateData invalid - 0x%x\n", &CommunicateHeader->Data[0])); Status = EFI_SUCCESS; goto Done; } // // Call dispatch function // DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Data - %x\n", &CommunicateHeader->Data[0])); Status = gSmst->SmiManage ( &CommunicateHeader->HeaderGuid, NULL, &CommunicateHeader->Data[0], &CommSize ); } Done: DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler %r\n", Status)); DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Exit\n")); return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_INTERRUPT_PENDING; } /** Allocate EfiACPIMemoryNVS below 4G memory address. This function allocates EfiACPIMemoryNVS below 4G memory address. @param Size Size of memory to allocate. @return Allocated address for output. **/ VOID* AllocateAcpiNvsMemoryBelow4G ( IN UINTN Size ) { UINTN Pages; EFI_PHYSICAL_ADDRESS Address; EFI_STATUS Status; VOID* Buffer; Pages = EFI_SIZE_TO_PAGES (Size); Address = 0xffffffff; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiACPIMemoryNVS, Pages, &Address ); ASSERT_EFI_ERROR (Status); Buffer = (VOID *) (UINTN) Address; ZeroMem (Buffer, Size); return Buffer; } /** Entry Point for PI SMM communication SMM driver. @param[in] ImageHandle Image handle of this driver. @param[in] SystemTable A Pointer to the EFI System Table. @retval EFI_SUCEESS @return Others Some error occurs. **/ EFI_STATUS EFIAPI PiSmmCommunicationSmmEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_SMM_SW_DISPATCH2_PROTOCOL *SmmSwDispatch2; EFI_SMM_SW_REGISTER_CONTEXT SmmSwDispatchContext; EFI_HANDLE DispatchHandle; EFI_PHYSICAL_ADDRESS *BufferPtrAddress; // // Register software SMI handler // Status = gSmst->SmmLocateProtocol ( &gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID **)&SmmSwDispatch2 ); ASSERT_EFI_ERROR (Status); SmmSwDispatchContext.SwSmiInputValue = (UINTN)-1; Status = SmmSwDispatch2->Register ( SmmSwDispatch2, PiSmmCommunicationHandler, &SmmSwDispatchContext, &DispatchHandle ); ASSERT_EFI_ERROR (Status); DEBUG ((EFI_D_INFO, "SmmCommunication SwSmi: %x\n", (UINTN)SmmSwDispatchContext.SwSmiInputValue)); BufferPtrAddress = AllocateAcpiNvsMemoryBelow4G (sizeof(EFI_PHYSICAL_ADDRESS)); ASSERT (BufferPtrAddress != NULL); DEBUG ((EFI_D_INFO, "SmmCommunication BufferPtrAddress: 0x%016lx, BufferPtr: 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress, *BufferPtrAddress)); // // Save context // mSmmCommunicationContext.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue; mSmmCommunicationContext.BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress; SetCommunicationContext (); return Status; }